|
@@ -0,0 +1,134 @@
|
|
1
|
+#! /usr/bin/env python3
|
|
2
|
+
|
|
3
|
+import argparse
|
|
4
|
+import docker
|
|
5
|
+import sys
|
|
6
|
+import re
|
|
7
|
+
|
|
8
|
+def get_zones(container):
|
|
9
|
+ out = container.exec_run(['pdnsutil', 'list-all-zones'])
|
|
10
|
+ if out is not None:
|
|
11
|
+ out = out.decode('UTF-8') # bytres to string
|
|
12
|
+ zones = out.split('\n') # convert to list, one zone per line
|
|
13
|
+ zones = list(filter(None, zones)) # remove any empty lines
|
|
14
|
+ zones = zones[0:len(zones) - 1] # remove last line 'All zonecount: xx'
|
|
15
|
+ return zones
|
|
16
|
+ return None
|
|
17
|
+
|
|
18
|
+def add_zone(container, zone):
|
|
19
|
+ out = container.exec_run(['pdnsutil', 'create-zone', zone])
|
|
20
|
+ if out is not None:
|
|
21
|
+ out = out.decode('UTF-8')
|
|
22
|
+ return out == 'Creating empty zone \'%s\'\n' % (zone) # might to strict, but as we can not get return code
|
|
23
|
+ return False
|
|
24
|
+
|
|
25
|
+def get_tsig_keys(container):
|
|
26
|
+ out = container.exec_run(['pdnsutil', 'list-tsig-keys'])
|
|
27
|
+ if out is not None:
|
|
28
|
+ out = out.decode('UTF-8') # bytres to string
|
|
29
|
+ keys = out.split('\n') # convert to list, one key per line
|
|
30
|
+ keys = list(filter(None, keys)) # remove any empty lines
|
|
31
|
+ keys = {"%s|%s" % (key[0], key[1]): key for key in [key.split(' ') for key in keys]}
|
|
32
|
+ return keys
|
|
33
|
+ return None
|
|
34
|
+
|
|
35
|
+def add_tsig_key(container, key_name, key_algo):
|
|
36
|
+ out = container.exec_run(['pdnsutil', 'generate-tsig-key', key_name, key_algo])
|
|
37
|
+ if out is not None:
|
|
38
|
+ out = out.decode('UTF-8')
|
|
39
|
+ match = re.search('Create new TSIG key %s %s (.+)' % (re.escape(key_name), re.escape(key_algo)), out)
|
|
40
|
+ if match:
|
|
41
|
+ key = match.group(1)
|
|
42
|
+ return key
|
|
43
|
+ else:
|
|
44
|
+ return None
|
|
45
|
+ return None
|
|
46
|
+
|
|
47
|
+def add_tsig_key_to_zone(container, zone, key_name):
|
|
48
|
+ out = container.exec_run(['pdnsutil', 'set-meta', zone, 'TSIG-ALLOW-DNSUPDATE', key_name])
|
|
49
|
+ if out is not None:
|
|
50
|
+ out = out.decode('UTF-8')
|
|
51
|
+ return out == 'Enabled TSIG key %s for %s\n' % (key_name, zone) # might to strict, but as we can not get return code
|
|
52
|
+ return False
|
|
53
|
+
|
|
54
|
+def main():
|
|
55
|
+ parser = argparse.ArgumentParser(description='Init Powerdns server')
|
|
56
|
+ parser.add_argument('--dhcp-zone', dest='dhcp_zone', default=None, help='DHCP zone to create (eg: dhcp.city-a.example.com)')
|
|
57
|
+ parser.add_argument('--site-zone', dest='site_zone', default=None, help='Site zone to create (eg: city-a.example.com)')
|
|
58
|
+ 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')
|
|
59
|
+ parser.add_argument('--tsig-key-name', dest='tsig_key_name', default='dhcpupdate', help='TSIG key name to add (eg: dnsupdate)')
|
|
60
|
+ parser.add_argument('--tsig-key-algo', dest='tsig_key_algo', default='hmac-md5', help='TSIG key algorithm to use (eg: hmac-md5)')
|
|
61
|
+ parser.add_argument('--container-pdns', dest='container_pdns', default='pdns-pdns', help='Name of pdns auth docker container (eg: pdns-pdns)')
|
|
62
|
+
|
|
63
|
+ args = parser.parse_args()
|
|
64
|
+
|
|
65
|
+ if args.dhcp_zone is None and args.site_zone is None:
|
|
66
|
+ print('At least one of dhcp-zone or site-zone is required')
|
|
67
|
+ return 64
|
|
68
|
+
|
|
69
|
+ if args.rev_zone is not None and not args.rev_zone.endswith('.in-addr.arpa'):
|
|
70
|
+ args.rev_zone = args.rev_zone + '.in-addr.arpa'
|
|
71
|
+
|
|
72
|
+ print('Getting docker client instance...')
|
|
73
|
+ try:
|
|
74
|
+ client = docker.DockerClient(version='auto')
|
|
75
|
+ client.ping()
|
|
76
|
+ except Exception as e:
|
|
77
|
+ print('Failed to ping docker server: %s' % (e))
|
|
78
|
+ return 1
|
|
79
|
+
|
|
80
|
+ print('Getting docker container %s...' % (args.container_pdns))
|
|
81
|
+ try:
|
|
82
|
+ container = client.containers.get(args.container_pdns)
|
|
83
|
+ except Exception as e:
|
|
84
|
+ print('Can not find container %s' % (e))
|
|
85
|
+ return 2
|
|
86
|
+
|
|
87
|
+ if container.status != 'running':
|
|
88
|
+ print('Container is not running: %s' % (container.status))
|
|
89
|
+ return 3
|
|
90
|
+
|
|
91
|
+ print('Checking existing zones...')
|
|
92
|
+ zones = get_zones(container)
|
|
93
|
+ if zones is None:
|
|
94
|
+ print('Failes to get existing zones: Unknown error')
|
|
95
|
+ return 4
|
|
96
|
+
|
|
97
|
+ print('Checking existing TSIG keys...')
|
|
98
|
+ keys = get_tsig_keys(container)
|
|
99
|
+ if keys is None:
|
|
100
|
+ print('Failes to get existing TSIG keys: Unknown error')
|
|
101
|
+ return 5
|
|
102
|
+
|
|
103
|
+ if '%s.|%s.' % (args.tsig_key_name, args.tsig_key_algo) in keys:
|
|
104
|
+ print('Not adding TSIG key %s %s: already exists' % (args.tsig_key_name, args.tsig_key_algo))
|
|
105
|
+ tsig_key_secret = keys['%s.|%s.' % (args.tsig_key_name, args.tsig_key_algo)][2]
|
|
106
|
+ else:
|
|
107
|
+ print('Adding TSIG key %s %s...' % (args.tsig_key_name, args.tsig_key_algo))
|
|
108
|
+ tsig_key_secret = add_tsig_key(container, args.tsig_key_name, args.tsig_key_algo)
|
|
109
|
+ if tsig_key_secret is None:
|
|
110
|
+ print('Failed to add TSIG key: Unknown error')
|
|
111
|
+ return 6
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+ for zone in [args.dhcp_zone, args.site_zone, args.rev_zone]:
|
|
115
|
+ if zone is not None:
|
|
116
|
+ if zone in zones:
|
|
117
|
+ print('Not adding zone %s: already exists' % (zone))
|
|
118
|
+ else:
|
|
119
|
+ print('Adding zone...')
|
|
120
|
+ if not add_zone(container, zone):
|
|
121
|
+ print('Failed to add zone: Unknown error')
|
|
122
|
+ return 7
|
|
123
|
+ print('Adding TSIG %s to zone %s...' % (args.tsig_key_name, zone))
|
|
124
|
+ if not add_tsig_key_to_zone(container, zone, args.tsig_key_name):
|
|
125
|
+ print('Failed to add TSIG key to zone: Unknown error')
|
|
126
|
+
|
|
127
|
+ print('DHCP_TSIG_KEY_NAME=%s' % (args.tsig_key_name))
|
|
128
|
+ print('DHCP_TSIG_KEY_ALGO=%s' % (args.tsig_key_algo))
|
|
129
|
+ print('DHCP_TSIG_KEY_SECRET=%s' % (tsig_key_secret))
|
|
130
|
+
|
|
131
|
+ return 0
|
|
132
|
+
|
|
133
|
+if __name__ == '__main__':
|
|
134
|
+ sys.exit(main())
|