diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..a500f44 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,5 @@ +Examples: + +* Getting started with a [basic octoDNS configuration](basic/) - new to octoDNS + this is the place to start. It'll walk you through the main pieces of DNS IaC + with octoDNS including the process of planning and applying changes. diff --git a/examples/basic/README.md b/examples/basic/README.md new file mode 100644 index 0000000..e485ff7 --- /dev/null +++ b/examples/basic/README.md @@ -0,0 +1,250 @@ +## Basic octoDNS Setup + +This is the starting point octoDNS config, it's pretty similar to what you +might see for managing a set of personal domains or a small business. + +Most of the actual documentation for this example is in comments in the YAML configuration files. + +* [config/octodns.yaml](config/octodns.yaml) +* [config/my-domain.com.yaml](config/my-domain.com.yaml) +* [config/unused.io.yaml](config/unused.io.yaml) + +From here on this README focuses on the general process of running octoDNS. + +## Checking out the code and setting up the environment + +You would not normally need to check out octoDNS itself, you instead would have +a git repo with only your configuration files. Here we're cloing the repo only +to get a copy of the example files. + +```console +$ git clone https://github.com/octodns/octodns.git +$ cd octodns/examples/basic/ +$ python3 -mvenv env +$ source env/bin/activate +(env) $ pip install -r requirements.txt +``` + +## Running octoDNS the first time + +Once you have your configuration files and octoDNS installed you're ready to +run the sync command to get it to plan an initial set of changes. + +```console +(env) $ octodns-sync --config-file=config/octodns.yaml +2023-08-23T15:09:51 [4577488384] INFO Manager __init__: config_file=config/octodns.yaml, (octoDNS 1.0.1) +2023-08-23T15:09:51 [4577488384] INFO Manager _config_executor: max_workers=1 +2023-08-23T15:09:51 [4577488384] INFO Manager _config_include_meta: include_meta=False +2023-08-23T15:09:51 [4577488384] INFO Manager _config_auto_arpa: auto_arpa=False +2023-08-23T15:09:51 [4577488384] INFO Manager __init__: global_processors=[] +2023-08-23T15:09:51 [4577488384] INFO Manager __init__: provider=config (octodns.provider.yaml 1.0.1) +2023-08-23T15:09:51 [4577488384] INFO SpfSource[no-mail] __init__: id=no-mail, a_records=[], mx_records=[], ip4_addresses=[], ip6_addresses=[], includes=[], exists=[], soft_fail=False, merging_enabled=False, ttl=3600 +2023-08-23T15:09:51 [4577488384] INFO Manager __init__: provider=no-mail (octodns_spf 0.0.2) +2023-08-23T15:09:51 [4577488384] INFO Manager __init__: provider=yaml (octodns.provider.yaml 1.0.1) +2023-08-23T15:09:51 [4577488384] INFO Manager sync: eligible_zones=[], eligible_targets=[], dry_run=True, force=False, plan_output_fh= +2023-08-23T15:09:51 [4577488384] INFO Manager sync: sources=['config', 'no-mail'] +2023-08-23T15:09:51 [4577488384] INFO Manager sync: dynamic zone=*, sources=[YamlProvider, SpfSource] +2023-08-23T15:09:51 [4577488384] INFO Manager sync: adding dynamic zone=my-domain.com. +2023-08-23T15:09:51 [4577488384] INFO Manager sync: adding dynamic zone=unused-domain.io. +2023-08-23T15:09:51 [4577488384] INFO Manager sync: zone=my-domain.com. +2023-08-23T15:09:51 [4577488384] INFO Manager sync: sources=['config', 'no-mail'] +2023-08-23T15:09:51 [4577488384] INFO Manager sync: targets=['yaml'] +2023-08-23T15:09:51 [4577488384] INFO Manager sync: zone=unused-domain.io. +2023-08-23T15:09:51 [4577488384] INFO Manager sync: sources=['config', 'no-mail'] +2023-08-23T15:09:51 [4577488384] INFO Manager sync: targets=['yaml'] +2023-08-23T15:09:51 [4577488384] INFO YamlProvider[config] populate: found 9 records, exists=False +2023-08-23T15:09:51 [4577488384] INFO SpfSource[no-mail] populate: found 0 records, exists=False +2023-08-23T15:09:51 [4577488384] INFO YamlProvider[yaml] plan: desired=my-domain.com. +2023-08-23T15:09:51 [4577488384] WARNING YamlProvider[yaml] root NS record supported, but no record is configured for my-domain.com. +2023-08-23T15:09:51 [4577488384] INFO YamlProvider[yaml] plan: Creates=9, Updates=0, Deletes=0, Existing Records=0 +2023-08-23T15:09:51 [4577488384] INFO YamlProvider[config] populate: found 0 records, exists=False +2023-08-23T15:09:51 [4577488384] INFO SpfSource[no-mail] populate: found 1 records, exists=False +2023-08-23T15:09:51 [4577488384] INFO YamlProvider[yaml] plan: desired=unused-domain.io. +2023-08-23T15:09:51 [4577488384] WARNING YamlProvider[yaml] root NS record supported, but no record is configured for unused-domain.io. +2023-08-23T15:09:51 [4577488384] INFO YamlProvider[yaml] plan: Creates=1, Updates=0, Deletes=0, Existing Records=0 +2023-08-23T15:09:51 [4577488384] INFO Plan +******************************************************************************** +* unused-domain.io. +******************************************************************************** +* yaml (YamlProvider) +* Create Zone +* Create () +* Summary: Creates=1, Updates=0, Deletes=0, Existing Records=0 +******************************************************************************** +* my-domain.com. +******************************************************************************** +* yaml (YamlProvider) +* Create Zone +* Create (config) +* Create (config) +* Create (config) +* Create (config) +* Create (config) +* Create (config) +* Create (config) +* Create (config) +* Create (config) +* Summary: Creates=9, Updates=0, Deletes=0, Existing Records=0 +******************************************************************************** +``` + +### The log output + +It's always a good idea to scan over the logging output of an octoDNS run. Most +of it is informational, telling you what has been configured and providing a +big picture idea of what's happening while planning. You will sometimes see +WARNINGS, these are generally telling you that there's something you should +think about or look into. + +In the run above there was a warning about root/APEX NS records being supported +by the provider, YamlProvider, and not present in the config. Not all providers +support managing the root NS records, some just hard code their own name +servers. + +```console +2023-08-23T15:09:51 [4577488384] WARNING YamlProvider[yaml] root NS record supported, but no record is configured for my-domain.com. +``` + +### The plan output + +``` +******************************************************************************** +* unused-domain.io. +******************************************************************************** +* yaml (YamlProvider) +* Create Zone +* Create () +* Summary: Creates=1, Updates=0, Deletes=0, Existing Records=0 +******************************************************************************** +* my-domain.com. +******************************************************************************** +* yaml (YamlProvider) +* Create Zone +* Create (config) +* Create (config) +* Create (config) +* Create (config) +* Create (config) +* Create (config) +* Create (config) +* Create (config) +* Create (config) +* Summary: Creates=9, Updates=0, Deletes=0, Existing Records=0 +******************************************************************************** +``` + +### Applying the changes + +```console +(env) $ octodns-sync --config-file=config/octodns.yaml --doit +... +******************************************************************************** +* unused-domain.io. +******************************************************************************** +* yaml (YamlProvider) +* Create Zone +* Create () +* Summary: Creates=1, Updates=0, Deletes=0, Existing Records=0 +******************************************************************************** +* my-domain.com. +******************************************************************************** +* yaml (YamlProvider) +* Create Zone +* Create (config) +* Create (config) +* Create (config) +* Create (config) +* Create (config) +* Create (config) +* Create (config) +* Create (config) +* Create (config) +* Summary: Creates=9, Updates=0, Deletes=0, Existing Records=0 +******************************************************************************** + +2023-08-23T15:17:00 [4671815168] INFO YamlProvider[yaml] apply: making 1 changes to unused-domain.io. +2023-08-23T15:17:00 [4671815168] INFO YamlProvider[yaml] apply: making 9 changes to my-domain.com. +2023-08-23T15:17:00 [4671815168] INFO Manager sync: 10 total changes +``` + +``` +(env) coho:basic ross$ PYTHONPATH=/Users/ross/octodns/octodns octodns-sync --config-file=config/octodns.yaml +******************************************************************************** +No changes were planned +******************************************************************************** +``` + +That's it. You're now managing your DNS with octoDNS. + +## Making a change + +At some point down the road you need to make a change, maybe one of your web +boxes was replaced and there's a new IP address. The first step is to open up +the zone's YAML file and modify the YAML, removing 203.0.113.42 and adding +203.0.113.44. + +## Running octoDNS to see the plan + +Just like during the first run section above we'll first run octoDNS to see what changes it would make. +We'd skim the log lines again looking for unexpected WARNINGS and then take a look at the changes. + +``` +(env) coho:basic ross$ PYTHONPATH=/Users/ross/octodns/octodns octodns-sync --config-file=config/octodns.yaml +... +******************************************************************************** +* my-domain.com. +******************************************************************************** +* yaml (YamlProvider) +* Create Zone +* Update +* -> +* (config) +* Update +* -> +* (config) +* Summary: Creates=0, Updates=2, Deletes=0, Existing Records=9 +******************************************************************************** +``` + +Since we have used YAML anchors to share the values across both the root and +www A's we see that octoDNS will be making changes to both those records. + +If there were unexpected things here we'd need to investigate what's changed. +Maybe there were other alterations in the YAML that hadn't been applied yet or +someone modified the records through another means. + +Here we only see the expected changes so we're good to move forward with +applying them. + +``` +(env) coho:basic ross$ PYTHONPATH=/Users/ross/octodns/octodns octodns-sync --config-file=config/octodns.yaml --doit +... +******************************************************************************** +* my-domain.com. +******************************************************************************** +* yaml (YamlProvider) +* Create Zone +* Update +* -> +* (config) +* Update +* -> +* (config) +* Summary: Creates=0, Updates=2, Deletes=0, Existing Records=9 +******************************************************************************** +``` + +If we want we can run another plan to make sure there are no further pending changes. + +``` +(env) coho:basic ross$ PYTHONPATH=/Users/ross/octodns/octodns octodns-sync --config-file=config/octodns.yaml +******************************************************************************** +No changes were planned +******************************************************************************** +``` + +## What's Next + +* Check out [migrating to octoDNS](../migrating-to-octodns) for an example of how to create zone configuration YAML files from your existing provider's configuration +* Have a look at [managing SPF values](../managing-spf) for details on the best practices for configuring email related DNS records with octoDNS +* For a complete list check out the [Examples Directory](../) diff --git a/examples/basic/config/my-domain.com.yaml b/examples/basic/config/my-domain.com.yaml new file mode 100644 index 0000000..f447217 --- /dev/null +++ b/examples/basic/config/my-domain.com.yaml @@ -0,0 +1,58 @@ +--- +# These are root/APEX records, things that live at the top-level of the zone. +# There are multiple records so there's a YAML list, each element in that list +# defines its own record. +'': + # We first have an A record, mapping A my-domain.com to two IPv4 addresses, we + # also use a YAML anchor to effectively store the values for later use. + - type: A + values: &WEB_A_VALUES + - 203.0.113.42 + - 203.0.113.43 + # Similar to the A above, this is a AAAA for my-domain.com with a single IPv6 + # addresse. + - type: AAAA + values: &WEB_AAAA_VALUES + - 2001:DB8::44 + # Finally it's common to have to prove ownership of a domain with a TXT value + # in an APEX record. The following are a couple made up examples of how that + # would be done. As you'll see when you plan things The SpfSource will merge + # its SPF value in with the values defined here + - type: TXT + values: + - some-verification=3becb991-932f-4433-a280-9df6f39b6194 + - z-other-thing=this proves i have control over this domain +# This is a wildcard record, any A or AAAA query not matching a more specific +# answer defined in this file will match this name and receive the associated +# value in response. +'*': + - type: A + # Note here we have a single value rather than values and use `value`. + value: 203.0.113.45 + - type: AAAA + value: 2001:DB8::46 +# Note that the records in this zone are sorted, by default YamlProvider +# enforces alphabetical sorting of records and even the keys within record +# data. This is an organizational best practice, but can be disabled with the +# enforce_order parameter to YamlProvider +NADCBiQKBgQ._companyname: + type: TXT + value: a-different-proof-of-ownership +# We want www and the APEX to return the same values for A/AAAA queries. We +# stored the values earlier in YAML anchors so we can use them now on. +# This is a CNAME record +pointer: + type: CNAME + # CNAMEs can only have a single value so they require `value` to be used. As a + # best practice the target name must end with a `.` If you have a specific + # case where you need to omit the `.`, or other enforced best practices, see + # the lenience example for more information. + value: look.over-here.net. +# This is an example of a record with a `.` in it's name, it would result for a +# TXT query of NADCBiQKBgQ._companyname.my-domain.com. This specific example is +# another commonly required proof of overship record. +www: + - type: A + values: *WEB_A_VALUES + - type: AAAA + values: *WEB_AAAA_VALUES diff --git a/examples/basic/config/octodns.yaml b/examples/basic/config/octodns.yaml new file mode 100644 index 0000000..bf70655 --- /dev/null +++ b/examples/basic/config/octodns.yaml @@ -0,0 +1,64 @@ +--- +providers: + # The primary source of record data in most setup is YAML files on disk. By + # convention it's named config. + config: + class: octodns.provider.yaml.YamlProvider + # There are a number of configuration options available to customize the + # behavior of the provider, but the defaults are generally suitable and the + # only required value is the name of the directory where the files can be + # found. Convention is the same config directory in which this file lives. + directory: ./config + + # Having a no mail SPF record is considered best practice for any domains + # that you do not plan to use for email. The octodns-spf module provides + # SpfSource which by default adds the SPF value `v=spf1 -all` to accomplish + # this. If you have one or more domains that involve mail check out the email + # example after you're done here. + no-mail: + class: octodns_spf.SpfSource + + # This is just a placeholder for the purposes of this example, in your + # configuration you would replace it with configuration for the DNS + # provider(s) you wish to use, e.g. Route53, NS1, Azure DNS, ... See + # https://github.com/octodns/octodns#providers for a list of supported + # providers and have a look in each provider's repo for details on installing + # and configuring the provider. Convention is to name the provider with the + # unique portion of the provider class/company name in all lowercase, here + # YamlProvider -> yaml. Route53 would be route53, NS1 -> ns1, etc. + yaml: + class: octodns.provider.yaml.YamlProvider + directory: ./target + # This is a rarely used option that tells the YamlProvider that it should + # load existing records from disk rather than assume nothing exists + # created every a plan is made. + # TODO: + #populate_existing: true + + # If you wish to push your record data to multiple providers you'd define the + # other here and include them in the targets list down below. See the + # multiple-provider example for more details. + +zones: + + # This configuration is using dynamic zone config. Rather than having to + # explicitly list out all of the zones here with their coresponding + # configuration there's a single wildcard entry. Here the `config` source + # will look for zone files defined in its configured directory, the files + # alongside this one. For more details see the dynamic-zone-config example. + + '*': + # This is the place(s) we look for the records in each zone + sources: + # The conig provider will be firs in line to provide records for the + # zones, and since we're using dynamic zone config it will also be + # responsible for defining what zones exist. + - config + # After config has added its records the we'll add an no email SPF value. + # It'll create the APEX TXT record if necessary. Again see the email + # example for more details. + - no-mail + # This is the place(s) we push the record data to when applying changes + targets: + # Here we're pushing things to our example provider. + - yaml diff --git a/examples/basic/config/unused-domain.io.yaml b/examples/basic/config/unused-domain.io.yaml new file mode 100644 index 0000000..d513fd6 --- /dev/null +++ b/examples/basic/config/unused-domain.io.yaml @@ -0,0 +1,2 @@ +--- +# Nothing in here, just an empty domain b/c it's not actually used for anything diff --git a/examples/basic/requirements.txt b/examples/basic/requirements.txt new file mode 100644 index 0000000..b30fe47 --- /dev/null +++ b/examples/basic/requirements.txt @@ -0,0 +1,2 @@ +octodns>=1.0.1 +octodns_spf>=0.0.2 diff --git a/examples/basic/target/my-domain.com.yaml b/examples/basic/target/my-domain.com.yaml new file mode 100644 index 0000000..e7735ae --- /dev/null +++ b/examples/basic/target/my-domain.com.yaml @@ -0,0 +1,31 @@ +--- +? '' +: - type: A + values: + - 203.0.113.42 + - 203.0.113.43 + - type: AAAA + value: 2001:db8::44 + - type: TXT + values: + - some-verification=3becb991-932f-4433-a280-9df6f39b6194 + - v=spf1 -all + - z-other-thing=this proves i have control over this domain +'*': +- type: A + value: 203.0.113.45 +- type: AAAA + value: 2001:db8::46 +nadcbiqkbgq._companyname: + type: TXT + value: a-different-proof-of-ownership +pointer: + type: CNAME + value: look.over-here.net. +www: +- type: A + values: + - 203.0.113.42 + - 203.0.113.43 +- type: AAAA + value: 2001:db8::44 diff --git a/examples/basic/target/unused-domain.io.yaml b/examples/basic/target/unused-domain.io.yaml new file mode 100644 index 0000000..00cf2f7 --- /dev/null +++ b/examples/basic/target/unused-domain.io.yaml @@ -0,0 +1,4 @@ +--- +? '' +: type: TXT + value: v=spf1 -all