1
1
Fork 1
mirror of https://github.com/oddlama/nix-config.git synced 2025-10-10 14:50:40 +02:00
oddlama_nix-config/hosts/ward/guests/kanidm.nix

263 lines
8.4 KiB
Nix

{
config,
globals,
pkgs,
...
}:
let
kanidmDomain = "auth.${globals.domains.me}";
kanidmPort = 8300;
mkRandomSecret = {
generator.script = "alnum";
mode = "440";
group = "kanidm";
};
in
{
globals.wireguard.proxy-sentinel.hosts.${config.node.name}.firewallRuleForNode.sentinel.allowedTCPPorts =
[ kanidmPort ];
age.secrets."kanidm-self-signed.crt" = {
rekeyFile = config.node.secretsDir + "/kanidm-self-signed.crt.age";
mode = "440";
group = "kanidm";
};
age.secrets."kanidm-self-signed.key" = {
rekeyFile = config.node.secretsDir + "/kanidm-self-signed.key.age";
mode = "440";
group = "kanidm";
};
age.secrets.kanidm-admin-password = mkRandomSecret;
age.secrets.kanidm-idm-admin-password = mkRandomSecret;
age.secrets.kanidm-oauth2-forgejo = mkRandomSecret;
age.secrets.kanidm-oauth2-grafana = mkRandomSecret;
age.secrets.kanidm-oauth2-immich = mkRandomSecret;
age.secrets.kanidm-oauth2-firezone = mkRandomSecret;
age.secrets.kanidm-oauth2-mealie = mkRandomSecret;
age.secrets.kanidm-oauth2-paperless = mkRandomSecret;
age.secrets.kanidm-oauth2-web-sentinel = mkRandomSecret;
globals.services.kanidm.domain = kanidmDomain;
globals.monitoring.http.kanidm = {
url = "https://${kanidmDomain}/status";
network = "internet";
expectedBodyRegex = "true";
skipTlsVerification = true;
};
nodes.sentinel = {
services.nginx = {
upstreams.kanidm = {
servers."${
globals.wireguard.proxy-sentinel.hosts.${config.node.name}.ipv4
}:${toString kanidmPort}" =
{ };
extraConfig = ''
zone kanidm 64k;
keepalive 2;
'';
monitoring = {
enable = true;
path = "/status";
expectedBodyRegex = "true";
skipTlsVerification = true;
useHttps = true;
};
};
virtualHosts.${kanidmDomain} = {
forceSSL = true;
useACMEWildcardHost = true;
locations."/".proxyPass = "https://kanidm";
# Allow using self-signed certs to satisfy kanidm's requirement
# for TLS connections. (Although this is over wireguard anyway)
extraConfig = ''
proxy_ssl_verify off;
'';
};
};
};
environment.persistence."/persist".directories = [
{
directory = "/var/lib/kanidm";
user = "kanidm";
group = "kanidm";
mode = "0700";
}
];
services.kanidm = {
package = pkgs.kanidm.withSecretProvisioning;
enableServer = true;
serverSettings = {
domain = kanidmDomain;
origin = "https://${kanidmDomain}";
tls_chain = config.age.secrets."kanidm-self-signed.crt".path;
tls_key = config.age.secrets."kanidm-self-signed.key".path;
bindaddress = "0.0.0.0:${toString kanidmPort}";
trust_x_forward_for = true;
};
enableClient = true;
clientSettings = {
uri = config.services.kanidm.serverSettings.origin;
verify_ca = true;
verify_hostnames = true;
};
provision = {
enable = true;
adminPasswordFile = config.age.secrets.kanidm-admin-password.path;
idmAdminPasswordFile = config.age.secrets.kanidm-idm-admin-password.path;
inherit (globals.kanidm) persons;
# Immich
groups."immich.access" = { };
systems.oauth2.immich = {
displayName = "Immich";
originUrl = [
"https://${globals.services.immich.domain}/auth/login"
"https://${globals.services.immich.domain}/api/oauth/mobile-redirect"
];
originLanding = "https://${globals.services.immich.domain}/";
basicSecretFile = config.age.secrets.kanidm-oauth2-immich.path;
preferShortUsername = true;
scopeMaps."immich.access" = [
"openid"
"email"
"profile"
];
};
# Firezone
groups."firezone.access" = { };
systems.oauth2.firezone = {
displayName = "Firezone VPN";
# NOTE: state: both uuids are runtime values
originUrl = [
"https://${globals.services.firezone.domain}/50e16678-6e95-49e2-b59e-d70d0e658843/sign_in/providers/fc8afaa3-ce60-4073-9cae-81dec9453a2d/handle_callback"
"https://${globals.services.firezone.domain}/50e16678-6e95-49e2-b59e-d70d0e658843/settings/identity_providers/openid_connect/fc8afaa3-ce60-4073-9cae-81dec9453a2d/handle_callback"
];
originLanding = "https://${globals.services.firezone.domain}/";
basicSecretFile = config.age.secrets.kanidm-oauth2-firezone.path;
preferShortUsername = true;
scopeMaps."firezone.access" = [
"openid"
"email"
"profile"
];
};
# Mealie
groups."mealie.access" = { };
groups."mealie.admins" = { };
systems.oauth2.mealie = {
displayName = "Mealie";
originUrl = "https://${globals.services.mealie.domain}/login";
originLanding = "https://${globals.services.mealie.domain}/";
basicSecretFile = config.age.secrets.kanidm-oauth2-mealie.path;
preferShortUsername = true;
scopeMaps."mealie.access" = [
"openid"
"email"
"profile"
"groups"
];
};
# Paperless
groups."paperless.access" = { };
systems.oauth2.paperless = {
displayName = "Paperless";
originUrl = "https://${globals.services.paperless.domain}/accounts/oidc/kanidm/login/callback/";
originLanding = "https://${globals.services.paperless.domain}/";
basicSecretFile = config.age.secrets.kanidm-oauth2-paperless.path;
preferShortUsername = true;
scopeMaps."paperless.access" = [
"openid"
"email"
"profile"
];
};
# Grafana
groups."grafana.access" = { };
groups."grafana.editors" = { };
groups."grafana.admins" = { };
groups."grafana.server-admins" = { };
systems.oauth2.grafana = {
displayName = "Grafana";
originUrl = "https://${globals.services.grafana.domain}/login/generic_oauth";
originLanding = "https://${globals.services.grafana.domain}/";
basicSecretFile = config.age.secrets.kanidm-oauth2-grafana.path;
preferShortUsername = true;
scopeMaps."grafana.access" = [
"openid"
"email"
"profile"
];
claimMaps.groups = {
joinType = "array";
valuesByGroup = {
"grafana.editors" = [ "editor" ];
"grafana.admins" = [ "admin" ];
"grafana.server-admins" = [ "server_admin" ];
};
};
};
# Forgejo
groups."forgejo.access" = { };
groups."forgejo.admins" = { };
systems.oauth2.forgejo = {
displayName = "Forgejo";
originUrl = "https://${globals.services.forgejo.domain}/user/oauth2/kanidm/callback";
originLanding = "https://${globals.services.forgejo.domain}/";
basicSecretFile = config.age.secrets.kanidm-oauth2-forgejo.path;
scopeMaps."forgejo.access" = [
"openid"
"email"
"profile"
];
# XXX: PKCE is currently not supported by gitea/forgejo,
# see https://github.com/go-gitea/gitea/issues/21376.
allowInsecureClientDisablePkce = true;
preferShortUsername = true;
claimMaps.groups = {
joinType = "array";
valuesByGroup."forgejo.admins" = [ "admin" ];
};
};
# Web Sentinel
groups."web-sentinel.access" = { };
groups."web-sentinel.adguardhome" = { };
groups."web-sentinel.openwebui" = { };
groups."web-sentinel.analytics" = { };
systems.oauth2.web-sentinel = {
displayName = "Web Sentinel";
originUrl = "https://oauth2.${globals.domains.me}/oauth2/callback";
originLanding = "https://oauth2.${globals.domains.me}/";
basicSecretFile = config.age.secrets.kanidm-oauth2-web-sentinel.path;
preferShortUsername = true;
scopeMaps."web-sentinel.access" = [
"openid"
"email"
];
claimMaps.groups = {
joinType = "array";
valuesByGroup."web-sentinel.adguardhome" = [ "access_adguardhome" ];
valuesByGroup."web-sentinel.openwebui" = [ "access_openwebui" ];
valuesByGroup."web-sentinel.analytics" = [ "access_analytics" ];
};
};
};
};
systemd.services.kanidm.serviceConfig.RestartSec = "60"; # Retry every minute
}