readthedocs configpull/1291/head
| @ -0,0 +1,4 @@ | |||
| --- | |||
| type: none | |||
| --- | |||
| WIP: major restructuring of docs, README/doc split | |||
| @ -0,0 +1,19 @@ | |||
| version: 2 | |||
| build: | |||
| os: ubuntu-24.04 | |||
| tools: | |||
| python: "3.13" | |||
| sphinx: | |||
| configuration: docs/conf.py | |||
| formats: | |||
| - epub | |||
| python: | |||
| install: | |||
| - requirements: requirements.txt | |||
| - requirements: requirements-dev.txt | |||
| - requirements: requirements-doc.txt | |||
| @ -1,212 +0,0 @@ | |||
| # Dynamic Record Support | |||
| Dynamic records provide support for GeoDNS and weighting to records. `A` and `AAAA` are fully supported and reasonably well tested for both Dyn (via Traffic Directors) and Route53. There is preliminary support for `CNAME` records, but caution should be exercised as they have not been thoroughly tested. | |||
| Configuring GeoDNS is complex and the details of the functionality vary widely from provider to provider. octoDNS has an opinionated view mostly to give a reasonably consistent behavior across providers which is similar to the overall philosophy and approach of octoDNS itself. It may not fit your needs or use cases, in which case please open an issue for discussion. We expect this functionality to grow and evolve over time as it's more widely used. | |||
| ## An Annotated Example | |||
| ```yaml | |||
| --- | |||
| test: | |||
| # This is a dynamic record when used with providers that support it | |||
| dynamic: | |||
| # These are the pools of records that can be referenced and thus used by rules | |||
| pools: | |||
| apac: | |||
| # An optional fallback, if all of the records in this pool fail this pool should be tried | |||
| fallback: na | |||
| # One or more values for this pool | |||
| values: | |||
| - value: 1.1.1.1 | |||
| - value: 2.2.2.2 | |||
| eu: | |||
| fallback: na | |||
| values: | |||
| - value: 3.3.3.3 | |||
| # Weight for this value, if omitted the default is 1 | |||
| weight: 2 | |||
| - value: 4.4.4.4 | |||
| weight: 3 | |||
| na: | |||
| # Implicitly goes to the backup pool (below) if all values are failing | |||
| # health checks | |||
| values: | |||
| - value: 5.5.5.5 | |||
| - value: 6.6.6.6 | |||
| - value: 7.7.7.7 | |||
| # Rules that assign queries to pools | |||
| rules: | |||
| - geos: | |||
| # Geos used in matching queries | |||
| - AF-ZA | |||
| - AS | |||
| - OC | |||
| # The pool to service the query from | |||
| pool: apac | |||
| - geos: | |||
| # AF-ZA was sent to apac above and the rest of AF else goes to eu here, | |||
| # sub-locations (e.g. AF-ZA) should come before their parents (AF.) If a | |||
| # more specific geo occured after a general one requests in that | |||
| # location would have already matched the previous rule. For the same | |||
| # reasons locations may not be repeated in multiple rules. | |||
| - AF | |||
| - EU | |||
| pool: eu | |||
| # No geos means match all queries, the final rule should generally be a | |||
| # "catch-all", served to any requests that didn't match the preceeding | |||
| # rules. The catch-all is the only case where a pool may be re-used. | |||
| - pool: na | |||
| ttl: 60 | |||
| type: A | |||
| # These values become a non-healthchecked backup/default pool, generally it | |||
| # should be a superset of the catch-all pool and include enough capacity to | |||
| # try and serve all global requests (with degraded performance.) The main | |||
| # case they will come into play is if all dynamic healthchecks are failing, | |||
| # either on the service side or if the providers systems are expeiencing | |||
| # problems. They will also be used for when the record is pushed to a | |||
| # provider that doesn't support dynamic records. | |||
| values: | |||
| - 3.3.3.3 | |||
| - 4.4.4.4 | |||
| - 5.5.5.5 | |||
| - 6.6.6.6 | |||
| - 7.7.7.7 | |||
| ``` | |||
| If you encounter validation errors in dynamic records suggesting best practices that you have specific reasons for not following see [records.md#Lenience](records.md#Lenience) for how to turn the errors into warnings. Doing so is taking on the burden of thoroughly testing and verifying that what you're doing behaves the way you expect. You may well encounter situations where the octoDNS providers and/or the underlying DNS services do not behave as desired. | |||
| ### Visual Representation of the Rules and Pools | |||
| ```mermaid | |||
| --- | |||
| title: Visual Representation of the Rules and Pools | |||
| --- | |||
| flowchart LR | |||
| query((Query)) --> rule_0[Rule 0<br>AF-ZA<br>AS<br>OC] | |||
| rule_0 --no match--> rule_1[Rule 1<br>AF<br>EU] | |||
| rule_1 --no match--> rule_2["Rule 2<br>(catch all)"] | |||
| rule_0 --match--> pool_apac[Pool apac<br>1.1.1.1<br>2.2.2.2] | |||
| pool_apac --fallback--> pool_na | |||
| rule_1 --match--> pool_eu["Pool eu<br>3.3.3.3 (2/5)<br>4.4.4.4 (3/5)"] | |||
| pool_eu --fallback--> pool_na | |||
| rule_2 --> pool_na[Pool na<br>5.5.5.5<br>6.6.6.6<br>7.7.7.7] | |||
| pool_na --backup--> values[values<br>3.3.3.3<br>4.4.4.4<br>5.5.5.5<br>6.6.6.6<br>7.7.7.7] | |||
| classDef queryColor fill:#3B67A8,color:#ffffff | |||
| classDef ruleColor fill:#D8F57A,color:#000000 | |||
| classDef poolColor fill:#F57261,color:#000000 | |||
| classDef valueColor fill:#498FF5,color:#000000 | |||
| class query queryColor | |||
| class rule_0,rule_1,rule_2 ruleColor | |||
| class pool_apac,pool_eu,pool_na poolColor | |||
| class values valueColor | |||
| ``` | |||
| ### Geo Codes | |||
| Geo codes consist of one to three parts depending on the scope of the area being targeted. Examples of these look like: | |||
| * 'NA-US-KY' - North America, United States, Kentucky | |||
| * 'NA-US' - North America, United States | |||
| * 'NA' - North America | |||
| The first portion is the continent: | |||
| * 'AF': 14, # Continental Africa | |||
| * 'AN': 17, # Continental Antarctica | |||
| * 'AS': 15, # Continental Asia | |||
| * 'EU': 13, # Continental Europe | |||
| * 'NA': 11, # Continental North America | |||
| * 'OC': 16, # Continental Australia/Oceania | |||
| * 'SA': 12, # Continental South America | |||
| The second is the two-letter ISO Country Code https://en.wikipedia.org/wiki/ISO_3166-2 and the third is the ISO Country Code Subdivision as per https://en.wikipedia.org/wiki/ISO_3166-2:US. Change the code at the end for the country you are subdividing. Note that these may not always be supported depending on the providers in use. | |||
| ### Subnets | |||
| Dynamic record rules also support subnet targeting in some providers: | |||
| ``` | |||
| ... | |||
| rules: | |||
| - geos: | |||
| - AS | |||
| - OC | |||
| subnets: | |||
| # Subnets used in matching queries | |||
| - 5.149.176.0/24 | |||
| pool: apac | |||
| ... | |||
| ``` | |||
| ## Rule ordering | |||
| octoDNS has validations in place to ensure that sources have the rules ordered from the most specific match to the least specific match per the following categories: | |||
| 1. Subnet-only rules | |||
| 2. Subnet+Geo rules | |||
| 3. Geo-only rules | |||
| 4. Catch-all rule (with no subnet or geo matching) | |||
| The first 3 categories are optional, while the last one is mandatory. | |||
| Subnet targeting is considered more specific than geo targeting. This means that if there is a subnet rule match as well as a geo rule match, subnet match must take precedence. Provider implementations must ensure this behavior of targeting precedence. | |||
| ## Health Checks | |||
| octoDNS will automatically configure the provider to monitor each IP and check for a 200 response for **https://<ip_address>/_dns**. | |||
| These checks can be customized via the `healthcheck` configuration options. | |||
| ```yaml | |||
| --- | |||
| test: | |||
| ... | |||
| octodns: | |||
| healthcheck: | |||
| host: my-host-name | |||
| path: /dns-health-check | |||
| port: 443 | |||
| protocol: HTTPS | |||
| ... | |||
| ``` | |||
| | Key | Description | Default | | |||
| |--|--|--| | |||
| | host | FQDN for host header and SNI | - | | |||
| | path | path to check | _dns | | |||
| | port | port to check | 443 | | |||
| | protocol | HTTP/HTTPS/TCP | HTTPS | | |||
| Healthchecks can also be skipped for individual pool values. These values can be forced to always-serve or never-serve using the `status` flag. | |||
| `status` flag is optional and accepts one of three possible values, `up`/`down`/`obey`, with `obey` being the default: | |||
| ```yaml | |||
| test: | |||
| ... | |||
| dynamic: | |||
| pools: | |||
| na: | |||
| values: | |||
| - value: 1.2.3.4 | |||
| status: down | |||
| - value: 2.3.4.5 | |||
| status: up | |||
| - value: 3.4.5.6 | |||
| # defaults to status: obey | |||
| ... | |||
| ``` | |||
| Support matrix: | |||
| * NS1 and Azure DNS support all 3 flag values | |||
| * All other dynamic-capable providers only support the default `obey` | |||
| See "Health Check Options" in individual provider documentation for customization support. | |||
| @ -1,33 +0,0 @@ | |||
| # 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. | |||
| * [Migrating to octoDNS](migrating-to-octodns/) - have an existing DNS setup | |||
| you'd like to bring into octoDNS check this example out right after | |||
| [basic](basic/). It'll walk you through the steps of using `octodns-dump` to | |||
| pull the existing data out of your provider into matching YAML config files on | |||
| disk. | |||
| This is a WIP and will definitely be rough around the edges, but in the spirit | |||
| of not letting perfect get in the way of good enough, or really existing at | |||
| all. It's being uploaded as a starting point. PRs/suggestions welcome as are | |||
| ideas for other subjects to cover. | |||
| ## Running PowerDNS | |||
| If you'd like to play around with running the examples in this directory | |||
| interactively you'll need a target for pushing data to. | |||
| [octodns-powerdns](https://github.com/octodns/octodns-powerdns) is the best | |||
| stand-alone option for this and the examples directory makes extensive use of | |||
| it. There is a [docker-compose.yml](docker-compose.yml) file that should get a | |||
| fully functional copy of PowerDNS backed my MySQL with the API enabled along | |||
| with other relivant functionality. For any of the examples that refer to the | |||
| local PowerDNS instance the following instructions below should get it up and | |||
| running. | |||
| 1. If you haven't already [install docker compose](https://docs.docker.com/compose/install/) | |||
| 1. If you don't already have a copy of octoDNS checked out run `git clone https://github.com/octodns/octodns.git` | |||
| 1. In a seperate terminal window or tab | |||
| 1. cd into the examples directory `cd octodns/examples` | |||
| 1. Run docker-compose up `docker-compose up`, this will start up MySQL and PowerDNS running them in the foreground with their logs printing to the terminal | |||
| @ -1,103 +0,0 @@ | |||
| # Geo Record Support | |||
| Note: Geo DNS records are still supported for the time being, but it is still strongly encouraged that you look at [Dynamic Records](/docs/dynamic_records.md) instead as they are a superset of functionality. | |||
| GeoDNS is currently supported for `A` and `AAAA` records on the Dyn (via Traffic Directors) and Route53 providers. Records with geo information pushed to providers without support for them will be managed as non-geo records using the base values. | |||
| Configuring GeoDNS is complex and the details of the functionality vary widely from provider to provider. octoDNS has an opinionated view of how GeoDNS should be set up and does its best to map that to each provider's offering in a way that will result in similar behavior. It may not fit your needs or use cases, in which case please open an issue for discussion. We expect this functionality to grow and evolve over time as it's more widely used. | |||
| The following is an example of GeoDNS with three entries NA-US-CA, NA-US-NY, OC-AU. octoDNS creates another one labeled 'default' with the details for the actual A record, This default record is the failover record if the monitoring check fails. | |||
| ```yaml | |||
| --- | |||
| ? '' | |||
| : type: TXT | |||
| value: v=spf1 -all | |||
| test: | |||
| geo: | |||
| NA-US-NY: | |||
| - 111.111.111.1 | |||
| NA-US-CA: | |||
| - 111.111.111.2 | |||
| OC-AU: | |||
| - 111.111.111.3 | |||
| EU: | |||
| - 111.111.111.4 | |||
| ttl: 300 | |||
| type: A | |||
| value: 111.111.111.5 | |||
| ``` | |||
| The geo labels breakdown based on: | |||
| 1. | |||
| - 'AF': 14, # Continental Africa | |||
| - 'AN': 17, # Continental Antarctica | |||
| - 'AS': 15, # Continental Asia | |||
| - 'EU': 13, # Continental Europe | |||
| - 'NA': 11, # Continental North America | |||
| - 'OC': 16, # Continental Australia/Oceania | |||
| - 'SA': 12, # Continental South America | |||
| 2. ISO Country Code https://en.wikipedia.org/wiki/ISO_3166-2 | |||
| 3. ISO Country Code Subdivision as per https://en.wikipedia.org/wiki/ISO_3166-2:US (change the code at the end for the country you are subdividing) * these may not always be supported depending on the provider. | |||
| So the example is saying: | |||
| - North America - United States - New York: gets served an "A" record of 111.111.111.1 | |||
| - North America - United States - California: gets served an "A" record of 111.111.111.2 | |||
| - Oceania - Australia: Gets served an "A" record of 111.111.111.3 | |||
| - Europe: gets an "A" record of 111.111.111.4 | |||
| - Everyone else gets an "A" record of 111.111.111.5 | |||
| ## Health Checks | |||
| octoDNS will automatically set up monitors check for a 200 response for **https://<ip_address>/_dns**. | |||
| These checks can be configured by adding a `healthcheck` configuration to the record: | |||
| ```yaml | |||
| --- | |||
| test: | |||
| geo: | |||
| AS: | |||
| - 1.2.3.4 | |||
| EU: | |||
| - 2.3.4.5 | |||
| octodns: | |||
| healthcheck: | |||
| host: my-host-name | |||
| path: /dns-health-check | |||
| port: 443 | |||
| protocol: HTTPS | |||
| ``` | |||
| | Key | Description | Default | | |||
| |--|--|--| | |||
| | host | FQDN for host header and SNI | - | | |||
| | path | path to check | _dns | | |||
| | port | port to check | 443 | | |||
| | protocol | HTTP/HTTPS | HTTPS | | |||
| ### Route53 Healtch Check Options | |||
| | Key | Description | Default | | |||
| |--|--|--| | |||
| | measure_latency | Show latency in AWS console | true | | |||
| | request_interval | Healthcheck interval [10\|30] seconds | 10 | | |||
| ```yaml | |||
| --- | |||
| octodns: | |||
| healthcheck: | |||
| host: my-host-name | |||
| path: /dns-health-check | |||
| port: 443 | |||
| protocol: HTTPS | |||
| route53: | |||
| healthcheck: | |||
| measure_latency: false | |||
| request_interval: 30 | |||
| ``` | |||
| @ -1,92 +0,0 @@ | |||
| # octodns documentation | |||
| ```{include} ../README.md | |||
| --- | |||
| end-before: '## Table of Contents' | |||
| --- | |||
| ``` | |||
| ______________________________________________________________________ | |||
| ## User documentation | |||
| ```{toctree} | |||
| :caption: Getting Started: | |||
| :maxdepth: 1 | |||
| examples/README.md | |||
| examples/basic/README.md | |||
| examples/migrating-to-octodns/README.md | |||
| records.md | |||
| ``` | |||
| ```{toctree} | |||
| :caption: Guides: | |||
| :maxdepth: 1 | |||
| :glob: | |||
| [a-q]* | |||
| ``` | |||
| ______________________________________________________________________ | |||
| ## Module documentation | |||
| ```{toctree} | |||
| :caption: Providers: | |||
| :maxdepth: 2 | |||
| :glob: | |||
| modules/provider/* | |||
| ``` | |||
| ```{toctree} | |||
| :caption: Sources: | |||
| :maxdepth: 2 | |||
| :glob: | |||
| modules/source/* | |||
| ``` | |||
| ```{toctree} | |||
| :caption: Records: | |||
| :maxdepth: 2 | |||
| :glob: | |||
| modules/record/* | |||
| ``` | |||
| ```{toctree} | |||
| :caption: Processors: | |||
| :maxdepth: 2 | |||
| :glob: | |||
| modules/processor/* | |||
| ``` | |||
| ```{toctree} | |||
| :caption: Other modules: | |||
| :titlesonly: | |||
| :glob: | |||
| modules/* | |||
| modules/cmds/* | |||
| modules/secret/* | |||
| ``` | |||
| ______________________________________________________________________ | |||
| ## Indices and tables | |||
| - {ref}`genindex` | |||
| - {ref}`modindex` | |||
| ```{toctree} | |||
| :caption: Project info: | |||
| :titlesonly: | |||
| info/changelog.md | |||
| info/license.md | |||
| ``` | |||
| @ -1,59 +0,0 @@ | |||
| # octoDNS processors | |||
| ## Available processors | |||
| These are listed in the main [`README`](../README.md#processors) | |||
| ## Configuring processors | |||
| Configuring processors is done in the main config file. | |||
| ### Defining a processor configuration | |||
| This is done under the top-level `processors` key in the octoDNS config file (for example `config.yaml`), as a sibling to the `manager` key. | |||
| The `processors` key contains YAML objects, where the key is the name of the processor, and the `class` value within that object refers to the processor name. | |||
| For example, to define a provider called `custom_meta` using the [`MetaProcessor`](../octodns/processor/meta.py) in order to extend the default `include_meta` behaviour: | |||
| ```yaml | |||
| manager: | |||
| include_meta: false # disable default, basic `meta` records | |||
| processors: | |||
| custom_meta: | |||
| class: octodns.processor.meta.MetaProcessor | |||
| record_name: meta | |||
| include_time: true | |||
| include_uuid: true | |||
| include_provider: true | |||
| include_version: false | |||
| ``` | |||
| **NOTE:** the specific parameters for each processor are only documented within [the code](../octodns/processor/) | |||
| ### Utilising the processor configuration | |||
| #### On **individual** domains | |||
| Each domain can utilise the processor independently by adding the name of the defined processor to a `processors` key beneath a `zone`: | |||
| ```yaml | |||
| zones: | |||
| example.com.: | |||
| source: | |||
| - yaml_config | |||
| target: | |||
| - hetzner | |||
| processors: | |||
| - custom_meta | |||
| ``` | |||
| #### On **all** domains | |||
| To utilise the processor on **all** domains automatically, including new domains added to the `zones` config in future then you can add this to the `processors` key under the `manager` section of the configuration: | |||
| ```yaml | |||
| manager: | |||
| processors: | |||
| - custom_meta | |||
| ``` | |||
| @ -1,201 +0,0 @@ | |||
| # octoDNS records | |||
| ## Record types | |||
| octoDNS supports the following record types: | |||
| * `A` | |||
| * `AAAA` | |||
| * `ALIAS` | |||
| * `CAA` | |||
| * `CNAME` | |||
| * `DNAME` | |||
| * `DS` | |||
| * `LOC` | |||
| * `MX` | |||
| * `NAPTR` | |||
| * `NS` | |||
| * `PTR` | |||
| * `SPF` | |||
| * `SRV` | |||
| * `SSHFP` | |||
| * `TLSA` | |||
| * `TXT` | |||
| * `URLFWD` | |||
| Underlying provider support for each of these varies and some providers have extra requirements or limitations. In cases where a record type is not supported by a provider octoDNS will ignore it there and continue to manage the record elsewhere. For example `SSHFP` is supported by Dyn, but not Route53. If your source data includes an SSHFP record octoDNS will keep it in sync on Dyn, but not consider it when evaluating the state of Route53. The best way to find out what types are supported by a provider is to look for its `supports` method. If that method exists the logic will drive which records are supported and which are ignored. If the provider does not implement the method it will fall back to `BaseProvider.supports` which indicates full support. | |||
| Adding new record types to octoDNS is relatively straightforward, but will require careful evaluation of each provider to determine whether or not it will be supported and the addition of code in each to handle and test the new type. | |||
| ## Advanced Record Support (GeoDNS, Weighting) | |||
| * [Dynamic Records](/docs/dynamic_records.md) - the preferred method for configuring geo-location, weights, and healthcheck based fallback between pools of services. | |||
| * [Geo Records](/docs/geo_records.md) - the original implementation of geo-location based records, now superseded by Dynamic Records (above) | |||
| ## Config (`YamlProvider`) | |||
| octoDNS records and `YamlProvider`'s schema is essentially a 1:1 match. Properties on the objects will match keys in the config. | |||
| ### Names | |||
| Each top-level key in the yaml file is a record name. Two common special cases are the root record `''`, and a wildcard `'*'`. | |||
| ```yaml | |||
| --- | |||
| '': | |||
| type: A | |||
| values: | |||
| - 1.2.3.4 | |||
| - 1.2.3.5 | |||
| '*': | |||
| type: CNAME | |||
| value: www.example.com. | |||
| www: | |||
| type: A | |||
| values: | |||
| - 1.2.3.4 | |||
| - 1.2.3.5 | |||
| www.sub: | |||
| type: A | |||
| values: | |||
| - 1.2.3.6 | |||
| - 1.2.3.7 | |||
| ``` | |||
| The above config lays out 4 records, `A`s for `example.com.`, `www.example.com.`, and `www.sub.example.com` and a wildcard `CNAME` mapping `*.example.com.` to `www.example.com.`. | |||
| ### Multiple records | |||
| In the above example each name had a single record, but there are cases where a name will need to have multiple records associated with it. This can be accomplished by using a list. | |||
| ```yaml | |||
| --- | |||
| '': | |||
| - type: A | |||
| values: | |||
| - 1.2.3.4 | |||
| - 1.2.3.5 | |||
| - type: MX | |||
| values: | |||
| - exchange: mx1.example.com. | |||
| preference: 10 | |||
| - exchange: mx2.example.com. | |||
| preference: 10 | |||
| ``` | |||
| ### Record data | |||
| Each record type has a corresponding set of required data. The easiest way to determine what's required is probably to look at the record object in [`octodns/record/__init__.py`](/octodns/record/__init__.py). You may also utilize `octodns-validate` which will throw errors about what's missing when run. | |||
| `type` is required for all records. `ttl` is optional. When TTL is not specified the `YamlProvider`'s default will be used. In any situation where an array of `values` can be used you can opt to go with `value` as a single item if there's only one. | |||
| ### Lenience | |||
| octoDNS is fairly strict in terms of standards compliance and is opinionated in terms of best practices. Examples of the former include SRV record naming requirements and the latter that ALIAS records are constrained to the root of zones. The strictness and support of providers varies so you may encounter existing records that fail validation when you try to dump them or you may even have use cases for which you need to create or preserve records that don't validate. octoDNS's solution to this is the `lenient` flag. | |||
| It's best to think of the `lenient` flag as "I know what I'm doing and accept any problems I run across." The main reason being is that some providers may allow the non-compliant setup and others may not. The behavior of the non-compliant records may even vary from one provider to another. Caveat emptor. | |||
| #### Record priority for AutoArpa | |||
| When multiple A or AAAA records point to the same IP, it is possible to set an optional priority on each record. The records with the lowest priority will have the highest preference when being processed by AutoArpa. The AutoArpa provider will create PTR records in order of preference, up to a set limit defined by the `max_auto_arpa` option in the provider configuration. | |||
| ```yaml | |||
| test: | |||
| - type: A | |||
| value: 1.2.3.4 | |||
| octodns: | |||
| auto_arpa_priority: 1 | |||
| ``` | |||
| #### octodns-dump | |||
| If you're trying to import a zone into octoDNS config file using `octodns-dump` which fails due to validation errors you can supply the `--lenient` argument to tell octoDNS that you acknowledge that things aren't lining up with its expectations, but you'd like it to go ahead anyway. This will do its best to populate the zone and dump the results out into an octoDNS zone file and include the non-compliant bits. If you go to use that config file octoDNS will again complain about the validation problems. You can correct them in cases where that makes sense, but if you need to preserve the non-compliant records read on for options. | |||
| #### Record level lenience | |||
| When there are non-compliant records configured in Yaml you can add the following to tell octoDNS to do it's best to proceed with them anyway. If you use `--lenient` above to dump a zone and you'd like to sync it as-is you can mark the problematic records this way. | |||
| ```yaml | |||
| 'not-root': | |||
| octodns: | |||
| lenient: true | |||
| type: ALIAS | |||
| values: something.else.com. | |||
| ``` | |||
| #### Zone level lenience | |||
| If you'd like to enable lenience for a whole zone you can do so with the following, thought it's strongly encouraged to mark things at record level when possible. The most common case where things may need to be done at the zone level is when using something other than `YamlProvider` as a source, e.g. syncing from `Route53Provider` to `Ns1Provider` when there are non-compliant records in the zone in Route53. | |||
| ```yaml | |||
| non-compliant-zone.com.: | |||
| lenient: true | |||
| sources: | |||
| - route53 | |||
| targets: | |||
| - ns1 | |||
| ``` | |||
| #### Restrict Record manipulations | |||
| octoDNS currently provides the ability to limit the number of updates/deletes on | |||
| DNS records by configuring a percentage of allowed operations as a provider threshold. | |||
| If left unconfigured, suitable defaults take over instead. In the below example, | |||
| the Dyn provider is configured with limits of 40% on both update and | |||
| delete operations over all the records present. | |||
| ````yaml | |||
| dyn: | |||
| class: octodns.provider.dyn.DynProvider | |||
| update_pcent_threshold: 0.4 | |||
| delete_pcent_threshold: 0.4 | |||
| ```` | |||
| Additionally, thresholds can be configured at the zone level. Zone thresholds | |||
| take precedence over any provider default or explicit configuration. Zone | |||
| thresholds do not have a default. | |||
| ```yaml | |||
| zones: | |||
| example.com.: | |||
| update_pcent_threshold: 0.2 | |||
| delete_pcent_threshold: 0.1 | |||
| ``` | |||
| ## Provider specific record types | |||
| ### Creating and registering | |||
| octoDNS has support for provider specific record types through a dynamic type registration system. This functionality is powered by `Route.register_type` and can be used as follows. | |||
| ```python | |||
| class _SpecificValue(object): | |||
| ... | |||
| class SomeProviderSpecificRecord(ValuesMixin, Record): | |||
| _type = 'SomeProvider/SPECIFIC' | |||
| _value_type = _SpecificValue | |||
| Record.register_type(SomeProviderSpecificRecord) | |||
| ``` | |||
| Have a look in [octodns.record](/octodns/record/__init__.py) for examples of how records are implemented. `NsRecord` and `_NsValue` are fairly simple examples to start with. You can also take a look at [`Route53Provider`'s `Route53Provider/ALIAS` type](https://github.com/octodns/octodns-route53/blob/main/octodns_route53/record.py). | |||
| In general this support is intended for record types that only make sense for a single provider. If multiple providers have a similar record it may make sense to implement it in octoDNS core. | |||
| ### Naming | |||
| By convention the record type should be prefixed with the provider class, e.g. `Route53Provider` followed by a `/` and an all-caps record type name `ALIAS`, e.g. `Route53Provider/ALIAS`. | |||
| ### YamlProvider support | |||
| Once the type is registered `YamlProvider` will automatically gain support for it and they can be included in your zone yaml files. | |||
| ```yaml | |||
| alias: | |||
| type: Route53Provider/ALIAS | |||
| values: | |||
| - name: www | |||
| type: A | |||
| - name: www | |||
| type: AAAA | |||
| ``` | |||
| @ -0,0 +1,12 @@ | |||
| .. _api: | |||
| Developer Interface | |||
| =================== | |||
| .. module:: octodns | |||
| .. toctree:: | |||
| :maxdepth: 1 | |||
| :glob: | |||
| /api/* | |||
| @ -0,0 +1,72 @@ | |||
| Processor | |||
| ========= | |||
| Defining a processor configuration | |||
| ---------------------------------- | |||
| This is done under the top-level ``processors`` key in the octoDNS config file | |||
| (for example ``config.yaml``), as a sibling to the ``manager`` key. | |||
| The ``processors`` key contains YAML objects, where the key is the name of the | |||
| processor, and the ``class`` value within that object refers to the processor | |||
| name. | |||
| For example, to define a provider called ``custom_meta`` using the | |||
| :py:class:`octodns.processor.meta.MetaProcessor` in order to extend the default | |||
| ``include_meta`` behaviour:: | |||
| manager: | |||
| include_meta: false # disable default, basic `meta` records | |||
| processors: | |||
| custom_meta: | |||
| class: octodns.processor.meta.MetaProcessor | |||
| record_name: meta | |||
| include_time: true | |||
| include_uuid: true | |||
| include_provider: true | |||
| include_version: false | |||
| Utilising the processor configuration | |||
| ------------------------------------- | |||
| On **individual** domains | |||
| ......................... | |||
| Each domain can utilise the processor independently by adding the name of the | |||
| defined processor to a ``processors`` key beneath a ``zone``:: | |||
| zones: | |||
| example.com.: | |||
| source: | |||
| - yaml_config | |||
| target: | |||
| - hetzner | |||
| processors: | |||
| - custom_meta | |||
| On **all** domains | |||
| .................. | |||
| To utilise the processor on **all** domains automatically, including new | |||
| domains added to the ``zones`` config in future then you can add this to the | |||
| ``processors`` key under the ``manager`` section of the configuration:: | |||
| manager: | |||
| processors: | |||
| - custom_meta | |||
| .. currentmodule:: octodns.processor | |||
| .. autosummary:: | |||
| :toctree: processors | |||
| base | |||
| acme | |||
| arpa | |||
| filter | |||
| meta | |||
| ownership | |||
| restrict | |||
| spf | |||
| templating | |||
| trailing_dots | |||
| @ -0,0 +1,5 @@ | |||
| YamlProvider | |||
| ============ | |||
| .. automodule:: octodns.provider.yaml | |||
| :inherited-members: | |||
| @ -0,0 +1,5 @@ | |||
| Provider | |||
| ======== | |||
| .. automodule:: octodns.provider.base | |||
| :inherited-members: | |||
| @ -0,0 +1,38 @@ | |||
| Records | |||
| ======= | |||
| .. autosummary:: | |||
| :toctree: records | |||
| octodns.record.base | |||
| octodns.record.aaaa | |||
| octodns.record.alias | |||
| octodns.record.a | |||
| octodns.record.caa | |||
| octodns.record.change | |||
| octodns.record.chunked | |||
| octodns.record.cname | |||
| octodns.record.dname | |||
| octodns.record.ds | |||
| octodns.record.dynamic | |||
| octodns.record.exception | |||
| octodns.record.geo_data | |||
| octodns.record.geo | |||
| octodns.record.https | |||
| octodns.record.ip | |||
| octodns.record.loc | |||
| octodns.record.mx | |||
| octodns.record.naptr | |||
| octodns.record.ns | |||
| octodns.record.ptr | |||
| octodns.record.rr | |||
| octodns.record.spf | |||
| octodns.record.srv | |||
| octodns.record.sshfp | |||
| octodns.record.subnet | |||
| octodns.record.svcb | |||
| octodns.record.target | |||
| octodns.record.tlsa | |||
| octodns.record.txt | |||
| octodns.record.uri | |||
| octodns.record.urlfwd | |||
| @ -0,0 +1,5 @@ | |||
| Source | |||
| ====== | |||
| .. automodule:: octodns.source.base | |||
| :inherited-members: | |||
| @ -0,0 +1,148 @@ | |||
| Configuration | |||
| ============= | |||
| Basics | |||
| ------ | |||
| This document picks up where :doc:`getting-started` and :doc:`records` leave off, | |||
| discussing details and less common scenarios. | |||
| YamlProvider | |||
| ------------ | |||
| :doc:`api/provider-yaml` lays out the options for configuring the most commonly | |||
| used source of record data. | |||
| Static Zone Config | |||
| ------------------ | |||
| In cases where finer grained control is desired and the configuration of | |||
| individual zones varies ``zones`` can be an explicit list with each configured | |||
| zone listed along with its specific setup. As exemplified below ``alias`` zones | |||
| can be useful when two zones are exact copies of each other, with the same | |||
| configuration and records. YAML anchors are also helpful to avoid duplication | |||
| where zones share config, but not records.:: | |||
| --- | |||
| manager: | |||
| include_meta: True | |||
| max_workers: 2 | |||
| providers: | |||
| config: | |||
| class: octodns.provider.yaml.YamlProvider | |||
| directory: ./config | |||
| default_ttl: 3600 | |||
| enforce_order: True | |||
| ns1: | |||
| class: octodns_ns1.Ns1Provider | |||
| api_key: env/NS1_API_KEY | |||
| route53: | |||
| class: octodns_route53.Route53Provider | |||
| access_key_id: env/AWS_ACCESS_KEY_ID | |||
| secret_access_key: env/AWS_SECRET_ACCESS_KEY | |||
| zones: | |||
| example.com.: &dual_target | |||
| sources: | |||
| - config | |||
| targets: | |||
| - ns1 | |||
| - route53 | |||
| # these have the same setup as example.com., but will have their own files | |||
| # in the configuration directory for records. | |||
| third.tv.: *dual_target | |||
| fourth.tv.: *dual_target | |||
| example.net.: | |||
| # example.net. is an exact copy of example.com., there will not be an | |||
| # example.net.yaml file in the config directory as `alias` includes | |||
| # duplicating the records of the aliased zone along with its config. | |||
| alias: example.com. | |||
| other.com.: | |||
| lenient: True | |||
| sources: | |||
| - config | |||
| targets: | |||
| - ns1 | |||
| General Configuration Concepts | |||
| ------------------------------ | |||
| ``class`` is a special key that tells octoDNS what python class should be | |||
| loaded. Any other keys will be passed as configuration values to that | |||
| provider. In general any sensitive or frequently rotated values should come | |||
| from environmental variables. When octoDNS sees a value that starts with | |||
| ``env/`` it will look for that value in the process's environment and pass the | |||
| result along. | |||
| Further information can be found in the docstring of each source and provider | |||
| class. | |||
| The ``include_meta`` key in the ``manager`` section of the config controls the | |||
| creation of a TXT record at the root of a zone that is managed by octoDNS. If | |||
| set to ``True``, octoDNS will create a TXT record for the root of the zone with | |||
| the value ``provider=<target-provider>``. If not specified, the default value for | |||
| ``include_meta`` is ``False``. | |||
| The ``max_workers`` key in the ``manager`` section of the config enables threading | |||
| to parallelize the planning portion of the sync. | |||
| ``lenient`` | |||
| ----------- | |||
| ``lenient`` mostly focuses on the details of ``Record``s and standards | |||
| compliance. When set to ``true`` octoDNS will allow non-compliant | |||
| configurations & values where possible. For example CNAME values that don't end | |||
| with a ``.``, label length restrictions, and invalid geo codes on ``dynamic`` | |||
| records. When in lenient mode octoDNS will log validation problems at | |||
| ``WARNING`` and try and continue with the configuration or source data as it | |||
| exists. See Lenience_ for more information on the concept and how it can be | |||
| configured. | |||
| .. _Lenience: records.rst#lenience | |||
| ``strict_supports`` | |||
| ------------------- | |||
| ``strict_supports`` is a ``Provider`` level parameter that comes into play when | |||
| a provider has been asked to create a record that it is unable to support. The | |||
| simplest case of this would be record type, e.g. ``SSHFP`` not being supported | |||
| by ``AzureProvider``. If such a record is passed to an ``AzureProvider`` as a | |||
| target the provider will take action based on the ``strict_supports``. When | |||
| ``true`` it will throw an exception saying that it's unable to create the | |||
| record, when set to ``false`` it will log at ``WARNING`` with information about | |||
| what it's unable to do and how it is attempting to work around it. Other | |||
| examples of things that cannot be supported would be ``dynamic`` records on a | |||
| provider that only supports simple or the lack of support for specific geos in | |||
| a provider, e.g. Route53Provider does not support ``NA-CA-*``. | |||
| It is worth noting that these errors will happen during the plan phase of | |||
| things so that problems will be visible without having to make changes. | |||
| As of octoDNS 1.x ``strict_supports`` is on by default. You have the choice to | |||
| set ``strict_supports=false`` on a per provider basis to request that things warn | |||
| and continue in a best-effort fashion. | |||
| Configuring ``strict_supports`` | |||
| ............................... | |||
| The ``strict_supports`` parameter is available on all providers and can be | |||
| configured in YAML as follows:: | |||
| providers: | |||
| someprovider: | |||
| class: whatever.TheProvider | |||
| ... | |||
| strict_supports: true | |||
| .. _automatic-ptr-generation: | |||
| Automatic PTR generation | |||
| ------------------------ | |||
| octoDNS supports automatically generating PTR records from the ``A``/``AAAA`` | |||
| records it manages. For more information see the :doc:`auto_arpa` | |||
| documentation. | |||
| @ -0,0 +1,249 @@ | |||
| Dynamic Record Support | |||
| ====================== | |||
| Dynamic records provide support for GeoDNS and weighting to records. ``A`` and | |||
| ``AAAA`` are fully supported and reasonably well tested for both Dyn (via | |||
| Traffic Directors) and Route53. There is preliminary support for ``CNAME`` | |||
| records, but caution should be exercised as they have not been thoroughly | |||
| tested. | |||
| Configuring GeoDNS is complex and the details of the functionality vary widely | |||
| from provider to provider. octoDNS has an opinionated view mostly to give a | |||
| reasonably consistent behavior across providers which is similar to the overall | |||
| philosophy and approach of octoDNS itself. It may not fit your needs or use | |||
| cases, in which case please open an issue for discussion. We expect this | |||
| functionality to grow and evolve over time as it's more widely used. | |||
| An Annotated Example | |||
| -------------------- | |||
| :: | |||
| --- | |||
| test: | |||
| # This is a dynamic record when used with providers that support it | |||
| dynamic: | |||
| # These are the pools of records that can be referenced and thus used by rules | |||
| pools: | |||
| apac: | |||
| # An optional fallback, if all of the records in this pool fail this pool should be tried | |||
| fallback: na | |||
| # One or more values for this pool | |||
| values: | |||
| - value: 1.1.1.1 | |||
| - value: 2.2.2.2 | |||
| eu: | |||
| fallback: na | |||
| values: | |||
| - value: 3.3.3.3 | |||
| # Weight for this value, if omitted the default is 1 | |||
| weight: 2 | |||
| - value: 4.4.4.4 | |||
| weight: 3 | |||
| na: | |||
| # Implicitly goes to the backup pool (below) if all values are failing | |||
| # health checks | |||
| values: | |||
| - value: 5.5.5.5 | |||
| - value: 6.6.6.6 | |||
| - value: 7.7.7.7 | |||
| # Rules that assign queries to pools | |||
| rules: | |||
| - geos: | |||
| # Geos used in matching queries | |||
| - AF-ZA | |||
| - AS | |||
| - OC | |||
| # The pool to service the query from | |||
| pool: apac | |||
| - geos: | |||
| # AF-ZA was sent to apac above and the rest of AF else goes to eu here, | |||
| # sub-locations (e.g. AF-ZA) should come before their parents (AF.) If a | |||
| # more specific geo occured after a general one requests in that | |||
| # location would have already matched the previous rule. For the same | |||
| # reasons locations may not be repeated in multiple rules. | |||
| - AF | |||
| - EU | |||
| pool: eu | |||
| # No geos means match all queries, the final rule should generally be a | |||
| # "catch-all", served to any requests that didn't match the preceeding | |||
| # rules. The catch-all is the only case where a pool may be re-used. | |||
| - pool: na | |||
| ttl: 60 | |||
| type: A | |||
| # These values become a non-healthchecked backup/default pool, generally it | |||
| # should be a superset of the catch-all pool and include enough capacity to | |||
| # try and serve all global requests (with degraded performance.) The main | |||
| # case they will come into play is if all dynamic healthchecks are failing, | |||
| # either on the service side or if the providers systems are expeiencing | |||
| # problems. They will also be used for when the record is pushed to a | |||
| # provider that doesn't support dynamic records. | |||
| values: | |||
| - 3.3.3.3 | |||
| - 4.4.4.4 | |||
| - 5.5.5.5 | |||
| - 6.6.6.6 | |||
| - 7.7.7.7 | |||
| If you encounter validation errors in dynamic records suggesting best practices | |||
| that you have specific reasons for not following see :doc:records#lenience for | |||
| how to turn the errors into warnings. Doing so is taking on the burden of | |||
| thoroughly testing and verifying that what you're doing behaves the way you | |||
| expect. You may well encounter situations where the octoDNS providers and/or | |||
| the underlying DNS services do not behave as desired. | |||
| Visual Representation of the Rules and Pools | |||
| ............................................ | |||
| .. mermaid:: | |||
| flowchart LR | |||
| query((Query)) --> rule_0[Rule 0<br>AF-ZA<br>AS<br>OC] | |||
| rule_0 --no match--> rule_1[Rule 1<br>AF<br>EU] | |||
| rule_1 --no match--> rule_2["Rule 2<br>(catch all)"] | |||
| rule_0 --match--> pool_apac[Pool apac<br>1.1.1.1<br>2.2.2.2] | |||
| pool_apac --fallback--> pool_na | |||
| rule_1 --match--> pool_eu["Pool eu<br>3.3.3.3 (2/5)<br>4.4.4.4 (3/5)"] | |||
| pool_eu --fallback--> pool_na | |||
| rule_2 --> pool_na[Pool na<br>5.5.5.5<br>6.6.6.6<br>7.7.7.7] | |||
| pool_na --backup--> values[values<br>3.3.3.3<br>4.4.4.4<br>5.5.5.5<br>6.6.6.6<br>7.7.7.7] | |||
| classDef queryColor fill:#3B67A8,color:#ffffff | |||
| classDef ruleColor fill:#D8F57A,color:#000000 | |||
| classDef poolColor fill:#F57261,color:#000000 | |||
| classDef valueColor fill:#498FF5,color:#000000 | |||
| class query queryColor | |||
| class rule_0,rule_1,rule_2 ruleColor | |||
| class pool_apac,pool_eu,pool_na poolColor | |||
| class values valueColor | |||
| Geo Codes | |||
| ......... | |||
| Geo codes consist of one to three parts depending on the scope of the area | |||
| being targeted. Examples of these look like: | |||
| * 'NA-US-KY' - North America, United States, Kentucky | |||
| * 'NA-US' - North America, United States | |||
| * 'NA' - North America | |||
| The first portion is the continent: | |||
| * 'AF': 14, # Continental Africa | |||
| * 'AN': 17, # Continental Antarctica | |||
| * 'AS': 15, # Continental Asia | |||
| * 'EU': 13, # Continental Europe | |||
| * 'NA': 11, # Continental North America | |||
| * 'OC': 16, # Continental Australia/Oceania | |||
| * 'SA': 12, # Continental South America | |||
| The second is the two-letter ISO Country Code | |||
| https://en.wikipedia.org/wiki/ISO_3166-2 and the third is the ISO Country Code | |||
| Subdivision as per https://en.wikipedia.org/wiki/ISO_3166-2:US. Change the code | |||
| at the end for the country you are subdividing. Note that these may not always | |||
| be supported depending on the providers in use. | |||
| Subnets | |||
| ....... | |||
| Dynamic record rules also support subnet targeting in some providers:: | |||
| ... | |||
| rules: | |||
| - geos: | |||
| - AS | |||
| - OC | |||
| subnets: | |||
| # Subnets used in matching queries | |||
| - 5.149.176.0/24 | |||
| pool: apac | |||
| ... | |||
| Rule ordering | |||
| ------------- | |||
| octoDNS has validations in place to ensure that sources have the rules ordered | |||
| from the most specific match to the least specific match per the following | |||
| categories: | |||
| 1. Subnet-only rules | |||
| 2. Subnet+Geo rules | |||
| 3. Geo-only rules | |||
| 4. Catch-all rule (with no subnet or geo matching) | |||
| The first 3 categories are optional, while the last one is mandatory. | |||
| Subnet targeting is considered more specific than geo targeting. This means | |||
| that if there is a subnet rule match as well as a geo rule match, subnet match | |||
| must take precedence. Provider implementations must ensure this behavior of | |||
| targeting precedence. | |||
| Health Checks | |||
| ------------- | |||
| octoDNS will automatically configure the provider to monitor each IP and check | |||
| for a 200 response for **https://<ip_address>/_dns**. | |||
| These checks can be customized via the ``healthcheck`` configuration options.:: | |||
| --- | |||
| test: | |||
| ... | |||
| octodns: | |||
| healthcheck: | |||
| host: my-host-name | |||
| path: /dns-health-check | |||
| port: 443 | |||
| protocol: HTTPS | |||
| ... | |||
| .. list-table:: | |||
| :header-rows: 1 | |||
| * - Key | |||
| - Description | |||
| - Default | |||
| * - host | |||
| - FQDN for host header and SNI | |||
| - | |||
| * - path | |||
| - path to check | |||
| - _dns | |||
| * - port | |||
| - port to check | |||
| - 443 | |||
| * - protocol | |||
| - HTTP/HTTPS/TCP | |||
| - HTTPS | |||
| Healthchecks can also be skipped for individual pool values. These values can | |||
| be forced to always-serve or never-serve using the ``status`` flag. | |||
| ``status`` flag is optional and accepts one of three possible values, | |||
| ``up``/``down``/``obey``, with ``obey`` being the default:: | |||
| test: | |||
| ... | |||
| dynamic: | |||
| pools: | |||
| na: | |||
| values: | |||
| - value: 1.2.3.4 | |||
| status: down | |||
| - value: 2.3.4.5 | |||
| status: up | |||
| - value: 3.4.5.6 | |||
| # defaults to status: obey | |||
| ... | |||
| Support matrix: | |||
| * NS1 and Azure DNS support all 3 flag values | |||
| * All other dynamic-capable providers only support the default ``obey`` | |||
| See "Health Check Options" in individual provider documentation for | |||
| customization support. | |||
| @ -0,0 +1,47 @@ | |||
| Examples | |||
| ======== | |||
| * Getting started with a [basic octoDNS configuration](basic/README.md) - 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. | |||
| * [Migrating to octoDNS](migrating-to-octodns/README.md) - have an existing DNS | |||
| setup you'd like to bring into octoDNS check this example out right after | |||
| [basic](basic/README.md). It'll walk you through the steps of using | |||
| ``octodns-dump`` to pull the existing data out of your provider into matching | |||
| YAML config files on disk. | |||
| This is a WIP and will definitely be rough around the edges, but in the spirit | |||
| of not letting perfect get in the way of good enough, or really existing at | |||
| all. It's being uploaded as a starting point. PRs/suggestions welcome as are | |||
| ideas for other subjects to cover. | |||
| .. _running-powerdns: | |||
| Running PowerDNS | |||
| ---------------- | |||
| If you'd like to play around with running the examples in this directory | |||
| interactively you'll need a target for pushing data to. `octodns-powerdns`_ is | |||
| the best stand-alone option for this and the examples directory makes extensive | |||
| use of it. There is a [docker-compose.yml](docker-compose.yml) file that should | |||
| get a fully functional copy of PowerDNS backed my MySQL with the API enabled | |||
| along with other relivant functionality. For any of the examples that refer to | |||
| the local PowerDNS instance the following instructions below should get it up | |||
| and running. | |||
| .. _octodns-powerdns: https://github.com/octodns/octodns-powerdns | |||
| 1. If you haven't already `install docker compose`_ | |||
| 1. If you don't already have a copy of octoDNS checked out run ``git clone https://github.com/octodns/octodns.git`` | |||
| 1. In a seperate terminal window or tab | |||
| 1. cd into the examples directory ``cd octodns/examples`` | |||
| 1. Run docker-compose up ``docker-compose up``, this will start up MySQL and PowerDNS running them in the foreground with their logs printing to the terminal | |||
| .. _install docker compose: https://docs.docker.com/compose/install/ | |||
| .. toctree:: | |||
| :maxdepth: 1 | |||
| basic/README.md | |||
| migrating-to-octodns/README.md | |||
| @ -0,0 +1,253 @@ | |||
| Getting Started | |||
| =============== | |||
| Workspace | |||
| --------- | |||
| Running through the following commands will install the latest release of | |||
| octoDNS and set up a place for your config files to live. To determine if | |||
| provider specific requirements are necessary see the :ref:`provider-list` | |||
| below.:: | |||
| $ mkdir dns | |||
| $ cd dns | |||
| $ python -m venv env | |||
| ... | |||
| $ source env/bin/activate | |||
| # provider-specific-requirements would be things like: octodns-route53 octodns-azure | |||
| $ pip install octodns <provider-specific-requirements> | |||
| $ mkdir config | |||
| Installing a specific commit SHA | |||
| ................................ | |||
| If you'd like to install a version that has not yet been released in a | |||
| repeatable/safe manner you can do the following. In general octoDNS is fairly | |||
| stable in between releases thanks to the plan and apply process, but care | |||
| should be taken regardless.:: | |||
| $ pip install -e git+https://git@github.com/octodns/octodns.git@<SHA>#egg=octodns | |||
| Config | |||
| ------ | |||
| We start by creating a config file to tell octoDNS about our providers and the | |||
| zone(s) we want it to manage. Below we're setting up a ``YamlProvider`` to | |||
| source records from our config files and both a ``Route53Provider`` and | |||
| ``DynProvider`` to serve as the targets for those records. You can have any | |||
| number of zones set up and any number of sources of data and targets for | |||
| records for each. You can also have multiple config files, that make use of | |||
| separate accounts and each manage a distinct set of zones. A good example of | |||
| this this might be ``./config/staging.yaml`` & ``./config/production.yaml``. | |||
| We'll focus on a ``config/production.yaml``. | |||
| .. _dynamic-zone-config: | |||
| Dynamic Zone Config | |||
| ................... | |||
| octoDNS supports dynamically building the list of zones it will work with when | |||
| source providers support it. The most common use of this would be with | |||
| ``YamlProvider`` and a single dynamic entry to in effect use the files that | |||
| exist in the provider's directory as the source of truth. Other providers may | |||
| support the ``list_zones`` method and be available to populate zones | |||
| dynamically as well. This can be especially useful when using ``octodns-dump`` | |||
| to create an initial setup from an existing provider. | |||
| An example config would look something like:: | |||
| --- | |||
| providers: | |||
| config: | |||
| class: octodns.provider.yaml.YamlProvider | |||
| directory: ./config | |||
| default_ttl: 3600 | |||
| enforce_order: True | |||
| ns1: | |||
| class: octodns_ns1.Ns1Provider | |||
| api_key: env/NS1_API_KEY | |||
| route53: | |||
| class: octodns_route53.Route53Provider | |||
| access_key_id: env/AWS_ACCESS_KEY_ID | |||
| secret_access_key: env/AWS_SECRET_ACCESS_KEY | |||
| zones: | |||
| # This is a dynamic zone config. The source(s), here `config`, will be | |||
| # queried for a list of zone names and each will dynamically be set up to | |||
| # match the dynamic entry. | |||
| '*': | |||
| sources: | |||
| - config | |||
| targets: | |||
| - ns1 | |||
| - route53 | |||
| Quick Example Record | |||
| .................... | |||
| Now that we have something to tell octoDNS about our providers & zones we need | |||
| to tell it about our records. We'll keep it simple for now and just create a | |||
| single ``A`` record at the top-level of the domain. | |||
| ``config/example.com.yaml``:: | |||
| --- | |||
| '': | |||
| ttl: 60 | |||
| type: A | |||
| values: | |||
| - 1.2.3.4 | |||
| - 1.2.3.5 | |||
| Further information can be found in :doc:`records` documentation. | |||
| Noop | |||
| ---- | |||
| We're ready to do a dry-run with our new setup to see what changes it would | |||
| make. Since we're pretending here we'll act like there are no existing records | |||
| for ``example.com.`` in our accounts on either provider.:: | |||
| $ octodns-sync --config-file=./config/production.yaml | |||
| ... | |||
| ******************************************************************************** | |||
| * example.com. | |||
| ******************************************************************************** | |||
| * route53 (Route53Provider) | |||
| * Create <ARecord A 60, example.com., [u'1.2.3.4', '1.2.3.5']> | |||
| * Summary: Creates=1, Updates=0, Deletes=0, Existing Records=0 | |||
| * dyn (DynProvider) | |||
| * Create <ARecord A 60, example.com., [u'1.2.3.4', '1.2.3.5']> | |||
| * Summary: Creates=1, Updates=0, Deletes=0, Existing Records=0 | |||
| ******************************************************************************** | |||
| ... | |||
| There will be other logging information presented on the screen, but successful | |||
| runs of sync will always end with a summary like the above for any providers & | |||
| zones with changes. If there are no changes a message saying so will be printed | |||
| instead. Above we're creating a new zone in both providers so they show the | |||
| same change, but that doesn't always have to be the case. If, to start, one of | |||
| them had a different state, you would see the changes octoDNS intends to make | |||
| to sync them up. | |||
| Making changes | |||
| -------------- | |||
| **WARNING**: octoDNS assumes ownership of any domain you point it to. When you | |||
| tell it to act it will do whatever is necessary to try and match up states | |||
| including deleting any unexpected records. Be careful when playing around with | |||
| octoDNS. It's best to experiment with a fake zone or one without any data that | |||
| matters until you're comfortable with the system. | |||
| Now it's time to tell octoDNS to make things happen. We'll invoke it again with | |||
| the same options and add a ``--doit`` on the end to tell it this time we | |||
| actually want it to try and make the specified changes.:: | |||
| $ octodns-sync --config-file=./config/production.yaml --doit | |||
| ... | |||
| The output here would be the same as before with a few more log lines at the | |||
| end as it makes the actual changes. After which the config in Route53 and Dyn | |||
| should match what's in the yaml file. | |||
| Workflow | |||
| -------- | |||
| In the above case we manually ran octoDNS from the command line. That works and | |||
| it's better than heading into the provider GUIs and making changes by clicking | |||
| around, but octoDNS is designed to be run as part of a deploy process. The | |||
| implementation details are well beyond the scope of this README, but here is an | |||
| example of the workflow we use at GitHub. It follows the way `GitHub itself is | |||
| branch deployed`_. | |||
| .. _GitHub itself is branch deployed: https://githubengineering.com/deploying-branches-to-github-com/ | |||
| The first step is to create a PR with your changes. | |||
| .. image:: assets/pr.png | |||
| :alt: GitHub user interface of a pull request | |||
| Assuming the code tests and config validation statuses are green the next step | |||
| is to do a noop deploy and verify that the changes octoDNS plans to make are | |||
| the ones you expect. | |||
| .. image:: assets/noop.png | |||
| :alt: Output of a noop deployment command | |||
| After that comes a set of reviews. One from a teammate who should have full | |||
| context on what you're trying to accomplish and visibility into the changes | |||
| you're making to do it. The other is from a member of the team here at GitHub | |||
| that owns DNS, mostly as a sanity check and to make sure that best practices | |||
| are being followed. As much of that as possible is baked into | |||
| ``octodns-validate``. | |||
| After the reviews it's time to branch deploy the change. | |||
| .. image:: assets/deploy.png | |||
| :alt: Output of a deployment command | |||
| If that goes smoothly, you again see the expected changes, and verify them with | |||
| ``dig`` and/or ``octodns-report`` you're good to hit the merge button. If there | |||
| are problems you can quickly do a ``.deploy dns/main`` to go back to the | |||
| previous state. | |||
| Other Uses | |||
| ---------- | |||
| Syncing between providers | |||
| ......................... | |||
| While the primary use-case is to sync a set of yaml config files up to one or | |||
| more DNS providers, octoDNS has been built in such a way that you can easily | |||
| source and target things arbitrarily. As a quick example the config below would | |||
| sync ``githubtest.net.`` from Route53 to Dyn.:: | |||
| --- | |||
| providers: | |||
| route53: | |||
| class: octodns.provider.route53.Route53Provider | |||
| access_key_id: env/AWS_ACCESS_KEY_ID | |||
| secret_access_key: env/AWS_SECRET_ACCESS_KEY | |||
| dyn: | |||
| class: octodns.provider.dyn.DynProvider | |||
| customer: env/DYN_CUSTOMER | |||
| username: env/DYN_USERNAME | |||
| password: env/DYN_PASSWORD | |||
| zones: | |||
| githubtest.net.: | |||
| sources: | |||
| - route53 | |||
| targets: | |||
| - dyn | |||
| Dynamic sources | |||
| ............... | |||
| Internally we use custom sources to create records based on dynamic data that | |||
| changes frequently without direct human intervention. An example of that might | |||
| look something like the following. For hosts this mechanism is janitorial, run | |||
| periodically, making sure the correct records exist as long as the host is | |||
| alive and ensuring they are removed after the host is destroyed. The host | |||
| provisioning and destruction processes do the actual work to create and destroy | |||
| the records.:: | |||
| --- | |||
| providers: | |||
| gpanel-site: | |||
| class: github.octodns.source.gpanel.GPanelProvider | |||
| host: 'gpanel.site.github.foo' | |||
| token: env/GPANEL_SITE_TOKEN | |||
| powerdns-site: | |||
| class: octodns.provider.powerdns.PowerDnsProvider | |||
| host: "internal-dns.site.github.foo" | |||
| api_key: env/POWERDNS_SITE_API_KEY | |||
| zones: | |||
| hosts.site.github.foo.: | |||
| sources: | |||
| - gpanel-site | |||
| targets: | |||
| - powerdns-site | |||
| @ -0,0 +1,460 @@ | |||
| .. image:: assets/octodns-logo.png | |||
| :alt: GitHub user interface of a pull request | |||
| DNS as Code | |||
| =========== | |||
| Tools for managing DNS across multiple providers | |||
| ------------------------------------------------ | |||
| In the vein of infrastructure as code octoDNS provides a set of tools & | |||
| patterns that make it easy to manage your DNS records across multiple | |||
| providers. The resulting config can live in a repository and be deployed just | |||
| like the rest of your code, maintaining a clear history and using your existing | |||
| review & workflow. | |||
| The architecture is pluggable and the tooling is flexible to make it applicable | |||
| to a wide variety of use-cases. Effort has been made to make adding new | |||
| providers as easy as possible. In the simple case that involves writing of a | |||
| single class and a couple hundred lines of code, most of which is translating | |||
| between the provider's schema and octoDNS's. | |||
| Documentation | |||
| ------------- | |||
| .. toctree:: | |||
| :maxdepth: 1 | |||
| getting-started.rst | |||
| records.md | |||
| configuration.rst | |||
| dynamic_records.rst | |||
| auto_arpa.rst | |||
| examples/README.rst | |||
| api.rst | |||
| .. _provider-list: | |||
| Providers | |||
| --------- | |||
| The table below lists the providers octoDNS supports. They are maintained in | |||
| their own repositories and released as independent modules. | |||
| .. list-table:: | |||
| :header-rows: 1 | |||
| * - Provider | |||
| - Module | |||
| - Notes | |||
| * - /etc/hosts | |||
| - `octodns_etchosts`_ | |||
| - | |||
| * - `Akamai Edge DNS`_ | |||
| - `octodns_edgedns`_ | |||
| - | |||
| * - `Amazon Route 53`_ | |||
| - `octodns_route53`_ | |||
| - | |||
| * - `AutoDNS`_ | |||
| - `octodns_autodns`_ | |||
| - | |||
| * - `Azion DNS`_ | |||
| - `octodns_azion`_ | |||
| - | |||
| * - `Azure DNS`_ | |||
| - `octodns_azure`_ | |||
| - | |||
| * - `BIND, AXFR, RFC-2136`_ | |||
| - `octodns_bind`_ | |||
| - | |||
| * - `Bunny DNS`_ | |||
| - `octodns_bunny`_ | |||
| - | |||
| * - `Cloudflare DNS`_ | |||
| - `octodns_cloudflare`_ | |||
| - | |||
| * - `ClouDNS`_ | |||
| - `octodns_cloudns`_ | |||
| - | |||
| * - `Constellix`_ | |||
| - `octodns_constellix`_ | |||
| - | |||
| * - `deSEC`_ | |||
| - `octodns_desec`_ | |||
| - | |||
| * - `DigitalOcean`_ | |||
| - `octodns_digitalocean`_ | |||
| - | |||
| * - `DNS Made Easy`_ | |||
| - `octodns_dnsmadeeasy`_ | |||
| - | |||
| * - `DNSimple`_ | |||
| - `octodns_dnsimple`_ | |||
| - | |||
| * - `Dyn`_ [deprecated] | |||
| - `octodns_dyn`_ | |||
| - | |||
| * - `easyDNS`_ | |||
| - `octodns_easydns`_ | |||
| - | |||
| * - `EdgeCenter DNS`_ | |||
| - `octodns_edgecenter`_ | |||
| - | |||
| * - `Fastly`_ | |||
| - `Financial-Times/octodns-fastly`_ | |||
| - | |||
| * - `G-Core Labs DNS`_ | |||
| - `octodns_gcore`_ | |||
| - | |||
| * - `Gandi`_ | |||
| - `octodns_gandi`_ | |||
| - | |||
| * - `Google Cloud DNS`_ | |||
| - `octodns_googlecloud`_ | |||
| - | |||
| * - `Hetzner DNS`_ | |||
| - `octodns_hetzner`_ | |||
| - | |||
| * - `Infoblox`_ | |||
| - `asyncon/octoblox`_ | |||
| - | |||
| * - `Infomaniak`_ | |||
| - `octodns_infomaniak`_ | |||
| - | |||
| * - `Lexicon`_ | |||
| - `dns-lexicon/dns-lexicon`_ | |||
| - | |||
| * - `Mythic Beasts DNS`_ | |||
| - `octodns_mythicbeasts`_ | |||
| - | |||
| * - `NetBox-DNS Plugin`_ | |||
| - `olofvndrhr/octodns-netbox-dns`_ | |||
| - | |||
| * - `NS1`_ | |||
| - `octodns_ns1`_ | |||
| - | |||
| * - `OVHcloud DNS`_ | |||
| - `octodns_ovh`_ | |||
| - | |||
| * - `Pi-hole`_ | |||
| - `jvoss/octodns-pihole`_ | |||
| - | |||
| * - `PowerDNS`_ | |||
| - `octodns_powerdns`_ | |||
| - | |||
| * - `Rackspace`_ | |||
| - `octodns_rackspace`_ | |||
| - | |||
| * - `Scaleway`_ | |||
| - `octodns_scaleway`_ | |||
| - | |||
| * - `Selectel`_ | |||
| - `octodns_selectel`_ | |||
| - | |||
| * - `SPF Value Management`_ | |||
| - `octodns_spf`_ | |||
| - | |||
| * - `TransIP`_ | |||
| - `octodns_transip`_ | |||
| - | |||
| * - `UltraDNS`_ | |||
| - `octodns_ultra`_ | |||
| - | |||
| * - `YamlProvider`_ | |||
| - built-in | |||
| - Supports all record types and core functionality | |||
| * - Zonefile | |||
| - `kompetenzbolzen/octodns-custom-provider`_ | |||
| - | |||
| .. _octodns_etchosts: https://github.com/octodns/octodns-etchosts/ | |||
| .. _Akamai Edge DNS: https://www.akamai.com/products/edge-dns | |||
| .. _octodns_edgedns: https://github.com/octodns/octodns-edgedns/ | |||
| .. _Amazon Route 53: https://aws.amazon.com/route53/ | |||
| .. _octodns_route53: https://github.com/octodns/octodns-route53 | |||
| .. _AutoDNS: https://www.internetx.com/autodns/ | |||
| .. _octodns_autodns: https://github.com/octodns/octodns-autodns | |||
| .. _Azion DNS: https://www.azion.com/en/products/edge-dns/ | |||
| .. _octodns_azion: https://github.com/aziontech/octodns-azion/ | |||
| .. _Azure DNS: https://azure.microsoft.com/en-us/services/dns/ | |||
| .. _octodns_azure: https://github.com/octodns/octodns-azure/ | |||
| .. _BIND, AXFR, RFC-2136: https://www.isc.org/bind/ | |||
| .. _octodns_bind: https://github.com/octodns/octodns-bind/ | |||
| .. _Bunny DNS: https://bunny.net/dns/ | |||
| .. _octodns_bunny: https://github.com/Relkian/octodns-bunny | |||
| .. _Cloudflare DNS: https://www.cloudflare.com/dns/ | |||
| .. _octodns_cloudflare: https://github.com/octodns/octodns-cloudflare/ | |||
| .. _ClouDNS: https://www.cloudns.net/ | |||
| .. _octodns_cloudns: https://github.com/ClouDNS/octodns_cloudns | |||
| .. _Constellix: https://constellix.com/ | |||
| .. _octodns_constellix: https://github.com/octodns/octodns-constellix/ | |||
| .. _deSEC: https://desec.io/ | |||
| .. _octodns_desec: https://github.com/rootshell-labs/octodns-desec | |||
| .. _DigitalOcean: https://docs.digitalocean.com/products/networking/dns/ | |||
| .. _octodns_digitalocean: https://github.com/octodns/octodns-digitalocean/ | |||
| .. _DNS Made Easy: https://dnsmadeeasy.com/ | |||
| .. _octodns_dnsmadeeasy: https://github.com/octodns/octodns-dnsmadeeasy/ | |||
| .. _DNSimple: https://dnsimple.com/ | |||
| .. _octodns_dnsimple: https://github.com/octodns/octodns-dnsimple/ | |||
| .. _Dyn: https://www.oracle.com/cloud/networking/dns/ | |||
| .. _octodns_dyn: https://github.com/octodns/octodns-dyn/ | |||
| .. _easyDNS: https://easydns.com/ | |||
| .. _octodns_easydns: https://github.com/octodns/octodns-easydns/ | |||
| .. _EdgeCenter DNS: https://edgecenter.ru/dns/ | |||
| .. _octodns_edgecenter: https://github.com/octodns/octodns-edgecenter/ | |||
| .. _Fastly: https://www.fastly.com/de/ | |||
| .. _Financial-Times/octodns-fastly: https://github.com/Financial-Times/octodns-fastly | |||
| .. _G-Core Labs DNS: https://gcorelabs.com/dns/ | |||
| .. _octodns_gcore: https://github.com/octodns/octodns-gcore/ | |||
| .. _Gandi: https://www.gandi.net/en-US/domain/dns | |||
| .. _octodns_gandi: https://github.com/octodns/octodns-gandi/ | |||
| .. _Google Cloud DNS: https://cloud.google.com/dns | |||
| .. _octodns_googlecloud: https://github.com/octodns/octodns-googlecloud/ | |||
| .. _Hetzner DNS: https://www.hetzner.com/dns-console | |||
| .. _octodns_hetzner: https://github.com/octodns/octodns-hetzner/ | |||
| .. _Infoblox: https://www.infoblox.com/ | |||
| .. _asyncon/octoblox: https://github.com/asyncon/octoblox | |||
| .. _Infomaniak: https://www.infomaniak.com/ | |||
| .. _octodns_infomaniak: https://github.com/M0NsTeRRR/octodns-infomaniak | |||
| .. _Lexicon: https://dns-lexicon.github.io/dns-lexicon/# | |||
| .. _dns-lexicon/dns-lexicon: https://github.com/dns-lexicon/dns-lexicon | |||
| .. _Mythic Beasts DNS: https://www.mythic-beasts.com/support/hosting/dns | |||
| .. _octodns_mythicbeasts: https://github.com/octodns/octodns-mythicbeasts/ | |||
| .. _NetBox-DNS Plugin: https://github.com/peteeckel/netbox-plugin-dns | |||
| .. _olofvndrhr/octodns-netbox-dns: https://github.com/olofvndrhr/octodns-netbox-dns | |||
| .. _NS1: https://ns1.com/products/managed-dns | |||
| .. _octodns_ns1: https://github.com/octodns/octodns-ns1/ | |||
| .. _OVHcloud DNS: https://www.ovhcloud.com/en/domains/dns-subdomain/ | |||
| .. _octodns_ovh: https://github.com/octodns/octodns-ovh/ | |||
| .. _Pi-hole: https://pi-hole.net/ | |||
| .. _jvoss/octodns-pihole: https://github.com/jvoss/octodns-pihole | |||
| .. _PowerDNS: https://www.powerdns.com/ | |||
| .. _octodns_powerdns: https://github.com/octodns/octodns-powerdns/ | |||
| .. _Rackspace: https://www.rackspace.com/library/what-is-dns | |||
| .. _octodns_rackspace: https://github.com/octodns/octodns-rackspace/ | |||
| .. _Scaleway: https://www.scaleway.com/en/dns/ | |||
| .. _octodns_scaleway: https://github.com/scaleway/octodns-scaleway | |||
| .. _Selectel: https://selectel.ru/en/services/additional/dns/ | |||
| .. _octodns_selectel: https://github.com/octodns/octodns-selectel/ | |||
| .. _SPF Value Management: https://github.com/octodns/octodns-spf | |||
| .. _octodns_spf: https://github.com/octodns/octodns-spf/ | |||
| .. _TransIP: https://www.transip.eu/knowledgebase/entry/155-dns-and-nameservers/ | |||
| .. _octodns_transip: https://github.com/octodns/octodns-transip/ | |||
| .. _UltraDNS: https://vercara.com/authoritative-dns | |||
| .. _octodns_ultra: https://github.com/octodns/octodns-ultra/ | |||
| .. _YamlProvider: /octodns/provider/yaml.py | |||
| .. _kompetenzbolzen/octodns-custom-provider: https://github.com/kompetenzbolzen/octodns-custom-provider | |||
| Sources | |||
| ------- | |||
| Similar to providers, but can only serve to populate records into a zone, | |||
| cannot be synced to. | |||
| .. list-table:: | |||
| :header-rows: 1 | |||
| :widths: 50 50 | |||
| * - Source/Module | |||
| - Notes | |||
| * - `AxfrSource (BIND)`_ | |||
| - | |||
| * - `DDNS Source`_ | |||
| - | |||
| * - `EnvVarSource`_ | |||
| - read-only environment variable injection | |||
| * - `Lexicon Source`_ | |||
| - | |||
| * - `Netbox Source`_ | |||
| - | |||
| * - `PHPIPAM Source`_ | |||
| - | |||
| * - `TinyDnsFileSource`_ | |||
| - | |||
| * - `ZoneFileSource`_ | |||
| - | |||
| .. _AxfrSource (BIND): https://github.com/octodns/octodns-bind/ | |||
| .. _DDNS Source: https://github.com/octodns/octodns-ddns | |||
| .. _EnvVarSource: /octodns/source/envvar.py | |||
| .. _Lexicon Source: https://github.com/doddo/octodns-lexicon | |||
| .. _Netbox Source: https://github.com/sukiyaki/octodns-netbox | |||
| .. _PHPIPAM Source: https://github.com/kompetenzbolzen/octodns-custom-provider | |||
| .. _TinyDnsFileSource: /octodns/source/tinydns.py | |||
| .. _ZoneFileSource: https://github.com/octodns/octodns-bind/ | |||
| Processors | |||
| ---------- | |||
| .. list-table:: | |||
| :header-rows: 1 | |||
| * - Processor | |||
| - Description | |||
| * - `AcmeManagingProcessor`_ | |||
| - Useful when processes external to octoDNS are managing acme challenge DNS records, e.g. LetsEncrypt | |||
| * - `AutoArpa`_ | |||
| - See :ref:`automatic-ptr-generation` | |||
| * - `EnsureTrailingDots`_ | |||
| - Processor that ensures ALIAS, CNAME, DNAME, MX, NS, PTR, and SRVs have trailing dots | |||
| * - `ExcludeRootNsChanges`_ | |||
| - Filter that errors or warns on planned root/APEX NS records changes. | |||
| * - `IgnoreRootNsFilter`_ | |||
| - Filter that IGNORES root/APEX NS records and prevents octoDNS from trying to manage them (where supported.) | |||
| * - `MetaProcessor`_ | |||
| - Adds a special meta record with timing, UUID, providers, and/or version to aid in debugging and monitoring. | |||
| * - `NameAllowlistFilter`_ | |||
| - Filter that ONLY manages records that match specified naming patterns, all others will be ignored | |||
| * - `NameRejectlistFilter`_ | |||
| - Filter that IGNORES records that match specified naming patterns, all others will be managed | |||
| * - `ValueAllowlistFilter`_ | |||
| - Filter that ONLY manages records that match specified value patterns based on `rdata_text`, all others will be ignored | |||
| * - `ValueRejectlistFilter`_ | |||
| - Filter that IGNORES records that match specified value patterns based on `rdata_text`, all others will be managed | |||
| * - `OwnershipProcessor`_ | |||
| - Processor that implements ownership in octoDNS so that it can manage only the records in a zone in sources and will ignore all others. | |||
| * - `SpfDnsLookupProcessor`_ | |||
| - Processor that checks SPF values for violations of DNS query limits | |||
| * - `TtlRestrictionFilter`_ | |||
| - Processor that restricts the allow TTL values to a specified range or list of specific values | |||
| * - `TypeAllowlistFilter`_ | |||
| - Filter that ONLY manages records of specified types, all others will be ignored | |||
| * - `TypeRejectlistFilter`_ | |||
| - Filter that IGNORES records of specified types, all others will be managed | |||
| * - `octodns-spf`_ | |||
| - SPF Value Management for octoDNS | |||
| .. _AcmeManagingProcessor: https://github.com/octodns/octodns/tree/main/octodns/processor/acme.py) | |||
| .. _AutoArpa: https://github.com/octodns/octodns/tree/main/octodns/processor/arpa.py) | |||
| .. _EnsureTrailingDots: https://github.com/octodns/octodns/tree/main/octodns/processor/trailing_dots.py) | |||
| .. _ExcludeRootNsChanges: https://github.com/octodns/octodns/tree/main/octodns/processor/filter.py) | |||
| .. _IgnoreRootNsFilter: https://github.com/octodns/octodns/tree/main/octodns/processor/filter.py) | |||
| .. _MetaProcessor: https://github.com/octodns/octodns/tree/main/octodns/processor/meta.py) | |||
| .. _NameAllowlistFilter: https://github.com/octodns/octodns/tree/main/octodns/processor/filter.py) | |||
| .. _NameRejectlistFilter: https://github.com/octodns/octodns/tree/main/octodns/processor/filter.py) | |||
| .. _ValueAllowlistFilter: https://github.com/octodns/octodns/tree/main/octodns/processor/filter.py) | |||
| .. _ValueRejectlistFilter: https://github.com/octodns/octodns/tree/main/octodns/processor/filter.py) | |||
| .. _OwnershipProcessor: https://github.com/octodns/octodns/tree/main/octodns/processor/ownership.py) | |||
| .. _SpfDnsLookupProcessor: https://github.com/octodns/octodns/tree/main/octodns/processor/spf.py) | |||
| .. _TtlRestrictionFilter: https://github.com/octodns/octodns/tree/main/octodns/processor/restrict.py) | |||
| .. _TypeAllowlistFilter: https://github.com/octodns/octodns/tree/main/octodns/processor/filter.py) | |||
| .. _TypeRejectlistFilter: https://github.com/octodns/octodns/tree/main/octodns/processor/filter.py) | |||
| .. _octodns-spf: https://github.com/octodns/octodns/tree/main//github.com/octodns/octodns-spf) | |||
| Custom Sources and Providers | |||
| ---------------------------- | |||
| You can check out the source_ and provider_ directories to see what's currently | |||
| supported. Sources act as a source of record information. AxfrSource and | |||
| TinyDnsFileSource are currently the only OSS sources, though we have several | |||
| others internally that are specific to our environment. These include something | |||
| to pull host data from gPanel_ and a similar provider that sources information | |||
| about our network gear to create both ``A`` & ``PTR`` records for their | |||
| interfaces. Things that might make good OSS sources might include an | |||
| ``ElbSource`` that pulls information about `AWS Elastic Load Balancers`_ and | |||
| dynamically creates ``CNAME``s for them, or ``Ec2Source`` that pulls instance | |||
| information so that records can be created for hosts similar to how our | |||
| ``GPanelProvider`` works. | |||
| .. _source: https://github.com/octodns/octodns/tree/main/octodns/source/ | |||
| .. _provider: https://github.com/octodns/octodns/tree/main/octodns/provider/ | |||
| .. _gPanel: https://githubengineering.com/githubs-metal-cloud/ | |||
| .. _AWS Elastic Load Balancers: https://aws.amazon.com/elasticloadbalancing/ | |||
| Most of the things included in octoDNS are providers, the obvious difference | |||
| being that they can serve as both sources and targets of data. We'd really like | |||
| to see this list grow over time so if you use an unsupported provider then PRs | |||
| are welcome. The existing providers should serve as reasonable examples. Those | |||
| that have no GeoDNS support are relatively straightforward. Unfortunately most | |||
| of the APIs involved to do GeoDNS style traffic management are complex and | |||
| somewhat inconsistent so adding support for that function would be nice, but is | |||
| optional and best done in a separate pass. | |||
| The ``class`` key in the providers config section can be used to point to | |||
| arbitrary classes in the python path so internal or 3rd party providers can | |||
| easily be included with no coordination beyond getting them into | |||
| ``PYTHONPATH``, most likely installed into the virtualenv with octoDNS. | |||
| For examples of building third-party sources and providers, see `Related | |||
| Projects and Resources`_ | |||
| Contributing | |||
| ------------ | |||
| Please see our contributing_ document if you would like to participate! | |||
| .. _contributing: https://github.com/octodns/octodns/tree/main/CONTRIBUTING.md | |||
| Getting help | |||
| ------------ | |||
| If you have a problem or suggestion, please `open an issue`_ in this repository, and | |||
| we will do our best to help. | |||
| Please note that this project adheres to the `Contributor Covenant Code of | |||
| Conduct`_. | |||
| .. _open an issue: https://github.com/octodns/octodns/issues/new | |||
| .. _Contributor Covenant Code of Conduct: https://github.com/octodns/octodns/tree/main/CODE_OF_CONDUCT.md | |||
| Related Projects and Resources | |||
| ------------------------------ | |||
| * GitHub Action: `octoDNS-Sync`_ | |||
| * NixOS Integration: `NixOS-DNS`_ | |||
| * Sample Implementations, see how others are using it | |||
| - `hackclub/dns`_ | |||
| - `kubernetes/k8s.io:/dns`_ | |||
| - `g0v-network/domains`_ | |||
| - `jekyll/dns`_ | |||
| * Resources | |||
| - Article: `Visualising DNS records with Neo4j`_ + code | |||
| - Video: `FOSDEM 2019 - DNS as code with octodns`_ | |||
| - GitHub Blog: `Enabling DNS split authority with octoDNS`_ | |||
| - Tutorial: `How To Deploy and Manage Your DNS using octoDNS on Ubuntu 18.04`_ | |||
| - Cloudflare Blog: `Improving the Resiliency of Our Infrastructure DNS Zone`_ | |||
| .. _octoDNS-Sync: https://github.com/marketplace/actions/octodns-sync | |||
| .. _NixOS-DNS: https://github.com/Janik-Haag/nixos-dns/ | |||
| .. _hackclub/dns: https://github.com/hackclub/dns) | |||
| .. _`kubernetes/k8s.io:/dns`: https://github.com/kubernetes/k8s.io/tree/main/dns) | |||
| .. _g0v-network/domains: https://github.com/g0v-network/domains) | |||
| .. _jekyll/dns: https://github.com/jekyll/dns) | |||
| .. _Visualising DNS records with Neo4j: https://medium.com/@costask/querying-and-visualising-octodns-records-with-neo4j-f4f72ab2d474 | |||
| .. _FOSDEM 2019 - DNS as code with octodns: https://archive.fosdem.org/2019/schedule/event/dns_octodns/ | |||
| .. _Enabling DNS split authority with octoDNS: https://github.blog/2017-04-27-enabling-split-authority-dns-with-octodns/ | |||
| .. _How To Deploy and Manage Your DNS using octoDNS on Ubuntu 18.04: https://www.digitalocean.com/community/tutorials/how-to-deploy-and-manage-your-dns-using-octodns-on-ubuntu-18-04 | |||
| .. _Improving the Resiliency of Our Infrastructure DNS Zone: https://blog.cloudflare.com/improving-the-resiliency-of-our-infrastructure-dns-zone/ | |||
| If you know of any other resources, please do let us know! | |||
| License | |||
| ------- | |||
| octoDNS is licensed under the `MIT license`_. | |||
| .. _MIT license: https://github.com/octodns/octodns/tree/mainLICENSE | |||
| The MIT license grant is not for GitHub's trademarks, which include the logo | |||
| designs. GitHub reserves all trademark and copyright rights in and to all | |||
| GitHub trademarks. GitHub's logos include, for instance, the stylized designs | |||
| that include "logo" in the file title in the following folder: | |||
| https://github.com/octodns/octodns/tree/main/docs/logos/ | |||
| GitHub® and its stylized versions and the Invertocat mark are GitHub's | |||
| Trademarks or registered Trademarks. When using GitHub's logos, be sure to | |||
| follow the GitHub logo guidelines. | |||
| Authors | |||
| ------- | |||
| octoDNS was designed and authored by `Ross McFarland`_ and `Joe Williams`_. See | |||
| https://github.com/octodns/octodns/graphs/contributors for a complete list of | |||
| people who've contributed. | |||
| .. _Ross McFarland: https://github.com/ross | |||
| .. _Joe Williams: https://github.com/joewilliams | |||
| @ -0,0 +1,243 @@ | |||
| Records | |||
| ======= | |||
| Underlying provider support for each of octoDNS's record types varies and some | |||
| providers have extra requirements or limitations. In cases where a record type | |||
| is not supported by a provider octoDNS will ignore it there and continue to | |||
| manage the record elsewhere. For example ``SSHFP`` is supported by Dyn, but not | |||
| Route53. If your source data includes an SSHFP record octoDNS will keep it in | |||
| sync on Dyn, but not consider it when evaluating the state of Route53. The best | |||
| way to find out what types are supported by a provider is to look for its | |||
| ``supports`` method. If that method exists the logic will drive which records are | |||
| supported and which are ignored. If the provider does not implement the method | |||
| it will fall back to :py:attr:`BaseProvider.supports` which indicates full support. | |||
| Adding new record types to octoDNS is relatively straightforward, but will | |||
| require careful evaluation of each provider to determine whether or not it will | |||
| be supported and the addition of code in each to handle and test the new type. | |||
| Advanced Record Support | |||
| ----------------------- | |||
| * :doc:`dynamic_records` - the preferred method for configuring geo-location, weights, and healthcheck based fallback between pools of services. | |||
| Config (``YamlProvider``) | |||
| ------------------------- | |||
| octoDNS records and :py:class:`octodns.provider.yaml.YamlProvider`'s schema is | |||
| essentially a 1:1 match. Properties on the objects will match keys in the | |||
| config. | |||
| Names | |||
| ..... | |||
| Each top-level key in the yaml file is a record name. Two common special cases | |||
| are the root record ``''``, and a wildcard ``'*'``:: | |||
| --- | |||
| '': | |||
| type: A | |||
| values: | |||
| - 1.2.3.4 | |||
| - 1.2.3.5 | |||
| '*': | |||
| type: CNAME | |||
| value: www.example.com. | |||
| www: | |||
| type: A | |||
| values: | |||
| - 1.2.3.4 | |||
| - 1.2.3.5 | |||
| www.sub: | |||
| type: A | |||
| values: | |||
| - 1.2.3.6 | |||
| - 1.2.3.7 | |||
| The above config lays out 4 records, ``A``s for ``example.com.``, | |||
| ``www.example.com.``, and ``www.sub.example.com`` and a wildcard ``CNAME`` mapping | |||
| ``*.example.com.`` to ``www.example.com.``. | |||
| Multiple records | |||
| ................ | |||
| In the above example each name had a single record, but there are cases where a | |||
| name will need to have multiple records associated with it. This can be | |||
| accomplished by using a list:: | |||
| --- | |||
| '': | |||
| - type: A | |||
| values: | |||
| - 1.2.3.4 | |||
| - 1.2.3.5 | |||
| - type: MX | |||
| values: | |||
| - exchange: mx1.example.com. | |||
| preference: 10 | |||
| - exchange: mx2.example.com. | |||
| preference: 10 | |||
| Record data | |||
| ........... | |||
| Each record type has a corresponding set of required data. The easiest way to | |||
| determine what's required is probably to look at | |||
| :py:class:`octodns.record.Record`. You may also utilize ``octodns-validate`` | |||
| which will throw errors about what's missing when run. | |||
| ``type`` is required for all records. ``ttl`` is optional. When TTL is not | |||
| specified the :py:class:`octodns.provider.yaml.YamlProvider`'s default will be | |||
| used. In any situation where an array of ``values`` can be used you can opt to | |||
| go with ``value`` as a single item if there's only one. | |||
| .. _lenience: | |||
| Lenience | |||
| ........ | |||
| octoDNS is fairly strict in terms of standards compliance and is opinionated in | |||
| terms of best practices. Examples of the former include SRV record naming | |||
| requirements and the latter that ALIAS records are constrained to the root of | |||
| zones. The strictness and support of providers varies so you may encounter | |||
| existing records that fail validation when you try to dump them or you may even | |||
| have use cases for which you need to create or preserve records that don't | |||
| validate. octoDNS's solution to this is the ``lenient`` flag. | |||
| It's best to think of the ``lenient`` flag as "I know what I'm doing and accept | |||
| any problems I run across." The main reason being is that some providers may | |||
| allow the non-compliant setup and others may not. The behavior of the | |||
| non-compliant records may even vary from one provider to another. Caveat | |||
| emptor. | |||
| Record priority for AutoArpa | |||
| ++++++++++++++++++++++++++++ | |||
| When multiple A or AAAA records point to the same IP, it is possible to set an | |||
| optional priority on each record. The records with the lowest priority will | |||
| have the highest preference when being processed by AutoArpa. The AutoArpa | |||
| provider will create PTR records in order of preference, up to a set limit | |||
| defined by the ``max_auto_arpa`` option in the provider configuration:: | |||
| test: | |||
| - type: A | |||
| value: 1.2.3.4 | |||
| octodns: | |||
| auto_arpa_priority: 1 | |||
| octodns-dump | |||
| ++++++++++++ | |||
| If you're trying to import a zone into octoDNS config file using | |||
| ``octodns-dump`` which fails due to validation errors you can supply the | |||
| ``--lenient`` argument to tell octoDNS that you acknowledge that things aren't | |||
| lining up with its expectations, but you'd like it to go ahead anyway. This | |||
| will do its best to populate the zone and dump the results out into an octoDNS | |||
| zone file and include the non-compliant bits. If you go to use that config file | |||
| octoDNS will again complain about the validation problems. You can correct them | |||
| in cases where that makes sense, but if you need to preserve the non-compliant | |||
| records read on for options. | |||
| Record level lenience | |||
| +++++++++++++++++++++ | |||
| When there are non-compliant records configured in Yaml you can add the | |||
| following to tell octoDNS to do it's best to proceed with them anyway. If you | |||
| use ``--lenient`` above to dump a zone and you'd like to sync it as-is you can | |||
| mark the problematic records this way:: | |||
| 'not-root': | |||
| octodns: | |||
| lenient: true | |||
| type: ALIAS | |||
| values: something.else.com. | |||
| Zone level lenience | |||
| +++++++++++++++++++ | |||
| If you'd like to enable lenience for a whole zone you can do so with the | |||
| following, thought it's strongly encouraged to mark things at record level when | |||
| possible. The most common case where things may need to be done at the zone | |||
| level is when using something other than | |||
| :py:class:`octodns.provider.yaml.YamlProvider` as a source, e.g. syncing from | |||
| ``Route53Provider`` to ``Ns1Provider`` when there are non-compliant records in | |||
| the zone in Route53:: | |||
| non-compliant-zone.com.: | |||
| lenient: true | |||
| sources: | |||
| - route53 | |||
| targets: | |||
| - ns1 | |||
| Restrict Record manipulations | |||
| +++++++++++++++++++++++++++++ | |||
| octoDNS currently provides the ability to limit the number of updates/deletes | |||
| on DNS records by configuring a percentage of allowed operations as a provider | |||
| threshold. If left unconfigured, suitable defaults take over instead. In the | |||
| below example, the Dyn provider is configured with limits of 40% on both update | |||
| and delete operations over all the records present:: | |||
| dyn: | |||
| class: octodns.provider.dyn.DynProvider | |||
| update_pcent_threshold: 0.4 | |||
| delete_pcent_threshold: 0.4 | |||
| Additionally, thresholds can be configured at the zone level. Zone thresholds | |||
| take precedence over any provider default or explicit configuration. Zone | |||
| thresholds do not have a default:: | |||
| zones: | |||
| example.com.: | |||
| update_pcent_threshold: 0.2 | |||
| delete_pcent_threshold: 0.1 | |||
| Provider specific record types | |||
| ------------------------------ | |||
| Creating and registering | |||
| ........................ | |||
| octoDNS has support for provider specific record types through a dynamic type | |||
| registration system. This functionality is powered by | |||
| py:meth:`octodns.record.Record.register_type` and can be used as follows:: | |||
| class _SpecificValue(object): | |||
| ... | |||
| class SomeProviderSpecificRecord(ValuesMixin, Record): | |||
| _type = 'SomeProvider/SPECIFIC' | |||
| _value_type = _SpecificValue | |||
| Record.register_type(SomeProviderSpecificRecord) | |||
| Have a look at ``Route53Provider``'s `Route53Provider/ALIAS`_ for an example. | |||
| _`Route53Provider/ALIAS`: https://github.com/octodns/octodns-route53/blob/main/octodns_route53/record.py | |||
| In general this support is intended for record types that only make sense for a | |||
| single provider. If multiple providers have a similar record it may make sense | |||
| to implement it in octoDNS core. | |||
| Naming | |||
| ...... | |||
| By convention the record type should be prefixed with the provider class, e.g. | |||
| ``Route53Provider`` followed by a ``/`` and an all-caps record type name | |||
| ``ALIAS``, e.g. ``Route53Provider/ALIAS``. | |||
| YamlProvider support | |||
| .................... | |||
| Once the type is registered :py:class:`octodns.provider.yaml.YamlProvider` will | |||
| automatically gain support for it and they can be included in your zone yaml | |||
| files:: | |||
| alias: | |||
| type: Route53Provider/ALIAS | |||
| values: | |||
| - name: www | |||
| type: A | |||
| - name: www | |||
| type: AAAA | |||
| @ -1,23 +1,27 @@ | |||
| #!/bin/bash | |||
| #!/bin/sh | |||
| set -e | |||
| cd "$(dirname "$0")/.." | |||
| ROOT=$(pwd) | |||
| cd "$ROOT" | |||
| rm -rf ./docs/_build ./docs/modules | |||
| if [ -z "$VENV_NAME" ]; then | |||
| VENV_NAME="env" | |||
| fi | |||
| ACTIVATE="$VENV_NAME/bin/activate" | |||
| if [ ! -f "$ACTIVATE" ]; then | |||
| echo "$ACTIVATE does not exist, run ./script/bootstrap" >&2 | |||
| exit 1 | |||
| fi | |||
| . "$ACTIVATE" | |||
| cd docs | |||
| if [ -z "$BUILDER" ]; then | |||
| BUILDER=html | |||
| fi | |||
| for f in $(find octodns -name "*.py" | grep -v __init__.py); do | |||
| module_name=$(echo $f | sed -e 's#/#.#g' -e 's/.py//') | |||
| outdir="docs/modules$(dirname $f | sed -e 's#octodns##')" | |||
| mkdir -p "$outdir" | |||
| cat <<EOL > "${outdir}/${module_name}.rst" | |||
| ==================================== | |||
| ``${module_name}`` | |||
| ==================================== | |||
| .. automodule:: ${module_name} | |||
| EOL | |||
| done | |||
| build="_build/${BUILDER}" | |||
| rm -rf "$build" source/api/records/ source/api/processors/ | |||
| sphinx-build -M html "${ROOT}/docs" "${ROOT}/docs/_build" "$@" | |||
| sphinx-build --builder "$BUILDER" --conf-dir . --fail-on-warning "$@" "source/" "$build" | |||