hswaw/machines/customs: check in code.hackerspace.pl/vuko/customs

Change-Id: Ic698cce2ef0060a54b195cf90574696b8be1eb0f
Reviewed-on: https://gerrit.hackerspace.pl/c/hscloud/+/1162
Reviewed-by: informatic <informatic@hackerspace.pl>
diff --git a/hswaw/machines/customs.hackerspace.pl/update_authorized_keys.py b/hswaw/machines/customs.hackerspace.pl/update_authorized_keys.py
new file mode 100755
index 0000000..2b336f2
--- /dev/null
+++ b/hswaw/machines/customs.hackerspace.pl/update_authorized_keys.py
@@ -0,0 +1,82 @@
+#!/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)