{ inputs', inputs, lib, pkgs, self', self, config, ... }: let inherit (lib) mkDefault mkIf ; inherit (self') packages; debug = true; fqdn = "keycloak-pam.test"; passwordFile = builtins.toFile "super-secure-password" "nuhuh"; in { virtualisation.vmVariant.virtualisation = { cores = 2; diskSize = 8192; graphics = false; memorySize = 4096; qemu.networkingOptions = lib.mkForce [ "-nic bridge,br=virbr0,id=hn0,model=virt-net-pci,helper=\${QEMU_BRIDGE_HELPER_PATH}" "-device virtio-net-pci,netdev=hn0,id=nic1,\${QEMU_NET_OPTS:+,$QEMU_NET_OPTS}" ]; }; system = { configurationRevision = self.rev or self.dirtyRev or null; stateVersion = "25.11"; }; networking = { inherit fqdn; firewall.enable = false; networkmanager.enable = true; extraHosts = let subdomains = [ ]; hosts = [ fqdn ] ++ map (sub: "${sub}.${fqdn}") subdomains; in lib.concatMapStrings (host: '' 127.0.0.1 ${host} ::1 ${host} '') hosts; }; services.getty.autologinUser = "root"; services.nginx = let mkVhost = attrs: locations: { forceSSL = false; inherit locations; } // attrs; mkProxy = port: { proxyPass = "http://127.0.0.1:${toString port}/"; extraConfig = '' proxy_buffering off; proxy_request_buffering off; proxy_set_header X-Forwarded-For $remote_addr; ''; }; in { enable = true; recommendedProxySettings = true; recommendedOptimisation = true; virtualHosts = { "${fqdn}" = mkVhost { default = true; } { "/" = mkProxy config.services.keycloak.settings.http-port; }; }; }; users = { users.admin = { password = config.services.keycloak.initialAdminPassword; isNormalUser = true; extraGroups = [ "keycloak-login" ]; }; groups.keycloak-login = { }; }; environment.systemPackages = with pkgs; [ croc neovim ]; services.keycloak = { enable = true; initialAdminPassword = "dontchangeme"; settings = { hostname = "http://${fqdn}"; http-port = 3000; http-enabled = true; proxy-headers = "forwarded"; }; database = { host = "localhost"; inherit passwordFile; }; }; services.postgresql = { enable = true; authentication = pkgs.lib.mkOverride 10 '' #type database DBuser auth-method local all all trust host keycloak keycloak 127.0.0.1/32 md5 ''; }; security.pam.services = let modulePath = "${packages.keycloak-pam}/lib/libkeycloak_pam.so"; keycloakPamConfig = builtins.toFile "keycloak-pam.json" ( builtins.toJSON { base_url = "http://127.0.0.1:${toString config.services.keycloak.settings.http-port}"; default_realm = "master"; client_id = "account"; client_secret = "7bsrMrRuNKpqsxcOOJavWjEqek12ZCkj"; unix_group = "keycloak-login"; admin_username = "admin"; admin_password = "dontchangeme"; admincli_client = "admin-cli"; } ); settings = { inherit debug; config = keycloakPamConfig; }; mkRuleBeforeUnix = type: service: { "${type}" = { keycloak-pam = { order = config.security.pam.services."${service}".rules."${type}".unix.order - 10; control = "sufficient"; inherit modulePath settings; }; keycloak-deny = { order = config.security.pam.services."${service}".rules."${type}".unix.order - 9; control = "requisite"; settings = settings // { asdeny = true; }; inherit modulePath; }; }; }; mkRulesBeforeUnix = types: service: builtins.foldl' (rules: type: rules // mkRuleBeforeUnix type service) { } types; mkServicesWith = withfn: builtins.foldl' (attrs: service: attrs // { "${service}".rules = withfn service; }) { }; mkAuths = mkServicesWith (mkRuleBeforeUnix "auth"); mkPasswds = mkServicesWith (mkRulesBeforeUnix [ "auth" "password" ]); in mkAuths [ "login" "su" "sudo" "passwd" ] // mkPasswds [ "passwd" ]; }