customs/update_authorized_keys.py

83 lines
2.8 KiB
Python
Executable File

#!/usr/bin/env nix-shell
#!nix-shell -i python3 -p python3Packages.ldap3
from ldap3 import Server, Connection, LEVEL
from ldap3.utils.dn import escape_rdn
import getpass
import logging
from pathlib import Path
import filecmp
import os
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("hostname", help="hostname")
parser.add_argument("ldap_pass_file", type=Path, help="file containing lap password")
header_warning = """
################################### WARNING ####################################
# This file was created automatically from LDAP database and *WILL* be
# overwritten. If you need to add / remove keys make changes to
# {}-admin group / members sshPublicKey attributes in LDAP and rerun
# update_authorized_keys script
################################################################################
""".lstrip()
def get_keys(connection: Connection, group: str):
c = connection
c.search(
search_base="ou=People,dc=hackerspace,dc=pl",
search_filter=(
"(&"
"(objectClass=hsMember)"
f"(memberOf=cn={escape_rdn(group)},ou=Group,dc=hackerspace,dc=pl)"
")"
),
search_scope=LEVEL,
attributes=["sshPublicKey"],
)
admin_keys = []
for entry in c.response:
attributes = entry["attributes"]
for key in entry["attributes"]["sshPublicKey"]:
yield key.strip()
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
args = parser.parse_args()
user = f"cn={escape_rdn(args.hostname)},ou=Boxen,dc=hackerspace,dc=pl"
password = args.ldap_pass_file.read_text().strip()
s = Server("ldap.hackerspace.pl", use_ssl=True)
with Connection(s, user=user, password=password, raise_exceptions=True) as c:
keys = list(get_keys(c, f"{args.hostname}-admin"))
if len(keys) < 2:
raise Exception("Less then two keys found - aborting")
ssh_dir = Path("/", "root", ".ssh")
ssh_dir.mkdir(mode=700, exist_ok=True)
ssh_dir.chmod(0o700)
new_file = ssh_dir.joinpath("authorized_keys_new")
old_file = ssh_dir.joinpath("authorized_keys")
try:
new_file.unlink()
except FileNotFoundError:
pass
new_file.write_bytes(
header_warning.format(args.hostname).encode() + b"\n".join(keys)
)
if not old_file.exists():
logging.info('Creating new "authorized_keys" file')
os.rename(new_file, old_file)
elif filecmp.cmp(new_file, old_file, shallow=False):
logging.info('Nothing changed - "authorized_keys" file is up to date')
new_file.unlink()
else:
logging.info('Keys changed - overwriting "authorized_keys" file')
os.rename(new_file, old_file)