You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

init.py 5.5KB

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