diff --git a/README.md b/README.md index 6fa8f6f..e6e0616 100644 --- a/README.md +++ b/README.md @@ -125,95 +125,3 @@ openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes \ -keyout selfcert.key -out selfcert.crt -subj \ "/CN=example.com" -addext "subjectAltName=DNS:example.com,DNS:sub1.example.com,DNS:sub2.example.com,IP:10.0.0.1" ``` - - - - - - -```nix -{ - services.kanidm.provision = { - persons.myuser = { - legalname = "Full Name"; - mail = "mail@example.com"; - groups = ["grafana-access" "grafana-server-admins"]; - }; - - groups.grafana-access = {}; - groups.grafana-server-admins = {}; - groups.grafana-admins = {}; - groups.grafana-editors = {}; - - systems.oauth2.grafana = { - displayName = "Grafana"; - originUrl = "https://grafana.${personalDomain}"; - basicSecretFile = pkgs.writeText "bs" "verygoodsecret"; - scopeMaps = { - grafana-access = ["openid" "email" "profile"]; - }; - supplementaryScopeMaps = { - grafana-server-admins = ["server_admin"]; - grafana-admins = ["admin"]; - grafana-editors = ["editor"]; - }; - }; - }; -} -``` - - - - -```bash -# Recover admin account -kanidmd recover-account admin -> FrEELN4tfyVbUAfhGeuUyZyaKk8cbpFufuDwyCPhY3xhb3X2 -# Login with recovered root account -kanidm login --name admin -# Generate new credentials for idm_admin account -kanidm service-account credential generate -D admin idm_admin -> Yk0W24SQGzkLp97DNxxExCcryDLvA7Q2dR0A7ZuaVQevLR6B -# Generate new oauth2 app for grafana -kanidm group create grafana-access -kanidm group create grafana-server-admins -kanidm group create grafana-admins -kanidm group create grafana-editors -kanidm system oauth2 create grafana "Grafana" https://grafana.${personalDomain} -kanidm system oauth2 update-scope-map grafana grafana-access openid email profile -kanidm system oauth2 update-sup-scope-map grafana grafana-server-admins server_admin -kanidm system oauth2 update-sup-scope-map grafana grafana-admins admin -kanidm system oauth2 update-sup-scope-map grafana grafana-editors editor -kanidm system oauth2 show-basic-secret grafana -# Generate new oauth2 app for proxied webapps -kanidm group create web-sentinel-access -kanidm group create web-sentinel-adguardhome-access -kanidm group create web-sentinel-influxdb-access -kanidm system oauth2 create web-sentinel "Web services" https://oauth2.${personalDomain} -kanidm system oauth2 update-scope-map web-sentinel web-sentinel-access openid email -kanidm system oauth2 update-sup-scope-map web-sentinel web-sentinel-adguardhome-access access_adguardhome -kanidm system oauth2 update-sup-scope-map web-sentinel web-sentinel-influxdb-access access_influxdb -kanidm system oauth2 show-basic-secret web-sentinel -# Generate new oauth2 app for forgejo -kanidm group create forgejo-access -kanidm group create forgejo-admins -kanidm system oauth2 create forgejo "Forgejo" https://git.${personalDomain} -kanidm system oauth2 update-scope-map forgejo forgejo-access openid email profile -kanidm system oauth2 update-sup-scope-map forgejo forgejo-server-admins server_admin -kanidm system oauth2 update-sup-scope-map forgejo forgejo-admins admin -kanidm system oauth2 update-sup-scope-map forgejo forgejo-editors editor -kanidm system oauth2 show-basic-secret forgejo -# Add new user -kanidm login --name idm_admin -kanidm person create myuser "My User" -kanidm person update myuser --legalname "Full Name" --mail "myuser@example.com" -kanidm group add-members grafana-access myuser -kanidm group add-members grafana-server-admins myuser -kanidm group add-members web-sentinel-access myuser -kanidm group add-members web-sentinel-adguardhome-access myuser -kanidm group add-members web-sentinel-influxdb-access myuser -``` - - - - diff --git a/hosts/sentinel/oauth2.nix b/hosts/sentinel/oauth2.nix index 6130b11..19ff6f2 100644 --- a/hosts/sentinel/oauth2.nix +++ b/hosts/sentinel/oauth2.nix @@ -2,6 +2,7 @@ lib, config, pkgs, + nodes, ... }: { meta.oauth2_proxy = { @@ -11,8 +12,27 @@ # TODO portal redirect to dashboard (in case someone clicks on kanidm "Web services") }; - age.secrets.oauth2-proxy-secret = { - rekeyFile = ./secrets/oauth2-proxy-secret.age; + age.secrets.oauth2-cookie-secret = { + rekeyFile = ./secrets/oauth2-cookie-secret.age; + mode = "440"; + group = "oauth2_proxy"; + }; + + # Mirror the original oauth2 secret, but prepend OAUTH2_PROXY_CLIENT_SECRET= + # so it can be used as an EnvironmentFile + age.secrets.oauth2-client-secret = { + generator.dependencies = [ + nodes.ward-kanidm.config.age.secrets.kanidm-oauth2-web-sentinel + ]; + generator.script = { + lib, + decrypt, + deps, + ... + }: '' + echo -n "OAUTH2_PROXY_CLIENT_SECRET=" + ${decrypt} ${lib.escapeShellArg (lib.head deps).file} + ''; mode = "440"; group = "oauth2_proxy"; }; @@ -26,7 +46,7 @@ redeemURL = "https://${config.networking.providedDomains.kanidm}/oauth2/token"; validateURL = "https://${config.networking.providedDomains.kanidm}/oauth2/openid/${clientId}/userinfo"; clientID = clientId; - keyFile = config.age.secrets.oauth2-proxy-secret.path; + keyFile = config.age.secrets.oauth2-cookie-secret.path; email.domains = ["*"]; extraConfig = { diff --git a/hosts/sentinel/secrets/oauth2-cookie-secret.age b/hosts/sentinel/secrets/oauth2-cookie-secret.age new file mode 100644 index 0000000..e2b0718 --- /dev/null +++ b/hosts/sentinel/secrets/oauth2-cookie-secret.age @@ -0,0 +1,10 @@ +age-encryption.org/v1 +-> X25519 KdpmgjrRS0ELGwUakn4bKF56nftZLenn3NB7PYgiNQE +52zchN0TRUP3/fdSTQ83aDi+0DZ07zxRRANNBe9i0IY +-> piv-p256 xqSe8Q An0xez98f0vVvi2E+pwwGzKOsI4HzQE7cJN59T8yl3n0 +vvX2Yqergv0XqNOV37Qs4YUbCEGQbIF5O9NxkRpy11Q +-> S_J0JSh-grease ] +5Wf2tYlp7iszD54QfYkV95WGpcQ3HEeGACA3Y97NTr7uzUck4OPuKJwEwgK6pman +AjB3lmIusWODZvwnuAL3fG/X4JEOJ2T21eBp5/Qfg/TsvHGH +--- qjh6E4UM8Yd5zl8gOaQQJLk2AH+vDh7dCEv0ig0rO2k +P]7\p(:'3E]Rw8/Z&Jz2I#Ko炝w qyW-/i)+ +fSF(Y_4Һ?j2l0# \ No newline at end of file diff --git a/hosts/sentinel/secrets/oauth2-proxy-secret.age b/hosts/sentinel/secrets/oauth2-proxy-secret.age deleted file mode 100644 index 8208406..0000000 Binary files a/hosts/sentinel/secrets/oauth2-proxy-secret.age and /dev/null differ diff --git a/hosts/ward/microvms/forgejo.nix b/hosts/ward/microvms/forgejo.nix index 285e48d..dd575ef 100644 --- a/hosts/ward/microvms/forgejo.nix +++ b/hosts/ward/microvms/forgejo.nix @@ -20,6 +20,13 @@ in { inherit (config.services.gitea) group; }; + # Mirror the original oauth2 secret + age.secrets.forgejo-oauth2-client-secret = { + inherit (nodes.ward-kanidm.config.age.secrets.kanidm-oauth2-forgejo) rekeyFile; + mode = "440"; + inherit (config.services.gitea) group; + }; + nodes.sentinel = { networking.providedDomains.forgejo = forgejoDomain; diff --git a/hosts/ward/microvms/grafana.nix b/hosts/ward/microvms/grafana.nix index aa63d8f..a29839c 100644 --- a/hosts/ward/microvms/grafana.nix +++ b/hosts/ward/microvms/grafana.nix @@ -28,6 +28,13 @@ in { group = "grafana"; }; + # Mirror the original oauth2 secret + age.secrets.grafana-oauth2-client-secret = { + inherit (nodes.ward-kanidm.config.age.secrets.kanidm-oauth2-grafana) rekeyFile; + mode = "440"; + group = "grafana"; + }; + nodes.ward-influxdb = { # Mirror the original secret on the influx host age.secrets."grafana-influxdb-token-${config.node.name}" = { @@ -100,8 +107,7 @@ in { allow_sign_up = true; #auto_login = true; client_id = "grafana"; - #client_secret = "$__file{${config.age.secrets.grafana-oauth-client-secret.path}}"; - client_secret = "aZKNCM6KpjBy4RqwKJXMLXzyx9rKH6MZTFk4wYrKWuBqLj6t"; # TODO temporary test not a real secret + client_secret = "$__file{${config.age.secrets.grafana-oauth2-client-secret.path}}"; scopes = "openid email profile"; login_attribute_path = "prefered_username"; auth_url = "https://${sentinelCfg.networking.providedDomains.kanidm}/ui/oauth2"; diff --git a/hosts/ward/microvms/kanidm.nix b/hosts/ward/microvms/kanidm.nix index 00c9473..dda7076 100644 --- a/hosts/ward/microvms/kanidm.nix +++ b/hosts/ward/microvms/kanidm.nix @@ -5,8 +5,9 @@ pkgs, ... }: let + inherit (sentinelCfg.repo.secrets.local) personalDomain; sentinelCfg = nodes.sentinel.config; - kanidmDomain = "auth.${sentinelCfg.repo.secrets.local.personalDomain}"; + kanidmDomain = "auth.${personalDomain}"; kanidmPort = 8300; in { meta.wireguard-proxy.sentinel.allowedTCPPorts = [kanidmPort]; @@ -23,6 +24,27 @@ in { group = "kanidm"; }; + age.secrets.kanidm-oauth2-grafana = { + generator.script = "alnum"; + generator.tags = ["oauth2"]; + mode = "440"; + group = "kanidm"; + }; + + age.secrets.kanidm-oauth2-forgejo = { + generator.script = "alnum"; + generator.tags = ["oauth2"]; + mode = "440"; + group = "kanidm"; + }; + + age.secrets.kanidm-oauth2-web-sentinel = { + generator.script = "alnum"; + generator.tags = ["oauth2"]; + mode = "440"; + group = "kanidm"; + }; + nodes.sentinel = { networking.providedDomains.kanidm = kanidmDomain; @@ -49,7 +71,6 @@ in { services.kanidm = { enableServer = true; - # enablePAM = true; serverSettings = { domain = kanidmDomain; origin = "https://${kanidmDomain}"; @@ -58,18 +79,65 @@ in { bindaddress = "0.0.0.0:${toString kanidmPort}"; trust_x_forward_for = true; }; - }; - environment.systemPackages = [pkgs.kanidm]; - - services.kanidm = { enableClient = true; clientSettings = { uri = config.services.kanidm.serverSettings.origin; verify_ca = true; verify_hostnames = true; }; + + provision = { + inherit (config.secrets.global.kanidm) persons; + + # Grafana + groups.grafana = {}; + groups."grafana.admins" = {}; + groups."grafana.editors" = {}; + groups."grafana.server-admins" = {}; + systems.oauth2.grafana = { + displayName = "Grafana"; + originUrl = "https://${config.networking.providedDomains.grafana}"; + basicSecretFile = config.age.secrets.kanidm-oauth2-grafana.path; + scopeMaps.grafana = ["openid" "email" "profile"]; + supplementaryScopeMaps = { + "grafana.admins" = ["admin"]; + "grafana.editors" = ["editor"]; + "grafana.server-admins" = ["server_admin"]; + }; + }; + + # Forgejo + groups.forgejo = {}; + groups."forgejo.admins" = {}; + systems.oauth2.forgejo = { + displayName = "Forgejo"; + originUrl = "https://${config.networking.providedDomains.forgejo}"; + basicSecretFile = config.age.secrets.kanidm-oauth2-forgejo.path; + scopeMaps.forgejo = ["openid" "email" "profile"]; + supplementaryScopeMaps = { + "forgejo.admins" = ["admin"]; + "forgejo.editors" = ["editor"]; + "forgejo.server-admins" = ["server_admin"]; + }; + }; + + # Web Sentinel + groups.web-sentinel = {}; + groups."web-sentinel.adguardhome" = {}; + systems.oauth2.web-sentinel = { + displayName = "Web Sentinel"; + originUrl = "https://oauth2.${personalDomain}"; + basicSecretFile = config.age.secrets.kanidm-oauth2-web-sentinel.path; + scopeMaps.web-sentinel = ["openid" "email"]; + supplementaryScopeMaps = { + "web-sentinel.adguardhome" = ["access_adguardhome"]; + "web-sentinel.influxdb" = ["access_influxdb"]; + }; + }; + }; }; - systemd.services.grafana.serviceConfig.RestartSec = "60"; # Retry every minute + environment.systemPackages = [pkgs.kanidm]; + systemd.services.kanidm.serviceConfig.RestartSec = "60"; # Retry every minute } diff --git a/modules/repo/distributed-config.nix b/modules/repo/distributed-config.nix index c11117e..becec99 100644 --- a/modules/repo/distributed-config.nix +++ b/modules/repo/distributed-config.nix @@ -47,6 +47,8 @@ in { networking.providedDomains = mergeFromOthers ["networking" "providedDomains"]; services.nginx.upstreams = mergeFromOthers ["services" "nginx" "upstreams"]; services.nginx.virtualHosts = mergeFromOthers ["services" "nginx" "virtualHosts"]; - services.influxdb2.provision.organizations = mergeFromOthers ["services" "influxdb2" "organizations"]; + services.influxdb2.provision.organizations = mergeFromOthers ["services" "influxdb2" "provision" "organizations"]; + services.kanidm.provision.groups = mergeFromOthers ["services" "kanidm" "provision" "groups"]; + services.kanidm.provision.systems.oauth2 = mergeFromOthers ["services" "kanidm" "provision" "systems" "oauth2"]; }; } diff --git a/secrets/global.nix.age b/secrets/global.nix.age index 34c4d44..a5c6b36 100644 Binary files a/secrets/global.nix.age and b/secrets/global.nix.age differ