diff --git a/hosts/elisabeth/guests.nix b/hosts/elisabeth/guests.nix index 7974758..2c279c0 100644 --- a/hosts/elisabeth/guests.nix +++ b/hosts/elisabeth/guests.nix @@ -17,6 +17,7 @@ vaultwardendomain = "pw.${config.secrets.secrets.global.domains.web}"; spotifydomain = "spotify.${config.secrets.secrets.global.domains.web}"; apispotifydomain = "api.spotify.${config.secrets.secrets.global.domains.web}"; + autheliadomain = "auth.${config.secrets.secrets.global.domains.web}"; ipOf = hostName: lib.net.cidr.host config.secrets.secrets.global.net.ips."${config.guests.${hostName}.nodeName}" config.secrets.secrets.global.net.privateSubnetv4; in { services.nginx = { @@ -212,6 +213,23 @@ in { client_max_body_size 4G ; ''; }; + + upstreams.authelia = { + servers."${ipOf "authelia"}:${nodes.elisabeth-authelia.config.services.authelia.instances.main.settings.server.port}" = {}; + + extraConfig = '' + zone authelia 64k ; + keepalive 5 ; + ''; + }; + virtualHosts.${autheliadomain} = { + forceSSL = true; + useACMEHost = "web"; + locations."/".proxyPass = "http://authelia"; + extraConfig = '' + client_max_body_size 4G ; + ''; + }; }; guests = let mkGuest = guestName: { @@ -301,6 +319,7 @@ in { // mkContainer "ollama" {} // mkContainer "ttrss" {} // mkContainer "your_spotify" {} + // mkContainer "authelia" {} // mkContainer "nextcloud" { enablePanzer = true; } diff --git a/modules/services/authelia.nix b/modules/services/authelia.nix new file mode 100644 index 0000000..01e9ca5 --- /dev/null +++ b/modules/services/authelia.nix @@ -0,0 +1,80 @@ +{config, ...}: let + stateDir = "/var/lib/authelia-main"; +in { + age.secrets.jwtSecretFile = { + generator.script = "alnum"; + mode = "440"; + inherit (config.authelia.instances.main) group; + }; + + age.secrets.sessionSecretFile = { + generator.script = "alnum"; + mode = "440"; + inherit (config.authelia.instances.main) group; + }; + + age.secrets.storageEncryptionKeyFile = { + generator.script = "alnum"; + mode = "440"; + inherit (config.authelia.instances.main) group; + }; + + age.secrets.oidcHmacSecretFile = { + generator.script = "alnum"; + mode = "440"; + inherit (config.authelia.instances.main) group; + }; + + age.secrets.oidcIssuerPrivateKeyFile = { + generator.script = {pkgs, ...}: '' + ${pkgs.openssl}/bin/openssl genrsa --outform PEM 4096 + ''; + mode = "440"; + inherit (config.authelia.instances.main) group; + }; + + services.authelia.instances.main = { + enable = true; + secrets = { + jwtSecretFile = config.age.secrets.jwtSecretsFile.path; + sessionSecretFile = config.age.secrets.sessionSecretFile.path; + storageEncryptionKeyFile = config.age.secrets.storageEncryptionKeyFile.path; + oidcHmacSecretFile = config.age.secrets.oidcHmacSecretFile.path; + oidcIssuerPrivateKeyFile = config.age.secrets.oidcIssuerPrivateKeyFile.path; + }; # TODO + settings = { + session = { + domain = config.secrets.secrets.global.domains.web; + }; + totp.disable = true; + dua_api.disable = true; + ntp.disable_startup_check = true; + theme = "dark"; + default_2fa_method = "webauthn"; + server.host = "0.0.0.0"; + + authentication_backend = { + password_reset.disable = true; + file = { + path = + builtins.toJSON { + }; + }; + }; + password_policy.standard = { + enabled = true; + min_length = 32; + }; + storage.local.path = "${stateDir}/db.sqlite3"; + identity_providers.oidc.clients = [ + { + id = "forgejo"; + secret = ""; + redirect_uris = ["git.${config.secrets.secrets.global.domains.web}/user/oauth2/authelia/callback"]; + public = false; + scopes = ["openid" "email" "profile" "groups"]; + } + ]; + }; + }; +} diff --git a/modules/services/gitea.nix b/modules/services/gitea.nix index 95452d1..e1633ff 100644 --- a/modules/services/gitea.nix +++ b/modules/services/gitea.nix @@ -1,6 +1,7 @@ { config, pkgs, + lib, ... }: let giteaDomain = "git.${config.secrets.secrets.global.domains.web}"; @@ -82,6 +83,13 @@ in { USER = config.secrets.secrets.local.gitea.mail.user; SEND_AS_PLAIN_TEXT = true; }; + oauth2_client = { + ACCOUNT_LINKING = "auto"; + ENABLE_AUTO_REGISTRATION = true; + OPENID_CONNECT_SCOPES = "email profile"; + REGISTER_EMAIL_CONFIRM = false; + UPDATE_AVATAR = true; + }; # packages.ENABLED = true; repository = { DEFAULT_PRIVATE = "private"; @@ -117,7 +125,47 @@ in { }; }; + # XXX: PKCE is currently not supported by gitea/forgejo, + # see https://github.com/go-gitea/gitea/issues/21376. + # Disable PKCE manually in kanidm for now. + # `kanidm system oauth2 warning-insecure-client-disable-pkce forgejo` systemd.services.gitea = { serviceConfig.RestartSec = "600"; # Retry every 10 minutes + preStart = let + exe = lib.getExe config.services.gitea.package; + providerName = "authelia"; + clientId = "forgejo"; + args = lib.escapeShellArgs [ + "--name" + providerName + "--provider" + "openidConnect" + "--key" + clientId + "--auto-discover-url" + "https://auth.${config.secrets.secrets.global.domains.web}/.well-known/openid-configuration" + "--required-claim-name" + "groups" + "--group-claim-name" + "groups" + "--admin-group" + "forgejo_admins" + "--skip-local-2fa" + ]; + in + lib.mkAfter '' + provider_id=$(${exe} admin auth list | ${pkgs.gnugrep}/bin/grep -w '${providerName}' | cut -f1) + if [[ -z "$provider_id" ]]; then + FORGEJO_ADMIN_OAUTH2_SECRET="$(< ${config.age.secrets.openid-secret.path})" ${exe} admin auth add-oauth ${args} + else + FORGEJO_ADMIN_OAUTH2_SECRET="$(< ${config.age.secrets.openid-secret.path})" ${exe} admin auth update-oauth --id "$provider_id" ${args} + fi + ''; + }; + + age.secrets.openid-secret = { + generator.script = "alnum"; + mode = "440"; + inherit (config.services.gitea) group; }; }