Begin reworking some things around oauth apps
This commit is contained in:
parent
3d81e585db
commit
2064b4b006
14 changed files with 692 additions and 528 deletions
|
@ -24,10 +24,12 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
disko = lib.khscodes.disko-root-lvm-uefi {
|
disko = lib.mkDefault (
|
||||||
device = "/dev/sda";
|
lib.khscodes.disko-root-lvm-uefi {
|
||||||
diskName = cfg.diskName;
|
device = "/dev/sda";
|
||||||
};
|
diskName = cfg.diskName;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
boot.tmp.cleanOnBoot = lib.mkDefault true;
|
boot.tmp.cleanOnBoot = lib.mkDefault true;
|
||||||
boot.initrd.kernelModules = lib.mkIf (system == "aarch64-linux") [ "virtio_gpu" ];
|
boot.initrd.kernelModules = lib.mkIf (system == "aarch64-linux") [ "virtio_gpu" ];
|
||||||
|
|
|
@ -124,7 +124,6 @@ in
|
||||||
description = "The server type to create";
|
description = "The server type to create";
|
||||||
default = null;
|
default = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
extraFirewallRules = lib.mkOption {
|
extraFirewallRules = lib.mkOption {
|
||||||
type = lib.types.listOf lib.types.attrs;
|
type = lib.types.listOf lib.types.attrs;
|
||||||
description = "Extra firewall rules added to the instance";
|
description = "Extra firewall rules added to the instance";
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
{ config, lib, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.khscodes.infrastructure.kanidm-client-application;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.khscodes.infrastructure.kanidm-client-application = {
|
||||||
|
enable = lib.mkEnableOption "Enables securing client credentials for oauth2 application in kanidm";
|
||||||
|
appName = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
};
|
||||||
|
secretFile = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "/run/secret/kanidm/${cfg.appName}";
|
||||||
|
};
|
||||||
|
secretOwner = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
};
|
||||||
|
secretGroup = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = cfg.secretOwner;
|
||||||
|
};
|
||||||
|
reloadOrRestartUnits = lib.mkOption {
|
||||||
|
type = lib.types.listOf lib.types.str;
|
||||||
|
default = [ ];
|
||||||
|
};
|
||||||
|
restartUnits = lib.mkOption {
|
||||||
|
type = lib.types.listOf lib.types.str;
|
||||||
|
default = [ ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
khscodes.services.vault-agent.templates = [
|
||||||
|
{
|
||||||
|
inherit (cfg) reloadOrRestartUnits restartUnits;
|
||||||
|
contents = ''
|
||||||
|
{{- with secret "kanidm/data/apps/${cfg.appName}" -}}
|
||||||
|
{{ .Data.data.basic_secret }}
|
||||||
|
{{- end -}}
|
||||||
|
'';
|
||||||
|
destination = cfg.secretFile;
|
||||||
|
owner = cfg.secretOwner;
|
||||||
|
group = cfg.secretGroup;
|
||||||
|
perms = "0600";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
khscodes.infrastructure.vault-server-approle.policy = {
|
||||||
|
"kanidm/data/apps/${cfg.appName}" = {
|
||||||
|
capabilities = [ "read" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -60,18 +60,11 @@ in
|
||||||
};
|
};
|
||||||
khscodes.infrastructure.vault-prometheus-sender.exporters.enabled = [ "postfix" ];
|
khscodes.infrastructure.vault-prometheus-sender.exporters.enabled = [ "postfix" ];
|
||||||
services.fail2ban.jails = {
|
services.fail2ban.jails = {
|
||||||
postfix-sasl = {
|
|
||||||
settings = {
|
|
||||||
filter = "postfix[mode=auth]";
|
|
||||||
port = "smtp,submission,imap,imaps,pop3,pop3s";
|
|
||||||
findtime = 600;
|
|
||||||
maxretry = 5;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
postfix = {
|
postfix = {
|
||||||
settings = {
|
settings = {
|
||||||
enabled = true;
|
enabled = true;
|
||||||
mode = "aggressive";
|
mode = "aggressive";
|
||||||
|
port = "smtp,submission,imap,imaps,pop3,pop3s";
|
||||||
findtime = 600;
|
findtime = 600;
|
||||||
bantime = "1d";
|
bantime = "1d";
|
||||||
maxretry = 3;
|
maxretry = 3;
|
||||||
|
@ -86,7 +79,7 @@ in
|
||||||
maxretry = 3;
|
maxretry = 3;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
roundcube-atuh = {
|
roundcube-auth = {
|
||||||
settings = {
|
settings = {
|
||||||
enabled = true;
|
enabled = true;
|
||||||
findtime = 600;
|
findtime = 600;
|
||||||
|
|
|
@ -25,6 +25,7 @@ pkgs.writeShellApplication {
|
||||||
echo "No preprovisioning needed"
|
echo "No preprovisioning needed"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
echo -n "tempkey" | ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "$username@$host" -- "cat >/tmp/tempkey"
|
||||||
nixos-anywhere --flake "${inputs.self}#$hostname" --target-host "$username@$host"
|
nixos-anywhere --flake "${inputs.self}#$hostname" --target-host "$username@$host"
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
oauthSecretIdFile = "/run/forgejo/oauth_secret_id";
|
|
||||||
setApp = pkgs.writeShellApplication {
|
setApp = pkgs.writeShellApplication {
|
||||||
name = "forgejo-set-oauth-app";
|
name = "forgejo-set-oauth-app";
|
||||||
runtimeInputs = [
|
runtimeInputs = [
|
||||||
|
@ -14,7 +13,7 @@ let
|
||||||
];
|
];
|
||||||
text = ''
|
text = ''
|
||||||
config="${config.services.forgejo.stateDir}/custom/conf/app.ini"
|
config="${config.services.forgejo.stateDir}/custom/conf/app.ini"
|
||||||
secret="$(cat ${oauthSecretIdFile})"
|
secret="$(cat ${config.khscodes.infrastructure.kanidm-client-application.secretFile})"
|
||||||
|
|
||||||
options=(
|
options=(
|
||||||
"--name" "Kanidm" \
|
"--name" "Kanidm" \
|
||||||
|
@ -43,26 +42,11 @@ let
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
khscodes.services.vault-agent.templates = [
|
khscodes.infrastructure.kanidm-client-application = {
|
||||||
{
|
enable = true;
|
||||||
contents = ''
|
appName = "forgejo";
|
||||||
{{- with secret "kanidm/data/apps/forgejo" -}}
|
secretOwner = "git";
|
||||||
{{ .Data.data.basic_secret }}
|
restartUnits = [ "forgejo-setup-oauth.service" ];
|
||||||
{{- end -}}
|
|
||||||
'';
|
|
||||||
destination = oauthSecretIdFile;
|
|
||||||
perms = "0600";
|
|
||||||
owner = "git";
|
|
||||||
group = "git";
|
|
||||||
restartUnits = [
|
|
||||||
"forgejo-setup-oauth.service"
|
|
||||||
];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
khscodes.infrastructure.vault-server-approle.policy = {
|
|
||||||
"kanidm/data/apps/forgejo" = {
|
|
||||||
capabilities = [ "read" ];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
systemd.services.forgejo-setup-oauth = {
|
systemd.services.forgejo-setup-oauth = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
@ -73,7 +57,7 @@ in
|
||||||
"vault-agent-openbao.service"
|
"vault-agent-openbao.service"
|
||||||
];
|
];
|
||||||
unitConfig = {
|
unitConfig = {
|
||||||
ConditionPathExists = [ oauthSecretIdFile ];
|
ConditionPathExists = [ config.infrastructure.kanidm-client-application.secretFile ];
|
||||||
};
|
};
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
Type = "oneshot";
|
Type = "oneshot";
|
||||||
|
|
|
@ -1,64 +0,0 @@
|
||||||
{
|
|
||||||
inputs,
|
|
||||||
config,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
"${inputs.self}/nix/profiles/nixos/hetzner-server.nix"
|
|
||||||
./testuser.nix
|
|
||||||
];
|
|
||||||
khscodes.infrastructure.provisioning.pre.modules = [
|
|
||||||
{
|
|
||||||
khscodes.vault = {
|
|
||||||
enable = true;
|
|
||||||
mount."mail.kaareskovgaard.net" = {
|
|
||||||
path = "mail.kaareskovgaard.net";
|
|
||||||
type = "kv";
|
|
||||||
options = {
|
|
||||||
version = "2";
|
|
||||||
};
|
|
||||||
description = "Secrets used for mail.kaareskovgaard.net";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
];
|
|
||||||
khscodes.infrastructure = {
|
|
||||||
hetzner-instance = {
|
|
||||||
enable = true;
|
|
||||||
mapRdns = true;
|
|
||||||
server_type = "cax11";
|
|
||||||
};
|
|
||||||
mailserver = {
|
|
||||||
enable = true;
|
|
||||||
domains = [
|
|
||||||
"agerlin-skovgaard.dk"
|
|
||||||
"agerlinskovgaard.dk"
|
|
||||||
];
|
|
||||||
dkim = {
|
|
||||||
vault = {
|
|
||||||
mount = "mail.kaareskovgaard.net";
|
|
||||||
prefixPath = "dkim";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
services.roundcube = {
|
|
||||||
enable = true;
|
|
||||||
hostName = "mail.kaareskovgaard.net";
|
|
||||||
configureNginx = true;
|
|
||||||
extraConfig = ''
|
|
||||||
# starttls needed for authentication, so the fqdn required to match
|
|
||||||
# the certificate
|
|
||||||
$config['smtp_host'] = "tls://${config.mailserver.fqdn}";
|
|
||||||
$config['smtp_user'] = "%u";
|
|
||||||
$config['smtp_pass'] = "%p";
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
khscodes.services.nginx = {
|
|
||||||
enable = true;
|
|
||||||
virtualHosts."mail.kaareskovgaard.net" = { };
|
|
||||||
};
|
|
||||||
khscodes.networking.fqdn = "mail.kaareskovgaard.net";
|
|
||||||
system.stateVersion = "25.05";
|
|
||||||
}
|
|
71
nix/systems/aarch64-linux/mx.kaareskovgaard.net/default.nix
Normal file
71
nix/systems/aarch64-linux/mx.kaareskovgaard.net/default.nix
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
{
|
||||||
|
inputs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
"${inputs.self}/nix/profiles/nixos/hetzner-server.nix"
|
||||||
|
# ./testuser.nix
|
||||||
|
];
|
||||||
|
khscodes.infrastructure.provisioning.pre.modules = [
|
||||||
|
(
|
||||||
|
{ config, ... }:
|
||||||
|
{
|
||||||
|
khscodes.vault = {
|
||||||
|
enable = true;
|
||||||
|
mount."mx.kaareskovgaard.net" = {
|
||||||
|
path = "mx.kaareskovgaard.net";
|
||||||
|
type = "kv";
|
||||||
|
options = {
|
||||||
|
version = "2";
|
||||||
|
};
|
||||||
|
description = "Secrets used for mx.kaareskovgaard.net";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
resource.hcloud_volume.mail_disk = {
|
||||||
|
name = "mx.kaareskovgaard.net-mail1";
|
||||||
|
size = 20;
|
||||||
|
server_id = config.khscodes.output.server.compute.id;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
];
|
||||||
|
khscodes.infrastructure = {
|
||||||
|
hetzner-instance = {
|
||||||
|
enable = true;
|
||||||
|
mapRdns = true;
|
||||||
|
server_type = "cax11";
|
||||||
|
};
|
||||||
|
mailserver = {
|
||||||
|
enable = true;
|
||||||
|
domains = [
|
||||||
|
"agerlin-skovgaard.dk"
|
||||||
|
"agerlinskovgaard.dk"
|
||||||
|
];
|
||||||
|
dkim = {
|
||||||
|
vault = {
|
||||||
|
mount = "mx.kaareskovgaard.net";
|
||||||
|
prefixPath = "dkim";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
# services.roundcube = {
|
||||||
|
# enable = true;
|
||||||
|
# hostName = "mail.kaareskovgaard.net";
|
||||||
|
# configureNginx = true;
|
||||||
|
# extraConfig = ''
|
||||||
|
# # starttls needed for authentication, so the fqdn required to match
|
||||||
|
# # the certificate
|
||||||
|
# $config['smtp_host'] = "tls://${config.mailserver.fqdn}";
|
||||||
|
# $config['smtp_user'] = "%u";
|
||||||
|
# $config['smtp_pass'] = "%p";
|
||||||
|
# '';
|
||||||
|
# };
|
||||||
|
khscodes.services.nginx = {
|
||||||
|
enable = true;
|
||||||
|
# virtualHosts."mail.kaareskovgaard.net" = { };
|
||||||
|
};
|
||||||
|
khscodes.networking.fqdn = "mx.kaareskovgaard.net";
|
||||||
|
system.stateVersion = "25.05";
|
||||||
|
}
|
168
nix/systems/aarch64-linux/mx.kaareskovgaard.net/disko.nix
Normal file
168
nix/systems/aarch64-linux/mx.kaareskovgaard.net/disko.nix
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
{ pkgs, lib, ... }:
|
||||||
|
let
|
||||||
|
diskName = "nixos";
|
||||||
|
espSize = "500M";
|
||||||
|
bootPartName = "ESP";
|
||||||
|
rootPartName = "primary";
|
||||||
|
volumeGroupName = "mainpool";
|
||||||
|
rootLvName = "root";
|
||||||
|
zrootKey = "/run/secret/zroot.key";
|
||||||
|
zfsLoadKeyScript = pkgs.writeShellApplication {
|
||||||
|
name = "load-zfs-key";
|
||||||
|
runtimeInputs = [ pkgs.zfs ];
|
||||||
|
text = ''
|
||||||
|
if ! zfs load-key -L ${zrootKey} zroot; then
|
||||||
|
echo -n "tempkey" /tmp/tempkey
|
||||||
|
zfs load-key -L /temp/tempkey zroot
|
||||||
|
zfs change-key -o keylocation=${zrootKey} zroot
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
khscodes.services.vault-agent.templates = [
|
||||||
|
{
|
||||||
|
contents = ''
|
||||||
|
{{- with pkiCert "mx.kaareskovgaard.net/data/zroot_encryption" -}}
|
||||||
|
{{ .Data.data.key }}
|
||||||
|
{{- end -}}
|
||||||
|
'';
|
||||||
|
destination = zrootKey;
|
||||||
|
owner = "root";
|
||||||
|
group = "root";
|
||||||
|
perms = "0600";
|
||||||
|
exec = lib.getExe zfsLoadKeyScript;
|
||||||
|
restartUnits = [
|
||||||
|
"postfix.service"
|
||||||
|
"dovecot.service"
|
||||||
|
"rspamd.service"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
khscodes.infrastructure.provisioning.pre.modules = [
|
||||||
|
{
|
||||||
|
resource.random_password.zroot_encryption_key = {
|
||||||
|
length = 48;
|
||||||
|
numeric = true;
|
||||||
|
lower = true;
|
||||||
|
upper = true;
|
||||||
|
special = false;
|
||||||
|
};
|
||||||
|
resource.vault_kv_secret_v2.test = {
|
||||||
|
mount = "mx.kaareskovgaard.net";
|
||||||
|
name = "zroot_encryption";
|
||||||
|
data_json = ''
|
||||||
|
{
|
||||||
|
"key": ''${ jsonencode(resource.random_password.zroot_encryption_key.result) }
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
khscodes.infrastructure.vault-server-approle.policy = {
|
||||||
|
"mx.kaareskovgaard.net/data/zroot_encryption" = {
|
||||||
|
capabilities = [ "read" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
disko.devices.disk = {
|
||||||
|
"${diskName}" = {
|
||||||
|
device = "/dev/sda";
|
||||||
|
type = "disk";
|
||||||
|
content = {
|
||||||
|
type = "gpt";
|
||||||
|
partitions = {
|
||||||
|
"${bootPartName}" = {
|
||||||
|
size = espSize;
|
||||||
|
type = "EF00";
|
||||||
|
content = {
|
||||||
|
type = "filesystem";
|
||||||
|
format = "vfat";
|
||||||
|
mountpoint = "/boot";
|
||||||
|
mountOptions = [ "umask=0077" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
"${rootPartName}" = {
|
||||||
|
size = "100%";
|
||||||
|
content = {
|
||||||
|
type = "lvm_pv";
|
||||||
|
vg = volumeGroupName;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
zroot1 = {
|
||||||
|
device = "/dev/sdb";
|
||||||
|
type = "disk";
|
||||||
|
content = {
|
||||||
|
type = "gpt";
|
||||||
|
partitions = {
|
||||||
|
zfs = {
|
||||||
|
size = "100%";
|
||||||
|
content = {
|
||||||
|
type = "zfs";
|
||||||
|
pool = "zroot";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
devices.lvm_vg = {
|
||||||
|
"${volumeGroupName}" = {
|
||||||
|
type = "lvm_vg";
|
||||||
|
lvs = {
|
||||||
|
"${rootLvName}" = {
|
||||||
|
size = "100%";
|
||||||
|
content = {
|
||||||
|
type = "filesystem";
|
||||||
|
format = "ext4";
|
||||||
|
mountpoint = "/";
|
||||||
|
mountOptions = [ "defaults" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
zpool = {
|
||||||
|
zroot = {
|
||||||
|
type = "zpool";
|
||||||
|
rootFsOptions = {
|
||||||
|
mountpoint = "none";
|
||||||
|
compression = "zstd";
|
||||||
|
acltype = "posixacl";
|
||||||
|
xattr = "sa";
|
||||||
|
"com.sun:auto-snapshot" = "true";
|
||||||
|
};
|
||||||
|
options.ashift = "12";
|
||||||
|
datasets = {
|
||||||
|
"mailserver" = {
|
||||||
|
type = "zfs_fs";
|
||||||
|
options = {
|
||||||
|
encryption = "aes-256-gcm";
|
||||||
|
keyformat = "passphrase";
|
||||||
|
keylocation = "file:///tmp/tempkey";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
"mailserver/vmail" = {
|
||||||
|
type = "zfs_fs";
|
||||||
|
mountpoint = "/var/mailserver/vmail";
|
||||||
|
};
|
||||||
|
"mailserver/indices" = {
|
||||||
|
type = "zfs_fs";
|
||||||
|
mountpoint = "/var/mailserver/indices";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
mode = {
|
||||||
|
topology = {
|
||||||
|
type = "topology";
|
||||||
|
vdev = [
|
||||||
|
{
|
||||||
|
members = [ "zroot1" ];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,22 +1,11 @@
|
||||||
{
|
{
|
||||||
config,
|
config,
|
||||||
pkgs,
|
pkgs,
|
||||||
lib,
|
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
domain = "login.kaareskovgaard.net";
|
domain = "login.kaareskovgaard.net";
|
||||||
bootstrapping = config.khscodes."security.kaareskovgaard.net".bootstrap.enable;
|
bootstrapping = config.khscodes."security.kaareskovgaard.net".bootstrap.enable;
|
||||||
openbaoAppBasicSecretFile = "/run/kanidm/openbao_basic_secret";
|
|
||||||
openbaoCliAppBasicSecretFile = "/run/kanidm/openbao_cli_basic_secret";
|
|
||||||
monitoringAppBasicSecretFile = "/run/kanidm/monitoring_basic_secret";
|
|
||||||
forgejoAppBasicSecretFile = "/run/kanidm/forgejo_basic_secret";
|
|
||||||
secretFiles = [
|
|
||||||
openbaoAppBasicSecretFile
|
|
||||||
openbaoCliAppBasicSecretFile
|
|
||||||
monitoringAppBasicSecretFile
|
|
||||||
forgejoAppBasicSecretFile
|
|
||||||
];
|
|
||||||
openbaoDomain = config.khscodes.infrastructure.openbao.domain;
|
openbaoDomain = config.khscodes.infrastructure.openbao.domain;
|
||||||
openbaoAllowedRedirectUrls = [
|
openbaoAllowedRedirectUrls = [
|
||||||
"https://${openbaoDomain}/ui/vault/auth/kanidm/oidc/callback"
|
"https://${openbaoDomain}/ui/vault/auth/kanidm/oidc/callback"
|
||||||
|
@ -51,424 +40,285 @@ let
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
services.kanidm = {
|
imports = [ ./kanidm_application.nix ];
|
||||||
enableServer = true;
|
config = {
|
||||||
# Verify upgrade will be successful by running `kanidmd domain upgrade-check` before bumping package version.
|
khscodes.security.kanidm.applications = {
|
||||||
package = pkgs.kanidmWithSecretProvisioning_1_6;
|
openbao = {
|
||||||
serverSettings = {
|
allowedRedirectUris = openbaoAllowedRedirectUrls;
|
||||||
inherit domain;
|
landingUri = "https://${openbaoDomain}";
|
||||||
tls_chain = "${config.security.acme.certs.${domain}.directory}/fullchain.pem";
|
displayName = "OpenBAO";
|
||||||
tls_key = "${config.security.acme.certs.${domain}.directory}/key.pem";
|
scopeMaps = {
|
||||||
origin = "https://${domain}";
|
"openbao_admin" = [
|
||||||
trust_x_forward_for = true;
|
"profile"
|
||||||
};
|
"email"
|
||||||
provision = {
|
"openid"
|
||||||
enable = true;
|
];
|
||||||
idmAdminPasswordFile = null;
|
|
||||||
adminPasswordFile = null;
|
|
||||||
acceptInvalidCerts = true;
|
|
||||||
persons.khs = {
|
|
||||||
present = true;
|
|
||||||
mailAddresses = [
|
|
||||||
"kaare@kaareskovgaard.net"
|
|
||||||
"kaare@agerlin-skovgaard.dk"
|
|
||||||
"kaare@agerlinskovgaard.dk"
|
|
||||||
];
|
|
||||||
legalName = "Kaare Skovgaard";
|
|
||||||
displayName = "khs";
|
|
||||||
};
|
|
||||||
groups.openbao_admin = {
|
|
||||||
present = true;
|
|
||||||
members = [ "khs" ];
|
|
||||||
};
|
|
||||||
groups.forgejo_user = {
|
|
||||||
present = true;
|
|
||||||
members = [ "khs" ];
|
|
||||||
};
|
|
||||||
groups.forgejo_comitter = {
|
|
||||||
present = true;
|
|
||||||
members = [ "khs" ];
|
|
||||||
};
|
|
||||||
groups.forgejo_admin = {
|
|
||||||
present = true;
|
|
||||||
members = [ "khs" ];
|
|
||||||
};
|
|
||||||
# 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 = lib.mkIf (!bootstrapping) openbaoAppBasicSecretFile;
|
|
||||||
originUrl = openbaoAllowedRedirectUrls;
|
|
||||||
originLanding = "https://${openbaoDomain}";
|
|
||||||
displayName = "OpenBAO";
|
|
||||||
scopeMaps = {
|
|
||||||
"openbao_admin" = [
|
|
||||||
"profile"
|
|
||||||
"email"
|
|
||||||
"openid"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
claimMaps.groups = {
|
|
||||||
joinType = "array";
|
|
||||||
valuesByGroup = {
|
|
||||||
"openbao_admin" = [
|
|
||||||
"openbao_writer"
|
|
||||||
"openbao_cli_writer"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
openbao-cli = {
|
claimMaps.groups = {
|
||||||
present = true;
|
joinType = "array";
|
||||||
public = false;
|
valuesByGroup = {
|
||||||
preferShortUsername = true;
|
|
||||||
basicSecretFile = lib.mkIf (!bootstrapping) openbaoCliAppBasicSecretFile;
|
|
||||||
originUrl = [ "http://localhost:8250/oidc/callback" ];
|
|
||||||
originLanding = "http://localhost:8250";
|
|
||||||
displayName = "OpenBAO CLI";
|
|
||||||
scopeMaps = {
|
|
||||||
"openbao_admin" = [
|
"openbao_admin" = [
|
||||||
"profile"
|
"openbao_writer"
|
||||||
"email"
|
"openbao_cli_writer"
|
||||||
"openid"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
claimMaps.groups = {
|
|
||||||
joinType = "array";
|
|
||||||
valuesByGroup = {
|
|
||||||
"openbao_admin" = [
|
|
||||||
"openbao_writer"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
monitoring = {
|
|
||||||
present = true;
|
|
||||||
public = false;
|
|
||||||
preferShortUsername = true;
|
|
||||||
basicSecretFile = lib.mkIf (!bootstrapping) monitoringAppBasicSecretFile;
|
|
||||||
originUrl = [ "https://monitoring.kaareskovgaard.net/login/generic_oauth" ];
|
|
||||||
originLanding = "http://monitoring.kaareskovgaard.net";
|
|
||||||
displayName = "Monitoring";
|
|
||||||
scopeMaps = {
|
|
||||||
"openbao_admin" = [
|
|
||||||
"profile"
|
|
||||||
"email"
|
|
||||||
"openid"
|
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
forgejo = {
|
};
|
||||||
present = true;
|
openbao-cli = {
|
||||||
public = false;
|
terranixName = "openbao_cli";
|
||||||
preferShortUsername = true;
|
allowedRedirectUris = [ "http://localhost:8250/oidc/callback" ];
|
||||||
basicSecretFile = lib.mkIf (!bootstrapping) forgejoAppBasicSecretFile;
|
landingUri = "http://localhost:8250";
|
||||||
originUrl = [ "https://kas.codes/user/oauth2/Kanidm/callback" ];
|
displayName = "OpenBAO CLI";
|
||||||
originLanding = "http://kas.codes";
|
scopeMaps = {
|
||||||
displayName = "KAS: Codes";
|
"openbao_admin" = [
|
||||||
scopeMaps = {
|
"profile"
|
||||||
"forgejo_user" = [
|
"email"
|
||||||
"profile"
|
"openid"
|
||||||
"email"
|
];
|
||||||
"openid"
|
};
|
||||||
|
claimMaps.groups = {
|
||||||
|
joinType = "array";
|
||||||
|
valuesByGroup = {
|
||||||
|
"openbao_admin" = [
|
||||||
|
"openbao_writer"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
claimMaps.groups = {
|
};
|
||||||
joinType = "array";
|
};
|
||||||
valuesByGroup = {
|
monitoring = {
|
||||||
"forgejo_comitter" = [
|
allowedRedirectUris = [ "https://monitoring.kaareskovgaard.net/login/generic_oauth" ];
|
||||||
"comitter"
|
landingUri = "http://monitoring.kaareskovgaard.net";
|
||||||
];
|
displayName = "Monitoring";
|
||||||
"forgejo_admin" = [
|
scopeMaps = {
|
||||||
"admin"
|
"openbao_admin" = [
|
||||||
];
|
"profile"
|
||||||
};
|
"email"
|
||||||
|
"openid"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
forgejo = {
|
||||||
|
allowedRedirectUris = [ "https://kas.codes/user/oauth2/Kanidm/callback" ];
|
||||||
|
landingUri = "http://kas.codes";
|
||||||
|
displayName = "KAS: Codes";
|
||||||
|
scopeMaps = {
|
||||||
|
"forgejo_user" = [
|
||||||
|
"profile"
|
||||||
|
"email"
|
||||||
|
"openid"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
claimMaps.groups = {
|
||||||
|
joinType = "array";
|
||||||
|
valuesByGroup = {
|
||||||
|
"forgejo_comitter" = [
|
||||||
|
"comitter"
|
||||||
|
];
|
||||||
|
"forgejo_admin" = [
|
||||||
|
"admin"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
services.kanidm = {
|
||||||
# Don't add dependencies from bootstrapping when not bootstrapping.
|
enableServer = true;
|
||||||
systemd.services.kanidm = lib.mkIf (!bootstrapping) {
|
# Verify upgrade will be successful by running `kanidmd domain upgrade-check` before bumping package version.
|
||||||
unitConfig = {
|
package = pkgs.kanidmWithSecretProvisioning_1_6;
|
||||||
ConditionPathExists = secretFiles;
|
serverSettings = {
|
||||||
|
inherit domain;
|
||||||
|
tls_chain = "${config.security.acme.certs.${domain}.directory}/fullchain.pem";
|
||||||
|
tls_key = "${config.security.acme.certs.${domain}.directory}/key.pem";
|
||||||
|
origin = "https://${domain}";
|
||||||
|
trust_x_forward_for = true;
|
||||||
|
};
|
||||||
|
provision = {
|
||||||
|
enable = true;
|
||||||
|
idmAdminPasswordFile = null;
|
||||||
|
adminPasswordFile = null;
|
||||||
|
acceptInvalidCerts = true;
|
||||||
|
persons.khs = {
|
||||||
|
present = true;
|
||||||
|
mailAddresses = [
|
||||||
|
"kaare@kaareskovgaard.net"
|
||||||
|
"kaare@agerlin-skovgaard.dk"
|
||||||
|
"kaare@agerlinskovgaard.dk"
|
||||||
|
];
|
||||||
|
legalName = "Kaare Skovgaard";
|
||||||
|
displayName = "khs";
|
||||||
|
};
|
||||||
|
groups.openbao_admin = {
|
||||||
|
present = true;
|
||||||
|
members = [ "khs" ];
|
||||||
|
};
|
||||||
|
groups.forgejo_user = {
|
||||||
|
present = true;
|
||||||
|
members = [ "khs" ];
|
||||||
|
};
|
||||||
|
groups.forgejo_comitter = {
|
||||||
|
present = true;
|
||||||
|
members = [ "khs" ];
|
||||||
|
};
|
||||||
|
groups.forgejo_admin = {
|
||||||
|
present = true;
|
||||||
|
members = [ "khs" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
# Allow the server to read the secrets for its own apps
|
khscodes.infrastructure.provisioning.post.modules = [
|
||||||
khscodes.infrastructure.vault-server-approle.policy."kanidm/data/apps/*" = {
|
(
|
||||||
capabilities = [ "read" ];
|
{ ... }:
|
||||||
};
|
|
||||||
|
|
||||||
khscodes.infrastructure.provisioning.post.modules = [
|
|
||||||
# Creates mount for kanidm apps and generates random passwords for the apps
|
|
||||||
(
|
|
||||||
{ config, ... }:
|
|
||||||
{
|
|
||||||
terraform.required_providers.random = {
|
|
||||||
source = "hashicorp/random";
|
|
||||||
version = "3.7.2";
|
|
||||||
};
|
|
||||||
provider.random = { };
|
|
||||||
# NOTE: This gets stored in the state file
|
|
||||||
resource.random_password.openbao_secret = {
|
|
||||||
length = 48;
|
|
||||||
numeric = true;
|
|
||||||
lower = true;
|
|
||||||
upper = true;
|
|
||||||
special = false;
|
|
||||||
};
|
|
||||||
khscodes.vault = {
|
|
||||||
enable = true;
|
|
||||||
mount.kanidm = {
|
|
||||||
path = "kanidm";
|
|
||||||
type = "kv";
|
|
||||||
options = {
|
|
||||||
version = "2";
|
|
||||||
};
|
|
||||||
description = "Secrets used for kanidm";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
resource.vault_kv_secret_v2.openbao_secret = {
|
|
||||||
mount = config.khscodes.vault.output.mount.kanidm.path;
|
|
||||||
name = "apps/openbao";
|
|
||||||
data_json = ''
|
|
||||||
{ "basic_secret": "''${ resource.random_password.openbao_secret.result }" }
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
resource.random_password.openbao_cli_secret = {
|
|
||||||
length = 48;
|
|
||||||
numeric = true;
|
|
||||||
lower = true;
|
|
||||||
upper = true;
|
|
||||||
special = false;
|
|
||||||
};
|
|
||||||
resource.vault_kv_secret_v2.openbao_cli_secret = {
|
|
||||||
mount = config.khscodes.vault.output.mount.kanidm.path;
|
|
||||||
name = "apps/openbao_cli";
|
|
||||||
data_json = ''
|
|
||||||
{ "basic_secret": "''${ resource.random_password.openbao_cli_secret.result }" }
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
resource.random_password.monitoring = {
|
|
||||||
length = 48;
|
|
||||||
numeric = true;
|
|
||||||
lower = true;
|
|
||||||
upper = true;
|
|
||||||
special = false;
|
|
||||||
};
|
|
||||||
resource.vault_kv_secret_v2.monitoring_secret = {
|
|
||||||
mount = config.khscodes.vault.output.mount.kanidm.path;
|
|
||||||
name = "apps/monitoring";
|
|
||||||
data_json = ''
|
|
||||||
{ "basic_secret": "''${ resource.random_password.monitoring.result }" }
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
resource.random_password.forgejo = {
|
|
||||||
length = 48;
|
|
||||||
numeric = true;
|
|
||||||
lower = true;
|
|
||||||
upper = true;
|
|
||||||
special = false;
|
|
||||||
};
|
|
||||||
resource.vault_kv_secret_v2.forgejo_secret = {
|
|
||||||
mount = config.khscodes.vault.output.mount.kanidm.path;
|
|
||||||
name = "apps/forgejo";
|
|
||||||
data_json = ''
|
|
||||||
{ "basic_secret": "''${ resource.random_password.forgejo.result }" }
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
}
|
|
||||||
)
|
|
||||||
# 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.kanidm_cli = {
|
khscodes.vault = {
|
||||||
description = "Kanidm cli auth backend";
|
enable = true;
|
||||||
path = "oidc";
|
mount.kanidm = {
|
||||||
type = "oidc";
|
path = "kanidm";
|
||||||
oidc_discovery_url = "https://${domain}/oauth2/openid/openbao-cli";
|
type = "kv";
|
||||||
oidc_client_id = "openbao-cli";
|
options = {
|
||||||
oidc_client_secret = "\${ resource.random_password.openbao_cli_secret.result }";
|
version = "2";
|
||||||
default_role = "kanidm_cli_writer";
|
};
|
||||||
jwt_supported_algs = [
|
description = "Secrets used for kanidm";
|
||||||
"ES256"
|
};
|
||||||
];
|
|
||||||
tune = [
|
|
||||||
{
|
|
||||||
listing_visibility = "hidden";
|
|
||||||
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.kanidm = {
|
|
||||||
description = "Kanidm auth backend";
|
|
||||||
path = "kanidm";
|
|
||||||
type = "oidc";
|
|
||||||
oidc_discovery_url = "https://${domain}/oauth2/openid/openbao";
|
|
||||||
oidc_client_id = "openbao";
|
|
||||||
oidc_client_secret = "\${ resource.random_password.openbao_secret.result }";
|
|
||||||
default_role = "kanidm_writer";
|
|
||||||
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.kanidm_cli_writer = {
|
|
||||||
backend = "\${ resource.vault_jwt_auth_backend.kanidm_cli.path }";
|
|
||||||
role_name = "kanidm_cli_writer";
|
|
||||||
bound_audiences = [ "openbao-cli" ];
|
|
||||||
allowed_redirect_uris = [ "http://localhost:8250/oidc/callback" ];
|
|
||||||
user_claim = "sub";
|
|
||||||
token_policies = [ "writer" ];
|
|
||||||
groups_claim = "groups";
|
|
||||||
oidc_scopes = [
|
|
||||||
"openid"
|
|
||||||
"profile"
|
|
||||||
"email"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
resource.vault_jwt_auth_backend_role.kanidm_writer = {
|
|
||||||
backend = "\${ resource.vault_jwt_auth_backend.kanidm.path }";
|
|
||||||
role_name = "kanidm_writer";
|
|
||||||
bound_audiences = [ "openbao" ];
|
|
||||||
allowed_redirect_uris = openbaoAllowedRedirectUrls;
|
|
||||||
user_claim = "sub";
|
|
||||||
token_policies = [ "writer" ];
|
|
||||||
groups_claim = "groups";
|
|
||||||
oidc_scopes = [
|
|
||||||
"openid"
|
|
||||||
"profile"
|
|
||||||
"email"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
resource.vault_identity_group.kanidm_writer = {
|
|
||||||
name = "kanidm_writer";
|
|
||||||
policies = [ "writer" ];
|
|
||||||
type = "external";
|
|
||||||
};
|
|
||||||
|
|
||||||
resource.vault_identity_group.kanidm_cli_writer = {
|
|
||||||
name = "kanidm_cli_writer";
|
|
||||||
policies = [ "writer" ];
|
|
||||||
type = "external";
|
|
||||||
};
|
|
||||||
|
|
||||||
resource.vault_identity_group_alias.oidc_writer = {
|
|
||||||
name = "openbao_cli_writer";
|
|
||||||
mount_accessor = "\${ vault_jwt_auth_backend.kanidm_cli.accessor }";
|
|
||||||
canonical_id = "\${ vault_identity_group.kanidm_cli_writer.id }";
|
|
||||||
};
|
|
||||||
|
|
||||||
resource.vault_identity_group_alias.kanidm_writer = {
|
|
||||||
name = "openbao_writer";
|
|
||||||
mount_accessor = "\${ vault_jwt_auth_backend.kanidm.accessor }";
|
|
||||||
canonical_id = "\${ vault_identity_group.kanidm_writer.id }";
|
|
||||||
};
|
|
||||||
|
|
||||||
resource.vault_policy.writer = {
|
|
||||||
name = "writer";
|
|
||||||
|
|
||||||
policy = ''
|
|
||||||
path "*" {
|
|
||||||
capabilities = ["create", "update", "patch", "read", "delete", "list"]
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
];
|
# 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.kanidm_cli = {
|
||||||
|
description = "Kanidm cli auth backend";
|
||||||
|
path = "oidc";
|
||||||
|
type = "oidc";
|
||||||
|
oidc_discovery_url = "https://${domain}/oauth2/openid/openbao-cli";
|
||||||
|
oidc_client_id = "openbao-cli";
|
||||||
|
oidc_client_secret = "\${ resource.random_password.openbao_cli_secret.result }";
|
||||||
|
default_role = "kanidm_cli_writer";
|
||||||
|
jwt_supported_algs = [
|
||||||
|
"ES256"
|
||||||
|
];
|
||||||
|
tune = [
|
||||||
|
{
|
||||||
|
listing_visibility = "hidden";
|
||||||
|
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.kanidm = {
|
||||||
|
description = "Kanidm auth backend";
|
||||||
|
path = "kanidm";
|
||||||
|
type = "oidc";
|
||||||
|
oidc_discovery_url = "https://${domain}/oauth2/openid/openbao";
|
||||||
|
oidc_client_id = "openbao";
|
||||||
|
oidc_client_secret = "\${ resource.random_password.openbao_secret.result }";
|
||||||
|
default_role = "kanidm_writer";
|
||||||
|
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 = [ ];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
khscodes.services.vault-agent.templates = [
|
resource.vault_jwt_auth_backend_role.kanidm_cli_writer = {
|
||||||
{
|
backend = "\${ resource.vault_jwt_auth_backend.kanidm_cli.path }";
|
||||||
contents = ''
|
role_name = "kanidm_cli_writer";
|
||||||
{{- with secret "kanidm/data/apps/openbao" -}}
|
bound_audiences = [ "openbao-cli" ];
|
||||||
{{ .Data.data.basic_secret }}
|
allowed_redirect_uris = [ "http://localhost:8250/oidc/callback" ];
|
||||||
{{- end -}}
|
user_claim = "sub";
|
||||||
'';
|
token_policies = [ "writer" ];
|
||||||
destination = openbaoAppBasicSecretFile;
|
groups_claim = "groups";
|
||||||
perms = "0600";
|
oidc_scopes = [
|
||||||
owner = "kanidm";
|
"openid"
|
||||||
group = "kanidm";
|
"profile"
|
||||||
reloadOrRestartUnits = [ "kanidm.service" ];
|
"email"
|
||||||
}
|
];
|
||||||
{
|
};
|
||||||
contents = ''
|
|
||||||
{{- with secret "kanidm/data/apps/openbao_cli" -}}
|
|
||||||
{{ .Data.data.basic_secret }}
|
|
||||||
{{- end -}}
|
|
||||||
'';
|
|
||||||
destination = openbaoCliAppBasicSecretFile;
|
|
||||||
perms = "0600";
|
|
||||||
owner = "kanidm";
|
|
||||||
group = "kanidm";
|
|
||||||
reloadOrRestartUnits = [ "kanidm.service" ];
|
|
||||||
}
|
|
||||||
{
|
|
||||||
contents = ''
|
|
||||||
{{- with secret "kanidm/data/apps/monitoring" -}}
|
|
||||||
{{ .Data.data.basic_secret }}
|
|
||||||
{{- end -}}
|
|
||||||
'';
|
|
||||||
destination = monitoringAppBasicSecretFile;
|
|
||||||
perms = "0600";
|
|
||||||
owner = "kanidm";
|
|
||||||
group = "kanidm";
|
|
||||||
reloadOrRestartUnits = [ "kanidm.service" ];
|
|
||||||
}
|
|
||||||
{
|
|
||||||
contents = ''
|
|
||||||
{{- with secret "kanidm/data/apps/forgejo" -}}
|
|
||||||
{{ .Data.data.basic_secret }}
|
|
||||||
{{- end -}}
|
|
||||||
'';
|
|
||||||
destination = forgejoAppBasicSecretFile;
|
|
||||||
perms = "0600";
|
|
||||||
owner = "kanidm";
|
|
||||||
group = "kanidm";
|
|
||||||
reloadOrRestartUnits = [ "kanidm.service" ];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
security.acme.certs.${domain}.reloadServices = [ "kanidm.service" ];
|
resource.vault_jwt_auth_backend_role.kanidm_writer = {
|
||||||
# Allow kanidm to read the certificate file
|
backend = "\${ resource.vault_jwt_auth_backend.kanidm.path }";
|
||||||
users.groups.nginx.members = [ "kanidm" ];
|
role_name = "kanidm_writer";
|
||||||
|
bound_audiences = [ "openbao" ];
|
||||||
|
allowed_redirect_uris = openbaoAllowedRedirectUrls;
|
||||||
|
user_claim = "sub";
|
||||||
|
token_policies = [ "writer" ];
|
||||||
|
groups_claim = "groups";
|
||||||
|
oidc_scopes = [
|
||||||
|
"openid"
|
||||||
|
"profile"
|
||||||
|
"email"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
khscodes.services.nginx.virtualHosts.${domain} = {
|
resource.vault_identity_group.kanidm_writer = {
|
||||||
locations."/" = {
|
name = "kanidm_writer";
|
||||||
proxyPass = "https://${config.services.kanidm.serverSettings.bindaddress}/";
|
policies = [ "writer" ];
|
||||||
recommendedProxySettings = true;
|
type = "external";
|
||||||
|
};
|
||||||
|
|
||||||
|
resource.vault_identity_group.kanidm_cli_writer = {
|
||||||
|
name = "kanidm_cli_writer";
|
||||||
|
policies = [ "writer" ];
|
||||||
|
type = "external";
|
||||||
|
};
|
||||||
|
|
||||||
|
resource.vault_identity_group_alias.oidc_writer = {
|
||||||
|
name = "openbao_cli_writer";
|
||||||
|
mount_accessor = "\${ vault_jwt_auth_backend.kanidm_cli.accessor }";
|
||||||
|
canonical_id = "\${ vault_identity_group.kanidm_cli_writer.id }";
|
||||||
|
};
|
||||||
|
|
||||||
|
resource.vault_identity_group_alias.kanidm_writer = {
|
||||||
|
name = "openbao_writer";
|
||||||
|
mount_accessor = "\${ vault_jwt_auth_backend.kanidm.accessor }";
|
||||||
|
canonical_id = "\${ vault_identity_group.kanidm_writer.id }";
|
||||||
|
};
|
||||||
|
|
||||||
|
resource.vault_policy.writer = {
|
||||||
|
name = "writer";
|
||||||
|
|
||||||
|
policy = ''
|
||||||
|
path "*" {
|
||||||
|
capabilities = ["create", "update", "patch", "read", "delete", "list"]
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
];
|
||||||
|
security.acme.certs.${domain}.reloadServices = [ "kanidm.service" ];
|
||||||
|
# Allow kanidm to read the certificate file
|
||||||
|
users.groups.nginx.members = [ "kanidm" ];
|
||||||
|
|
||||||
|
khscodes.services.nginx.virtualHosts.${domain} = {
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "https://${config.services.kanidm.serverSettings.bindaddress}/";
|
||||||
|
recommendedProxySettings = true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
environment.systemPackages = [
|
environment.systemPackages = [
|
||||||
kanidm-reset-password
|
kanidm-reset-password
|
||||||
];
|
];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
cfg = config.khscodes.security.kanidm;
|
||||||
|
secretFileForApplication = key: "/run/kanidm/${key}_secret";
|
||||||
|
secretFiles = lib.attrsets.mapAttrsToList (
|
||||||
|
key: value: secretFileForApplication key
|
||||||
|
) cfg.applications;
|
||||||
|
vaultAgentTemplates = lib.attrsets.mapAttrsToList (key: value: {
|
||||||
|
contents = ''
|
||||||
|
{{- with secret "kanidm/data/apps/${key}" -}}
|
||||||
|
{{ .Data.data.basic_secret }}
|
||||||
|
{{- end -}}
|
||||||
|
'';
|
||||||
|
destination = secretFileForApplication key;
|
||||||
|
perms = "0600";
|
||||||
|
owner = "kanidm";
|
||||||
|
group = "kanidm";
|
||||||
|
reloadOrRestartUnits = [ "kanidm.service" ];
|
||||||
|
}) cfg.applications;
|
||||||
|
terranixModules = lib.attrsets.mapAttrsToList (
|
||||||
|
key: value:
|
||||||
|
{ config, ... }:
|
||||||
|
let
|
||||||
|
sanitizedKey = lib.khscodes.sanitize-terraform-name (
|
||||||
|
if value.terranixName == null then key else value.terranixName
|
||||||
|
);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
resource.random_password."${sanitizedKey}_secret" = {
|
||||||
|
length = 48;
|
||||||
|
numeric = true;
|
||||||
|
lower = true;
|
||||||
|
upper = true;
|
||||||
|
special = false;
|
||||||
|
};
|
||||||
|
resource.vault_kv_secret_v2."${sanitizedKey}_secret" = {
|
||||||
|
mount = config.khscodes.vault.output.mount.kanidm.path;
|
||||||
|
name = "apps/${key}";
|
||||||
|
data_json = ''
|
||||||
|
{ "basic_secret": "''${ resource.random_password.${sanitizedKey}_secret.result }" }
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
) cfg.applications;
|
||||||
|
systemsOauth2 = lib.attrsets.mapAttrs (key: value: {
|
||||||
|
inherit (value) scopeMaps claimMaps;
|
||||||
|
present = true;
|
||||||
|
public = false;
|
||||||
|
preferShortUsername = true;
|
||||||
|
basicSecretFile = lib.mkIf (!bootstrapping) (secretFileForApplication key);
|
||||||
|
originUrl = value.allowedRedirectUris;
|
||||||
|
originLanding = value.landingUri;
|
||||||
|
displayName = value.displayName;
|
||||||
|
}) cfg.applications;
|
||||||
|
kanidmApplication = lib.khscodes.mkSubmodule {
|
||||||
|
description = "Kanidm application";
|
||||||
|
options = {
|
||||||
|
terranixName = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.str;
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
displayName = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
};
|
||||||
|
scopeMaps = lib.mkOption {
|
||||||
|
type = lib.types.attrsOf (lib.types.listOf lib.types.str);
|
||||||
|
};
|
||||||
|
allowedRedirectUris = lib.mkOption {
|
||||||
|
type = lib.types.listOf lib.types.str;
|
||||||
|
};
|
||||||
|
landingUri = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
};
|
||||||
|
claimMaps = lib.mkOption {
|
||||||
|
type = lib.types.anything;
|
||||||
|
default = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
bootstrapping = config.khscodes."security.kaareskovgaard.net".bootstrap.enable;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.khscodes.security.kanidm.applications = lib.mkOption {
|
||||||
|
type = lib.types.attrsOf kanidmApplication;
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
# Allow the server to read the secrets for its own apps
|
||||||
|
khscodes.infrastructure.vault-server-approle.policy."kanidm/data/apps/*" = {
|
||||||
|
capabilities = [ "read" ];
|
||||||
|
};
|
||||||
|
# Don't add dependencies from bootstrapping when not bootstrapping.
|
||||||
|
systemd.services.kanidm = lib.mkIf (!bootstrapping) {
|
||||||
|
unitConfig = {
|
||||||
|
ConditionPathExists = secretFiles;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
khscodes.services.vault-agent.templates = vaultAgentTemplates;
|
||||||
|
khscodes.infrastructure.provisioning.post.modules = terranixModules ++ [
|
||||||
|
{
|
||||||
|
terraform.required_providers.random = {
|
||||||
|
source = "hashicorp/random";
|
||||||
|
version = "3.7.2";
|
||||||
|
};
|
||||||
|
provider.random = { };
|
||||||
|
}
|
||||||
|
];
|
||||||
|
# We cannot add oauth2 apps before the secrets for them are generated.
|
||||||
|
services.kanidm.provision.systems.oauth2 = lib.mkIf (!bootstrapping) systemsOauth2;
|
||||||
|
};
|
||||||
|
}
|
|
@ -42,6 +42,9 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
khscodes.services.nginx.virtualHosts.${domain} = {
|
khscodes.services.nginx.virtualHosts.${domain} = {
|
||||||
|
rateLimit = {
|
||||||
|
burst = 100;
|
||||||
|
};
|
||||||
locations."/" = {
|
locations."/" = {
|
||||||
proxyPass = "https://${config.services.openbao.settings.listener.tcp.address}/";
|
proxyPass = "https://${config.services.openbao.settings.listener.tcp.address}/";
|
||||||
recommendedProxySettings = true;
|
recommendedProxySettings = true;
|
||||||
|
|
|
@ -52,7 +52,7 @@ in
|
||||||
token_url = "https://login.kaareskovgaard.net/oauth2/token";
|
token_url = "https://login.kaareskovgaard.net/oauth2/token";
|
||||||
api_url = "https://login.kaareskovgaard.net/oauth2/openid/monitoring/userinfo";
|
api_url = "https://login.kaareskovgaard.net/oauth2/openid/monitoring/userinfo";
|
||||||
client_id = "monitoring";
|
client_id = "monitoring";
|
||||||
client_secret = "$__file{/var/lib/vault-agent/grafana/kanidm_client_secret}";
|
client_secret = "$__file{${config.khscodes.infrastructure.kanidm-client-application.secretFile}}";
|
||||||
scopes = "openid profile email";
|
scopes = "openid profile email";
|
||||||
use_pkce = true;
|
use_pkce = true;
|
||||||
skip_org_role_sync = false;
|
skip_org_role_sync = false;
|
||||||
|
@ -252,23 +252,12 @@ in
|
||||||
perms = "0644";
|
perms = "0644";
|
||||||
reloadOrRestartUnits = [ "nginx.service" ];
|
reloadOrRestartUnits = [ "nginx.service" ];
|
||||||
}
|
}
|
||||||
{
|
|
||||||
contents = ''
|
|
||||||
{{- with secret "kanidm/data/apps/monitoring" -}}
|
|
||||||
{{ .Data.data.basic_secret }}
|
|
||||||
{{- end -}}
|
|
||||||
'';
|
|
||||||
destination = "/var/lib/vault-agent/grafana/kanidm_client_secret";
|
|
||||||
owner = "grafana";
|
|
||||||
group = "grafana";
|
|
||||||
perms = "0600";
|
|
||||||
reloadOrRestartUnits = [ "grafana.service" ];
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
infrastructure.vault-server-approle.policy = {
|
infrastructure.kanidm-client-application = {
|
||||||
"kanidm/data/apps/monitoring" = {
|
enable = true;
|
||||||
capabilities = [ "read" ];
|
appName = "monitoring";
|
||||||
};
|
secretOwner = "grafana";
|
||||||
|
reloadOrRestartUnits = [ "grafana.service" ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
khscodes.networking.fqdn = "monitoring.kaareskovgaard.net";
|
khscodes.networking.fqdn = "monitoring.kaareskovgaard.net";
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue