e1e0.net

sources for e1e0 website
git clone https://git.e1e0.net/e1e0.net.git
Log | Files | Refs

easy-dns-zone-management-accross-providers.md (7190B)


      1 Title: Easy DNS zone management across providers
      2 Author: paco
      3 Date: 2020-06-07
      4 Type: article
      5 
      6 For personal projects and at work I have to manage some DNS zones.  They are
      7 not that many, but I would say that if they are more than 2 or 3, or if the
      8 management interface is not _extremely_ easy and comfortable, a way to automate
      9 this process as much as possible is really beneficial.
     10 
     11 There are many alternatives out there, like Github's [Octodns][1] or
     12 StackExchange's [dnscontrol][2].  I personally use the latter.
     13 
     14 Using tools like these bring a couple of benefits.  For one, you can have your
     15 DNS zones under version control.  Ok, you can do that too with BIND zone files,
     16 but it's more difficult to do that if you use one of the _"cloud providers"_ as
     17 I do at work.  Another benefit is that you can wire this with your CI platform
     18 of choice.  Again, BIND zones are pretty good at this too.  Rsync + reload and
     19 you're set.  This is the magic of *the Unix way*.  Problem is that one cannot
     20 always choose what one works with, but I digress.
     21 
     22 Dnscontrol is both a [DSL][3] and a cli tool that interprets it and takes the
     23 appropriate actions to ensure that your zones are a reflection of what you have
     24 on disk.  Be that API calls to your fancy provider or interactions with
     25 ISC-BIND to update the zones on the fly.
     26 
     27 It's written in Go, so good for your fancy container life and supports a fairly
     28 comprehensive list of providers.
     29 
     30 It also has the ability to export your current zones to dnscontrol's DSL, so
     31 migration is easy.
     32 
     33 And finally, it can be used to issue LetsEncrypt certificates.
     34 
     35 The main problem for me is that the configuration file is JavaScript (or
     36 something pretty similar).  Yes, I facepalmed too.
     37 
     38 But, a part from that, is really simple to use and pretty fast.
     39 
     40 I personally only tested it against `GANDI` and Amazon's `R53`, but I assume it
     41 works the same way for other providers.  There's a fairly good documentation on
     42 their website.
     43 
     44 What I put here are some notes on a basic setup.  The installation process can
     45 take many paths depending on what you want.  So take a look at their
     46 documentation.  There's a port for OpenBSD, so that's what I used.
     47 
     48 Create a folder that will contain all your zone info and credentials to access
     49 your providers.  Remember to ignore the credentials file in your version
     50 control system of choice.
     51 
     52 The credentials file is called `creds.js` by default, but can be anything.
     53 You'll have to pass some info to the cli if you do not use the default.  It
     54 looks like this:
     55 
     56 ```
     57 {
     58   "gandi": {
     59     "apikey": "super-secret-api-key"
     60   },
     61   "r53": {
     62     "KeyId": "super-secret-key-id",
     63     "SecretKey": "super-secret-secret-key"
     64   }
     65 }
     66 ```
     67 
     68 The main file, which describes your zones, it's called `dnsconfig.js` by
     69 default and looks like this:
     70 
     71 ```
     72 // Providers:
     73 
     74 var REG_NONE = NewRegistrar('none', 'NONE');                  // No registrar.
     75 var GANDI = NewDnsProvider("gandi", "GANDI_V5");              // Gandi.
     76 
     77 // Domains:
     78 
     79 D("example.com", REG_NONE, DnsProvider(GANDI),
     80         A('@', '100.100.100.100', TTL(86400)),
     81         AAAA('@', '2000:abc:dead:beef::1', TTL(86400)),
     82         CAA('@', 'issue', 'letsencrypt.org'),
     83         MX('@', 10, 'mail01.example.com.'),
     84         TXT('@', 'v=spf1 a mx ~all'),
     85         SRV('_xmpp-client._tcp', 5, 0, 5222, 'example.com.', TTL(86400)),
     86         SRV('_xmpp-server._tcp', 5, 0, 5269, 'example.com.', TTL(86400)),
     87         A('main', '100.100.100.200', TTL(86400)),
     88         CNAME('foo', 'example.com.', TTL(600)),
     89         CNAME('bar', 'main.example.com.', TTL(600))
     90 );
     91 ```
     92 
     93 As you can see, first there's the provider definition.  The `REG_NONE` line is
     94 there to define an "empty registrar".  I do this because my zones are already
     95 registered with my providers, but you could create the zone and register it
     96 automatically if all your config is correct.
     97 
     98 In fact, the only required parameters to the `D` function are the `fqdn` and
     99 the registrar.
    100 
    101 Each domain has its `D` function that defines it.  I usually organize it like
    102 you see on the example.  With the 1st line containing the `fqdn`, registrar and
    103 DNS provider, and then one line per DNS record.  That makes a lot of sense for
    104 visually clean diffs later on.  But you can use whatever you want as long as
    105 you respect the syntax.
    106 
    107 There's a complete description list of the DSL functions and modifiers at the
    108 [language reference][4] section of their website.
    109 
    110 Once you have your zones defined, execute `dnscontrol preview`.  I would
    111 recommend to set the records as you have them if the zone already exists (more
    112 on this later).  In that case the output should be similar to this:
    113 
    114 ```
    115 ******************** Domain: example.com
    116 ----- Getting nameservers from: gandi
    117 ----- DNS Provider: gandi...0 corrections
    118 ----- Registrar: none...0 corrections
    119 ```
    120 
    121 When you have changes it may look similar to this:
    122 
    123 ```
    124 ******************** Domain: example.com
    125 ----- Getting nameservers from: gandi
    126 ----- DNS Provider: gandi...2 corrections
    127 #1: CREATE CNAME blah.example.com foo.duckdns.org. ttl=600
    128 #2: MODIFY CNAME bar.example.com: (main.example.com. ttl=600) -> (abc.duckdns.org. ttl=600)
    129 ----- Registrar: none...0 corrections
    130 ```
    131 
    132 To actually apply the changes, execute `dnscontrol push`
    133 
    134 You can specify the location of the credentials file and the zones file using
    135 `--creds file` and `--config file`.  Check the command help for more
    136 information.
    137 
    138 As I said earlier, `dnscontrol` can export your current zone definitions
    139 converting them to its DSL in the process.  To do that, the command would look
    140 something like this:
    141 
    142 ```
    143 dnscontrol get-zones --format=js gandi GANDI_V5 example.com
    144 ```
    145 
    146 That will dump to `stdout` your zone in the JS DSL format.  I recommend to
    147 review the export.  Sometimes is not as good as you might expect.
    148 
    149 The first argument after the format is the credential definition, the second
    150 one is the provider type and then a list of zones to export.
    151 
    152 I should mention that it can also export in other formats, like BIND file
    153 format or TSV, so it can be used to do other kind of migrations too.
    154 
    155 And finally, the TLS certificates.
    156 
    157 This needs another config file, called `certs,json` by default.  Again pretty
    158 simple, it looks like this:
    159 
    160 ```
    161  [
    162      {
    163          "cert_name": "downloads",
    164          "names": [
    165              "dl.example.com"
    166          ]
    167      },
    168      {
    169          "cert_name": "web",
    170          "names": [
    171              "example.com",
    172              "www.example.com"
    173          ]
    174      }
    175  ]
    176 ```
    177 
    178 Then you can call it like this:
    179 
    180 ```
    181 dnscontrol get-certs --email me@example.com --agreeTOS --dir './certs'
    182 ```
    183 
    184 That will crate a hierarchy under `./certs` with the generated keys and
    185 certificates (plus some json metadata).
    186 
    187 There are some more options on this command to change the ACME issuer (which
    188 has defaults for Let's Encrypt), remaining days to renew, etc.  Take a look at
    189 the command help for more info.
    190 
    191 In combination with cron and scp/rsync/whatever it can be used to have
    192 a central point for certificate generation.
    193 
    194 Hope it's useful.
    195 
    196 [1]: https://github.com/github/octodns
    197 [2]: https://stackexchange.github.io/dnscontrol/
    198 [3]: https://en.wikipedia.org/wiki/Domain-specific_language
    199 [4]: https://stackexchange.github.io/dnscontrol/js