From f64c9e439c268004db324ee5fdd1a508da26ed00 Mon Sep 17 00:00:00 2001 From: bluepython508 Date: Thu, 9 Nov 2023 23:58:26 +0000 Subject: [PATCH] Nixos module --- config/config.exs | 4 +++ config/dev.exs | 6 ++-- config/runtime.exs | 18 +++++----- default.nix | 3 +- flake.nix | 87 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 105 insertions(+), 13 deletions(-) diff --git a/config/config.exs b/config/config.exs index 0cf9c9a..82e38f1 100644 --- a/config/config.exs +++ b/config/config.exs @@ -54,4 +54,8 @@ config :phoenix, :json_library, Jason # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. + +config :wax_, origin: "http://localhost:4000", rp_id: :auto +config :boruta, Boruta.Oauth, repo: SsoBsn.Repo, issuer: "http://localhost:4000/", contexts: [ resource_owners: SsoBsnWeb.ResourceOwners ] + import_config "#{config_env()}.exs" diff --git a/config/dev.exs b/config/dev.exs index f6db328..5733c04 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -26,7 +26,6 @@ config :sso_bsn, SsoBsnWeb.Endpoint, tailwind: {Tailwind, :install_and_run, [:default, ~w(--watch)]} ] -config :sso_bsn, :session_domain, "localhost" # ## SSL Support # @@ -77,5 +76,6 @@ config :phoenix, :plug_init_mode, :runtime # Include HEEx debug annotations as HTML comments in rendered markup config :phoenix_live_view, :debug_heex_annotations, true -config :wax_, origin: "http://localhost:4000", rp_id: :auto -config :boruta, Boruta.Oauth, repo: SsoBsn.Repo, issuer: "http://localhost:4000/", contexts: [ resource_owners: SsoBsnWeb.ResourceOwners ] \ No newline at end of file +config :wax_, origin: "http://localhost:4000" +config :boruta, Boruta.Oauth, issuer: "http://localhost:4000/" +config :sso_bsn, :session_domain, "localhost" diff --git a/config/runtime.exs b/config/runtime.exs index be64ab8..8d2771e 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -16,7 +16,7 @@ import Config # # Alternatively, you can use `mix phx.gen.release` to generate a `bin/server` # script that automatically sets the env var above. -if System.get_env("PHX_SERVER") do +if System.get_env("SERVER") do config :sso_bsn, SsoBsnWeb.Endpoint, server: true end @@ -44,20 +44,20 @@ if config_env() == :prod do You can generate one by calling: mix phx.gen.secret """ - host = System.get_env("PHX_HOST") || "example.com" - port = String.to_integer(System.get_env("PORT") || "4000") + host = System.get_env("SSO_BSN_HOST") || raise "SSO_BSN_HOST must be set to the external host of the service" + + config :wax_, origin: "https://#{host}/" + config :boruta, Boruta.Oauth, issuer: "https://#{host}/" config :sso_bsn, :dns_cluster_query, System.get_env("DNS_CLUSTER_QUERY") + config :sso_bsn, :session_domain, System.get_env("SESSION_DOMAIN") # A nil value will allow browser default of no subdomains, current domain + config :sso_bsn, SsoBsnWeb.Endpoint, url: [host: host, port: 443, scheme: "https"], http: [ - # Enable IPv6 and bind on all interfaces. - # Set it to {0, 0, 0, 0, 0, 0, 0, 1} for local network only access. - # See the documentation on https://hexdocs.pm/plug_cowboy/Plug.Cowboy.html - # for details about using IPv6 vs IPv4 and loopback vs public addresses. - ip: {0, 0, 0, 0, 0, 0, 0, 0}, - port: port + ip: {:local, System.get_env("BIND_UNIX")}, + port: 0 ], secret_key_base: secret_key_base diff --git a/default.nix b/default.nix index 80bae35..3ebdf26 100644 --- a/default.nix +++ b/default.nix @@ -14,8 +14,9 @@ mixRelease rec { mixFodDeps = fetchMixDeps { pname = "mix-deps-${pname}"; inherit version src; - sha256 = "sha256-hQlMy0e1Kv2zBXYCiNHYlIO0N00wuIW8B+ZlsEMTSy0="; + sha256 = "sha256-p74p7Dpi1xzddD+dygKF5cSLDATNKRXziKPNQgIhRPc="; }; ELIXIR_MAKE_CACHE_DIR = "/tmp/.elixir-make-cache"; + meta.mainProgram = "sso_bsn"; } diff --git a/flake.nix b/flake.nix index 6716983..867a031 100644 --- a/flake.nix +++ b/flake.nix @@ -23,5 +23,92 @@ inherit self; }; }); + + nixosModules = { + default = { lib, pkgs, config, ... }: let + sso-bsn = self.packages.${pkgs.system}.default; + gen-secret = pkgs.writeShellScript "gen-secret" '' + mkdir -p $1 + (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.sso.enable = lib.mkEnableOption "SSO BSN"; + config.extraConfig = lib.mkIf config.sso.enable '' + auth_request /__auth_sso_validate; + proxy_set_header X-Auth-Username $auth_resp_username; + + 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 url=https://${cfg.host}/user/log_in?next=$http_host$request_uri; + } + ''; + })); + }; + config.environment.systemPackages = lib.mkIf cfg.enable [ script ]; + config.systemd.services.sso-bsn = lib.mkIf cfg.enable { + description = "sso-bsn"; + 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 = { + DynamicUser = true; + ProtectHome = true; + PrivateUsers = true; + StateDirectory = "sso-bsn"; + RuntimeDirectory = "sso-bsn"; + }; + }; + 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; + }; + }; + }; + }; + }; }; }