Fix some notes
Some checks failed
/ check (push) Failing after 2m22s
/ dev-shell (push) Successful in 25s
/ rust-packages (push) Successful in 33s
/ systems (push) Successful in 18m35s
/ terraform-providers (push) Successful in 2m23s

This commit is contained in:
Kaare Hoff Skovgaard 2025-07-17 01:28:58 +02:00
parent f3175b9b03
commit 905b1096ac
Signed by: khs
GPG key ID: C7D890804F01E9F0
4 changed files with 211 additions and 165 deletions

View file

@ -41,3 +41,7 @@ To transfer the secrets needed for OpenTofu from Bitwarden to OpenBAO/Vault run:
```bash ```bash
nix run '.#bitwarden-to-vault' nix run '.#bitwarden-to-vault'
``` ```
## Immediate TODO list:
1. Make the hetzner-static-ip.service not fail when the IP is already assigned.

View file

@ -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 # 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). 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: After this, configure the OpenBAO instance with:
```bash ```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): 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 <user>
Open https://login.kaareskovgaard.net - and log into the account, setting up the Yubikey (Passkey) auth, as well as Bitwarden based TOTP/password auth. 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. Then `nix run '.#bitwarden-to-vault` can transfer the needed Bitwarden secrets to vault, enabling other instances to not rely on Bitwarden.

View file

