nixos/hosts/web-arm/modules/authelia.nix

433 lines
16 KiB
Nix

{ config, pkgs, ... }:
let
unstable = import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/nixos-unstable.tar.gz") {
config = config.nixpkgs.config;
system = pkgs.system;
};
in {
# Redis for Authelia session persistence
services.redis.servers.authelia = {
enable = true;
user = "authelia-main";
unixSocket = "/run/redis-authelia/redis.sock";
unixSocketPerm = 660;
settings = {
appendonly = "yes"; # Enable AOF persistence
appendfsync = "everysec"; # Sync every second
};
};
# Add authelia user to redis group for socket access
users.users.authelia-main.extraGroups = [ "redis-authelia" ];
sops.secrets.authelia-jwt-secret = {
owner = "authelia-main";
};
sops.secrets.authelia-backend-ldap-password = {
owner = "authelia-main";
};
sops.secrets.authelia-storage-encryption-key = {
owner = "authelia-main";
};
sops.secrets.authelia-session-secret = {
owner = "authelia-main";
};
sops.secrets.authelia-identity-providers-oidc-hmac-secret = {
owner = "authelia-main";
};
sops.secrets.authelia-identity-providers-oidc-issuer-certificate-chain = {
owner = "authelia-main";
};
sops.secrets.authelia-identity-providers-oidc-issuer-private-key = {
owner = "authelia-main";
};
services.authelia.instances.main = {
package = unstable.authelia;
enable = true;
secrets = {
jwtSecretFile = config.sops.secrets.authelia-jwt-secret.path;
storageEncryptionKeyFile = config.sops.secrets.authelia-storage-encryption-key.path;
sessionSecretFile = config.sops.secrets.authelia-session-secret.path;
oidcHmacSecretFile = config.sops.secrets.authelia-identity-providers-oidc-hmac-secret.path;
oidcIssuerPrivateKeyFile = config.sops.secrets.authelia-identity-providers-oidc-issuer-private-key.path;
};
environmentVariables = {
"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE" = config.sops.secrets.authelia-backend-ldap-password.path;
"AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE" = config.sops.secrets.authelia-backend-ldap-password.path;
};
settings = {
theme = "dark";
# log = {
# level = "debug";
# format = "text";
# };
authentication_backend = {
ldap = {
url = "ldaps://ldap.cloonar.com";
base_dn = "DC=cloonar,DC=com";
additional_users_dn = "OU=users";
users_filter = "(&({username_attribute}={input})(objectClass=person))";
username_attribute = "mail";
mail_attribute = "mail";
display_name_attribute = "cn";
additional_groups_dn = "OU=groups";
groups_filter = "(&(member={dn})(objectClass=groupOfNames))";
group_name_attribute = "cn";
permit_referrals = false;
permit_unauthenticated_bind = false;
user = "cn=authelia,ou=system,ou=users,dc=cloonar,dc=com";
};
};
webauthn = {
disable = false;
display_name = "Authelia";
attestation_conveyance_preference = "indirect";
user_verification = "preferred";
timeout = "60s";
};
totp = {
disable = false;
issuer = "auth.cloonar.com";
algorithm = "sha1";
digits = 6;
period = 30;
skew = 1;
secret_size = 32;
};
access_control = {
default_policy = "deny";
rules = [
{
domain = ["auth.cloonar.com"];
policy = "bypass";
}
{
domain = ["*.cloonar.com"];
subject = ["group:Administrators" "group:Mitarbeiter"];
policy = "two_factor";
}
];
};
session = {
redis = {
host = "/run/redis-authelia/redis.sock";
};
# Authelia 4.38+ replaced top-level session.domain with per-cookie
# entries. Each entry needs an authelia_url, so only cloonar.com is
# configured here — adding cloonar.dev / gbv-aktuell.at would require
# separate Authelia endpoints on those domains.
cookies = [
{
name = "authelia_session";
domain = "cloonar.com";
authelia_url = "https://auth.cloonar.com";
default_redirection_url = "https://cloonar.com";
expiration = "12h";
inactivity = "45m";
remember_me = "1M";
}
];
};
regulation = {
max_retries = 3;
find_time = "5m";
ban_time = "15m";
};
storage = {
# mysql = {
# host = "/run/mysqld/mysqld.sock'";
# port = 3306;
# database = "authelia_main";
# username = "authelia_main";
# password = "socket_auth";
# timeout = "5s";
# };
local = {
path = "/var/lib/authelia-main/db.sqlite3";
};
};
notifier = {
disable_startup_check = false;
smtp = {
host = "mail.cloonar.com";
port = 25;
username = "authelia@cloonar.com";
sender = "Authelia <authelia@cloonar.com>";
};
};
identity_providers = {
oidc = {
## The other portions of the mandatory OpenID Connect 1.0 configuration go here.
## See: https://www.authelia.com/c/oidc
lifespans = {
custom = {
ocis = {
access_token = "2 days";
refresh_token = "3 days";
};
};
};
cors = {
endpoints = [
"authorization"
"token"
"revocation"
"introspection"
"userinfo"
];
};
authorization_policies = {
"admin-only" = {
default_policy = "deny";
rules = [
{
policy = "one_factor";
subject = "group:Administrators";
}
];
};
internal = {
default_policy = "deny";
rules = [
{
policy = "one_factor";
subject = "group:Administrators";
}
{
policy = "one_factor";
subject = "group:Mitarbeiter";
}
{
policy = "one_factor";
subject = "group:macher.solutions";
}
];
};
};
clients = [
{
id = "gitea";
description = "Gitea";
secret = "$pbkdf2-sha512$310000$ngFGgCoDClB0xPLxxMJ.Qw$hFuXXizjiC73gZtwi2bPBHzpX8/1GmR8ux1aAz9esVhPEgB58d/vB2jLFKyc13mFJx7qc0ErIdla4/K0CsvM.A";
public = false;
authorization_policy = "admin-only";
redirect_uris = [ "https://git.cloonar.com/user/oauth2/authelia/callback" ];
consent_mode = "implicit";
scopes = [
"openid"
"profile"
"email"
];
userinfo_signing_algorithm = "none";
}
{
id = "nextcloud";
description = "Nextcloud";
secret = "$pbkdf2-sha512$310000$jPzRYxmYCCDC/Go0Xti9rg$5K70qyNktBEs6PVnJYMrve4insptBzRD1eTi76zFVnJ2aFEc1.7f3yzRTpQ9HVWfEfxRoowXNMNdLxHeDcbLDw";
public = false;
authorization_policy = "internal";
redirect_uris = [
"https://nextcloud.cloonar.com/apps/oidc_login/oidc"
];
consent_mode = "implicit";
scopes = [
"openid"
"profile"
"email"
"groups"
];
userinfo_signing_algorithm = "none";
}
{
id = "grafana";
description = "Grafana";
secret = "$pbkdf2-sha512$310000$TP7.qfcevrHJFGcIMdZgGw$mLQ.AC5M28ETouxyiCeRkenQuKPvH0.oF1exp6LXBpleV56PI6sWrwmBgD7sMsHrMbkvCX4lNPx0vMf0urVpYA";
public = false;
authorization_policy = "admin-only";
redirect_uris = [ "https://grafana.cloonar.com/login/generic_oauth" ];
consent_mode = "implicit";
scopes = [
"openid"
"profile"
"email"
"groups"
];
userinfo_signing_algorithm = "none";
}
{
id = "freescout";
description = "FreeScout Support platform";
secret = "$pbkdf2-sha512$310000$5D3wUR7CnuoeHu3eNWfETw$SY0GTnZor3BlZKPyU3evH9QTlQG6Bm32RoPAlUgdIRJ8HmL3jRLVtmPLxOcJj06ZS/dDTRfkYej2RmD5cA3T4A";
public = false;
authorization_policy = "admin-only";
redirect_uris = [ "https://support.cloonar.dev/oauth-login/callback/fryg87l64" ];
consent_mode = "implicit";
token_endpoint_auth_method = "client_secret_post";
scopes = [
"openid"
"profile"
"email"
"groups"
];
userinfo_signing_algorithm = "none";
}
{
id = "synapse";
description = "Matrix Authentication Service";
secret = "$pbkdf2-sha512$310000$eb85q6wn7juP3DnTjobqEQ$GFNbhkZrXRU8gM6SwMFkPPIYPIsJcGyaQXacGB0r.gI.xTEEoeWU3gG6hkSgJHYnjhZtZoELZLcaE4qCd9fKLg";
public = false;
authorization_policy = "one_factor";
redirect_uris = [ "https://matrix.cloonar.com/upstream/callback/01KJPRKN397E5N8D0CA2Z3TJ7Y" ];
consent_mode = "implicit";
token_endpoint_auth_method = "client_secret_post";
scopes = [
"openid"
"profile"
"email"
];
userinfo_signing_algorithm = "none";
}
# oCIS (ownCloud Infinite Scale) - web client (public, PKCE)
{
id = "ocis";
description = "ownCloud Infinite Scale";
lifespan = "ocis";
public = true;
authorization_policy = "internal";
require_pkce = true;
pkce_challenge_method = "S256";
redirect_uris = [
"https://files.cloonar.com/"
"https://files.cloonar.com/oidc-callback.html"
"https://files.cloonar.com/oidc-silent-redirect.html"
"https://files.cloonar.com/apps/openidconnect/redirect"
];
scopes = [ "openid" "offline_access" "groups" "profile" "email" ];
response_types = [ "code" ];
grant_types = [ "authorization_code" "refresh_token" ];
access_token_signed_response_alg = "none";
userinfo_signing_algorithm = "none";
token_endpoint_auth_method = "none";
}
# oCIS Desktop - static credentials hardcoded in the oCIS desktop app
{
id = "xdXOt13JKxym1B1QcEncf2XDkLAexMBFwiT9j6EfhhHFJhs2KM9jbjTmf8JBXE69";
description = "ownCloud Infinite Scale (Desktop)";
secret = "$pbkdf2-sha512$310000$NR4tztBecptj1ZiITK/Ktw$GkFNBfq1B3T1lDTKMci1aO8iulQFNlEtfydLwTrNTKIfrQFjM7EiOBaHGOBC7ohPaNfYCRAYYzcP2fDQf5XRGQ";
public = false;
authorization_policy = "internal";
require_pkce = true;
pkce_challenge_method = "S256";
redirect_uris = [ "http://127.0.0.1" "http://localhost" ];
scopes = [ "openid" "offline_access" "groups" "profile" "email" ];
response_types = [ "code" ];
grant_types = [ "authorization_code" "refresh_token" ];
access_token_signed_response_alg = "none";
userinfo_signing_algorithm = "none";
token_endpoint_auth_method = "client_secret_basic";
}
# oCIS Android - static credentials hardcoded in the oCIS Android app
{
id = "e4rAsNUSIUs0lF4nbv9FmCeUkTlV9GdgTLDH1b5uie7syb90SzEVrbN7HIpmWJeD";
description = "ownCloud Infinite Scale (Android)";
secret = "$pbkdf2-sha512$310000$NjEumkph77Gql.CH0Oq3zg$I9ubOZ3VRCXPbHpW1U4bQmvLgP5DdiFeGgple2nIjtUJsFgkdiV/hcCt1h6adr1uvJSJAtHDRnMhYf3Zp2BpcQ";
public = false;
authorization_policy = "internal";
require_pkce = true;
pkce_challenge_method = "S256";
redirect_uris = [ "oc://android.owncloud.com" ];
scopes = [ "openid" "offline_access" "groups" "profile" "email" ];
response_types = [ "code" ];
grant_types = [ "authorization_code" "refresh_token" ];
access_token_signed_response_alg = "none";
userinfo_signing_algorithm = "none";
token_endpoint_auth_method = "client_secret_basic";
}
# oCIS iOS - static credentials hardcoded in the oCIS iOS app
{
id = "mxd5OQDk6es5LzOzRvidJNfXLUZS2oN3oUFeXPP8LpPrhx3UroJFduGEYIBOxkY1";
description = "ownCloud Infinite Scale (iOS)";
secret = "$pbkdf2-sha512$310000$.nIk0IUua7n8VAUoR85yyA$6UhT/gi7spH/0PRqTa6clz7QMRSmP/FZ0BDIumJupM4V2Ai6MgGKdzlEaNTc2IDqpGL3NxF626g4zAHFRgD7Zg";
public = false;
authorization_policy = "internal";
require_pkce = true;
pkce_challenge_method = "S256";
redirect_uris = [ "oc://ios.owncloud.com" "oc.ios://ios.owncloud.com" ];
scopes = [ "openid" "offline_access" "groups" "profile" "email" ];
response_types = [ "code" ];
grant_types = [ "authorization_code" "refresh_token" ];
access_token_signed_response_alg = "none";
userinfo_signing_algorithm = "none";
token_endpoint_auth_method = "client_secret_basic";
}
];
};
};
};
};
services.nginx.virtualHosts."auth.cloonar.com" = {
enableACME = true;
forceSSL = true;
acmeRoot = null;
locations."/api/verify" = {
proxyPass = "http://127.0.0.1:9091";
proxyWebsockets = true;
extraConfig = ''
allow 127.0.0.1;
allow 49.12.244.139;
allow 77.119.230.30;
deny all;
'';
};
locations."/" = {
proxyPass = "http://127.0.0.1:9091";
proxyWebsockets = true;
extraConfig = ''
client_body_buffer_size 128k;
#Timeout if the real server is dead
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
# Advanced Proxy Config
send_timeout 5m;
proxy_read_timeout 360;
proxy_send_timeout 360;
proxy_connect_timeout 360;
# Basic Proxy Config
# Host, X-Real-IP, X-Forwarded-For, X-Forwarded-Proto, X-Forwarded-Host
# and Connection are already set by recommendedProxySettings; redefining
# them here caused duplicate headers and fasthttp "too many Host headers" 400s.
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
proxy_set_header X-Forwarded-Uri $request_uri;
proxy_set_header X-Forwarded-Ssl on;
proxy_redirect http:// $scheme://;
proxy_cache_bypass $cookie_session;
proxy_no_cache $cookie_session;
proxy_buffers 64 256k;
# If behind reverse proxy, forwards the correct IP
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 172.0.0.0/8;
set_real_ip_from 192.168.0.0/16;
set_real_ip_from fc00::/7;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
'';
};
};
}