#! /usr/bin/env python3 import argparse import docker import sys import re def get_zones(container): out = container.exec_run(['pdnsutil', 'list-all-zones']) if out is not None: out = out.decode('UTF-8') # bytres to string zones = out.split('\n') # convert to list, one zone per line zones = list(filter(None, zones)) # remove any empty lines zones = zones[0:len(zones) - 1] # remove last line 'All zonecount: xx' return zones return None def add_zone(container, zone): out = container.exec_run(['pdnsutil', 'create-zone', zone]) if out is not None: out = out.decode('UTF-8') if out != 'Creating empty zone \'%s\'\n' % (zone): # might to strict, but as we can not get return code return False out = container.exec_run(['pdnsutil', 'set-kind', zone, 'master']) out = out.decode('UTF-8') return out == ''; return False def get_tsig_keys(container): out = container.exec_run(['pdnsutil', 'list-tsig-keys']) if out is not None: out = out.decode('UTF-8') # bytres to string keys = out.split('\n') # convert to list, one key per line keys = list(filter(None, keys)) # remove any empty lines keys = {"%s|%s" % (key[0], key[1]): key for key in [key.split(' ') for key in keys]} return keys return None def add_tsig_key(container, key_name, key_algo): out = container.exec_run(['pdnsutil', 'generate-tsig-key', key_name, key_algo]) if out is not None: out = out.decode('UTF-8') match = re.search('Create new TSIG key %s %s (.+)' % (re.escape(key_name), re.escape(key_algo)), out) if match: key = match.group(1) return key else: return None return None def add_tsig_key_to_zone(container, zone, key_name): out = container.exec_run(['pdnsutil', 'set-meta', zone, 'TSIG-ALLOW-DNSUPDATE', key_name]) if out is not None: out = out.decode('UTF-8') return out == 'Enabled TSIG key %s for %s\n' % (key_name, zone) # might to strict, but as we can not get return code return False def main(): parser = argparse.ArgumentParser(description='Init Powerdns server') parser.add_argument('--dhcp-zone', dest='dhcp_zone', default=None, help='DHCP zone to create (eg: dhcp.city-a.example.com)') parser.add_argument('--site-zone', dest='site_zone', default=None, help='Site zone to create (eg: city-a.example.com)') parser.add_argument('--rev-zone', dest='rev_zone', default=None, help='Reverse zone to create (eg: 100.15.10), arpa suffix will be added automatically') parser.add_argument('--tsig-key-name', dest='tsig_key_name', default='dhcpupdate', help='TSIG key name to add (eg: dnsupdate)') parser.add_argument('--tsig-key-algo', dest='tsig_key_algo', default='hmac-md5', help='TSIG key algorithm to use (eg: hmac-md5)') parser.add_argument('--container-pdns', dest='container_pdns', default='pdns-pdns', help='Name of pdns auth docker container (eg: pdns-pdns)') args = parser.parse_args() if args.dhcp_zone is None and args.site_zone is None: print('At least one of dhcp-zone or site-zone is required') return 64 if args.rev_zone is not None and not args.rev_zone.endswith('.in-addr.arpa'): args.rev_zone = args.rev_zone + '.in-addr.arpa' print('Getting docker client instance...') try: client = docker.DockerClient(version='auto') client.ping() except Exception as e: print('Failed to ping docker server: %s' % (e)) return 1 print('Getting docker container %s...' % (args.container_pdns)) try: container = client.containers.get(args.container_pdns) except Exception as e: print('Can not find container %s' % (e)) return 2 if container.status != 'running': print('Container is not running: %s' % (container.status)) return 3 print('Checking existing zones...') zones = get_zones(container) if zones is None: print('Failes to get existing zones: Unknown error') return 4 print('Checking existing TSIG keys...') keys = get_tsig_keys(container) if keys is None: print('Failes to get existing TSIG keys: Unknown error') return 5 if '%s.|%s.' % (args.tsig_key_name, args.tsig_key_algo) in keys: print('Not adding TSIG key %s %s: already exists' % (args.tsig_key_name, args.tsig_key_algo)) tsig_key_secret = keys['%s.|%s.' % (args.tsig_key_name, args.tsig_key_algo)][2] else: print('Adding TSIG key %s %s...' % (args.tsig_key_name, args.tsig_key_algo)) tsig_key_secret = add_tsig_key(container, args.tsig_key_name, args.tsig_key_algo) if tsig_key_secret is None: print('Failed to add TSIG key: Unknown error') return 6 for zone in [args.dhcp_zone, args.site_zone, args.rev_zone]: if zone is not None: if zone in zones: print('Not adding zone %s: already exists' % (zone)) else: print('Adding zone...') if not add_zone(container, zone): print('Failed to add zone: Unknown error') return 7 print('Adding TSIG %s to zone %s...' % (args.tsig_key_name, zone)) if not add_tsig_key_to_zone(container, zone, args.tsig_key_name): print('Failed to add TSIG key to zone: Unknown error') print('DHCP_TSIG_KEY_NAME=%s' % (args.tsig_key_name)) print('DHCP_TSIG_KEY_ALGO=%s' % (args.tsig_key_algo)) print('DHCP_TSIG_KEY_SECRET=%s' % (tsig_key_secret)) return 0 if __name__ == '__main__': sys.exit(main())