@ -1,32 +1,40 @@
{ {
inputs, inputs,
lib,
pkgs, 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 = [ imports = [
"${inputs.self}/nix/profiles/nixos/hetzner-server.nix" "${inputs.self}/nix/profiles/nixos/hetzner-server.nix"
./kanidm.nix ./kanidm.nix
./openbao.nix ./openbao.nix
./post ./post
]; ];
environment.systemPackages = [ pkgs.khscodes.bao-import-secret ]; config = {
khscodes.services.nginx.enable = true; environment.systemPackages = [ pkgs.khscodes.bao-import-secret ];
khscodes.infrastructure.hetzner-instance = { khscodes.services.nginx.enable = true;
enable = true; khscodes.infrastructure.hetzner-instance = {
server_type = "cax11"; 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";
} }

View file

@ -1,6 +1,12 @@
{ config, pkgs, ... }: {
config,
pkgs,
lib,
...
}:
let let
domain = "login.kaareskovgaard.net"; domain = "login.kaareskovgaard.net";
bootstrapping = config.khscodes."security.kaareskovgaard.net".bootstrap.enable;
openbaoAppBasicSecretFile = "/var/lib/vault-agent/kanidm/openbao_basic_secret"; openbaoAppBasicSecretFile = "/var/lib/vault-agent/kanidm/openbao_basic_secret";
openbaoDomain = config.khscodes.infrastructure.openbao.domain; openbaoDomain = config.khscodes.infrastructure.openbao.domain;
openbaoAllowedRedirectUrls = [ openbaoAllowedRedirectUrls = [
@ -63,35 +69,39 @@ in
present = true; present = true;
members = [ "khs" ]; members = [ "khs" ];
}; };
systems.oauth2.openbao = { # We cannot add oauth2 apps before the secrets for them are generated.
present = true; systems.oauth2 = lib.mkIf (!bootstrapping) {
public = false; openbao = {
preferShortUsername = true; present = true;
basicSecretFile = openbaoAppBasicSecretFile; public = false;
originUrl = openbaoAllowedRedirectUrls; preferShortUsername = true;
originLanding = "https://${openbaoDomain}"; basicSecretFile = openbaoAppBasicSecretFile;
displayName = "OpenBAO"; originUrl = openbaoAllowedRedirectUrls;
scopeMaps = { originLanding = "https://${openbaoDomain}";
"openbao_admin" = [ displayName = "OpenBAO";
"profile" scopeMaps = {
"email"
"openid"
];
};
claimMaps.groups = {
joinType = "array";
valuesByGroup = {
"openbao_admin" = [ "openbao_admin" = [
"openbao_reader" "profile"
"openbao_writer" "email"
"openbao_sudo" "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 = { unitConfig = {
ConditionPathExists = [ ConditionPathExists = [
openbaoAppBasicSecretFile openbaoAppBasicSecretFile
@ -142,144 +152,150 @@ in
}; };
} }
) )
# Sets up OIDC authentication within OpenBAO # Sets up OIDC authentication within OpenBAO.
{ # OpenBAO queries the openid url for its configuration when adding it, so it is not possible,
resource.vault_jwt_auth_backend.oidc = { # to add this before
description = "Kanidm auth backend"; (
path = "oidc"; if bootstrapping then
type = "oidc"; { }
oidc_discovery_url = "https://${domain}/oauth2/openid/openbao"; else
oidc_client_id = "openbao"; {
oidc_client_secret = "\${ resource.random_password.openbao_secret.result }"; resource.vault_jwt_auth_backend.oidc = {
jwt_supported_algs = [ description = "Kanidm auth backend";
"ES256" path = "oidc";
]; type = "oidc";
tune = [ oidc_discovery_url = "https://${domain}/oauth2/openid/openbao";
{ oidc_client_id = "openbao";
listing_visibility = "unauth"; oidc_client_secret = "\${ resource.random_password.openbao_secret.result }";
default_lease_ttl = "2h"; jwt_supported_algs = [
max_lease_ttl = "2h"; "ES256"
token_type = "default-service"; ];
passthrough_request_headers = [ ]; tune = [
allowed_response_headers = [ ]; {
audit_non_hmac_request_keys = [ ]; listing_visibility = "unauth";
audit_non_hmac_response_keys = [ ]; 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 = { resource.vault_jwt_auth_backend_role.oidc_reader = {
backend = "\${ resource.vault_jwt_auth_backend.oidc.path }"; backend = "\${ resource.vault_jwt_auth_backend.oidc.path }";
role_name = "reader"; role_name = "reader";
bound_audiences = [ "openbao" ]; bound_audiences = [ "openbao" ];
allowed_redirect_uris = openbaoAllowedRedirectUrls; allowed_redirect_uris = openbaoAllowedRedirectUrls;
user_claim = "sub"; user_claim = "sub";
token_policies = [ "reader" ]; token_policies = [ "reader" ];
groups_claim = "groups"; groups_claim = "groups";
oidc_scopes = [ oidc_scopes = [
"openid" "openid"
"profile" "profile"
"email" "email"
]; ];
}; };
resource.vault_jwt_auth_backend_role.oidc_writer = { resource.vault_jwt_auth_backend_role.oidc_writer = {
backend = "\${ resource.vault_jwt_auth_backend.oidc.path }"; backend = "\${ resource.vault_jwt_auth_backend.oidc.path }";
role_name = "writer"; role_name = "writer";
bound_audiences = [ "openbao" ]; bound_audiences = [ "openbao" ];
allowed_redirect_uris = openbaoAllowedRedirectUrls; allowed_redirect_uris = openbaoAllowedRedirectUrls;
user_claim = "sub"; user_claim = "sub";
token_policies = [ "writer" ]; token_policies = [ "writer" ];
groups_claim = "groups"; groups_claim = "groups";
oidc_scopes = [ oidc_scopes = [
"openid" "openid"
"profile" "profile"
"email" "email"
]; ];
}; };
resource.vault_jwt_auth_backend_role.oidc_sudo = { resource.vault_jwt_auth_backend_role.oidc_sudo = {
backend = "\${ resource.vault_jwt_auth_backend.oidc.path }"; backend = "\${ resource.vault_jwt_auth_backend.oidc.path }";
role_name = "sudo"; role_name = "sudo";
bound_audiences = [ "openbao" ]; bound_audiences = [ "openbao" ];
allowed_redirect_uris = openbaoAllowedRedirectUrls; allowed_redirect_uris = openbaoAllowedRedirectUrls;
user_claim = "sub"; user_claim = "sub";
token_policies = [ "sudo" ]; token_policies = [ "sudo" ];
groups_claim = "groups"; groups_claim = "groups";
oidc_scopes = [ oidc_scopes = [
"openid" "openid"
"profile" "profile"
"email" "email"
]; ];
}; };
resource.vault_identity_group.reader = { resource.vault_identity_group.reader = {
name = "reader"; name = "reader";
policies = [ "reader" ]; policies = [ "reader" ];
type = "external"; type = "external";
}; };
resource.vault_identity_group.writer = { resource.vault_identity_group.writer = {
name = "writer"; name = "writer";
policies = [ "writer" ]; policies = [ "writer" ];
type = "external"; type = "external";
}; };
resource.vault_identity_group.sudo = { resource.vault_identity_group.sudo = {
name = "sudo"; name = "sudo";
policies = [ "sudo" ]; policies = [ "sudo" ];
type = "external"; type = "external";
}; };
resource.vault_identity_group_alias.reader = { resource.vault_identity_group_alias.reader = {
name = "openbao_reader"; name = "openbao_reader";
mount_accessor = "\${ vault_jwt_auth_backend.oidc.accessor }"; mount_accessor = "\${ vault_jwt_auth_backend.oidc.accessor }";
canonical_id = "\${ vault_identity_group.reader.id }"; canonical_id = "\${ vault_identity_group.reader.id }";
}; };
resource.vault_identity_group_alias.writer = { resource.vault_identity_group_alias.writer = {
name = "openbao_writer"; name = "openbao_writer";
mount_accessor = "\${ vault_jwt_auth_backend.oidc.accessor }"; mount_accessor = "\${ vault_jwt_auth_backend.oidc.accessor }";
canonical_id = "\${ vault_identity_group.writer.id }"; canonical_id = "\${ vault_identity_group.writer.id }";
}; };
resource.vault_identity_group_alias.sudo = { resource.vault_identity_group_alias.sudo = {
name = "openbao_sudo"; name = "openbao_sudo";
mount_accessor = "\${ vault_jwt_auth_backend.oidc.accessor }"; mount_accessor = "\${ vault_jwt_auth_backend.oidc.accessor }";
canonical_id = "\${ vault_identity_group.writer.id }"; canonical_id = "\${ vault_identity_group.writer.id }";
}; };
resource.vault_policy.reader = { resource.vault_policy.reader = {
name = "reader"; name = "reader";
policy = '' policy = ''
path "*" { path "*" {
capabilities = ["read", "list"] capabilities = ["read", "list"]
} }
''; '';
}; };
resource.vault_policy.writer = { resource.vault_policy.writer = {
name = "writer"; name = "writer";
policy = '' policy = ''
path "*" { path "*" {
capabilities = ["create", "update", "patch", "read", "delete", "list"] capabilities = ["create", "update", "patch", "read", "delete", "list"]
} }
''; '';
}; };
resource.vault_policy.sudo = { resource.vault_policy.sudo = {
name = "sudo"; name = "sudo";
policy = '' policy = ''
path "auth/token/create" { path "auth/token/create" {
capabilities = ["create", "update", "sudo"] capabilities = ["create", "update", "sudo"]
} }
''; '';
}; };
}
} )
]; ];
khscodes.services.vault-agent.templates = [ khscodes.services.vault-agent.templates = [