# DNS zone versioning

14 April 2018

I’ve been using PowerDNS with a SQL backend as a hidden master DNS server for a few years now.

I’ve been wanting to write a quick shell script to version my DNS zones for a while, and since I’ve finally taken the time to do so today, I figured I’d share it here.

The script uses PowerDNS API to list the configured zones. It then exports them to a file in an AXFR-like format, commits and finally pushes them on a git repository

# Configuration

## PowerDNS

For the script to work, we have to activate PowerDNS’ API.

To do so, let’s create a `/etc/powerdns/pdns.d/api.conf` file with the following content :

    api=yes
    api-key=mysupersecretapikey
    webserver=yes
    webserver-address=10.0.0.10
    webserver-allow-from=10.0.0.0/8
    webserver-port=8081

You should change mysupersecretapikey to an actual secret.

You should also adapt the `webserver-address` and `webserver-allow-from` to reflect your network configuration.

Once the file is created, we have to restart pdnsd :

    systemctl restart pdns.service

N.B. : As with all my other articles, I’m assuming here you’re running Debian. The path of the configuration file you have to create or edit might not be the same if you’re running another distribution or if you’ve installed PowerDNS from source.

## jq

jq is required for the script to work, so let’s install it !

    apt install jq

## Git

We now have to create a git repository to host our zone files.

To do so, you can follow my previous tutorial on the subject if you want.

I’ve personnaly migrated my git repos to a self-hosted Gogs installation a while back.

If you don’t care about your zones content being public (it already is, technically), you could create a GitHub repo for that use (or on any other available git hosting).

Once you’ve created your repo, you should clone it on the machine that will run the script. For me, the path to the repo will be `/home/captainark/backup/dnsexport`.

    apt install git
    mkdir ~/backup && cd ~/backup
    git clone ssh://git@git.captainark.net/captainark/dnsexport.git

You should also create a `~/.gitconfig` for the user that will run the script with the following parameters configured :

    [user]
            email = captainark@captainark.net
            name = CaptainArk
    [push]
            default = simple

Also, make sure your user can push to the remote server before running the script. The following should work :

    cd ~/backup/dnsexport
    echo '# DNSEXPORT' > README.md
    git add README.md
    git commit README.md -m 'adding README'
    git push

# Script

Once we’ve finished configuring PowerDNS and Git, we can run the script.

You can copy the following to `~/bin/dnsexport` :

    #!/bin/bash

    ApiKey="mysupersecretapikey"
    PdnsUrl="10.0.0.10:8081"
    PdnsServerName="localhost"
    PdnsZoneUrl="http://${PdnsUrl}/api/v1/servers/${PdnsServerName}/zones"
    ZoneList=$(/usr/bin/curl -sH "X-API-Key: ${ApiKey}" ${PdnsZoneUrl} | jq -r '.[].id')
    ExportFolder="/home/captainark/backup/dnsexport"

    updateremote() {
      cd $ExportFolder
      git add db.${Zone%.}
      git commit -m "Automated commit due to modification on ${Zone%.} at $(date -Iseconds)"
      git push
      cd -
    }

    for Zone in ${ZoneList}; do
      ZoneFile="${ExportFolder}/db.${Zone%.}"
      CurrentShaSum=$(/usr/bin/sha256sum ${ZoneFile})
      /usr/bin/curl -o ${ZoneFile} -sH "X-API-Key: ${ApiKey}" ${PdnsZoneUrl}/${Zone}/export
      NewShaSum=$(/usr/bin/sha256sum ${ZoneFile})
      [[ ${NewShaSum%  *} != ${CurrentShaSum%  *} ]] && updateremote
    done

It’s nothing fancy, but it does the job.

You’ll have to adapt the `ApiKey`, `PdnsUrl` and `ExportFolder` variables to your configuration.

Once that’s done, let’s fix the permissions on the script :

    chmod 700 ~/bin/dnsexport

You should run the script manually once to make sure everything is working OK. If it is, you should see a new commit on the repo for each zone you have configured in PowerDNS.

Once the script has executed once without issue, you can schedule it regularly. I have it running every 10 minutes in my user’s crontab :

    crontab -e
    # DNSEXPORT
    */10 * * * * /home/captainark/bin/dnsexport

# Conclusion

That’s all !

As always, if you’ve found this article useful, please feel free to make use of the comments section below !

Hopefully it won’t take as long before I write another article here next time !

## Self-hosted report-uri

## Installing Ghost