Piotr Dobrowolski | a01905a | 2021-10-16 18:22:46 +0200 | [diff] [blame] | 1 | #!/usr/bin/env nix-shell |
| 2 | #!nix-shell -i python3 -p python3Packages.ldap3 |
| 3 | |
| 4 | from ldap3 import Server, Connection, LEVEL |
| 5 | from ldap3.utils.dn import escape_rdn |
| 6 | import getpass |
| 7 | import logging |
| 8 | from pathlib import Path |
| 9 | import filecmp |
| 10 | import os |
| 11 | |
| 12 | import argparse |
| 13 | |
| 14 | parser = argparse.ArgumentParser() |
| 15 | parser.add_argument("hostname", help="hostname") |
| 16 | parser.add_argument("ldap_pass_file", type=Path, help="file containing lap password") |
| 17 | |
| 18 | header_warning = """ |
| 19 | ################################### WARNING #################################### |
| 20 | # This file was created automatically from LDAP database and *WILL* be |
| 21 | # overwritten. If you need to add / remove keys make changes to |
| 22 | # {}-admin group / members sshPublicKey attributes in LDAP and rerun |
| 23 | # update_authorized_keys script |
| 24 | ################################################################################ |
| 25 | """.lstrip() |
| 26 | |
| 27 | def get_keys(connection: Connection, group: str): |
| 28 | c = connection |
| 29 | |
| 30 | c.search( |
| 31 | search_base="ou=People,dc=hackerspace,dc=pl", |
| 32 | search_filter=( |
| 33 | "(&" |
| 34 | "(objectClass=hsMember)" |
| 35 | f"(memberOf=cn={escape_rdn(group)},ou=Group,dc=hackerspace,dc=pl)" |
| 36 | ")" |
| 37 | ), |
| 38 | search_scope=LEVEL, |
| 39 | attributes=["sshPublicKey"], |
| 40 | ) |
| 41 | |
| 42 | admin_keys = [] |
| 43 | for entry in c.response: |
| 44 | attributes = entry["attributes"] |
| 45 | for key in entry["attributes"]["sshPublicKey"]: |
| 46 | yield key.strip() |
| 47 | |
| 48 | |
| 49 | if __name__ == "__main__": |
| 50 | logging.basicConfig(level=logging.INFO) |
| 51 | args = parser.parse_args() |
| 52 | |
| 53 | user = f"cn={escape_rdn(args.hostname)},ou=Boxen,dc=hackerspace,dc=pl" |
| 54 | password = args.ldap_pass_file.read_text().strip() |
| 55 | |
| 56 | s = Server("ldap.hackerspace.pl", use_ssl=True) |
| 57 | with Connection(s, user=user, password=password, raise_exceptions=True) as c: |
| 58 | keys = list(get_keys(c, f"{args.hostname}-admin")) |
| 59 | if len(keys) < 2: |
| 60 | raise Exception("Less then two keys found - aborting") |
| 61 | |
| 62 | ssh_dir = Path("/", "root", ".ssh") |
| 63 | ssh_dir.mkdir(mode=700, exist_ok=True) |
| 64 | ssh_dir.chmod(0o700) |
| 65 | new_file = ssh_dir.joinpath("authorized_keys_new") |
| 66 | old_file = ssh_dir.joinpath("authorized_keys") |
| 67 | try: |
| 68 | new_file.unlink() |
| 69 | except FileNotFoundError: |
| 70 | pass |
| 71 | new_file.write_bytes( |
| 72 | header_warning.format(args.hostname).encode() + b"\n".join(keys) |
| 73 | ) |
| 74 | if not old_file.exists(): |
| 75 | logging.info('Creating new "authorized_keys" file') |
| 76 | os.rename(new_file, old_file) |
| 77 | elif filecmp.cmp(new_file, old_file, shallow=False): |
| 78 | logging.info('Nothing changed - "authorized_keys" file is up to date') |
| 79 | new_file.unlink() |
| 80 | else: |
| 81 | logging.info('Keys changed - overwriting "authorized_keys" file') |
| 82 | os.rename(new_file, old_file) |