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
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
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 <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.
## 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.

View file

@ -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";
}

View file

@ -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 = [