|
@@ -4,46 +4,68 @@
|
|
|
Pure Python TSIG key generator, with multiple output formats.
|
|
|
"""
|
|
|
|
|
|
-import os, base64, argparse
|
|
|
+import os, base64, argparse, jinja2
|
|
|
|
|
|
algorithm_bits = dict(("hmac-sha{}".format(bits), bits // 8) for bits in (256, 384, 512))
|
|
|
+algorithm_choices = tuple(sorted(algorithm_bits))
|
|
|
|
|
|
-bind9_template = '''
|
|
|
-key {name} {{
|
|
|
- algorithm {algorithm};
|
|
|
- secret "{secret}";
|
|
|
-}};
|
|
|
-'''
|
|
|
+templates = dict(
|
|
|
|
|
|
-nsd_template = '''
|
|
|
+ bind9 = '''
|
|
|
+key {{ args.name }} {
|
|
|
+ algorithm {{ args.algorithm }};
|
|
|
+ secret "{{ args.key }}";
|
|
|
+};
|
|
|
+
|
|
|
+{% if args.servers %}
|
|
|
+{%- for server in args.servers -%}
|
|
|
+server {{ server }} { keys { {{ args.name }}; }; };
|
|
|
+{% endfor -%}
|
|
|
+{% for zone in args.zones %}
|
|
|
+zone "{{ zone }}" {
|
|
|
+ file "{{args.directory }}/{{ zone }}";
|
|
|
+ type slave;
|
|
|
+ masters { {%- for server in args.servers %} {{ server }}; {% endfor %} };
|
|
|
+};
|
|
|
+{% endfor %}
|
|
|
+{% endif %}
|
|
|
+''',
|
|
|
+
|
|
|
+ nsd = '''
|
|
|
key:
|
|
|
- name: "{name}"
|
|
|
- algorithm: {algorithm}
|
|
|
- secret: "{secret}"
|
|
|
-'''
|
|
|
+ name: "{{ args.name }}"
|
|
|
+ algorithm: {{ args.algorithm }}
|
|
|
+ secret: "{{ args.key }}"
|
|
|
+
|
|
|
+{% if args.servers -%}
|
|
|
+pattern:
|
|
|
+ name: "secondary.{{ args.name }}"
|
|
|
+ zonefile: "{{ args.directory }}/%s"
|
|
|
+{%- for server in args.servers %}
|
|
|
+ allow-notify: {{ server }} {{ args.name }}
|
|
|
+ request-xfr: {{ server }} {{ args.name }}
|
|
|
+{%- endfor %}
|
|
|
+{%- for zone in args.zones %}
|
|
|
+
|
|
|
+zone:
|
|
|
+ name: "{{ zone }}"
|
|
|
+ include-pattern: "secondary.{{ args.name }}"
|
|
|
+{%- endfor %}
|
|
|
+{% endif %}
|
|
|
+''')
|
|
|
|
|
|
ap = argparse.ArgumentParser(description = __doc__)
|
|
|
-ap.add_argument("-a", "--algorithm",
|
|
|
- choices = tuple(sorted(algorithm_bits)),
|
|
|
- default = sorted(algorithm_bits)[0])
|
|
|
-ap.add_argument("-f", "--format",
|
|
|
- choices = ("bind9", "nsd"))
|
|
|
-ap.add_argument("-n", "--name",
|
|
|
- default = "tsig.example.org")
|
|
|
-ap.add_argument("-o", "--output",
|
|
|
- default = "-", type = argparse.FileType("w"))
|
|
|
-ap.add_argument("-s", "--servers", nargs = "+")
|
|
|
-ap.add_argument("-z", "--zones", nargs = "+")
|
|
|
+ap.add_argument("-a", "--algorithm", choices = algorithm_choices, default = algorithm_choices[0])
|
|
|
+ap.add_argument("-d", "--directory", default = "secondary", help = "where to store secondary zone files")
|
|
|
+ap.add_argument("-f", "--format", choices = tuple(templates), default = "nsd")
|
|
|
+ap.add_argument("-k", "--key", help = "TSIG shared secret (default: generate new secret)")
|
|
|
+ap.add_argument("-n", "--name", default = "tsig.example.org", help = "DNS name for TSIG shared secret")
|
|
|
+ap.add_argument("-o", "--output", default = "-", type = argparse.FileType("w"), help = "output file"))
|
|
|
+ap.add_argument("-s", "--servers", nargs = "+", default = [], help = "address(es) of primary nameserver(s)")
|
|
|
+ap.add_argument("-z", "--zones", nargs = "+", default = [], help = "zone(s) to xfr from specified nameserver(s)")
|
|
|
args = ap.parse_args()
|
|
|
|
|
|
-params = dict(
|
|
|
- name = args.name,
|
|
|
- algorithm = args.algorithm,
|
|
|
- secret = base64.b64encode(os.urandom(algorithm_bits[args.algorithm])).decode("ascii"),
|
|
|
-)
|
|
|
-
|
|
|
-if args.format is None or args.format == "bind9":
|
|
|
- args.output.write(bind9_template.format(**params))
|
|
|
+if args.key is None:
|
|
|
+ args.key = base64.b64encode(os.urandom(algorithm_bits[args.algorithm])).decode("ascii")
|
|
|
|
|
|
-if args.format is None or args.format == "nsd":
|
|
|
- args.output.write(nsd_template.format(**params))
|
|
|
+args.output.write(jinja2.Template(templates[args.format]).render(args = args))
|