{ config, lib, pkgs, ... }: let cfg = config.sydnix.deertopia.authelia; in { options.sydnix.deertopia.authelia = { enable = lib.mkEnableOption ''Deertopia's Authelia''; httpPort = lib.mkOption { description = '' The port on which Authelia's web UI will be served. ''; type = lib.types.port; default = 9091; }; bindUserName = lib.mkOption { description = '' The name of the LDAP user Authelia will bind as. ''; type = lib.types.str; default = "authelia"; }; }; config = lib.mkIf cfg.enable (let authelia-state-dir = "/var/lib/authelia-deertopia"; in { sydnix.sops.secrets = let e = { mode = "0600"; owner = config.services.authelia.instances."deertopia".user; group = config.services.authelia.instances."deertopia".group; }; in { authelia-jwt-secret = e; authelia-session-secret = e; authelia-storage-encryption-key = e; authelia-authentication-backend-ldap-password = e; }; sydnix.impermanence.directories = [ authelia-state-dir ]; # See: # - https://github.com/authelia/authelia/blob/v4.38.19/config.template.yml # - https://matwick.ca/authelia-nginx-sso/ # - https://www.gandalfk7.it/posts/20220713_01_sso-with-lldap-authelia-and-nginx/ services.authelia.instances."deertopia" = { enable = true; # "Automatic" secrets are seemingly broken and offer little more than # some assertions from the Nix module. secrets.manual = true; environmentVariables = { AUTHELIA_JWT_SECRET_FILE = "/run/secrets/authelia-jwt-secret"; AUTHELIA_SESSION_SECRET_FILE = "/run/secrets/authelia-session-secret"; AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE = "/run/secrets/authelia-storage-encryption-key"; AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE = "/run/secrets/authelia-authentication-backend-ldap-password"; }; settings = { default_2fa_method = "totp"; theme = "auto"; server = { address = "tcp://:${builtins.toString cfg.httpPort}"; # asset_path = "${authelia-state-dir}/assets"; # Necessary for Nginx integration. No, I do not understand what it # does. endpoints.authz.auth-request.implementation = "AuthRequest"; }; authentication_backend = let base-dn = config.services.lldap.settings.ldap_base_dn; ldap-port = builtins.toString config.services.lldap.settings.ldap_port; in { password_reset.disable = false; refresh_interval = "1 minutes"; ldap = { implementation = "custom"; address = "ldap://127.0.0.1:${ldap-port}"; timeout = "5s"; start_tls = "false"; base_dn = base-dn; additional_users_dn = "ou=people"; additional_groups_dn = "ou=groups"; groups_filter = "(member={dn})"; users_filter = "(&({username_attribute}={input})(objectClass=person))"; attributes = { username = "uid"; group_name = "cn"; mail = "mail"; display_name = "displayName"; }; user = "uid=${cfg.bindUserName},ou=people,${base-dn}"; }; }; access_control = { default_policy = "deny"; rules = [ { domain = "*.deertopia.net"; policy = "one_factor"; } ]; }; session = { name = "authelia_session"; same_site = "lax"; inactivity = "5 minutes"; expiration = "1 hour"; remember_me = "1 month"; cookies = [ { domain = "deertopia.net"; authelia_url = "https://auth.deertopia.net"; default_redirection_url = "https://deertopia.net"; } ]; }; storage.local.path = "${authelia-state-dir}/db.sqlite"; notifier = { disable_startup_check = false; filesystem.filename = "${authelia-state-dir}/notifications"; }; # Default is false, which prevents anything from showing up when you run # `systemctl status authelia-deertopia`, which is really, really confusing. log = { keep_stdout = true; file_path = "${authelia-state-dir}/authelia.log"; }; }; }; sydnix.deertopia.nginx.vhosts."auth" = { directory = null; vhost = { forceSSL = true; enableACME = true; extraConfig = '' set $upstream http://127.0.0.1:${builtins.toString cfg.httpPort}; ''; locations."/".extraConfig = '' include ${./authelia/proxy.conf}; proxy_pass $upstream; ''; locations."/api/verify".proxyPass = "$upstream"; locations."/api/authz".proxyPass = "$upstream"; }; }; }); }