diff --git a/README.md b/README.md index 17b0fab..3093a5e 100644 --- a/README.md +++ b/README.md @@ -41,3 +41,7 @@ To transfer the secrets needed for OpenTofu from Bitwarden to OpenBAO/Vault run: ```bash nix run '.#bitwarden-to-vault' ``` + +## Immediate TODO list: + +1. Make the hetzner-static-ip.service not fail when the IP is already assigned. diff --git a/nix/systems/aarch64-linux/security.kaareskovgaard.net/README.md b/nix/systems/aarch64-linux/security.kaareskovgaard.net/README.md index 4a85b7a..a0e7460 100644 --- a/nix/systems/aarch64-linux/security.kaareskovgaard.net/README.md +++ b/nix/systems/aarch64-linux/security.kaareskovgaard.net/README.md @@ -1,3 +1,7 @@ +# Before beginning + +Enable bootstrapping of the instance, by setting `config.khscodes."security.kaareskovgaard.net".bootstrap.enable = true` in `default.nix`. + # After creating the instance Open https://secrets.kaareskovgaard.net and initialize OpenBAO. Remember to get some sort of auto unsealing set up afterwards, currently this is implemented with a cronjob on TrueNAS. Doing it this way allows various certificates to continue getting issued, even as OpenBAO gets sealed (due to auto updates). @@ -5,7 +9,7 @@ Open https://secrets.kaareskovgaard.net and initialize OpenBAO. Remember to get After this, configure the OpenBAO instance with: ```bash -nix run '.#configure-instance` -- security.kaareskovgaard.net +nix run '.#configure-instance' -- security.kaareskovgaard.net ``` In order for `security.kaareskovgaard.net` to authenticate itself with OpenBAO, the printed credentials needs to be passed to the server with (on the server): @@ -22,4 +26,18 @@ kanidm-reset-password Open https://login.kaareskovgaard.net - and log into the account, setting up the Yubikey (Passkey) auth, as well as Bitwarden based TOTP/password auth. +## Disable bootstrapping + +Now remove the previously enabled bootstrapping. Then update the instance + +```bash +nix run '.#update-instance' -- security.kaareskovgaard.net +``` + +And reconfigure it: + +```bash +nix run '.#configure-instance' -- security-kaareskovgaard.net +``` + Then `nix run '.#bitwarden-to-vault` can transfer the needed Bitwarden secrets to vault, enabling other instances to not rely on Bitwarden. diff --git a/nix/systems/aarch64-linux/security.kaareskovgaard.net/default.nix b/nix/systems/aarch64-linux/security.kaareskovgaard.net/default.nix index 0e6e2c6..58d26c2 100644 --- a/nix/systems/aarch64-linux/security.kaareskovgaard.net/default.nix +++ b/nix/systems/aarch64-linux/security.kaareskovgaard.net/default.nix @@ -1,32 +1,40 @@ { inputs, + lib, pkgs, ... }: { + options.khscodes."security.kaareskovgaard.net" = { + bootstrap = { + enable = lib.mkEnableOption "Enables bootstrapping mode for security.kaareskovgaard.net. This should be set when first setting up the server. See the README"; + }; + }; imports = [ "${inputs.self}/nix/profiles/nixos/hetzner-server.nix" ./kanidm.nix ./openbao.nix ./post ]; - environment.systemPackages = [ pkgs.khscodes.bao-import-secret ]; - khscodes.services.nginx.enable = true; - khscodes.infrastructure.hetzner-instance = { - enable = true; - server_type = "cax11"; + config = { + environment.systemPackages = [ pkgs.khscodes.bao-import-secret ]; + khscodes.services.nginx.enable = true; + khscodes.infrastructure.hetzner-instance = { + enable = true; + server_type = "cax11"; + }; + # Cannot use vault for secrets source, as this is the server containing vault. + khscodes.infrastructure.provisioning.pre.secretsSource = "bitwarden"; + khscodes.infrastructure.provisioning.post.secretsSource = "bitwarden"; + khscodes.infrastructure.vault-server-approle.stage = "post"; + khscodes.networking.fqdn = "security.kaareskovgaard.net"; + users.users.khs = { + 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==" + ]; + }; + khscodes.infrastructure.openbao.domain = "secrets.kaareskovgaard.net"; + system.stateVersion = "25.05"; }; - # Cannot use vault for secrets source, as this is the server containing vault. - khscodes.infrastructure.provisioning.pre.secretsSource = "bitwarden"; - khscodes.infrastructure.provisioning.post.secretsSource = "bitwarden"; - khscodes.infrastructure.vault-server-approle.stage = "post"; - khscodes.networking.fqdn = "security.kaareskovgaard.net"; - users.users.khs = { - 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==" - ]; - }; - khscodes.infrastructure.openbao.domain = "secrets.kaareskovgaard.net"; - system.stateVersion = "25.05"; } diff --git a/nix/systems/aarch64-linux/security.kaareskovgaard.net/kanidm.nix b/nix/systems/aarch64-linux/security.kaareskovgaard.net/kanidm.nix index 71d0055..bf73cf8 100644 --- a/nix/systems/aarch64-linux/security.kaareskovgaard.net/kanidm.nix +++ b/nix/systems/aarch64-linux/security.kaareskovgaard.net/kanidm.nix @@ -1,6 +1,12 @@ -{ config, pkgs, ... }: +{ + config, + pkgs, + lib, + ... +}: let domain = "login.kaareskovgaard.net"; + bootstrapping = config.khscodes."security.kaareskovgaard.net".bootstrap.enable; openbaoAppBasicSecretFile = "/var/lib/vault-agent/kanidm/openbao_basic_secret"; openbaoDomain = config.khscodes.infrastructure.openbao.domain; openbaoAllowedRedirectUrls = [ @@ -63,35 +69,39 @@ in present = true; members = [ "khs" ]; }; - systems.oauth2.openbao = { - present = true; - public = false; - preferShortUsername = true; - basicSecretFile = openbaoAppBasicSecretFile; - originUrl = openbaoAllowedRedirectUrls; - originLanding = "https://${openbaoDomain}"; - displayName = "OpenBAO"; - scopeMaps = { - "openbao_admin" = [ - "profile" - "email" - "openid" - ]; - }; - claimMaps.groups = { - joinType = "array"; - valuesByGroup = { + # We cannot add oauth2 apps before the secrets for them are generated. + systems.oauth2 = lib.mkIf (!bootstrapping) { + openbao = { + present = true; + public = false; + preferShortUsername = true; + basicSecretFile = openbaoAppBasicSecretFile; + originUrl = openbaoAllowedRedirectUrls; + originLanding = "https://${openbaoDomain}"; + displayName = "OpenBAO"; + scopeMaps = { "openbao_admin" = [ - "openbao_reader" - "openbao_writer" - "openbao_sudo" + "profile" + "email" + "openid" ]; }; + claimMaps.groups = { + joinType = "array"; + valuesByGroup = { + "openbao_admin" = [ + "openbao_reader" + "openbao_writer" + "openbao_sudo" + ]; + }; + }; }; }; }; }; - systemd.services.kanidm = { + # Don't add dependencies from bootstrapping when not bootstrapping. + systemd.services.kanidm = lib.mkIf (!bootstrapping) { unitConfig = { ConditionPathExists = [ openbaoAppBasicSecretFile @@ -142,144 +152,150 @@ in }; } ) - # Sets up OIDC authentication within OpenBAO - { - resource.vault_jwt_auth_backend.oidc = { - description = "Kanidm auth backend"; - path = "oidc"; - type = "oidc"; - oidc_discovery_url = "https://${domain}/oauth2/openid/openbao"; - oidc_client_id = "openbao"; - oidc_client_secret = "\${ resource.random_password.openbao_secret.result }"; - jwt_supported_algs = [ - "ES256" - ]; - tune = [ - { - listing_visibility = "unauth"; - default_lease_ttl = "2h"; - max_lease_ttl = "2h"; - token_type = "default-service"; - passthrough_request_headers = [ ]; - allowed_response_headers = [ ]; - audit_non_hmac_request_keys = [ ]; - audit_non_hmac_response_keys = [ ]; - } - ]; - }; + # Sets up OIDC authentication within OpenBAO. + # OpenBAO queries the openid url for its configuration when adding it, so it is not possible, + # to add this before + ( + if bootstrapping then + { } + else + { + resource.vault_jwt_auth_backend.oidc = { + description = "Kanidm auth backend"; + path = "oidc"; + type = "oidc"; + oidc_discovery_url = "https://${domain}/oauth2/openid/openbao"; + oidc_client_id = "openbao"; + oidc_client_secret = "\${ resource.random_password.openbao_secret.result }"; + jwt_supported_algs = [ + "ES256" + ]; + tune = [ + { + listing_visibility = "unauth"; + default_lease_ttl = "2h"; + max_lease_ttl = "2h"; + token_type = "default-service"; + passthrough_request_headers = [ ]; + allowed_response_headers = [ ]; + audit_non_hmac_request_keys = [ ]; + audit_non_hmac_response_keys = [ ]; + } + ]; + }; - resource.vault_jwt_auth_backend_role.oidc_reader = { - backend = "\${ resource.vault_jwt_auth_backend.oidc.path }"; - role_name = "reader"; - bound_audiences = [ "openbao" ]; - allowed_redirect_uris = openbaoAllowedRedirectUrls; - user_claim = "sub"; - token_policies = [ "reader" ]; - groups_claim = "groups"; - oidc_scopes = [ - "openid" - "profile" - "email" - ]; - }; + resource.vault_jwt_auth_backend_role.oidc_reader = { + backend = "\${ resource.vault_jwt_auth_backend.oidc.path }"; + role_name = "reader"; + bound_audiences = [ "openbao" ]; + allowed_redirect_uris = openbaoAllowedRedirectUrls; + user_claim = "sub"; + token_policies = [ "reader" ]; + groups_claim = "groups"; + oidc_scopes = [ + "openid" + "profile" + "email" + ]; + }; - resource.vault_jwt_auth_backend_role.oidc_writer = { - backend = "\${ resource.vault_jwt_auth_backend.oidc.path }"; - role_name = "writer"; - bound_audiences = [ "openbao" ]; - allowed_redirect_uris = openbaoAllowedRedirectUrls; - user_claim = "sub"; - token_policies = [ "writer" ]; - groups_claim = "groups"; - oidc_scopes = [ - "openid" - "profile" - "email" - ]; - }; + resource.vault_jwt_auth_backend_role.oidc_writer = { + backend = "\${ resource.vault_jwt_auth_backend.oidc.path }"; + role_name = "writer"; + bound_audiences = [ "openbao" ]; + allowed_redirect_uris = openbaoAllowedRedirectUrls; + user_claim = "sub"; + token_policies = [ "writer" ]; + groups_claim = "groups"; + oidc_scopes = [ + "openid" + "profile" + "email" + ]; + }; - resource.vault_jwt_auth_backend_role.oidc_sudo = { - backend = "\${ resource.vault_jwt_auth_backend.oidc.path }"; - role_name = "sudo"; - bound_audiences = [ "openbao" ]; - allowed_redirect_uris = openbaoAllowedRedirectUrls; - user_claim = "sub"; - token_policies = [ "sudo" ]; - groups_claim = "groups"; - oidc_scopes = [ - "openid" - "profile" - "email" - ]; - }; + resource.vault_jwt_auth_backend_role.oidc_sudo = { + backend = "\${ resource.vault_jwt_auth_backend.oidc.path }"; + role_name = "sudo"; + bound_audiences = [ "openbao" ]; + allowed_redirect_uris = openbaoAllowedRedirectUrls; + user_claim = "sub"; + token_policies = [ "sudo" ]; + groups_claim = "groups"; + oidc_scopes = [ + "openid" + "profile" + "email" + ]; + }; - resource.vault_identity_group.reader = { - name = "reader"; - policies = [ "reader" ]; - type = "external"; - }; + resource.vault_identity_group.reader = { + name = "reader"; + policies = [ "reader" ]; + type = "external"; + }; - resource.vault_identity_group.writer = { - name = "writer"; - policies = [ "writer" ]; - type = "external"; - }; + resource.vault_identity_group.writer = { + name = "writer"; + policies = [ "writer" ]; + type = "external"; + }; - resource.vault_identity_group.sudo = { - name = "sudo"; - policies = [ "sudo" ]; - type = "external"; - }; + resource.vault_identity_group.sudo = { + name = "sudo"; + policies = [ "sudo" ]; + type = "external"; + }; - resource.vault_identity_group_alias.reader = { - name = "openbao_reader"; - mount_accessor = "\${ vault_jwt_auth_backend.oidc.accessor }"; - canonical_id = "\${ vault_identity_group.reader.id }"; - }; + resource.vault_identity_group_alias.reader = { + name = "openbao_reader"; + mount_accessor = "\${ vault_jwt_auth_backend.oidc.accessor }"; + canonical_id = "\${ vault_identity_group.reader.id }"; + }; - resource.vault_identity_group_alias.writer = { - name = "openbao_writer"; - mount_accessor = "\${ vault_jwt_auth_backend.oidc.accessor }"; - canonical_id = "\${ vault_identity_group.writer.id }"; - }; + resource.vault_identity_group_alias.writer = { + name = "openbao_writer"; + mount_accessor = "\${ vault_jwt_auth_backend.oidc.accessor }"; + canonical_id = "\${ vault_identity_group.writer.id }"; + }; - resource.vault_identity_group_alias.sudo = { - name = "openbao_sudo"; - mount_accessor = "\${ vault_jwt_auth_backend.oidc.accessor }"; - canonical_id = "\${ vault_identity_group.writer.id }"; - }; + resource.vault_identity_group_alias.sudo = { + name = "openbao_sudo"; + mount_accessor = "\${ vault_jwt_auth_backend.oidc.accessor }"; + canonical_id = "\${ vault_identity_group.writer.id }"; + }; - resource.vault_policy.reader = { - name = "reader"; + resource.vault_policy.reader = { + name = "reader"; - policy = '' - path "*" { - capabilities = ["read", "list"] - } - ''; - }; + policy = '' + path "*" { + capabilities = ["read", "list"] + } + ''; + }; - resource.vault_policy.writer = { - name = "writer"; + resource.vault_policy.writer = { + name = "writer"; - policy = '' - path "*" { - capabilities = ["create", "update", "patch", "read", "delete", "list"] - } - ''; - }; + policy = '' + path "*" { + capabilities = ["create", "update", "patch", "read", "delete", "list"] + } + ''; + }; - resource.vault_policy.sudo = { - name = "sudo"; + resource.vault_policy.sudo = { + name = "sudo"; - policy = '' - path "auth/token/create" { - capabilities = ["create", "update", "sudo"] - } - ''; - }; - - } + policy = '' + path "auth/token/create" { + capabilities = ["create", "update", "sudo"] + } + ''; + }; + } + ) ]; khscodes.services.vault-agent.templates = [