{ description = "A simple OIDC SSO service"; inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; outputs = { self, nixpkgs, systems, }: let inherit (nixpkgs) lib; eachSystem = f: lib.genAttrs (import systems) (system: f { inherit system; pkgs = nixpkgs.legacyPackages.${system}; ownPkgs = self.packages.${system}; }); in { devShells = eachSystem ({pkgs, ...}: { default = pkgs.beam.packages.erlang_26.callPackage ./shell.nix {}; }); packages = eachSystem ({pkgs, ...}: { default = pkgs.beam.packages.erlang_26.callPackage ./default.nix { inherit self; }; }); nixosModules = { default = { lib, pkgs, config, ... }: let sso-bsn = self.packages.${pkgs.system}.default; gen-secret = pkgs.writeShellScript "gen-secret" '' (umask 077; [ -f $1/$2 ] || ${pkgs.coreutils}/bin/head -c 128 /dev/urandom | ${pkgs.coreutils}/bin/base64 -w0 > $1/$2) ''; secret = var: dir: file: '' ${gen-secret} "${dir}" "${file}" ${var}=$(${pkgs.coreutils}/bin/cat "${dir}/${file}") ''; script = pkgs.writeShellScriptBin "sso-bsn" '' ${secret "RELEASE_COOKIE" "/run/sso-bsn" "cookie"} RELEASE_COOKIE="$RELEASE_COOKIE" ${lib.getExe sso-bsn} "$@" ''; cfg = config.services.bluepython508.sso-bsn; in { options.services.bluepython508.sso-bsn = { enable = lib.mkEnableOption "sso-bsn"; host = lib.mkOption { type = lib.types.str; }; session-domain = lib.mkOption { type = with lib.types; nullOr str; }; }; options.services.nginx.virtualHosts = lib.mkOption { type = lib.types.attrsOf (lib.types.submodule ({ config, ...}: { options.locations = lib.mkOption { type = lib.types.attrsOf (lib.types.submodule { extraConfig = lib.mkIf config.sso.enable '' proxy_set_header X-Auth-Username $auth_resp_username ''; }); }; options.sso.enable = lib.mkEnableOption "SSO BSN"; config.extraConfig = lib.mkIf config.sso.enable '' auth_request /__auth_sso_validate; location = /__auth_sso_validate { internal; proxy_pass https://${cfg.host}/whoami; proxy_pass_request_body off; # no need to send the POST body proxy_set_header Content-Length ""; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; auth_request_set $auth_resp_username $upstream_http_x_auth_username; } error_page 401 = @error401; location @error401 { return 302 https://${cfg.host}/users/log_in?next=$scheme://$http_host$request_uri; } ''; })); }; config.environment.systemPackages = lib.mkIf cfg.enable [ script ]; config.users = lib.mkIf cfg.enable { groups.sso-bsn = {}; users.nginx.extraGroups = ["sso-bsn"]; users.sso-bsn = { group = "sso-bsn"; isSystemUser = true; }; }; config.systemd.services.sso-bsn = lib.mkIf cfg.enable { description = "sso-bsn"; path = [pkgs.tailscale]; environment = { SERVER = "true"; DATABASE_PATH = "/var/lib/sso-bsn/db.sqlite"; BIND_UNIX = "/run/sso-bsn/sock"; SSO_BSN_HOST = cfg.host; SESSION_DOMAIN = cfg.session-domain; }; script = '' ${secret "SECRET_KEY_BASE" "/var/lib/sso-bsn" "secret-key-base"} SECRET_KEY_BASE="$SECRET_KEY_BASE" ${lib.getExe script} start ''; wantedBy = [ "multi-user.target" ]; serviceConfig = { ProtectHome = true; PrivateUsers = true; RuntimeDirectory = "sso-bsn"; UMask = "007"; User = "sso-bsn"; Group = "sso-bsn"; PrivateTmp = true; RemoveIPC = true; NoNewPrivileges = true; RestrictSUIDSGID = true; }; }; config.services.nginx.virtualHosts = lib.mkIf cfg.enable { ${cfg.host} = { forceSSL = true; enableACME = true; locations."/" = { proxyPass = "http://unix:/run/sso-bsn/sock:/"; recommendedProxySettings = true; proxyWebsockets = true; }; }; }; }; }; }; }