captainarkdotnet/public/2018/04/14/dns-zone-versioning/index.html

522 lines
16 KiB
HTML

<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="twitter:card" content="summary"/>
<meta name="twitter:title" content="DNS zone versioning"/>
<meta name="twitter:description" content=""/>
<meta name="twitter:site" content="@"/>
<meta property="og:title" content="DNS zone versioning &middot; Sysadmining. All day. Every day." />
<meta property="og:site_name" content="Sysadmining. All day. Every day." />
<meta property="og:url" content="https://www.captainark.net/2018/04/14/dns-zone-versioning/" />
<meta property="og:image" content="/images/cover.jpg"/>
<meta property="og:description" content="" />
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2018-04-14T00:00:00&#43;01:00" />
<title>DNS zone versioning &middot; Sysadmining. All day. Every day.</title>
<meta name="description" content="I&amp;rsquo;ve been using PowerDNS with a SQL backend as a hidden master DNS server for a few years now.
I&amp;rsquo;ve been wanting to write a quick shell script to ve" />
<meta name="HandheldFriendly" content="True" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="shortcut icon" href="https://www.captainark.net/images/favicon.ico">
<link rel="apple-touch-icon" href="https://www.captainark.net/images/apple-touch-icon.png" />
<link rel="stylesheet" type="text/css" href="https://www.captainark.net/css/screen.css" />
<link rel="stylesheet" type="text/css" href="https://www.captainark.net/css/nav.css" />
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Merriweather:300,700,700italic,300italic|Open+Sans:700,400|Inconsolata:700,400" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/styles/solarized-light.min.css" integrity="sha384-bFKDPkG3geCujYJIbPornilfOgmYQoPS45Oh/8daqqo1SUwNY06OeHorpgnNvx82" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/highlight.min.js" integrity="sha384-BlPof9RtjBqeJFskKv3sK3dh4Wk70iKlpIe92FeVN+6qxaGUOUu+mZNpALZ+K7ya" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://www.captainark.net/js/hjsload.js"></script>
<link href="https://www.captainark.net/index.xml" rel="alternate" type="application/rss+xml" title="Sysadmining. All day. Every day." />
<meta name="generator" content="Hugo 0.53" />
<link rel="canonical" href="https://www.captainark.net/2018/04/14/dns-zone-versioning/" />
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"publisher": {
"@type": "Organization",
"name": ,
"logo": https://www.captainark.net/images/logo.png
},
"author": {
"@type": "Person",
"name": ,
"image": {
"@type": "ImageObject",
"url": https://www.captainark.net/images/author.jpg,
"width": 250,
"height": 250
},
"url": https://www.captainark.net,
"sameAs": [
],
"description": Geek | Gamer | TV Shows Aficionado
},
"headline": DNS zone versioning,
"name": DNS zone versioning,
"wordCount": 621,
"timeRequired": "PT3M",
"inLanguage": {
"@type": "Language",
"alternateName": en
},
"url": https://www.captainark.net/2018/04/14/dns-zone-versioning/,
"datePublished": 2018-04-14T00:00Z,
"dateModified": 2018-04-14T00:00Z,
"description": ,
"mainEntityOfPage": {
"@type": "WebPage",
"@id": https://www.captainark.net/2018/04/14/dns-zone-versioning/
}
}
</script>
<script type="text/javascript" src="https://www.captainark.net/js/stats.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fork-awesome@1.1.5/css/fork-awesome.min.css" integrity="sha256-P64qV9gULPHiZTdrS1nM59toStkgjM0dsf5mK/UwBV4=" crossorigin="anonymous">
</head>
<body class="nav-closed">
<div class="nav">
<h3 class="nav-title">Menu</h3>
<a href="#" class="nav-close">
<span class="hidden">Close</span>
</a>
<ul>
<h3>This site</h3>
<li class="nav-opened" role="presentation">
<a href="https://www.captainark.net/">Home</a>
</li>
<li class="nav-opened" role="presentation">
<a href="https://www.captainark.net/about">About</a>
</li>
<li class="nav-opened" role="presentation">
<a href="https://www.captainark.net/resume">Resume</a>
</li>
<h3>Other services</h3>
<li class="nav-opened" role="presentation">
<a href="https://git.captainark.net">Gitea</a>
</li>
<li class="nav-opened" role="presentation">
<a href="https://pics.captainark.net">Chevereto</a>
</li>
<li class="nav-opened" role="presentation">
<a href="https://paste.captainark.net">Privatebin</a>
</li>
<li class="nav-opened" role="presentation">
<a href="https://chat.captainark.net">Rocket.Chat</a>
</li>
</ul>
<a class="subscribe-button icon-feed" href="https://www.captainark.net/index.xml">Subscribe</a>
</div>
<span class="nav-cover"></span>
<div class="site-wrapper">
<header class="main-header post-head no-cover">
<nav class="main-nav clearfix">
<a class="blog-logo" href="https://www.captainark.net/"><img src="https://www.captainark.net/images/logo.png" alt="Home" /></a>
<a class="menu-button" href="#"><span class="burger">&#9776;</span><span class="word">Menu</span></a>
</nav>
</header>
<main class="content" role="main">
<article class="post post">
<header class="post-header">
<h1 class="post-title">DNS zone versioning</h1>
<small></small>
<section class="post-meta">
<time class="post-date" datetime="2018-04-14T00:00:00&#43;01:00">
14 April 2018
</time>
</section>
</header>
<section class="post-content">
<p>I&rsquo;ve been using <a href="https://doc.powerdns.com/md/">PowerDNS</a> with a SQL backend as a hidden master DNS server for a few years now.</p>
<p>I&rsquo;ve been wanting to write a quick shell script to version my DNS zones for a while, and since I&rsquo;ve finally taken the time to do so today, I figured I&rsquo;d share it here.</p>
<p>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</p>
<h1 id="configuration">Configuration</h1>
<h2 id="powerdns">PowerDNS</h2>
<p>For the script to work, we have to activate PowerDNS&rsquo; API.</p>
<p>To do so, let&rsquo;s create a <code>/etc/powerdns/pdns.d/api.conf</code> file with the following content :</p>
<pre><code>api=yes
api-key=mysupersecretapikey
webserver=yes
webserver-address=10.0.0.10
webserver-allow-from=10.0.0.0/8
webserver-port=8081
</code></pre>
<p>You should change <em>mysupersecretapikey</em> to an actual secret.</p>
<p>You should also adapt the <code>webserver-address</code> and <code>webserver-allow-from</code> to reflect your network configuration.</p>
<p>Once the file is created, we have to restart pdnsd :</p>
<pre><code>systemctl restart pdns.service
</code></pre>
<p><strong>N.B. :</strong> As with all my other articles, I&rsquo;m assuming here you&rsquo;re running Debian. The path of the configuration file you have to create or edit might not be the same if you&rsquo;re running another distribution or if you&rsquo;ve installed PowerDNS from source.</p>
<h2 id="jq">jq</h2>
<p><a href="https://stedolan.github.io/jq/">jq</a> is required for the script to work, so let&rsquo;s install it !</p>
<pre><code>apt install jq
</code></pre>
<h2 id="git">Git</h2>
<p>We now have to create a git repository to host our zone files.</p>
<p>To do so, you can follow my <a href="https://www.captainark.net/2016/01/31/private-git-repo/">previous tutorial</a> on the subject if you want.</p>
<p>I&rsquo;ve personnaly migrated my git repos to a self-hosted <a href="https://gogs.io/">Gogs</a> installation a while back.</p>
<p>If you don&rsquo;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).</p>
<p>Once you&rsquo;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 <code>/home/captainark/backup/dnsexport</code>.</p>
<pre><code>apt install git
mkdir ~/backup &amp;&amp; cd ~/backup
git clone ssh://git@git.captainark.net/captainark/dnsexport.git
</code></pre>
<p>You should also create a <code>~/.gitconfig</code> for the user that will run the script with the following parameters configured :</p>
<pre><code>[user]
email = captainark@captainark.net
name = CaptainArk
[push]
default = simple
</code></pre>
<p>Also, make sure your user can push to the remote server before running the script. The following should work :</p>
<pre><code>cd ~/backup/dnsexport
echo '# DNSEXPORT' &gt; README.md
git add README.md
git commit README.md -m 'adding README'
git push
</code></pre>
<h1 id="script">Script</h1>
<p>Once we&rsquo;ve finished configuring PowerDNS and Git, we can run the script.</p>
<p>You can copy the following to <code>~/bin/dnsexport</code> :</p>
<pre><code class="language-bash">#!/bin/bash
ApiKey=&quot;mysupersecretapikey&quot;
PdnsUrl=&quot;10.0.0.10:8081&quot;
PdnsServerName=&quot;localhost&quot;
PdnsZoneUrl=&quot;http://${PdnsUrl}/api/v1/servers/${PdnsServerName}/zones&quot;
ZoneList=$(/usr/bin/curl -sH &quot;X-API-Key: ${ApiKey}&quot; ${PdnsZoneUrl} | jq -r '.[].id')
ExportFolder=&quot;/home/captainark/backup/dnsexport&quot;
updateremote() {
cd $ExportFolder
git add db.${Zone%.}
git commit -m &quot;Automated commit due to modification on ${Zone%.} at $(date -Iseconds)&quot;
git push
cd -
}
for Zone in ${ZoneList}; do
ZoneFile=&quot;${ExportFolder}/db.${Zone%.}&quot;
CurrentShaSum=$(/usr/bin/sha256sum ${ZoneFile})
/usr/bin/curl -o ${ZoneFile} -sH &quot;X-API-Key: ${ApiKey}&quot; ${PdnsZoneUrl}/${Zone}/export
NewShaSum=$(/usr/bin/sha256sum ${ZoneFile})
[[ ${NewShaSum% *} != ${CurrentShaSum% *} ]] &amp;&amp; updateremote
done
</code></pre>
<p>It&rsquo;s nothing fancy, but it does the job.</p>
<p>You&rsquo;ll have to adapt the <code>ApiKey</code>, <code>PdnsUrl</code> and <code>ExportFolder</code> variables to your configuration.</p>
<p>Once that&rsquo;s done, let&rsquo;s fix the permissions on the script :</p>
<pre><code>chmod 700 ~/bin/dnsexport
</code></pre>
<p>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.</p>
<p>Once the script has executed once without issue, you can schedule it regularly. I have it running every 10 minutes in my user&rsquo;s crontab :</p>
<pre><code>crontab -e
# DNSEXPORT
*/10 * * * * /home/captainark/bin/dnsexport
</code></pre>
<h1 id="conclusion">Conclusion</h1>
<p>That&rsquo;s all !</p>
<p>As always, if you&rsquo;ve found this article useful, please feel free to make use of the comments section below !</p>
<p>Hopefully it won&rsquo;t take as long before I write another article here next time !</p>
</section>
<footer class="post-footer">
<figure class="author-image">
<a class="img" href="https://www.captainark.net/" style="background-image: url(/images/author.jpg)"><span class="hidden">Antoine Joubert's Picture</span></a>
</figure>
<section class="author">
<h4><a href="https://www.captainark.net/">Antoine Joubert</a></h4>
<p>Geek | Gamer | TV Shows Aficionado</p>
<div class="author-meta">
<span class="author-location icon-location">Angers, France</span>
<span class="author-link icon-link"><a href="https://www.captainark.net">https://www.captainark.net</a></span>
</div>
</section>
<!-- isso -->
<script data-isso="https://www.captainark.net/comments/" src="https://www.captainark.net/comments/js/embed.min.js"></script>
<noscript>Please enable JavaScript to view comments</noscript>
<section id="isso-thread"></section>
<!-- end isso -->
</footer>
</article>
</main>
<aside class="read-next">
<a class="read-next-story" style="no-cover" href="https://www.captainark.net/2018/11/27/self-hosted-report-uri/">
<section class="post">
<h2>Self-hosted report-uri</h2>
</section>
</a>
<a class="read-next-story prev" style="no-cover" href="https://www.captainark.net/2017/11/19/installing-ghost/">
<section class="post">
<h2>Installing Ghost</h2>
</section>
</a>
</aside>
<center>
<a class="fa-icons" href="mailto:contact@captainark.net">
<span class="fa-stack fa-lg">
<i class="fa fa-circle fa-stack-2x"></i>
<i class="fa fa-envelope fa-stack-1x fa-inverse"></i>
</span>
</a>
<a class="fa-icons" href="https://twitter.com/captainark">
<span class="fa-stack fa-lg">
<i class="fa fa-circle fa-stack-2x"></i>
<i class="fa fa-twitter fa-stack-1x fa-inverse"></i>
</span>
</a>
<a class="fa-icons" href="https://social.captainark.net/users/captainark">
<span class="fa-stack fa-lg">
<i class="fa fa-circle fa-stack-2x"></i>
<i class="fa fa-mastodon-alt fa-stack-1x fa-inverse"></i>
</span>
</a>
<a class="fa-icons" href="https://github.com/captainark">
<span class="fa-stack fa-lg">
<i class="fa fa-circle fa-stack-2x"></i>
<i class="fa fa-github fa-stack-1x fa-inverse"></i>
</span>
</a>
<a class="fa-icons" href="https://www.last.fm/user/captainark">
<span class="fa-stack fa-lg">
<i class="fa fa-circle fa-stack-2x"></i>
<i class="fa fa-lastfm fa-stack-1x fa-inverse"></i>
</span>
</a>
<a class="fa-icons" href="https://steamcommunity.com/id/captainark">
<span class="fa-stack fa-lg">
<i class="fa fa-circle fa-stack-2x"></i>
<i class="fa fa-steam fa-stack-1x fa-inverse"></i>
</span>
</a>
<a class="fa-icons" href="https://www.twitch.tv/captainark">
<span class="fa-stack fa-lg">
<i class="fa fa-circle fa-stack-2x"></i>
<i class="fa fa-twitch fa-stack-1x fa-inverse"></i>
</span>
</a>
</center>
<footer class="site-footer clearfix">
<section class="copyright"><a href="">Sysadmining. All day. Every day.</a> © 2015 - 2019</section>
<section class="poweredby">Proudly generated by <a class="icon-hugo" href="http://gohugo.io">HUGO</a>, with <a class="icon-theme" href="https://github.com/vjeantet/hugo-theme-casper">Casper</a> theme</section>
</footer>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js" integrity="sha384-CgeP3wqr9h5YanePjYLENwCTSSEz42NJkbFpAFgHWQz7u3Zk8D00752ScNpXqGjS" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fitvids/1.1.0/jquery.fitvids.min.js" integrity="sha384-2/VQUb0aZHixKnNLh7pD38DZk+acGpEw5LeHieWVDPR0h/H326kp/1qnRPDYmFXM" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://www.captainark.net/js/index.js"></script>
</body>
</html>