From 411e1368d50aee9347cc4e6e0dbef61040bd317e Mon Sep 17 00:00:00 2001 From: ibizaman Date: Sat, 8 Oct 2022 23:52:41 -0700 Subject: [PATCH] add keycloak --- all-packages.nix | 5 +++ haproxy/config.nix | 6 +-- haproxy/mkconfig.nix | 4 +- haproxy/siteconfig.nix | 37 +++++++++++++---- keycloak/config.nix | 62 ++++++++++++++++++++++++++++ keycloak/mkconfig.nix | 30 ++++++++++++++ keycloak/mkunit.nix | 26 ++++++++++++ keycloak/unit.nix | 94 ++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 251 insertions(+), 13 deletions(-) create mode 100644 keycloak/config.nix create mode 100644 keycloak/mkconfig.nix create mode 100644 keycloak/mkunit.nix create mode 100644 keycloak/unit.nix diff --git a/all-packages.nix b/all-packages.nix index 029bbd4..b24f455 100644 --- a/all-packages.nix +++ b/all-packages.nix @@ -38,6 +38,11 @@ let PHPFPMSiteConfig = callPackage ./php-fpm/siteconfig.nix {inherit utils;}; mkPHPFPMSiteConfig = callPackage ./php-fpm/mksiteconfig.nix {inherit PHPFPMSiteConfig;}; + KeycloakConfig = callPackage ./keycloak/config.nix {inherit utils;}; + mkKeycloakConfig = callPackage ./keycloak/mkconfig.nix {inherit KeycloakConfig;}; + KeycloakService = callPackage ./keycloak/unit.nix {inherit utils;}; + mkKeycloakService = callPackage ./keycloak/mkunit.nix {inherit KeycloakService;}; + TtrssEnvironment = callPackage ./ttrss/environment.nix {}; TtrssConfig = callPackage ./ttrss/config.nix {}; mkTtrssConfig = callPackage ./ttrss/mkconfig.nix {inherit TtrssConfig;}; diff --git a/haproxy/config.nix b/haproxy/config.nix index 2c8e67d..118ee4d 100644 --- a/haproxy/config.nix +++ b/haproxy/config.nix @@ -5,7 +5,7 @@ }: { configDir ? "/etc/haproxy" , configFile ? "haproxy.cfg" -, acls ? [] +, frontends ? [] , backends ? [] , certPath , user ? "haproxy" @@ -37,7 +37,7 @@ let (x: spaces + x + "\n") (lib.strings.splitString "\n" content); - acls_str = lib.strings.concatMapStrings (acl: indent " " acl) acls; + frontends_str = lib.strings.concatMapStrings (acl: indent " " acl) frontends; backends_str = builtins.concatStringsSep "\n" backends; in @@ -91,7 +91,7 @@ utils.mkConfigFile { http-request add-header X-Forwarded-Proto https http-response set-header Strict-Transport-Security "max-age=15552000; includeSubDomains; preload;" - ${acls_str} + ${frontends_str} ${backends_str} ''; diff --git a/haproxy/mkconfig.nix b/haproxy/mkconfig.nix index d40da34..237fff6 100644 --- a/haproxy/mkconfig.nix +++ b/haproxy/mkconfig.nix @@ -9,7 +9,7 @@ , statsPort ? null , prometheusStatsUri ? null , certPath ? null -, acls ? [] +, frontends ? [] , backends ? [] , dependsOn ? {} }: @@ -23,7 +23,7 @@ inherit prometheusStatsUri; inherit certPath; - inherit acls backends; + inherit frontends backends; }; inherit dependsOn; diff --git a/haproxy/siteconfig.nix b/haproxy/siteconfig.nix index fa9d5f4..6cfeef8 100644 --- a/haproxy/siteconfig.nix +++ b/haproxy/siteconfig.nix @@ -1,27 +1,41 @@ { stdenv , pkgs +, lib }: { serviceName -, serviceSocket +, serviceAddress ? null +, serviceSocket ? null , phpFastcgi ? false , phpDocroot ? null , phpIndex ? "index.php" +, extraUseBackendConditions ? {} +, extraFrontendOptions ? [] +, extraBackendOptions ? [] }: +assert lib.assertMsg ( + (serviceAddress == null && serviceSocket != null) + || (serviceAddress != null && serviceSocket == null) +) "set either serviceAddress or serviceSocket"; + let + backendOptions = lib.concatMapStrings (x : "\n " + x) extraBackendOptions; + + serviceBind = if serviceAddress != null then serviceAddress else serviceSocket; + backend = if !phpFastcgi then '' backend ${serviceName} mode http - option forwardfor - server ${serviceName}1 ${serviceSocket} + option forwardfor${backendOptions} + server ${serviceName}1 ${serviceBind} '' else '' backend ${serviceName} mode http - option forwardfor + option forwardfor${backendOptions} use-fcgi-app ${serviceName}-php-fpm - server ${serviceName}1 ${serviceSocket} proto fcgi + server ${serviceName}1 ${serviceBind} proto fcgi fcgi-app ${serviceName}-php-fpm log-stderr global @@ -29,11 +43,18 @@ let index ${phpIndex} path-info ^(/.+\.php)(/.*)?$ ''; + + extraAclsCondition = lib.concatStrings (lib.attrsets.mapAttrsToList (k: v: "\nacl acl_${serviceName}_${k} ${v}") extraUseBackendConditions); + + extraAclsOr = lib.concatStrings (lib.attrsets.mapAttrsToList (k: v: " OR acl_${serviceName}_${k}") extraUseBackendConditions); in { - acl = '' - acl acl_${serviceName} hdr_beg(host) ${serviceName}. - use_backend ${serviceName} if acl_${serviceName} + frontend = '' + acl acl_${serviceName} hdr_beg(host) ${serviceName}.${extraAclsCondition} + '' + + lib.concatMapStrings (x: x + "\n") extraFrontendOptions + + '' + use_backend ${serviceName} if acl_${serviceName}${extraAclsOr} ''; inherit backend; diff --git a/keycloak/config.nix b/keycloak/config.nix new file mode 100644 index 0000000..74b9a01 --- /dev/null +++ b/keycloak/config.nix @@ -0,0 +1,62 @@ +{ stdenv +, pkgs +, lib +, utils +}: +{ configDir ? "/etc/keycloak" +, configFile ? "keycloak.conf" +, logLevel ? "INFO" +, metricsEnabled ? false +, hostname ? "keycloak.hostname.com" + +, dbType ? "postgres" +, dbUsername ? "keycloak" +, dbHost ? x: "localhost" +, dbPort ? "5432" +, dbDatabase ? "keycloak" +}: +{ KeycloakPostgresDB +}: + +assert lib.assertOneOf "dbType" dbType ["postgres"]; + +utils.mkConfigFile { + name = configFile; + dir = configDir; + content = '' + # The password of the database user is given by an environment variable. + db=${dbType} + db-username=${dbUsername} + db-url-host=${dbHost {inherit KeycloakPostgresDB;}} + db-url-port=${dbPort} + db-url-database=${dbDatabase} + # db-url-properties= # Would be used for ssl, see https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/web-apps/keycloak.nix#L491 + + # Observability + + # If the server should expose metrics and healthcheck endpoints. + metrics-enabled=${if metricsEnabled then "true" else "false"} + + # HTTP + + # The file path to a server certificate or certificate chain in PEM format. + #https-certificate-file=''${kc.home.dir}conf/server.crt.pem + + # The file path to a private key in PEM format. + #https-certificate-key-file=''${kc.home.dir}conf/server.key.pem + + # The proxy address forwarding mode if the server is behind a reverse proxy. + # https://www.keycloak.org/server/reverseproxy + proxy=edge + + # Do not attach route to cookies and rely on the session affinity capabilities from reverse proxy + #spi-sticky-session-encoder-infinispan-should-attach-route=false + + # Hostname for the Keycloak server. + hostname=${hostname} + + spi-x509cert-lookup-provider=haproxy + + log-level=${logLevel} + ''; +} diff --git a/keycloak/mkconfig.nix b/keycloak/mkconfig.nix new file mode 100644 index 0000000..d8d7e9b --- /dev/null +++ b/keycloak/mkconfig.nix @@ -0,0 +1,30 @@ +{ KeycloakConfig +}: +{ name +, configDir ? "/etc/keycloak" +, configFile ? "keycloak.conf" +, logLevel ? "INFO" +, metricsEnabled ? false +, hostname ? "keycloak.hostname.com" + +, dbType ? "postgres" +, dbUsername ? "keycloak" +, dbHost ? x: "localhost" +, dbPort ? "5432" +, dbDatabase ? "keycloak" + +, dependsOn ? {} +}: + +{ + inherit name configDir configFile; + + pkg = KeycloakConfig { + inherit configDir configFile hostname; + inherit logLevel metricsEnabled; + inherit dbType dbUsername dbHost dbPort dbDatabase; + }; + + inherit dependsOn; + type = "fileset"; +} diff --git a/keycloak/mkunit.nix b/keycloak/mkunit.nix new file mode 100644 index 0000000..8641fd8 --- /dev/null +++ b/keycloak/mkunit.nix @@ -0,0 +1,26 @@ +{ KeycloakService +}: +{ name +, configDir +, configFile +, user +, group +, dbPasswordFile +, postgresServiceName +, initialAdminFile ? null + +, dependsOn ? {} +}: +{ + inherit name configDir configFile; + + pkg = KeycloakService { + inherit configDir configFile; + inherit user group; + inherit dbPasswordFile initialAdminFile; + inherit postgresServiceName; + }; + + inherit dependsOn; + type = "systemd-unit"; +} diff --git a/keycloak/unit.nix b/keycloak/unit.nix new file mode 100644 index 0000000..ffc0d2a --- /dev/null +++ b/keycloak/unit.nix @@ -0,0 +1,94 @@ +{ stdenv +, pkgs +, lib +, utils +}: +{ configDir ? "/etc/keycloak" +, configFile ? "keycloak.conf" +, user ? "keycloak" +, group ? "keycloak" +, dbType ? "postgres" +, dbPasswordFile +, postgresServiceName +, initialAdminFile ? null +}: +{ ... }: + +assert lib.assertOneOf "dbType" dbType ["postgres"]; + +let + keycloak = pkgs.keycloak.override { + # This is needed for keycloak to build with the correct driver. + confFile = pkgs.writeText "keycloak.conf" '' + db=${dbType} + ''; + }; +in + +utils.systemd.mkService rec { + name = "keycloak"; + + content = '' + [Unit] + Description=Keycloak server + After=network-online.target + Wants=network-online.target systemd-networkd-wait-online.service ${postgresServiceName} + + [Service] + User=${user} + Group=${group} + + EnvironmentFile=${dbPasswordFile} + ${if initialAdminFile != null then "EnvironmentFile="+initialAdminFile else ""} + Environment=PATH=${pkgs.coreutils}/bin + Environment=KC_HOME_DIR="/run/keycloak" + + # running the ExecStartPre as root is not ideal, but at the moment + # the only solution for Quarkus modifying the serialized + # data under /lib/quarkus + # Raised upstream as https://github.com/keycloak/keycloak/discussions/10323 + # ExecStartPre=!${keycloak}/bin/kc.sh -cf ${configDir}/${configFile} build + ExecStart=${keycloak}/bin/kc.sh -cf ${configDir}/${configFile} start + + # ReadWritePaths=/var/lib/keycloak + # ReadWritePaths=/var/log/keycloak + # ReadWritePaths=/usr/share/java/keycloak/lib/quarkus + # ReadOnlyPaths=${configDir} + RuntimeDirectory=keycloak + DynamicUser=true + + # Disable timeout logic and wait until process is stopped + TimeoutStopSec=0 + TimeoutStartSec=10min + + # SIGTERM signal is used to stop the Java process + KillSignal=SIGTERM + + # Send the signal only to the JVM rather than its control group + KillMode=process + + # Java process is never killed + SendSIGKILL=no + + # When a JVM receives a SIGTERM signal it exits with code 143 + SuccessExitStatus=143 + + # Hardening options + # CapabilityBoundingSet= + # AmbientCapabilities=CAP_NET_BIND_SERVICES + # NoNewPrivileges=true + # Fails with: + # Failed to set up mount namespacing: /run/systemd/unit-root/var/lib/keycloak: No such file or directory + # ProtectHome=true + # ProtectSystem=strict + # ProtectKernelTunables=true + # ProtectKernelModules=true + # ProtectControlGroups=true + # PrivateTmp=true + # PrivateDevices=true + # LockPersonality=true + + [Install] + WantedBy=multi-user.target + ''; +}