-
-
Notifications
You must be signed in to change notification settings - Fork 18.1k
pomerium: init at 0.13.3 #108745
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
pomerium: init at 0.13.3 #108745
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| { config, lib, pkgs, ... }: | ||
|
|
||
| with lib; | ||
|
|
||
| let | ||
| format = pkgs.formats.yaml {}; | ||
| in | ||
| { | ||
| options.services.pomerium = { | ||
| enable = mkEnableOption "the Pomerium authenticating reverse proxy"; | ||
|
|
||
| configFile = mkOption { | ||
| type = with types; nullOr path; | ||
| default = null; | ||
| description = "Path to Pomerium config YAML. If set, overrides services.pomerium.settings."; | ||
| }; | ||
|
|
||
| useACMEHost = mkOption { | ||
| type = with types; nullOr str; | ||
| default = null; | ||
| description = '' | ||
| If set, use a NixOS-generated ACME certificate with the specified name. | ||
|
|
||
| Note that this will require you to use a non-HTTP-based challenge, or | ||
| disable Pomerium's in-built HTTP redirect server by setting | ||
| http_redirect_addr to null and use a different HTTP server for serving | ||
| the challenge response. | ||
|
|
||
| If you're using an HTTP-based challenge, you should use the | ||
| Pomerium-native autocert option instead. | ||
| ''; | ||
| }; | ||
|
|
||
| settings = mkOption { | ||
| description = '' | ||
| The contents of Pomerium's config.yaml, in Nix expressions. | ||
|
|
||
| Specifying configFile will override this in its entirety. | ||
|
|
||
| See <link xlink:href="https://pomerium.io/reference/">the Pomerium | ||
| configuration reference</link> for more information about what to put | ||
| here. | ||
| ''; | ||
| default = {}; | ||
| type = format.type; | ||
| }; | ||
|
|
||
| secretsFile = mkOption { | ||
| type = with types; nullOr path; | ||
| default = null; | ||
| description = '' | ||
| Path to file containing secrets for Pomerium, in systemd | ||
| EnvironmentFile format. See the systemd.exec(5) man page. | ||
| ''; | ||
| }; | ||
| }; | ||
|
|
||
| config = let | ||
| cfg = config.services.pomerium; | ||
| cfgFile = if cfg.configFile != null then cfg.configFile else (format.generate "pomerium.yaml" cfg.settings); | ||
| in mkIf cfg.enable ({ | ||
| systemd.services.pomerium = { | ||
lukegb marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| description = "Pomerium authenticating reverse proxy"; | ||
| wants = [ "network.target" ] ++ (optional (cfg.useACMEHost != null) "acme-finished-${cfg.useACMEHost}.target"); | ||
| after = [ "network.target" ] ++ (optional (cfg.useACMEHost != null) "acme-finished-${cfg.useACMEHost}.target"); | ||
| wantedBy = [ "multi-user.target" ]; | ||
| environment = optionalAttrs (cfg.useACMEHost != null) { | ||
| CERTIFICATE_FILE = "fullchain.pem"; | ||
| CERTIFICATE_KEY_FILE = "key.pem"; | ||
| }; | ||
| startLimitIntervalSec = 60; | ||
|
|
||
| serviceConfig = { | ||
| DynamicUser = true; | ||
| StateDirectory = [ "pomerium" ]; | ||
| ExecStart = "${pkgs.pomerium}/bin/pomerium -config ${cfgFile}"; | ||
|
|
||
| PrivateUsers = false; # breaks CAP_NET_BIND_SERVICE | ||
| MemoryDenyWriteExecute = false; # breaks LuaJIT | ||
|
|
||
| NoNewPrivileges = true; | ||
| PrivateTmp = true; | ||
| PrivateDevices = true; | ||
| DevicePolicy = "closed"; | ||
| ProtectSystem = "strict"; | ||
| ProtectHome = true; | ||
| ProtectControlGroups = true; | ||
| ProtectKernelModules = true; | ||
| ProtectKernelTunables = true; | ||
| ProtectKernelLogs = true; | ||
| RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK"; | ||
| RestrictNamespaces = true; | ||
| RestrictRealtime = true; | ||
| RestrictSUIDSGID = true; | ||
| LockPersonality = true; | ||
| SystemCallArchitectures = "native"; | ||
|
|
||
| EnvironmentFile = cfg.secretsFile; | ||
| AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ]; | ||
| CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; | ||
|
|
||
| WorkingDirectory = mkIf (cfg.useACMEHost != null) "$CREDENTIALS_DIRECTORY"; | ||
| LoadCredential = optionals (cfg.useACMEHost != null) [ | ||
| "fullchain.pem:/var/lib/acme/${cfg.useACMEHost}/fullchain.pem" | ||
| "key.pem:/var/lib/acme/${cfg.useACMEHost}/key.pem" | ||
| ]; | ||
| }; | ||
| }; | ||
|
|
||
| # postRun hooks on cert renew can't be used to restart Nginx since renewal | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Says "Nginx" here ;) |
||
| # runs as the unprivileged acme user. sslTargets are added to wantedBy + before | ||
| # which allows the acme-finished-$cert.target to signify the successful updating | ||
| # of certs end-to-end. | ||
| systemd.services.pomerium-config-reload = mkIf (cfg.useACMEHost != null) { | ||
lukegb marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| # TODO(lukegb): figure out how to make config reloading work with credentials. | ||
|
|
||
| wantedBy = [ "acme-finished-${cfg.useACMEHost}.target" "multi-user.target" ]; | ||
| # Before the finished targets, after the renew services. | ||
| before = [ "acme-finished-${cfg.useACMEHost}.target" ]; | ||
| after = [ "acme-${cfg.useACMEHost}.service" ]; | ||
| # Block reloading if not all certs exist yet. | ||
| unitConfig.ConditionPathExists = [ "${certs.${cfg.useACMEHost}.directory}/fullchain.pem" ]; | ||
| serviceConfig = { | ||
| Type = "oneshot"; | ||
| TimeoutSec = 60; | ||
| ExecCondition = "/run/current-system/systemd/bin/systemctl -q is-active pomerium.service"; | ||
| ExecStart = "/run/current-system/systemd/bin/systemctl restart pomerium.service"; | ||
| }; | ||
| }; | ||
| }); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| import ./make-test-python.nix ({ pkgs, ... }: { | ||
| name = "pomerium"; | ||
| meta = with pkgs.stdenv.lib.maintainers; { | ||
| maintainers = [ lukegb ]; | ||
| }; | ||
|
|
||
| nodes = let base = myIP: { pkgs, lib, ... }: { | ||
| virtualisation.vlans = [ 1 ]; | ||
| networking = { | ||
| dhcpcd.enable = false; | ||
| firewall.allowedTCPPorts = [ 80 443 ]; | ||
| hosts = { | ||
| "192.168.1.1" = [ "pomerium" "pom-auth" ]; | ||
| "192.168.1.2" = [ "backend" "dummy-oidc" ]; | ||
| }; | ||
| interfaces.eth1.ipv4.addresses = pkgs.lib.mkOverride 0 [ | ||
| { address = myIP; prefixLength = 24; } | ||
| ]; | ||
| }; | ||
| }; in { | ||
| pomerium = { pkgs, lib, ... }: { | ||
| imports = [ (base "192.168.1.1") ]; | ||
| services.pomerium = { | ||
| enable = true; | ||
| settings = { | ||
| address = ":80"; | ||
| insecure_server = true; | ||
| authenticate_service_url = "http://pom-auth"; | ||
|
|
||
| idp_provider = "oidc"; | ||
| idp_scopes = [ "oidc" ]; | ||
| idp_client_id = "dummy"; | ||
| idp_provider_url = "http://dummy-oidc"; | ||
|
|
||
| policy = [{ | ||
| from = "https://my.website"; | ||
| to = "http://192.168.1.2"; | ||
| allow_public_unauthenticated_access = true; | ||
| preserve_host_header = true; | ||
| } { | ||
| from = "https://login.required"; | ||
| to = "http://192.168.1.2"; | ||
| allowed_domains = [ "my.domain" ]; | ||
| preserve_host_header = true; | ||
| }]; | ||
| }; | ||
| secretsFile = pkgs.writeText "pomerium-secrets" '' | ||
| # 12345678901234567890123456789012 in base64 | ||
| COOKIE_SECRET=MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI= | ||
| IDP_CLIENT_SECRET=dummy | ||
| ''; | ||
| }; | ||
| }; | ||
| backend = { pkgs, lib, ... }: { | ||
| imports = [ (base "192.168.1.2") ]; | ||
| services.nginx.enable = true; | ||
| services.nginx.virtualHosts."my.website" = { | ||
| root = pkgs.runCommand "testdir" {} '' | ||
| mkdir "$out" | ||
| echo hello world > "$out/index.html" | ||
| ''; | ||
| }; | ||
| services.nginx.virtualHosts."dummy-oidc" = { | ||
| root = pkgs.runCommand "testdir" {} '' | ||
| mkdir -p "$out/.well-known" | ||
| cat <<EOF >"$out/.well-known/openid-configuration" | ||
| { | ||
| "issuer": "http://dummy-oidc", | ||
| "authorization_endpoint": "http://dummy-oidc/auth.txt", | ||
| "token_endpoint": "http://dummy-oidc/token", | ||
| "jwks_uri": "http://dummy-oidc/jwks.json", | ||
| "userinfo_endpoint": "http://dummy-oidc/userinfo", | ||
| "id_token_signing_alg_values_supported": ["RS256"] | ||
| } | ||
| EOF | ||
| echo hello I am login page >"$out/auth.txt" | ||
| ''; | ||
| }; | ||
| }; | ||
| }; | ||
|
|
||
| testScript = { ... }: '' | ||
| backend.wait_for_unit("nginx") | ||
| backend.wait_for_open_port(80) | ||
|
|
||
| pomerium.wait_for_unit("pomerium") | ||
| pomerium.wait_for_open_port(80) | ||
|
|
||
| with subtest("no authentication required"): | ||
| pomerium.succeed( | ||
| "curl --resolve my.website:80:127.0.0.1 http://my.website | grep -q 'hello world'" | ||
| ) | ||
|
|
||
| with subtest("login required"): | ||
| pomerium.succeed( | ||
| "curl -I --resolve login.required:80:127.0.0.1 http://login.required | grep -q pom-auth" | ||
| ) | ||
| pomerium.succeed( | ||
| "curl -L --resolve login.required:80:127.0.0.1 http://login.required | grep -q 'hello I am login page'" | ||
| ) | ||
| ''; | ||
| }) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| { buildGoModule | ||
| , fetchFromGitHub | ||
| , lib | ||
| , envoy | ||
| , zip | ||
| , nixosTests | ||
| }: | ||
|
|
||
| let | ||
| inherit (lib) concatStringsSep mapAttrsToList; | ||
| in | ||
| buildGoModule rec { | ||
| pname = "pomerium"; | ||
| version = "0.13.3"; | ||
| src = fetchFromGitHub { | ||
| owner = "pomerium"; | ||
| repo = "pomerium"; | ||
| rev = "v${version}"; | ||
| hash = "sha256-g0w1aIHvf2rJANvGWHeUxdnyCDsvy/PQ9Kp8nDdT/0w="; | ||
| }; | ||
|
|
||
| vendorSha256 = "sha256-grihU85OcGyf9/KKrv87xZonX5r+Z1oHQTf84Ya61fg="; | ||
| subPackages = [ | ||
| "cmd/pomerium" | ||
| "cmd/pomerium-cli" | ||
| ]; | ||
|
|
||
| buildFlagsArray = let | ||
| # Set a variety of useful meta variables for stamping the build with. | ||
| setVars = { | ||
| Version = "v${version}"; | ||
| BuildMeta = "nixpkgs"; | ||
| ProjectName = "pomerium"; | ||
| ProjectURL = "github.com/pomerium/pomerium"; | ||
| }; | ||
| varFlags = concatStringsSep " " (mapAttrsToList (name: value: "-X github.com/pomerium/pomerium/internal/version.${name}=${value}") setVars); | ||
| in [ | ||
| "-ldflags=${varFlags}" | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing -s -w.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't seem to be set in pkgs/development/go-modules/generic/default.nix as a default, so it's not like we're overriding it off, I think?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It probably does not work for every package. Should be set anyway when specifying ldflags.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe does not work with all packages. Should be set anyway when specifying ldflags. |
||
| ]; | ||
|
|
||
| nativeBuildInputs = [ | ||
| zip | ||
| ]; | ||
|
|
||
| # Pomerium expects to have envoy append to it in a zip. | ||
| # We use a store-only (-0) zip, so that the Nix scanner can find any store references we had in the envoy binary. | ||
| postBuild = '' | ||
| # Append Envoy | ||
| pushd $NIX_BUILD_TOP | ||
| mkdir -p envoy | ||
| cd envoy | ||
| cp ${envoy}/bin/envoy envoy | ||
| zip -0 envoy.zip envoy | ||
| popd | ||
|
|
||
| mv $GOPATH/bin/pomerium $GOPATH/bin/pomerium.old | ||
| cat $GOPATH/bin/pomerium.old $NIX_BUILD_TOP/envoy/envoy.zip >$GOPATH/bin/pomerium | ||
| zip --adjust-sfx $GOPATH/bin/pomerium | ||
| ''; | ||
|
|
||
| # We also need to set dontStrip to avoid having the envoy ZIP stripped off the end. | ||
| dontStrip = true; | ||
|
|
||
| installPhase = '' | ||
| install -Dm0755 $GOPATH/bin/pomerium $out/bin/pomerium | ||
| install -Dm0755 $GOPATH/bin/pomerium-cli $out/bin/pomerium-cli | ||
| ''; | ||
|
|
||
| passthru.tests = { | ||
| inherit (nixosTests) pomerium; | ||
| }; | ||
|
|
||
| meta = with lib; { | ||
| homepage = "https://pomerium.io"; | ||
| description = "Authenticating reverse proxy"; | ||
| license = licenses.asl20; | ||
| maintainers = with maintainers; [ lukegb ]; | ||
| platforms = [ "x86_64-linux" ]; # Envoy derivation is x86_64-linux only. | ||
| }; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the use of DynamicUser in the systemd config, what would be the proper way to secure a secrets file on the local filesystem from other users?