diff --git a/hosts/bootstrap/default.nix b/hosts/bootstrap/default.nix index c36a525..482a431 100644 --- a/hosts/bootstrap/default.nix +++ b/hosts/bootstrap/default.nix @@ -2,6 +2,9 @@ { kropcloud = { networking.enable = false; - admin.password = "changeme"; + admin = { + password = "changeme"; + sudoRequirePassword = false; + }; }; } diff --git a/nixosModules/users/default.nix b/nixosModules/users/default.nix index d19618e..af557f8 100644 --- a/nixosModules/users/default.nix +++ b/nixosModules/users/default.nix @@ -19,12 +19,19 @@ in default = null; description = "Password for the admin user. Should be used only for initial setup."; }; + sudoRequirePassword = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Require password for sudo. Should be used only for initial setup."; + }; }; config = { age.secrets.mypassword.file = ../../secrets/mypassword.age; + security.sudo.wheelNeedsPassword = cfg.sudoRequirePassword; + # Define the admin user users = { mutableUsers = false; diff --git a/scripts/fresh_install.py b/scripts/fresh_install.py index bccf412..a706023 100755 --- a/scripts/fresh_install.py +++ b/scripts/fresh_install.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 import argparse import json -import ipaddress +import socket import time from subprocess import check_output @@ -16,10 +16,10 @@ def _get_available_machines() -> list: def _validate_ip(ip: str) -> bool: try: - ipaddress.ip_address(ip) - return True - except ValueError: + socket.inet_aton(ip) return False + except socket.error: + return True def _check_ssh_connection(ip: str) -> bool: @@ -29,6 +29,8 @@ def _check_ssh_connection(ip: str) -> bool: except Exception: return False +def add_key_to_secrets(key: str): + def bootstrap_machine(ip: str): check_output( @@ -50,7 +52,22 @@ def get_ssh_key(ip: str) -> str: """ This function uses machines ssh-keyscan to get the ssh key and then get the ed25519 key """ + ssh_keys = check_output( + [ + "ssh-keyscan", + "-q", + "-t", + "ed25519", + ip, + ] + ).decode("utf-8").strip().splitlines() + if len(ssh_keys) != 1: + raise ValueError("Exactly one key should be returned") + + key = ssh_keys.pop().lstrip(f"{ip} ").strip() + + return key def get_machine_config(machine_name: str) -> dict: output = check_output( @@ -82,18 +99,24 @@ def main() -> int: raise ValueError(f"Invalid IP address {args.machine_ip}") machine_config = get_machine_config(machine_name) - print(machine_config) # We are bootstraping the machine first because we need their ssh keys + print(f"Bootstrapping machine {args.machine_ip}") bootstrap_machine() + print("Machine bootstrapped") + print("Waiting for ssh connection") while not _check_ssh_connection(): time.sleep(5) + print("Machine is up and running") - # # connect and get ssh keys + print("Getting ssh key") + ssh_key = get_ssh_key(args.machine_ip) - # ssh_key = get_ssh_key() + print("Adding ssh key to secrets") + add_key_to_secrets(ssh_key) + rekey_secrets() - # Add the ssh key to keys in secrets/secrets.nix + # Add the ssh key to keys in secrets/keys.json # and rekey the secrets # install_machine() diff --git a/secrets/keys.json b/secrets/keys.json new file mode 100644 index 0000000..9c54dae --- /dev/null +++ b/secrets/keys.json @@ -0,0 +1,13 @@ + +{ + "hosts": { + "wenar-nix": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJl0Rdo2kHliBeIiPuiO4kYO5M0VZFNXw4siepV1p6Pj", + "lenar": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOUnlAjPnMwJYgZb7YuholdTxifOEFnAyXVqI+xFlHw6" + }, + "servers" : { + "test-server": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID4ioqiTzYe6Y6H0YfFkWyDBbCB25wYs3gKNZIufE/Sn" + }, + "secrets": { + "mypassword.age": ["hosts:wenar-nix", "hosts:lenar", "servers:test-server"] + } +} diff --git a/secrets/mypassword.age b/secrets/mypassword.age index 2752c16..f372b0a 100644 Binary files a/secrets/mypassword.age and b/secrets/mypassword.age differ diff --git a/secrets/secrets.nix b/secrets/secrets.nix index 069a97b..ba08120 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -1,17 +1,12 @@ let - wenar-nix = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJl0Rdo2kHliBeIiPuiO4kYO5M0VZFNXw4siepV1p6Pj"; - lenar = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOUnlAjPnMwJYgZb7YuholdTxifOEFnAyXVqI+xFlHw6"; - users = [ - wenar-nix - lenar - ]; + keyfile = builtins.fromJSON (builtins.readFile ./keys.json); - test-server = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID4ioqiTzYe6Y6H0YfFkWyDBbCB25wYs3gKNZIufE/Sn"; - systems = [ - test-server - ]; - allKeys = users ++ systems; + splitString = delim: str: builtins.filter builtins.isString (builtins.split delim str); + + getKey = pair: keyfile.${builtins.elemAt pair 0}.${builtins.elemAt pair 1}; + + getKeys = secretName: builtins.map (x: getKey (splitString ":" x)) keyfile.secrets.${secretName}; in { - "mypassword.age".publicKeys = allKeys; + "mypassword.age".publicKeys = getKeys "mypassword.age"; }