From 2e2968360c83bbf8b5e4fa9628864830edbeac32 Mon Sep 17 00:00:00 2001 From: xinyangli Date: Fri, 14 Feb 2025 13:51:50 +0800 Subject: [PATCH] idp: migrate to biotite --- machines/biotite/default.nix | 1 + machines/biotite/services/forgejo.nix | 43 ++-- machines/biotite/services/gotosocial.nix | 2 +- machines/biotite/services/hedgedoc.nix | 8 +- .../biotite/services/kanidm-provision.nix | 242 ++++++++++++++++++ machines/biotite/services/kanidm.nix | 54 ++++ machines/biotite/services/miniflux.nix | 2 +- machines/biotite/services/synapse.nix | 8 +- machines/weilite/services/immich.nix | 7 +- modules/nixos/common-settings/auth.nix | 3 + modules/nixos/monitor/grafana.nix | 6 +- modules/nixos/monitor/loki.nix | 10 +- overlays/my-lib/settings.nix | 2 +- 13 files changed, 347 insertions(+), 41 deletions(-) create mode 100644 machines/biotite/services/kanidm-provision.nix create mode 100644 machines/biotite/services/kanidm.nix diff --git a/machines/biotite/default.nix b/machines/biotite/default.nix index 741e281..13a01f2 100644 --- a/machines/biotite/default.nix +++ b/machines/biotite/default.nix @@ -15,6 +15,7 @@ ./services/hedgedoc.nix ./services/forgejo.nix ./services/vaultwarden.nix + ./services/kanidm.nix ]; networking.hostName = "biotite"; diff --git a/machines/biotite/services/forgejo.nix b/machines/biotite/services/forgejo.nix index 7321b89..b60352f 100644 --- a/machines/biotite/services/forgejo.nix +++ b/machines/biotite/services/forgejo.nix @@ -69,28 +69,29 @@ in systemd.services.forgejo = { serviceConfig = { EnvironmentFile = config.sops.templates."forgejo/env".path; - preStart = - let - providerName = "kanidm"; - args = lib.concatStringsSep " " [ - "--name ${providerName}" - "--provider openidConnect" - "--key forgejo" - "--secret $CLIENT_SECRET" - "--icon-url ${idpUrl}/pkg/img/favicon.png" - "--group-claim-name forgejo_role --admin-group Admin" - ]; - exe = getExe config.services.forgejo.package; - in - '' - provider_id=$(${exe} admin auth list | ${pkgs.gnugrep}/bin/grep -w '${providerName}' | cut -f1) - if [[ -z "$provider_id" ]]; then - ${exe} admin auth add-oauth ${args} - else - ${exe} admin auth update-oauth --id "$provider_id" ${args} - fi - ''; }; + preStart = + let + providerName = "kanidm"; + args = lib.concatStringsSep " " [ + "--name ${providerName}" + "--provider openidConnect" + "--key forgejo" + "--secret $CLIENT_SECRET" + "--auto-discover-url https://${idpUrl}/oauth2/openid/forgejo/.well-known/openid-configuration" + "--icon-url https://${idpUrl}/pkg/img/favicon.png" + "--group-claim-name forgejo_role --admin-group Admin" + ]; + exe = getExe config.services.forgejo.package; + in + '' + provider_id=$(${exe} admin auth list | ${pkgs.gnugrep}/bin/grep -w '${providerName}' | cut -f1) + if [[ -z "$provider_id" ]]; then + ${exe} admin auth add-oauth ${args} + else + ${exe} admin auth update-oauth --id "$provider_id" ${args} + fi + ''; }; users.users.git = { diff --git a/machines/biotite/services/gotosocial.nix b/machines/biotite/services/gotosocial.nix index 3114cf6..e2f4581 100644 --- a/machines/biotite/services/gotosocial.nix +++ b/machines/biotite/services/gotosocial.nix @@ -26,7 +26,7 @@ in instance-expose-public-timeline = true; oidc-enabled = true; oidc-idp-name = "Kanidm"; - oidc-issuer = "${idpUrl}/oauth2/openid/gotosocial"; + oidc-issuer = "https://${idpUrl}/oauth2/openid/gotosocial"; oidc-client-id = "gotosocial"; oidc-link-existing = true; }; diff --git a/machines/biotite/services/hedgedoc.nix b/machines/biotite/services/hedgedoc.nix index c8b33bc..af64be5 100644 --- a/machines/biotite/services/hedgedoc.nix +++ b/machines/biotite/services/hedgedoc.nix @@ -20,10 +20,10 @@ in email = false; allowEmailRegister = false; oauth2 = { - baseURL = "${idpUrl}/oauth2/openid/hedgedoc"; - authorizationURL = "${idpUrl}/ui/oauth2"; - tokenURL = "${idpUrl}/oauth2/token"; - userProfileURL = "${idpUrl}/oauth2/openid/hedgedoc/userinfo"; + baseURL = "https://${idpUrl}/oauth2/openid/hedgedoc"; + authorizationURL = "https://${idpUrl}/ui/oauth2"; + tokenURL = "https://${idpUrl}/oauth2/token"; + userProfileURL = "https://${idpUrl}/oauth2/openid/hedgedoc/userinfo"; userProfileEmailAttr = "email"; userProfileUsernameAttr = "name"; userProfileDisplayNameAttr = "preferred_name"; diff --git a/machines/biotite/services/kanidm-provision.nix b/machines/biotite/services/kanidm-provision.nix new file mode 100644 index 0000000..82bbd49 --- /dev/null +++ b/machines/biotite/services/kanidm-provision.nix @@ -0,0 +1,242 @@ +{ pkgs, config, ... }: +let + inherit (config.my-lib.settings) + gotosocialUrl + minifluxUrl + hedgedocDomain + forgejoDomain + grafanaUrl + synapseDelegateUrl + ; +in +{ + services.kanidm.provision = { + enable = true; + autoRemove = true; + groups = { + forgejo-access = { + members = [ "xin" ]; + }; + forgejo-admin = { + members = [ "xin" ]; + }; + gts-users = { + members = [ "xin" ]; + }; + ocis-users = { + members = [ "xin" ]; + }; + linux_users = { + members = [ "xin" ]; + }; + hedgedoc-users = { + members = [ "xin" ]; + }; + immich-users = { + members = [ + "xin" + "zhuo" + "ycm" + "yzl" + ]; + }; + grafana-superadmins = { + members = [ "xin" ]; + }; + grafana-admins = { + members = [ "xin" ]; + }; + grafana-editors = { + members = [ "xin" ]; + }; + grafana-users = { + members = [ "xin" ]; + }; + miniflux-users = { + members = [ "xin" ]; + }; + synapse-users = { + members = [ "xin" ]; + }; + idm_people_self_mail_write = { + members = [ ]; + }; + }; + persons = { + xin = { + displayName = "Xinyang Li"; + mailAddresses = [ "lixinyang411@gmail.com" ]; + }; + + zhuo = { + displayName = "Zhuo"; + mailAddresses = [ "13681104320@163.com" ]; + }; + + ycm = { + displayName = "Chunming"; + mailAddresses = [ "chunmingyou@gmail.com" ]; + }; + + yzl = { + displayName = "Zhengli Yang"; + mailAddresses = [ "13391935399@189.cn" ]; + }; + }; + systems.oauth2 = { + forgejo = { + displayName = "ForgeJo"; + originUrl = "https://${forgejoDomain}/user/oauth2/kanidm/callback"; + originLanding = "https://${forgejoDomain}/user/oauth2/kanidm"; + allowInsecureClientDisablePkce = true; + scopeMaps = { + forgejo-access = [ + "openid" + "email" + "profile" + "groups" + ]; + }; + claimMaps = { + forgejo_role = { + joinType = "array"; + valuesByGroup = { + forgejo-access = [ "Access" ]; + forgejo-admin = [ "Admin" ]; + }; + }; + }; + }; + gts = { + displayName = "GoToSocial"; + originUrl = "https://xinyang.life/auth/callback"; + originLanding = "https://xinyang.life/auth/callback"; + allowInsecureClientDisablePkce = true; + scopeMaps = { + gts-users = [ + "openid" + "email" + "profile" + "groups" + ]; + }; + }; + gotosocial = { + displayName = "GoToSocial"; + originUrl = "${gotosocialUrl}/auth/callback"; + originLanding = "${gotosocialUrl}/auth/callback"; + allowInsecureClientDisablePkce = true; + scopeMaps = { + gts-users = [ + "openid" + "email" + "profile" + "groups" + ]; + }; + }; + # It's used for all the clients. I'm too lazy to change the name. + owncloud-android = { + displayName = "ownCloud Apps"; + originLanding = "https://drive.xinyang.life:8443/"; + originUrl = [ + "http://localhost:38622/" + "http://localhost:43580/" + "https://drive.xinyang.life:8443/" + # TODO: Should allow mobile redirect url not ending with / + # "oc://android.owncloud.com" + ]; + public = true; + preferShortUsername = true; + scopeMaps = { + ocis-users = [ + "openid" + "email" + "profile" + "offline_access" + ]; + }; + }; + + hedgedoc = { + displayName = "HedgeDoc"; + originUrl = "https://${hedgedocDomain}/auth/oauth2/callback"; + originLanding = "https://${hedgedocDomain}/auth/oauth2"; + allowInsecureClientDisablePkce = true; + scopeMaps = { + hedgedoc-users = [ + "openid" + "email" + "profile" + ]; + }; + }; + immich = { + displayName = "Immich"; + originUrl = [ + "https://immich.xinyang.life:8000/api/oauth/mobile-redirect/" + "https://immich.xinyang.life:8000/auth/login" + "https://immich.xinyang.life:8000/user-settings" + "https://immich.xiny.li:8443/api/oauth/mobile-redirect/" + "https://immich.xiny.li:8443/auth/login" + "https://immich.xiny.li:8443/user-settings" + ]; + originLanding = "https://immich.xiny.li:8443/auth/login?autoLaunch=0"; + allowInsecureClientDisablePkce = true; + scopeMaps = { + immich-users = [ + "openid" + "email" + "profile" + ]; + }; + }; + miniflux = { + displayName = "Miniflux"; + originUrl = "${minifluxUrl}/oauth2/oidc/callback"; + originLanding = "${minifluxUrl}/oauth2/oidc/redirect"; + scopeMaps = { + miniflux-users = [ + "openid" + "email" + "profile" + ]; + }; + }; + grafana = { + displayName = "Grafana"; + originUrl = "${grafanaUrl}/login/generic_oauth"; + originLanding = "${grafanaUrl}/"; + scopeMaps = { + grafana-users = [ + "openid" + "email" + "profile" + "groups" + ]; + }; + claimMaps = { + grafana_role = { + joinType = "array"; + valuesByGroup = { + grafana-superadmins = [ "GrafanaAdmin" ]; + grafana-admins = [ "Admin" ]; + grafana-editors = [ "Editor" ]; + }; + }; + }; + }; + synapse = { + displayName = "Synapse"; + originUrl = "${synapseDelegateUrl}/_synapse/client/oidc/callback"; + originLanding = "${synapseDelegateUrl}/"; + scopeMaps = { + synapse-users = [ + "openid" + "profile" + ]; + }; + }; + }; + }; +} diff --git a/machines/biotite/services/kanidm.nix b/machines/biotite/services/kanidm.nix new file mode 100644 index 0000000..975f31b --- /dev/null +++ b/machines/biotite/services/kanidm.nix @@ -0,0 +1,54 @@ +{ + config, + pkgs, + lib, + ... +}: +let + kanidm_listen_port = 5324; + inherit (config.my-lib.settings) idpUrl; +in +{ + imports = [ + ./kanidm-provision.nix + ]; + + security.acme = { + acceptTerms = true; + certs.${idpUrl} = { + email = "lixinyang411@gmail.com"; + listenHTTP = "127.0.0.1:1360"; + group = "kanidm"; + }; + }; + + services.kanidm = { + package = pkgs.kanidm.withSecretProvisioning; + enableServer = true; + serverSettings = { + domain = idpUrl; + origin = "https://${idpUrl}"; + bindaddress = "[::]:${toString kanidm_listen_port}"; + tls_key = ''${config.security.acme.certs.${idpUrl}.directory}/key.pem''; + tls_chain = ''${config.security.acme.certs.${idpUrl}.directory}/fullchain.pem''; + online_backup.versions = 7; + # db_path = "/var/lib/kanidm/kanidm.db"; + }; + }; + + services.caddy = { + enable = true; + virtualHosts."http://${idpUrl}".extraConfig = '' + reverse_proxy ${config.security.acme.certs.${idpUrl}.listenHTTP} + ''; + virtualHosts."https://${idpUrl}".extraConfig = '' + reverse_proxy https://127.0.0.1:${toString kanidm_listen_port} { + header_up Host {upstream_hostport} + header_down Access-Control-Allow-Origin "*" + transport http { + tls_server_name ${config.services.kanidm.serverSettings.domain} + } + } + ''; + }; +} diff --git a/machines/biotite/services/miniflux.nix b/machines/biotite/services/miniflux.nix index 1bee3dc..7662b7e 100644 --- a/machines/biotite/services/miniflux.nix +++ b/machines/biotite/services/miniflux.nix @@ -17,7 +17,7 @@ in OAUTH2_CLIENT_ID = "miniflux"; OAUTH2_CLIENT_SECRET_FILE = "%d/oauth2_secret"; OAUTH2_REDIRECT_URL = "${minifluxUrl}/oauth2/oidc/callback"; - OAUTH2_OIDC_DISCOVERY_ENDPOINT = "${idpUrl}/oauth2/openid/miniflux"; + OAUTH2_OIDC_DISCOVERY_ENDPOINT = "https://${idpUrl}/oauth2/openid/miniflux"; OAUTH2_USER_CREATION = 1; CREATE_ADMIN = 0; }; diff --git a/machines/biotite/services/synapse.nix b/machines/biotite/services/synapse.nix index 552d31d..72e7516 100644 --- a/machines/biotite/services/synapse.nix +++ b/machines/biotite/services/synapse.nix @@ -85,11 +85,11 @@ in oidc_providers = [ { idp_id = "Kanidm"; - idp_name = lib.removePrefix "https://" idpUrl; + idp_name = idpUrl; issuer = "${idpUrl}/oauth2/openid/synapse"; - authorization_endpoint = "${idpUrl}/ui/oauth2"; - token_endpoint = "${idpUrl}/oauth2/token"; - userinfo_endpoint = "${idpUrl}/oauth2/openid/synapse/userinfo"; + authorization_endpoint = "https://${idpUrl}/ui/oauth2"; + token_endpoint = "https://${idpUrl}/oauth2/token"; + userinfo_endpoint = "https://${idpUrl}/oauth2/openid/synapse/userinfo"; client_id = "synapse"; client_secret_path = config.sops.secrets."synapse/oidc_client_secret".path; scopes = [ diff --git a/machines/weilite/services/immich.nix b/machines/weilite/services/immich.nix index 0b97f5c..262f187 100644 --- a/machines/weilite/services/immich.nix +++ b/machines/weilite/services/immich.nix @@ -3,11 +3,14 @@ ... }: let + inherit (config.my-lib.settings) idpUrl; + user = config.systemd.services.immich-server.serviceConfig.User; + immichUrl = "immich.xiny.li:8443"; jsonSettings = { oauth = { enabled = true; - issuerUrl = "https://auth.xinyang.life/oauth2/openid/immich/"; + issuerUrl = "https://${idpUrl}/oauth2/openid/immich/"; clientId = "immich"; clientSecret = config.sops.placeholder."immich/oauth_client_secret"; scope = "openid email profile"; @@ -16,7 +19,7 @@ let buttonText = "Login with Kanidm"; autoLaunch = true; mobileOverrideEnabled = true; - mobileRedirectUri = "https://immich.xinyang.life:8000/api/oauth/mobile-redirect/"; + mobileRedirectUri = "https://${immichUrl}/api/oauth/mobile-redirect/"; }; passwordLogin = { enabled = false; diff --git a/modules/nixos/common-settings/auth.nix b/modules/nixos/common-settings/auth.nix index 1cd85ec..d9739fe 100644 --- a/modules/nixos/common-settings/auth.nix +++ b/modules/nixos/common-settings/auth.nix @@ -2,6 +2,7 @@ config, lib, pkgs, + my-lib, ... }: @@ -11,6 +12,8 @@ let mkEnableOption ; + inherit (my-lib) idpUrl; + cfg = config.commonSettings.auth; in { diff --git a/modules/nixos/monitor/grafana.nix b/modules/nixos/monitor/grafana.nix index 9692fb5..7a72603 100644 --- a/modules/nixos/monitor/grafana.nix +++ b/modules/nixos/monitor/grafana.nix @@ -22,9 +22,9 @@ in name = "Kanidm"; client_id = "grafana"; scopes = "openid,profile,email,groups"; - auth_url = "${idpUrl}/ui/oauth2"; - token_url = "${idpUrl}/oauth2/token"; - api_url = "${idpUrl}/oauth2/openid/grafana/userinfo"; + auth_url = "https://${idpUrl}/ui/oauth2"; + token_url = "https://${idpUrl}/oauth2/token"; + api_url = "https://${idpUrl}/oauth2/openid/grafana/userinfo"; use_pkce = true; use_refresh_token = true; allow_sign_up = true; diff --git a/modules/nixos/monitor/loki.nix b/modules/nixos/monitor/loki.nix index 105a33a..d1197d9 100644 --- a/modules/nixos/monitor/loki.nix +++ b/modules/nixos/monitor/loki.nix @@ -15,6 +15,7 @@ let ; inherit (config.my-lib.settings) alertmanagerPort + internalDomain ; cfg = config.custom.monitoring; lokiPort = 3100; @@ -94,16 +95,17 @@ in rulerFile = pkgs.writeText "ruler.yml" (builtins.toJSON rulerConfig); in mkIf cfg.loki.enable { + systemd.services.loki.serviceConfig.After = "tailscaled.service"; services.loki = { enable = true; configuration = { auth_enabled = false; - server.http_listen_address = "${config.networking.hostName}.coho-tet.ts.net"; + server.http_listen_address = "${config.networking.hostName}.${internalDomain}"; server.http_listen_port = lokiPort; common = { ring = { - instance_addr = "${config.networking.hostName}.coho-tet.ts.net"; + instance_addr = "${config.networking.hostName}.${internalDomain}"; kvstore.store = "inmemory"; }; replication_factor = 1; @@ -160,7 +162,7 @@ in configuration = { server = { - http_listen_address = "${config.networking.hostName}.coho-tet.ts.net"; + http_listen_address = "${config.networking.hostName}.${internalDomain}"; http_listen_port = 28183; grpc_listen_port = 0; }; @@ -169,7 +171,7 @@ in clients = [ { - url = "http://thorite.coho-tet.ts.net:${toString lokiPort}/loki/api/v1/push"; + url = "http://thorite.${internalDomain}:${toString lokiPort}/loki/api/v1/push"; } ]; diff --git a/overlays/my-lib/settings.nix b/overlays/my-lib/settings.nix index e4a219f..649640f 100644 --- a/overlays/my-lib/settings.nix +++ b/overlays/my-lib/settings.nix @@ -1,7 +1,7 @@ { settings = { alertmanagerPort = 9093; - idpUrl = "https://auth.xinyang.life"; + idpUrl = "auth.xiny.li"; gotosocialUrl = "https://gts.xiny.li"; minifluxUrl = "https://rss.xiny.li"; hedgedocDomain = "docs.xiny.li";