idp: migrate to biotite

This commit is contained in:
xinyangli 2025-02-14 13:51:50 +08:00
parent 6bf1822141
commit 2e2968360c
Signed by: xin
SSH key fingerprint: SHA256:UU5pRTl7NiLFJbWJZa+snLylZSXIz5rgHmwjzv8v4oE
13 changed files with 347 additions and 41 deletions

View file

@ -15,6 +15,7 @@
./services/hedgedoc.nix
./services/forgejo.nix
./services/vaultwarden.nix
./services/kanidm.nix
];
networking.hostName = "biotite";

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -2,6 +2,7 @@
config,
lib,
pkgs,
my-lib,
...
}:
@ -11,6 +12,8 @@ let
mkEnableOption
;
inherit (my-lib) idpUrl;
cfg = config.commonSettings.auth;
in
{

View file

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

View file

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

View file

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