diff --git a/.forgejo/workflows/push.yaml b/.forgejo/workflows/push.yaml index c222f25..4f87af4 100644 --- a/.forgejo/workflows/push.yaml +++ b/.forgejo/workflows/push.yaml @@ -29,12 +29,3 @@ jobs: nix build --no-link '.#packages.x86_64-linux.terraform-provider-hcloud' nix build --no-link '.#packages.x86_64-linux.terraform-provider-openstack' nix build --no-link '.#packages.x86_64-linux.terraform-provider-unifi' - nix build --no-link '.#packages.x86_64-linux.terraform-provider-vault' - systems: - runs-on: cache.kaareskovgaard.net - steps: - - uses: actions/checkout@v4 - - run: | - nix build --no-link '.#nixosConfigurations."desktop.kaareskovgaard.net".config.system.build.toplevel' - nix build --no-link '.#nixosConfigurations."desktop.kaareskovgaard.net".config.system.build.vm' - nix build --no-link '.#nixosConfigurations."test.kaareskovgaard.net".config.system.build.toplevel' diff --git a/README.md b/README.md index 54f72ca..bb691af 100644 --- a/README.md +++ b/README.md @@ -40,8 +40,6 @@ To delete the resources again run: nix run '.#destroy-instance' -- ``` -NOTE: It is normal for the secret id associated with vault/openbao roles to not be deletable. Simply run the destroy-instance command a 2nd time and everything should work just fine. - ## Secrets To transfer the secrets needed for OpenTofu from Bitwarden to OpenBAO run: diff --git a/desktop.qcow2 b/desktop.qcow2 index c232e59..fdf6ba6 100644 Binary files a/desktop.qcow2 and b/desktop.qcow2 differ diff --git a/flake.lock b/flake.lock index 0ae0cda..b278631 100644 --- a/flake.lock +++ b/flake.lock @@ -546,11 +546,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1751943650, - "narHash": "sha256-7orTnNqkGGru8Je6Un6mq1T8YVVU/O5kyW4+f9C1mZQ=", + "lastModified": 1751741127, + "narHash": "sha256-t75Shs76NgxjZSgvvZZ9qOmz5zuBE8buUaYD28BMTxg=", "owner": "nixos", "repo": "nixpkgs", - "rev": "88983d4b665fb491861005137ce2b11a9f89f203", + "rev": "29e290002bfff26af1db6f64d070698019460302", "type": "github" }, "original": { @@ -624,11 +624,11 @@ ] }, "locked": { - "lastModified": 1752028888, - "narHash": "sha256-LRj3/PUpII6taWOrX1w/OeI6f1ncND02PP/kEHvPCqU=", + "lastModified": 1751942411, + "narHash": "sha256-01uMHCt2U9tP4f24DGch145tT8YQppLY5TC9mWK7O0A=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "a0f1c656e053463b47639234b151a05e4441bb19", + "rev": "c587235f892930a61c9e415f0d9792a1b27a41a2", "type": "github" }, "original": { @@ -681,11 +681,11 @@ "tinted-zed": "tinted-zed" }, "locked": { - "lastModified": 1752084754, - "narHash": "sha256-JorlZGCWxlYV01lXmUuDeKOZoLPdoN3fAKJv8YIuavs=", + "lastModified": 1752009340, + "narHash": "sha256-6IKc+fdgJ+mWW8pBOVS5MYvttHBhvWSbff/31pG3SAY=", "owner": "nix-community", "repo": "stylix", - "rev": "2df042576646d012d15637f43d6075995e785ce3", + "rev": "c647aaa1dead3752fb49f226a4f67ae1030d7747", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 06b5426..72b1f8c 100644 --- a/flake.nix +++ b/flake.nix @@ -97,7 +97,7 @@ inherit inputs; khscodesLib = inputs.self.lib; }; - terranixModules.vault = import ./nix/modules/terranix/vault { + terranixModules.openbao = import ./nix/modules/terranix/openbao { inherit inputs; khscodesLib = inputs.self.lib; }; diff --git a/nix/lib/disko-root-bios/default.nix b/nix/lib/disko-root-bios/default.nix deleted file mode 100644 index a8423bb..0000000 --- a/nix/lib/disko-root-bios/default.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ ... }: -{ - disko-root-bios = - { - diskName, - device, - bootPartName ? "boot", - rootPartName ? "root", - }: - { - devices.disk = { - "${diskName}" = { - inherit device; - type = "disk"; - content = { - type = "gpt"; - partitions = { - ${bootPartName} = { - size = "1M"; - type = "EF02"; # for grub MBR - }; - ${rootPartName} = { - size = "100%"; - content = { - type = "filesystem"; - format = "ext4"; - mountpoint = "/"; - }; - }; - }; - }; - }; - }; - }; -} diff --git a/nix/modules/nixos/infrastructure/hetzner-instance/default.nix b/nix/modules/nixos/infrastructure/hetzner-instance/default.nix index e42af94..d65e044 100644 --- a/nix/modules/nixos/infrastructure/hetzner-instance/default.nix +++ b/nix/modules/nixos/infrastructure/hetzner-instance/default.nix @@ -7,7 +7,6 @@ let cfg = config.khscodes.infrastructure.hetzner-instance; fqdn = config.khscodes.networking.fqdn; - provisioningUserData = config.khscodes.infrastructure.provisioning.instanceUserData; firewallTcpRules = lib.lists.map (p: { direction = "in"; protocol = "tcp"; @@ -161,7 +160,6 @@ in initial_image = "debian-12"; rdns = fqdn; ssh_keys = [ config.khscodes.hcloud.output.data.ssh_key.khs.id ]; - user_data = provisioningUserData; }; khscodes.cloudflare = { enable = true; diff --git a/nix/modules/nixos/infrastructure/khs-openstack-instance/default.nix b/nix/modules/nixos/infrastructure/khs-openstack-instance/default.nix index c4f283d..4478c81 100644 --- a/nix/modules/nixos/infrastructure/khs-openstack-instance/default.nix +++ b/nix/modules/nixos/infrastructure/khs-openstack-instance/default.nix @@ -7,7 +7,6 @@ let cfg = config.khscodes.infrastructure.khs-openstack-instance; fqdn = config.khscodes.networking.fqdn; - provisioningUserData = config.khscodes.infrastructure.provisioning.instanceUserData; firewallTcpRules = lib.lists.flatten ( lib.lists.map (p: [ { @@ -84,6 +83,14 @@ in default = "${fqdn}.tfstate"; }; }; + secretsSource = lib.mkOption { + type = lib.types.enum [ + "bitwarden" + "vault" + ]; + description = "Whether to load opentofu secrets from Bitwarden or Vault"; + default = "vault"; + }; flavor = lib.mkOption { type = lib.types.nullOr lib.types.str; description = "The server type to create"; @@ -181,7 +188,6 @@ in flavor = cfg.flavor; ssh_public_key = cfg.ssh_key; firewall_rules = firewallRules; - user_data = provisioningUserData; }; khscodes.unifi.enable = true; khscodes.unifi.static_route.compute = { @@ -230,15 +236,11 @@ in message = "Must set config.khscodes.networking.fqdn when using opentofu"; } ]; - khscodes.services.openssh = { - enable = true; - hostCertificate = { - enable = true; - }; - }; + khscodes.infrastructure.provisioning = { pre = { modules = modules; + secretsSource = cfg.secretsSource; endpoints = [ "aws" "cloudflare" diff --git a/nix/modules/nixos/infrastructure/provisioning/default.nix b/nix/modules/nixos/infrastructure/provisioning/default.nix index e62826a..afb8c28 100644 --- a/nix/modules/nixos/infrastructure/provisioning/default.nix +++ b/nix/modules/nixos/infrastructure/provisioning/default.nix @@ -29,8 +29,6 @@ let "unifi" "hcloud" "cloudflare" - "vault" - "authentik" ] ); description = "Needed endpoints to be used during provisioning"; @@ -42,11 +40,6 @@ in options.khscodes.infrastructure.provisioning = { pre = provisioning; post = provisioning; - instanceUserData = lib.mkOption { - type = lib.types.str; - description = "User data that should be added to the instance during provisioning"; - default = ""; - }; preConfig = lib.mkOption { type = lib.types.nullOr lib.types.path; description = "The generated config for the pre provisioning, if any was specified"; diff --git a/nix/modules/nixos/infrastructure/vault-server-approle/default.nix b/nix/modules/nixos/infrastructure/vault-server-approle/default.nix deleted file mode 100644 index c3bc8b8..0000000 --- a/nix/modules/nixos/infrastructure/vault-server-approle/default.nix +++ /dev/null @@ -1,121 +0,0 @@ -{ - config, - lib, - inputs, - ... -}: -let - cfg = config.khscodes.infrastructure.vault-server-approle; -in -{ - options.khscodes.infrastructure.vault-server-approle = { - enable = lib.mkEnableOption "Enables creating an OpenBAO role for the server"; - stage = lib.mkOption { - type = lib.types.enum [ - "pre" - "post" - ]; - description = "The provisioning stage that should include the provisioning. This should be pre for every server except the OpenBAO server itself"; - default = "pre"; - }; - role_name = lib.mkOption { - type = lib.types.str; - description = "Name of the role being created"; - default = config.networking.fqdnOrHostName; - }; - policy = lib.mkOption { - type = lib.types.attrsOf ( - lib.khscodes.mkSubmodule { - options = { - capabilities = lib.mkOption { - type = lib.types.listOf ( - lib.types.enum [ - "create" - "update" - "patch" - "read" - "delete" - "list" - ] - ); - }; - }; - description = "Vault role policy"; - } - ); - }; - stageModules = lib.mkOption { - type = lib.types.listOf lib.types.anything; - description = "Extra modules to add to the configured stage"; - default = [ ]; - }; - }; - - config = lib.mkIf cfg.enable { - khscodes.services.openstack-read-vault-auth-from-userdata.enable = true; - khscodes.infrastructure.provisioning.${cfg.stage} = { - endpoints = [ "vault" ]; - modules = [ - ( - { config, ... }: - { - imports = [ inputs.self.terranixModules.vault ]; - khscodes.vault = { - enable = true; - approle_auth_backend_role.${cfg.role_name} = { - backend = "approle"; - role_name = cfg.role_name; - # I keep the secret ids alive for quite long, as I have no way of - # automatically bootstrapping a new secret id. - secret_id_ttl = 5 * 60 * 60; - secret_id_num_uses = 5 * 60; - token_ttl = 20 * 60; - token_max_ttl = 30 * 60; - token_policies = [ cfg.role_name ]; - }; - approle_auth_backend_role_secret_id.${cfg.role_name} = { - backend = "approle"; - # Not hardcoding the role name here, as reading it like this will create a dependency - # on the role being created first, which is needed. - role_name = config.khscodes.vault.output.approle_auth_backend_role.${cfg.role_name}.role_name; - # Should only be 5-10 mins once done testing - wrapping_ttl = 5 * 60 * 60; - - # All of this simply tries to ensure that I never recreate this secret id - # even if the original wrapped secret id is expired (which I expect it to be). - with_wrapped_accessor = true; - lifecycle = { - ignore_changes = [ - "num_uses" - "ttl" - ]; - }; - }; - policy.${cfg.role_name} = { - name = cfg.role_name; - policy = lib.strings.concatStringsSep "\n\n" ( - lib.lists.map ( - { name, value }: - '' - path "${name}" { - capabilities = ${builtins.toJSON value.capabilities} - } - '' - ) (lib.attrsToList cfg.policy) - ); - }; - }; - } - ) - ] ++ cfg.stageModules; - }; - # I can only provide the user data if the stage is pre (along with the instance creation) - # Also I should probably find a way of injecting this in a nicer way than this mess. - khscodes.infrastructure.provisioning.instanceUserData = lib.mkIf (cfg.stage == "pre") '' - { - "VAULT_ROLE_ID": "''${ vault_approle_auth_backend_role.${lib.khscodes.sanitize-terraform-name cfg.role_name}.role_id }", - "VAULT_SECRET_ID_WRAPPED": "''${ vault_approle_auth_backend_role_secret_id.${lib.khscodes.sanitize-terraform-name cfg.role_name}.wrapping_token }" - } - ''; - }; -} diff --git a/nix/modules/nixos/networking/fqdn/default.nix b/nix/modules/nixos/networking/fqdn/default.nix index d419e36..0689292 100644 --- a/nix/modules/nixos/networking/fqdn/default.nix +++ b/nix/modules/nixos/networking/fqdn/default.nix @@ -21,7 +21,6 @@ in { networking.hostName = lib.mkForce hostname; networking.domain = lib.mkForce domain; - networking.fqdn = cfg; # Add the name of the server to the ssh host certificate domains, but let other configs enable getting the host certificates. khscodes.services.openssh.hostCertificate.hostNames = [ cfg ]; boot.kernel.sysctl = { diff --git a/nix/modules/nixos/openstack/default.nix b/nix/modules/nixos/openstack/default.nix index bbc4bcb..d372a03 100644 --- a/nix/modules/nixos/openstack/default.nix +++ b/nix/modules/nixos/openstack/default.nix @@ -16,12 +16,10 @@ in }; }; config = lib.mkIf cfg.enable { - disko = lib.mkDefault ( - lib.khscodes.disko-root-lvm-bios { - device = "/dev/sda"; - diskName = cfg.diskName; - } - ); + disko = lib.khscodes.disko-root-lvm-bios { + device = "/dev/sda"; + diskName = cfg.diskName; + }; boot.loader.grub.efiSupport = false; boot.loader.timeout = 1; khscodes.virtualisation.qemu-guest.enable = true; diff --git a/nix/modules/nixos/services/openssh/default.nix b/nix/modules/nixos/services/openssh/default.nix index fbbbbd1..56d8620 100644 --- a/nix/modules/nixos/services/openssh/default.nix +++ b/nix/modules/nixos/services/openssh/default.nix @@ -7,6 +7,11 @@ in enable = lib.mkEnableOption "Enables openssh service for the instance"; hostCertificate = { enable = lib.mkEnableOption "Enables getting host certificates from OpenBAO"; + secretName = lib.mkOption { + type = lib.types.str; + description = "Secret where the certificate is stored"; + example = "ssh-host/sign/ca-kaareskovgaard.net"; + }; hostNames = lib.mkOption { type = lib.types.listOf lib.types.str; description = "The list of host names to get certificates for"; @@ -19,9 +24,6 @@ in let certificateNames = lib.lists.unique cfg.hostCertificate.hostNames; hostCertificatEnable = cfg.hostCertificate.enable && cfg.hostCertificate.hostNames != [ ]; - vaultRoleName = config.khscodes.infrastructure.vault-server-approle.role_name; - fqdn = config.networking.fqdnOrHostName; - sshHostBackend = "ssh-host"; in { services.openssh = { @@ -35,34 +37,6 @@ in HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub ''; }; - khscodes.infrastructure.vault-server-approle = { - enable = true; - policy."${sshHostBackend}/sign/${vaultRoleName}" = { - capabilities = [ - "read" - "update" - "create" - ]; - }; - stageModules = [ - { - khscodes.vault.ssh_secret_backend_role.${vaultRoleName} = { - name = fqdn; - backend = sshHostBackend; - key_type = "ca"; - allow_host_certificates = true; - allow_bare_domains = true; - allowed_domains = certificateNames; - allowed_user_key_config = [ - { - type = "ed25519"; - lengths = [ 0 ]; - } - ]; - }; - } - ]; - }; khscodes.services.vault-agent = lib.mkIf hostCertificatEnable { enable = true; templates = [ @@ -70,7 +44,7 @@ in contents = '' {{- $public_key := file "/etc/ssh/ssh_host_ed25519_key.pub" -}} {{- $public_key = printf "public_key=%s" $public_key -}} - {{- with secret "ssh-host/sign/${fqdn}" "cert_type=host" $public_key "valid_principals=${lib.strings.concatStringsSep "," certificateNames}" -}} + {{- with secret "${cfg.hostCertificate.secretName}" "cert_type=host" $public_key "valid_principals=${lib.strings.concatStringsSep "," certificateNames}" -}} {{ .Data.signed_key }} {{- end -}} ''; diff --git a/nix/modules/nixos/services/openstack-read-vault-auth-from-userdata/default.nix b/nix/modules/nixos/services/openstack-read-vault-auth-from-userdata/default.nix deleted file mode 100644 index 480c60e..0000000 --- a/nix/modules/nixos/services/openstack-read-vault-auth-from-userdata/default.nix +++ /dev/null @@ -1,66 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: -let - cfg = config.khscodes.services.openstack-read-vault-auth-from-userdata; -in -{ - options.khscodes.services.openstack-read-vault-auth-from-userdata = { - enable = lib.mkEnableOption "Enables reading vault auth information from instance userdata"; - }; - - config = lib.mkIf (cfg.enable && config.khscodes.services.vault-agent.enable) ( - let - vault_addr = config.khscodes.services.vault-agent.vault.address; - secretIdFilePath = config.khscodes.services.vault-agent.vault.secretIdFilePath; - roleIdFilePath = config.khscodes.services.vault-agent.vault.roleIdFilePath; - in - { - systemd.services."openstack-read-vault-auth-from-userdata" = { - enable = true; - wantedBy = [ "multi-user.target" ]; - wants = [ "network-online.target" ]; - after = [ "network-online.target" ]; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - ExecStart = lib.getExe ( - pkgs.writeShellApplication { - name = "openstack-read-vault-auth-from-userdata"; - runtimeInputs = [ - pkgs.curl - pkgs.jq - pkgs.openbao - pkgs.getent - pkgs.systemd - ]; - text = '' - if [[ -f "${lib.escapeShellArg secretIdFilePath}" ]]; then - echo "Secret id already found, not copying new id" - exit 0 - fi - userdata="$(curl http://169.254.169.254/openstack/2012-08-10/user_data)" - role_id="$(echo "$userdata" | jq --raw-output '.VAULT_ROLE_ID')" - secret_id_wrapped="$(echo "$userdata" | jq --raw-output '.VAULT_SECRET_ID_WRAPPED')" - secret_id="$(BAO_ADDR=${lib.escapeShellArg vault_addr} bao unwrap -field=secret_id "$secret_id_wrapped")" - mkdir -p "$(dirname ${lib.escapeShellArg secretIdFilePath})" - mkdir -p "$(dirname ${lib.escapeShellArg roleIdFilePath})" - echo -n "$role_id" > ${lib.escapeShellArg roleIdFilePath} - echo -n "$secret_id" > ${lib.escapeShellArg secretIdFilePath} - chown root:root "${lib.escapeShellArg secretIdFilePath}" - chmod 0600 "${lib.escapeShellArg secretIdFilePath}" - chown root:root "${lib.escapeShellArg roleIdFilePath}" - chmod 0600 "${lib.escapeShellArg roleIdFilePath}" - echo "Role id and secret id copied, restart vault-agent" - systemctl restart vault-agent-openbao.service - ''; - } - ); - }; - }; - } - ); -} diff --git a/nix/modules/nixos/services/vault-agent/default.nix b/nix/modules/nixos/services/vault-agent/default.nix index 2b88c6a..bab6eb8 100644 --- a/nix/modules/nixos/services/vault-agent/default.nix +++ b/nix/modules/nixos/services/vault-agent/default.nix @@ -5,7 +5,9 @@ ... }: let - cfg = config.khscodes.services.vault-agent; + cfg = config.input-output.openbao.agent; + secretIdFilePath = "/var/lib/vault-agent/secret-id"; + roleIdFilePath = "/var/lib/vault-agent/role-id"; mkSubmodule = { options, @@ -60,8 +62,8 @@ let type = "approle"; config = { mount_path = "auth/approle"; - role_id_file_path = cfg.vault.roleIdFilePath; - secret_id_file_path = cfg.vault.secretIdFilePath; + role_id_file_path = roleIdFilePath; + secret_id_file_path = secretIdFilePath; remove_secret_id_file_after_reading = false; }; } @@ -88,22 +90,10 @@ in default = pkgs.openbao; defaultText = "pkgs.openbao"; }; - vault = { - address = lib.mkOption { - type = lib.types.str; - description = "Address of the Vault/OpenBAO service"; - default = "https://vault.kaareskovgaard.net"; - }; - roleIdFilePath = lib.mkOption { - type = lib.types.str; - description = "Location of the role id"; - default = "/var/lib/vault-agent/role-id"; - }; - secretIdFilePath = lib.mkOption { - type = lib.types.str; - description = "Location of the secret id"; - default = "/var/lib/vault-agent/secret-id"; - }; + vault.address = lib.mkOption { + type = lib.types.str; + description = "Address of the Vault/OpenBAO service"; + default = "https://vault.kaareskovgaard.net"; }; templates = lib.mkOption { default = [ ]; @@ -156,10 +146,42 @@ in wantedBy = unitsDependsOnAgent; unitConfig = { ConditionPathExists = [ - cfg.vault.secretIdFilePath - cfg.vault.roleIdFilePath + secretIdFilePath + roleIdFilePath ]; }; }; + environment.systemPackages = [ + (pkgs.writeShellApplication { + name = "vault-agent-load-credentials"; + meta = { + mainProgram = "vault-agent-load-credentials"; + }; + runtimeInputs = [ + pkgs.systemd + pkgs.openbao + ]; + text = '' + if [[ -z "''${1:-}" || -z "''${2:-}" ]]; then + >&2 echo "Usage: vault-agent-load-credentials " + exit 1 + fi + role_id="$1" + secret_id_wrapped="$2" + secret_id="$(BAO_ADDR=${lib.escapeShellArg cfg.vault.address} bao unwrap -field=secret_id "$secret_id_wrapped")" + mkdir -p "$(dirname ${lib.escapeShellArg secretIdFilePath})" + mkdir -p "$(dirname ${lib.escapeShellArg roleIdFilePath})" + echo -n "$role_id" > ${lib.escapeShellArg roleIdFilePath} + echo -n "$secret_id" > ${lib.escapeShellArg secretIdFilePath} + chown root:root "$${lib.escapeShellArg secretIdFilePath}" + chmod 0600 "$${lib.escapeShellArg secretIdFilePath}" + chown root:root "$${lib.escapeShellArg roleIdFilePath}" + chmod 0600 "$${lib.escapeShellArg roleIdFilePath}" + systemctl restart vault-agent-openbao.service + ${restartUnits unitsDependsOnAgent} + ${reloadOrRestartUnits unitsDependsOnAgent} + ''; + }) + ]; }; } diff --git a/nix/modules/nixos/virtualisation/qemu-guest/default.nix b/nix/modules/nixos/virtualisation/qemu-guest/default.nix index f40f946..4ab6ae4 100644 --- a/nix/modules/nixos/virtualisation/qemu-guest/default.nix +++ b/nix/modules/nixos/virtualisation/qemu-guest/default.nix @@ -1,6 +1,7 @@ { config, lib, + modulesPath, ... }: let @@ -23,24 +24,22 @@ in enableWhenVmTarget = lib.mkEnableOption "Enables some enhancement settings when building as a vm"; }; - imports = [ ./profile.nix ]; + imports = [ "${modulesPath}/virtualisation/qemu-vm.nix" ]; - config = lib.mkIf cfg.enable { - services.qemuGuest.enable = true; - virtualisation = lib.mkIf cfg.enableWhenVmTarget { + config = lib.mkIf cfg.enableWhenVmTarget { + virtualisation = { vmVariant = { - khscodes.virtualisation.qemu-guest.enable = true; + services.qemuGuest.enable = true; services.spice-vdagentd.enable = true; - virtualisation = { - memorySize = 1024 * 8; - qemu = { - options = [ - "-smp 8" - "-vga none -device virtio-gpu-gl,hostmem=2G,blob=true,venus=true" - rng - ] ++ spice; - }; - }; + khscodes.virtualisation.qemu-guest.enable = true; + }; + memorySize = 1024 * 8; + qemu = { + options = [ + "-smp 8" + "-vga none -device virtio-gpu-gl,hostmem=2G,blob=true,venus=true" + rng + ] ++ spice; }; }; }; diff --git a/nix/modules/terranix/hcloud/default.nix b/nix/modules/terranix/hcloud/default.nix index e5d22c3..039c649 100644 --- a/nix/modules/terranix/hcloud/default.nix +++ b/nix/modules/terranix/hcloud/default.nix @@ -51,11 +51,6 @@ let default = null; description = "FQDN to map rDNS to"; }; - user_data = lib.mkOption { - type = lib.types.str; - default = ""; - description = "User data for the instance"; - }; }; }; hcloudDataSshKeys = khscodesLib.mkSubmodule { @@ -111,7 +106,6 @@ in ipv6_enabled = true; ipv6 = "\${ hcloud_primary_ip.${name}_ipv6.id }"; }; - user_data = builtins.toJSON value.user_data; lifecycle = { ignore_changes = [ "ssh_keys" diff --git a/nix/modules/terranix/openbao/default.nix b/nix/modules/terranix/openbao/default.nix new file mode 100644 index 0000000..adfe0a6 --- /dev/null +++ b/nix/modules/terranix/openbao/default.nix @@ -0,0 +1,32 @@ +{ khscodesLib, inputs }: +{ lib, config, ... }: +let + cfg = config.khscodes.openbao; + modules = [ + ./output.nix + ./vault_mount.nix + ]; +in +{ + options.khscodes.openbao = { + enable = lib.mkEnableOption "Enables the openbao provider"; + }; + + imports = lib.lists.map (m: import m { inherit khscodesLib inputs; }) modules; + + config = lib.mkIf cfg.enable { + provider.vault = { + address = "https://auth.kaareskovgaard.net"; + }; + terraform.required_providers.vault = { + source = "hashicorp/vault"; + version = "5.0.0"; + }; + resource.vault_mount = lib.mapAttrs' ( + name: value: { + name = khscodesLib.sanitize-terraform-name name; + value = value; + } + ); + }; +} diff --git a/nix/modules/terranix/openbao/output.nix b/nix/modules/terranix/openbao/output.nix new file mode 100644 index 0000000..9e92755 --- /dev/null +++ b/nix/modules/terranix/openbao/output.nix @@ -0,0 +1,10 @@ +{ khscodesLib, ... }: +{ config, lib, ... }: +let + cfg = config.khscodes.openbao; +in +{ + options.khscodes.openbao = { }; + config = { + }; +} diff --git a/nix/modules/terranix/openbao/ssh_secret_backend_ca.nix b/nix/modules/terranix/openbao/ssh_secret_backend_ca.nix new file mode 100644 index 0000000..4521947 --- /dev/null +++ b/nix/modules/terranix/openbao/ssh_secret_backend_ca.nix @@ -0,0 +1,45 @@ +{ khscodesLib, ... }: +{ lib, config, ... }: +let + cfg = config.khscodes.openbao; +in +{ + options.khscodes.openbao = { + vault_ssh_secret_backend_ca = lib.mkOption { + type = lib.types.attrsOf ( + khscodesLib.mkSubmodule { + options = { + backend = lib.mkOption { + type = lib.types.str; + description = "Path of the backend mount"; + }; + generate_signing_key = lib.mkOption { + type = lib.types.bool; + description = "Generate a signing key on the server"; + }; + key_type = lib.mkOption { + type = lib.types.str; + description = "The type of the signing key to use/generate"; + }; + }; + description = "vault_ssh_secret_backend_ca"; + } + ); + }; + }; + config = lib.mkIf cfg.enable { + provider.vault = { + address = "https://auth.kaareskovgaard.net"; + }; + terraform.required_providers.vault = { + source = "hashicorp/vault"; + version = "5.0.0"; + }; + resource.vault_ssh_secret_backend_ca = lib.mapAttrs' ( + name: value: { + name = khscodesLib.sanitize-terraform-name name; + value = value; + } + ); + }; +} diff --git a/nix/modules/terranix/vault/mount.nix b/nix/modules/terranix/openbao/vault_mount.nix similarity index 67% rename from nix/modules/terranix/vault/mount.nix rename to nix/modules/terranix/openbao/vault_mount.nix index 7618940..4f4be60 100644 --- a/nix/modules/terranix/vault/mount.nix +++ b/nix/modules/terranix/openbao/vault_mount.nix @@ -1,11 +1,11 @@ { khscodesLib, ... }: { lib, config, ... }: let - cfg = config.khscodes.vault; + cfg = config.khscodes.openbao; in { - options.khscodes.vault = { - mount = lib.mkOption { + options.khscodes.openbao = { + vault_mount = lib.mkOption { type = lib.types.attrsOf ( khscodesLib.mkSubmodule { options = { @@ -32,14 +32,21 @@ in description = "vault_mount"; } ); - description = "Defines a vault mount"; - default = { }; }; }; config = lib.mkIf cfg.enable { - resource.vault_mount = lib.mapAttrs' (name: value: { - name = khscodesLib.sanitize-terraform-name name; - value = value; - }) cfg.mount; + provider.vault = { + address = "https://auth.kaareskovgaard.net"; + }; + terraform.required_providers.vault = { + source = "hashicorp/vault"; + version = "5.0.0"; + }; + resource.vault_mount = lib.mapAttrs' ( + name: value: { + name = khscodesLib.sanitize-terraform-name name; + value = value; + } + ); }; } diff --git a/nix/modules/terranix/openstack/default.nix b/nix/modules/terranix/openstack/default.nix index c22c743..ba13dba 100644 --- a/nix/modules/terranix/openstack/default.nix +++ b/nix/modules/terranix/openstack/default.nix @@ -85,11 +85,6 @@ let "1.0.0.1" ]; }; - user_data = lib.mkOption { - type = lib.types.str; - default = ""; - description = "User data for the instance"; - }; volume_size = lib.mkOption { type = lib.types.int; description = "Size of the root volume, in gigabytes"; @@ -437,7 +432,6 @@ in uuid = "\${ openstack_networking_network_v2.${sanitizedName}.id }"; } ]; - user_data = value.user_data; }; } ) cfg.compute_instance; diff --git a/nix/modules/terranix/vault/approle_auth_backend.nix b/nix/modules/terranix/vault/approle_auth_backend.nix deleted file mode 100644 index 06ecb66..0000000 --- a/nix/modules/terranix/vault/approle_auth_backend.nix +++ /dev/null @@ -1,120 +0,0 @@ -{ khscodesLib, ... }: -{ lib, config, ... }: -let - cfg = config.khscodes.vault; -in -{ - options.khscodes.vault = { - approle_auth_backend_role = lib.mkOption { - type = lib.types.attrsOf ( - khscodesLib.mkSubmodule { - options = { - backend = lib.mkOption { - type = lib.types.str; - description = "Path of the backend"; - default = "approle"; - }; - role_name = lib.mkOption { - type = lib.types.str; - description = "Name of the role"; - }; - secret_id_ttl = lib.mkOption { - type = lib.types.int; - description = "TTL for the secret id, in seconds"; - }; - secret_id_num_uses = lib.mkOption { - type = lib.types.int; - description = "Maximum number of uses per secret id"; - }; - token_ttl = lib.mkOption { - type = lib.types.int; - description = "TTL for the tokens issued, in seconds"; - }; - token_max_ttl = lib.mkOption { - type = lib.types.int; - description = "Max TTL for the tokens issued, in seconds"; - }; - token_policies = lib.mkOption { - type = lib.types.listOf lib.types.str; - description = "Policies attached to the backend role"; - }; - }; - description = "vault_approle_auth_backend_role"; - } - ); - description = "Defines an app backend role"; - default = { }; - }; - approle_auth_backend_role_secret_id = lib.mkOption { - type = lib.types.attrsOf ( - khscodesLib.mkSubmodule { - options = { - backend = lib.mkOption { - type = lib.types.str; - description = "Path of the backend"; - default = "approle"; - }; - role_name = lib.mkOption { - type = lib.types.str; - description = "NThe name of the role to create the SecretID for"; - }; - cidr_list = lib.mkOption { - type = lib.types.listOf lib.types.str; - description = "If set, specifies blocks of IP addresses which can perform the login operation using this SecretID"; - default = [ ]; - }; - metadata = lib.mkOption { - type = lib.types.attrsOf lib.types.str; - description = "Metadata associated with tokens issued by this secret"; - default = { }; - }; - num_uses = lib.mkOption { - type = lib.types.int; - description = "Number of uses for the secret id"; - default = 300; - }; - wrapping_ttl = lib.mkOption { - type = lib.types.nullOr lib.types.int; - description = "If set, the SecretID response will be response-wrapped and available for the duration specified. Only a single unwrapping of the token is allowed."; - default = null; - }; - with_wrapped_accessor = lib.mkOption { - type = lib.types.bool; - description = "Set to `true` to use the wrapped secret-id accessor as the resource ID. If `false` (default value), a fresh secret ID will be regenerated whenever the wrapping token is expired or invalidated through unwrapping."; - default = false; - }; - lifecycle.ignore_changes = lib.mkOption { - type = lib.types.listOf lib.types.str; - description = "Ignores changes to the following properties when rerunning the terraform script"; - default = [ ]; - }; - }; - description = "vault_approle_auth_backend_role_secret_id"; - } - ); - description = "Defines an app backend role secret id"; - default = { }; - }; - }; - config = lib.mkIf cfg.enable { - resource.vault_approle_auth_backend_role = lib.mapAttrs' (name: value: { - name = khscodesLib.sanitize-terraform-name name; - value = value; - }) cfg.approle_auth_backend_role; - resource.vault_approle_auth_backend_role_secret_id = lib.mapAttrs' (name: value: { - name = khscodesLib.sanitize-terraform-name name; - value = { - inherit (value) - backend - role_name - cidr_list - wrapping_ttl - num_uses - with_wrapped_accessor - lifecycle - ; - metadata = if value.metadata != null then builtins.toJSON value.metadata else null; - }; - }) cfg.approle_auth_backend_role_secret_id; - }; -} diff --git a/nix/modules/terranix/vault/default.nix b/nix/modules/terranix/vault/default.nix deleted file mode 100644 index 11dfa26..0000000 --- a/nix/modules/terranix/vault/default.nix +++ /dev/null @@ -1,49 +0,0 @@ -{ khscodesLib, inputs }: -{ lib, config, ... }: -let - cfg = config.khscodes.vault; - modules = [ - ./approle_auth_backend.nix - ./output.nix - ./mount.nix - ./ssh_secret_backend.nix - ]; -in -{ - options.khscodes.vault = { - enable = lib.mkEnableOption "Enables the openbao provider"; - policy = lib.mkOption { - type = lib.types.attrsOf ( - khscodesLib.mkSubmodule { - options = { - name = lib.mkOption { - type = lib.types.str; - description = "Name of the policy"; - }; - policy = lib.mkOption { - type = lib.types.lines; - description = "The policy"; - }; - }; - description = "vault_policy"; - } - ); - }; - }; - - imports = lib.lists.map (m: import m { inherit khscodesLib inputs; }) modules; - - config = lib.mkIf cfg.enable { - provider.vault = { - address = "https://vault.kaareskovgaard.net"; - }; - terraform.required_providers.vault = { - source = "hashicorp/vault"; - version = "5.0.0"; - }; - resource.vault_policy = lib.mapAttrs' (name: value: { - name = khscodesLib.sanitize-terraform-name name; - value = value; - }) cfg.policy; - }; -} diff --git a/nix/modules/terranix/vault/output.nix b/nix/modules/terranix/vault/output.nix deleted file mode 100644 index da0b2b0..0000000 --- a/nix/modules/terranix/vault/output.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ khscodesLib, ... }: -{ config, lib, ... }: -let - cfg = config.khscodes.vault; -in -{ - options.khscodes.vault = { - output = { - approle_auth_backend_role = lib.mkOption { - type = lib.types.attrsOf ( - khscodesLib.mkSubmodule { - options = { - role_name = lib.mkOption { - type = lib.types.str; - description = "The name of the role. Can be used instead of hardcoding the role, to create a dependency in OpenTofu"; - }; - }; - description = "vault_approle_auth_backend_role output"; - } - ); - }; - }; - }; - config = { - khscodes.vault.output.approle_auth_backend_role = lib.mapAttrs ( - name: value: - let - sanitizedName = khscodesLib.sanitize-terraform-name name; - in - { - role_name = "\${ vault_approle_auth_backend_role.${sanitizedName}.role_name }"; - } - ) cfg.approle_auth_backend_role; - }; -} diff --git a/nix/modules/terranix/vault/ssh_secret_backend.nix b/nix/modules/terranix/vault/ssh_secret_backend.nix deleted file mode 100644 index 4543404..0000000 --- a/nix/modules/terranix/vault/ssh_secret_backend.nix +++ /dev/null @@ -1,129 +0,0 @@ -{ khscodesLib, ... }: -{ lib, config, ... }: -let - cfg = config.khscodes.vault; -in -{ - options.khscodes.vault = { - ssh_secret_backend_role = lib.mkOption { - type = lib.types.attrsOf ( - khscodesLib.mkSubmodule { - options = { - name = lib.mkOption { - type = lib.types.str; - description = "Specifies the name of the role to create."; - }; - backend = lib.mkOption { - type = lib.types.str; - description = "The path where the SSH secret backend is mounted."; - }; - key_type = lib.mkOption { - type = lib.types.enum [ - "otp" - "dynamic" - "ca" - ]; - description = "Specifies the type of credentials generated by this role."; - }; - allow_bare_domains = lib.mkOption { - type = lib.types.nullOr (lib.types.bool); - description = "Specifies if host certificates that are requested are allowed to use the base domains listed in allowed_domains."; - default = false; - }; - allow_host_certificates = lib.mkOption { - type = lib.types.nullOr (lib.types.bool); - description = "Specifies if certificates are allowed to be signed for use as a 'host'."; - default = false; - }; - allow_subdomains = lib.mkOption { - type = lib.types.nullOr (lib.types.bool); - description = "Specifies if host certificates that are requested are allowed to be subdomains of those listed in allowed_domains."; - default = false; - }; - allow_user_certificates = lib.mkOption { - type = lib.types.nullOr (lib.types.bool); - description = "Specifies if certificates are allowed to be signed for use as a 'user'."; - default = false; - }; - allowed_critical_options = lib.mkOption { - type = lib.types.listOf lib.types.str; - description = "Specifies a list of critical options that certificates can have when signed."; - default = [ ]; - }; - allowed_users = lib.mkOption { - type = lib.types.listOf lib.types.str; - description = "Specifies a list of usernames that are to be allowed, only if certain usernames are to be allowed."; - default = [ ]; - }; - default_user = lib.mkOption { - type = lib.types.nullOr lib.types.str; - description = "Specifies the default username for which a credential will be generated."; - default = null; - }; - allowed_domains = lib.mkOption { - type = lib.types.listOf lib.types.str; - description = "The list of domains for which a client can request a host certificate"; - default = [ ]; - }; - allowed_user_key_config = lib.mkOption { - type = lib.types.listOf ( - khscodesLib.mkSubmodule { - options = { - type = lib.mkOption { - type = lib.types.enum [ - "rsa" - "ecdsa" - "ec" - "dsa" - "ed25519" - "ssh-rsa" - "ssh-dss" - "ssh-ed25519" - "ecdsa-sha2-nistp256" - "ecdsa-sha2-nistp384" - "ecdsa-sha2-nistp521" - ]; - description = "The SSH public key type."; - }; - lengths = lib.mkOption { - type = lib.types.listOf lib.types.int; - description = "A list of allowed key lengths as integers. For key types that do not support setting the length a value of [0] should be used."; - }; - }; - description = "allowed_user_key_config"; - } - ); - description = "Set of configuration blocks to define allowed user key configuration, like key type and their lengths."; - }; - }; - description = "vault_ssh_secret_backend_role"; - } - ); - description = "Defines an ssh secret backend"; - default = { }; - }; - }; - config = lib.mkIf cfg.enable { - resource.vault_ssh_secret_backend_role = lib.mapAttrs' (name: value: { - name = khscodesLib.sanitize-terraform-name name; - value = { - inherit (value) - name - backend - key_type - allow_bare_domains - allow_host_certificates - allow_subdomains - allow_user_certificates - default_user - allowed_user_key_config - ; - allowed_critical_options = lib.strings.concatStringsSep "," ( - lib.lists.unique value.allowed_critical_options - ); - allowed_domains = lib.strings.concatStringsSep "," (lib.lists.unique value.allowed_domains); - allowed_users = lib.strings.concatStringsSep "," (lib.lists.unique value.allowed_users); - }; - }) cfg.ssh_secret_backend_role; - }; -} diff --git a/nix/packages/opentofu/default.nix b/nix/packages/opentofu/default.nix index 4212c13..2d18324 100644 --- a/nix/packages/opentofu/default.nix +++ b/nix/packages/opentofu/default.nix @@ -4,5 +4,4 @@ pkgs.opentofu.withPlugins (p: [ pkgs.khscodes.terraform-provider-cloudflare pkgs.khscodes.terraform-provider-hcloud pkgs.khscodes.terraform-provider-openstack - pkgs.khscodes.terraform-provider-vault ]) diff --git a/nix/packages/terraform-provider-vault/default.nix b/nix/packages/terraform-provider-vault/default.nix deleted file mode 100644 index 580112e..0000000 --- a/nix/packages/terraform-provider-vault/default.nix +++ /dev/null @@ -1,10 +0,0 @@ -{ pkgs }: -pkgs.terraform-providers.mkProvider { - hash = "sha256-Vqnmw69fktBQhSkj/W0legJ4sHOQP9Moqqi6Z5qYFy4="; - homepage = "https://registry.terraform.io/providers/hashicorp/vault"; - owner = "hashicorp"; - repo = "terraform-provider-vault"; - rev = "v5.0.0"; - spdx = "MPL-2.0"; - vendorHash = "sha256-6gWw4ypQZWPX7VC9cZxHiU/KhTYEdMTZ276B9neGAiI="; -} diff --git a/nix/packages/update-instance/default.nix b/nix/packages/update-instance/default.nix index 4cd2786..a18794d 100644 --- a/nix/packages/update-instance/default.nix +++ b/nix/packages/update-instance/default.nix @@ -5,6 +5,6 @@ pkgs.writeShellApplication { text = '' instance="''${1:-}" connect_host="''${2:-$1}" - nixos-rebuild switch --flake "${inputs.self}#$instance" --target-host "$connect_host" --build-host "$connect_host" --use-remote-sudo + nixos-rebuild switch --flake "${inputs.self}#$instance" --target-host "$connect_host" --build-host "localhost" ''; } diff --git a/nix/systems/aarch64-linux/khs.codes/default.nix b/nix/systems/aarch64-linux/khs.codes/default.nix index 6e096ac..aed4c34 100644 --- a/nix/systems/aarch64-linux/khs.codes/default.nix +++ b/nix/systems/aarch64-linux/khs.codes/default.nix @@ -8,6 +8,7 @@ enable = true; mapRdns = true; server_type = "cax11"; + secretsSource = "bitwarden"; }; khscodes.networking.fqdn = "khs.codes"; system.stateVersion = "25.05"; diff --git a/nix/systems/x86_64-linux/desktop.kaareskovgaard.net/default.nix b/nix/systems/x86_64-linux/desktop.kaareskovgaard.net/default.nix index 5e6b310..5a5ac3b 100644 --- a/nix/systems/x86_64-linux/desktop.kaareskovgaard.net/default.nix +++ b/nix/systems/x86_64-linux/desktop.kaareskovgaard.net/default.nix @@ -1,14 +1,9 @@ { inputs, - lib, ... }: { imports = [ "${inputs.self}/nix/profiles/nixos/khs-desktop.nix" ]; khscodes.networking.fqdn = "desktop.kaareskovgaard.net"; - disko = lib.khscodes.disko-root-bios { - device = "/dev/sda"; - diskName = "nixos"; - }; system.stateVersion = "25.05"; } diff --git a/nix/systems/x86_64-linux/test.kaareskovgaard.net/default.nix b/nix/systems/x86_64-linux/test.kaareskovgaard.net/default.nix index 8aa3a36..c6f0b6a 100644 --- a/nix/systems/x86_64-linux/test.kaareskovgaard.net/default.nix +++ b/nix/systems/x86_64-linux/test.kaareskovgaard.net/default.nix @@ -7,10 +7,11 @@ khscodes.infrastructure.khs-openstack-instance = { enable = true; flavor = "m.medium"; + secretsSource = "vault"; }; snowfallorg.users.khs.admin = true; users.users.khs = { - initialPassword = "changeme"; + initialPassword = "changeMe"; openssh.authorizedKeys.keys = [ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCqY0FHnWFKfLG2yfgr4qka5sR9CK+EMAhzlHUkaQyWHTKD+G0/vC/fNPyL1VV3Dxc/ajxGuPzVE+mBMoyxazL3EtuCDOVvHJ5CR+MUSEckg/DDwcGHqy6rC8BvVVpTAVL04ByQdwFnpE1qNSBaQLkxaFVdtriGKkgMkc7+UNeYX/bv7yn+APqfP1a3xr6wdkSSdO8x4N2jsSygOIMx10hLyCV4Ueu7Kp8Ww4rGY8j5o7lKJhbgfItBfSOuQHdppHVF/GKYRhdnK6Y2fZVYbhq4KipUtclbZ6O/VYd8/sOO98+LMm7cOX+K35PQjUpYgcoNy5+Sw3CNS/NHn4JvOtTaUEYP7fK6c9LhMULOO3T7Cm6TMdiFjUKHkyG+s2Mu/LXJJoilw571zwuh6chkeitW8+Ht7k0aPV96kNEvTdoXwLhBifVEaChlAsLAzSUjUq+YYCiXVk0VIXCZQWKj8LoVNTmaqDksWwbcT64fw/FpVC0N18WHbKcFUEIW/O4spJMa30CQwf9FeqpoWoaF1oRClCSDPvX0AauCu0JcmRinz1/JmlXljnXWbSfm20/V+WyvktlI0wTD0cdpNuSasT9vS77YfJ8nutcWWZKSkCj4R4uHeCNpDTX5YXzapy7FxpM9ANCXLIvoGX7Yafba2Po+er7SSsUIY1AsnBBr8ZoDVw==" ];