Skip to content

Instantly share code, notes, and snippets.

@nijave
Created April 1, 2021 01:02
Show Gist options
  • Save nijave/39353bcf4d7fec7bc27a1ad596b16344 to your computer and use it in GitHub Desktop.
Save nijave/39353bcf4d7fec7bc27a1ad596b16344 to your computer and use it in GitHub Desktop.
A simple opendkim key rotator
#!/usr/bin/env python3
# Note: many os-related methods in python3.5 don't accept
# pathlib.Path and require manual conversion to string, first
import os
import random
import re
import shutil
import subprocess
from pathlib import Path
KEY_SIZE = 2048
opendkim_user_group = ("opendkim", "opendkim")
opendkim_dir = Path("/etc/opendkim")
kt = open(str(opendkim_dir / "KeyTable"), "r").read().strip()
st = open(str(opendkim_dir / "SigningTable"), "r").read().strip()
key_table = [
dict(zip(("domain_record", "domain", "selector", "key_path"), key.split()[0:1] + key.split()[1].split(":")))
for key in kt.splitlines()
]
sorted(key_table, key=lambda x: x["domain"])
new_table = []
for key in key_table:
selector = "k" + hex(random.getrandbits(3*8))[2:]
key_path = opendkim_dir / "keys" / key["domain"]
if not key_path.is_dir():
key_path.mkdir()
output = subprocess.check_output(
["opendkim-genkey", "-n", str(KEY_SIZE), "-s", selector, "-d", key["domain"]],
cwd=str(key_path),
).decode()
if output:
print(output)
shutil.chown(str(key_path / ("%s.txt" % selector)), *opendkim_user_group)
os.chmod(str(key_path / ("%s.txt" % selector)), 0o644)
shutil.chown(str(key_path / ("%s.private" % selector)), *opendkim_user_group)
os.chmod(str(key_path / ("%s.private" % selector)), 0o600)
new_table.append(
{**key, **{
"selector": selector,
"domain_record": "%s._domainkey.%s" % (selector, key["domain"]),
"key_path": key_path / ("%s.private" % selector),
}}
)
print("New KeyTable:")
kt_data = "\n".join([
"%s %s:%s:%s" % (key["domain_record"], key["domain"], key["selector"], key["key_path"])
for key in new_table
])
print(kt_data)
print()
with open(str(opendkim_dir / "KeyTable"), "w") as kt_file:
kt_file.write(kt_data)
print("New SigningTable")
st_data = "\n".join([
"*@%s %s" % (key["domain"], key["domain_record"])
for key in new_table
])
print(st_data)
print()
with open(str(opendkim_dir / "SigningTable"), "w") as st_file:
st_file.write(st_data)
print("DNS Records:")
for key in new_table:
"""
This is designed to print out DNS records in a human copy/pastable way.
This might not work for other use cases where a machine should consume
the records.
"""
fn = str(
re.sub(r'\.private$', '.txt', str(key["key_path"]))
)
pk = open(fn, "r").read().strip()
# Strip comments
pk = re.sub(r'\s*; .+$', '', pk)
# Remove extra quotes around record
pk = re.sub(r'(?<!\\)"', '', pk)
# Compact space
pk = re.sub(r'[\s]+', ' ', pk)
# Un-escape quotes
pk = pk.replace(r'\"', '"')
pk = pk.strip()
pk = pk.replace("( ", '`').replace(" )", '`')
print(key["domain_record"], pk.split(" ", 1)[1])
print()
print("Restart opendkim after adding new DNS records")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment