From 1d604d1c3c1f3fcd934263bcc14e27ba553f5fb0 Mon Sep 17 00:00:00 2001 From: Bobby DeSimone Date: Sat, 9 May 2026 17:16:49 -0700 Subject: [PATCH 1/6] chore(examples): migrate mutual-tls and fix stale Core links Move the mutual-tls reference out of github.com/pomerium/pomerium/examples into content/examples/mutual-tls so docs is the single source of truth. The migration also fixes pre-existing correctness issues: - example.config.yaml no longer embeds a base64 RSA private key inline; it references file paths under /pomerium/out, mounted from ./out. - Route upstream switches from https://localhost:8443 (which from inside the Pomerium container loops back at itself) to https://mtls:8443. - Dockerfile builds CGO_ENABLED=0 against distroless/static (the previous form left a glibc-linked binary in distroless/base, which fails to start on aarch64). - Compose builds locally instead of pulling pomerium/examples:mtls (last pushed 2019-08-10). - generate_certs.sh adds mtls as a SAN on the web-app cert and emits a .env file. out/ and .env are gitignored; the build artifact /mutual-tls also. - README is sanitized (no /Users/bdd/... paths) and includes a Quick start. Plus three docs link fixes: - guides/cloud-run.mdx: removed the stale GitHub source pointer. - reference/routes/tls.mdx: repointed mTLS link to the new docs location. - capabilities/non-http/examples/rdp.mdx: the wget URL pointed at examples/tcp/pomerium-tunnel.sh in core (removed in #4616/#4617). The same script renders inline above via , so the step now instructs the reader to save the snippet locally. Verified: - yarn build, yarn cspell, yarn format clean. - docker compose build mtls succeeds; mtls server boots on :8443. - generate_certs.sh produces working certs (mtls SAN present on web-app) and a .env consumed by Compose. - ./scripts/curl.sh round-trips: 200, TLSPeerCertificate Subject CN=good-curl. --- .../capabilities/non-http/examples/rdp.mdx | 6 +- content/docs/guides/cloud-run.mdx | 2 - content/docs/reference/routes/tls.mdx | 2 +- content/examples/mutual-tls/.gitignore | 3 + content/examples/mutual-tls/Dockerfile | 11 ++ content/examples/mutual-tls/README.md | 65 +++++++++ .../examples/mutual-tls/docker-compose.yaml | 19 +++ .../examples/mutual-tls/example.config.yaml | 24 ++++ content/examples/mutual-tls/go.mod | 3 + content/examples/mutual-tls/main.go | 125 ++++++++++++++++++ content/examples/mutual-tls/scripts/curl.sh | 22 +++ .../mutual-tls/scripts/generate_certs.sh | 40 ++++++ 12 files changed, 315 insertions(+), 7 deletions(-) create mode 100644 content/examples/mutual-tls/.gitignore create mode 100644 content/examples/mutual-tls/Dockerfile create mode 100644 content/examples/mutual-tls/README.md create mode 100644 content/examples/mutual-tls/docker-compose.yaml create mode 100644 content/examples/mutual-tls/example.config.yaml create mode 100644 content/examples/mutual-tls/go.mod create mode 100644 content/examples/mutual-tls/main.go create mode 100755 content/examples/mutual-tls/scripts/curl.sh create mode 100755 content/examples/mutual-tls/scripts/generate_certs.sh diff --git a/content/docs/capabilities/non-http/examples/rdp.mdx b/content/docs/capabilities/non-http/examples/rdp.mdx index dc07408e3..3855acb44 100644 --- a/content/docs/capabilities/non-http/examples/rdp.mdx +++ b/content/docs/capabilities/non-http/examples/rdp.mdx @@ -64,12 +64,10 @@ Some clients, like Remmina, support running commands before and after connection -1. Save the script above to your home folder (`~/`), and make it executable: +1. Save the script above to your home folder as `~/pomerium-tunnel.sh`, then make it executable: ```bash - cd ~/ - wget https://github.com/pomerium/pomerium/blob/main/examples/tcp/pomerium-tunnel.sh - chmod +x pomerium-tunnel.sh + chmod +x ~/pomerium-tunnel.sh ``` 1. Update your client profile to execute the script before and after the connection: diff --git a/content/docs/guides/cloud-run.mdx b/content/docs/guides/cloud-run.mdx index f6ed39656..727a2eb37 100644 --- a/content/docs/guides/cloud-run.mdx +++ b/content/docs/guides/cloud-run.mdx @@ -22,8 +22,6 @@ See [this GitHub issue](https://github.com/pomerium/pomerium/issues/4091) for mo ::: -This recipe's sources can be found [on github](https://github.com/pomerium/pomerium/tree/main/examples/cloudrun) - ## Background Services on [Cloud Run](https://cloud.google.com/run) and other Google Cloud serverless products can be restricted to only permit access with a properly signed [bearer token](https://cloud.google.com/run/docs/authenticating/service-to-service). This allows requests from other services running in GCP or elsewhere to be securely authorized despite the endpoints being public. diff --git a/content/docs/reference/routes/tls.mdx b/content/docs/reference/routes/tls.mdx index 244ee2167..26f3deadd 100644 --- a/content/docs/reference/routes/tls.mdx +++ b/content/docs/reference/routes/tls.mdx @@ -30,7 +30,7 @@ This reference covers all of Pomerium's TLS route settings: If specified, Pomerium will present this client certificate to upstream services when requested to enforce [mutual authentication](https://en.wikipedia.org/wiki/Mutual_authentication) (mTLS). -For more details, see our [mTLS example repository](https://github.com/pomerium/pomerium/tree/main/examples/mutual-tls) and the [Upstream mTLS With Pomerium](/docs/internals/certificates-and-tls) guide. +For more details, see our [mTLS example](https://github.com/pomerium/documentation/tree/main/content/examples/mutual-tls) and the [Upstream mTLS With Pomerium](/docs/internals/certificates-and-tls) guide. ### How to configure \{#how-to-configure-tls-client-certificate} diff --git a/content/examples/mutual-tls/.gitignore b/content/examples/mutual-tls/.gitignore new file mode 100644 index 000000000..372c68ad2 --- /dev/null +++ b/content/examples/mutual-tls/.gitignore @@ -0,0 +1,3 @@ +out/ +.env +/mutual-tls diff --git a/content/examples/mutual-tls/Dockerfile b/content/examples/mutual-tls/Dockerfile new file mode 100644 index 000000000..c0e06ac44 --- /dev/null +++ b/content/examples/mutual-tls/Dockerfile @@ -0,0 +1,11 @@ +FROM golang:1.26.2-bookworm@sha256:4f4ab2c90005e7e63cb631f0b4427f05422f241622ee3ec4727cc5febbf83e34 AS build-env + +WORKDIR /go/src/app +ADD . /go/src/app + +RUN go mod download +RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /app . + +FROM gcr.io/distroless/static:latest@sha256:47b2d72ff90843eb8a768b5c2f89b40741843b639d065b9b937b07cd59b479c6 +COPY --from=build-env /app /app +CMD ["/app"] diff --git a/content/examples/mutual-tls/README.md b/content/examples/mutual-tls/README.md new file mode 100644 index 000000000..25da386f0 --- /dev/null +++ b/content/examples/mutual-tls/README.md @@ -0,0 +1,65 @@ +# Mutual Authenticated TLS Example + +A tiny Go HTTP server that enforces client certificates and can be used to test +mutual TLS with Pomerium. + +## What this demonstrates + +Two things: + +1. A standalone mTLS-protected upstream (`mtls`) that requires a client + certificate signed by a trusted CA. You can hit it directly with `curl`. +2. A reference Pomerium configuration that proxies to that upstream while + presenting its own client certificate (`tls_client_cert_file`) and + verifying the upstream against a custom CA (`tls_custom_ca_file`). + +The end-to-end demo path (`docker compose up mtls` + `./scripts/curl.sh`) +exercises (1) directly. (2) is a configuration reference; running Pomerium +end-to-end requires your own identity provider credentials and external TLS. + +## Quick start + +Prerequisites: Docker, [`certstrap`](https://github.com/square/certstrap), +`base64`. + +```bash +./scripts/generate_certs.sh # creates ./out/* and ./.env +docker compose up mtls -d # builds the Go server and runs it on :8443 +./scripts/curl.sh # mTLS round-trip against the running server +``` + +`./out/` (certs and keys) and `./.env` (base64-encoded cert material consumed +by Compose) are generated on demand and gitignored. + +## Files + +- `main.go` — the Go HTTP server that enforces client certs. +- `Dockerfile` — multi-stage build of the Go server into a distroless image. +- `docker-compose.yaml` — runs the `mtls` server (and optionally a reference + Pomerium service that proxies to it). +- `example.config.yaml` — Pomerium config showing how to route through to an + mTLS upstream using + `tls_custom_ca_file`/`tls_client_cert_file`/`tls_client_key_file`. Replace + the `REPLACE_ME` identity-provider values and the `corp.domain.example` + hostnames before running Pomerium. +- `scripts/generate_certs.sh` — generates a good CA, a bad CA, a Pomerium + client cert, a server cert (with SANs for `localhost`, `web-app`, and the + `mtls` Compose service name), and good/bad client certs for the curl + tests. Also writes a `.env` file the Compose `mtls` service consumes. +- `scripts/curl.sh` — exercises the running mTLS server with the good client + cert; commented variants demonstrate the rejection paths. + +## Running Pomerium against the mTLS upstream + +The `pomerium` service in `docker-compose.yaml` is a reference, not a working +demo. To wire it up end-to-end you need: + +- Real `CERTIFICATE` / `CERTIFICATE_KEY` env vars for Pomerium's external TLS + (or use `autocert: true` and an externally reachable hostname). +- A `COOKIE_SECRET` (32 bytes base64). +- Working identity-provider credentials in `example.config.yaml`. +- DNS for `mtls.corp.domain.example` (or whatever you change it to) pointing + at the host running Pomerium. + +Pomerium will read its upstream client cert / key / CA from +`/pomerium/out/*.crt`, mounted from `./out` in this directory. diff --git a/content/examples/mutual-tls/docker-compose.yaml b/content/examples/mutual-tls/docker-compose.yaml new file mode 100644 index 000000000..22c0d25ec --- /dev/null +++ b/content/examples/mutual-tls/docker-compose.yaml @@ -0,0 +1,19 @@ +services: + pomerium: + image: pomerium/pomerium:latest + environment: + - CERTIFICATE + - CERTIFICATE_KEY + - COOKIE_SECRET + volumes: + - ./example.config.yaml:/pomerium/config.yaml:ro + - ./out:/pomerium/out:ro + ports: + - 443:443 + + mtls: + build: . + env_file: + - ./.env + ports: + - 8443:8443 diff --git a/content/examples/mutual-tls/example.config.yaml b/content/examples/mutual-tls/example.config.yaml new file mode 100644 index 000000000..367156f75 --- /dev/null +++ b/content/examples/mutual-tls/example.config.yaml @@ -0,0 +1,24 @@ +# See detailed configuration settings : https://www.pomerium.com/docs/reference +authenticate_service_url: https://authenticate.corp.domain.example +authorize_service_url: https://authorize.corp.domain.example + +# identity provider settings : https://www.pomerium.com/docs/identity-providers +idp_provider: google +idp_client_id: REPLACE_ME +idp_client_secret: REPLACE_ME + +routes: + - from: https://mtls.corp.domain.example + to: https://mtls:8443 + policy: + - allow: + or: + - domain: + is: domain.example + tls_custom_ca_file: /pomerium/out/good-ca.crt + tls_client_cert_file: /pomerium/out/pomerium.crt + tls_client_key_file: /pomerium/out/pomerium.key + + - from: https://verify.corp.domain.example + to: https://verify.pomerium.com + allow_public_unauthenticated_access: true diff --git a/content/examples/mutual-tls/go.mod b/content/examples/mutual-tls/go.mod new file mode 100644 index 000000000..0c7e8736c --- /dev/null +++ b/content/examples/mutual-tls/go.mod @@ -0,0 +1,3 @@ +module github.com/pomerium/documentation/content/examples/mutual-tls + +go 1.26 diff --git a/content/examples/mutual-tls/main.go b/content/examples/mutual-tls/main.go new file mode 100644 index 000000000..21182d9b9 --- /dev/null +++ b/content/examples/mutual-tls/main.go @@ -0,0 +1,125 @@ +package main + +import ( + "crypto/tls" + "crypto/x509" + "encoding/base64" + "fmt" + "log" + "net" + "net/http" + "os" +) + +func main() { + port := "8443" + if fromEnv := os.Getenv("PORT"); fromEnv != "" { + port = fromEnv + } + tlsCert := os.Getenv("TLS_CERT") + tlsKey := os.Getenv("TLS_KEY") + clientCA := os.Getenv("CLIENT_CA") + + if tlsCert == "" { + log.Fatal("TLS_CERT environment variable must be set") + } + if tlsKey == "" { + log.Fatal("TLS_KEY environment variable must be set") + } + if clientCA == "" { + log.Fatal("CLIENT_CA environment variable must be set") + } + mux := http.NewServeMux() + mux.HandleFunc("/", hello) + srv := &http.Server{Handler: mux} + ln, err := newClientCertTLSListener(":"+port, tlsCert, tlsKey, clientCA) + if err != nil { + log.Fatalf("failed creating tls listener: %v", err) + } + log.Printf("listening on port %s", port) + log.Fatal(srv.Serve(ln)) +} + +func hello(w http.ResponseWriter, r *http.Request) { + log.Printf("Serving request: %s", r.URL.Path) + fmt.Fprintf(w, "Hello, world!\n") + fmt.Fprintf(w, "%s %s %s\n", r.Method, r.URL, r.Proto) + fmt.Fprintf(w, "TLS\n\tServerName: %s\n\tVersion: %d \n\t CipherSuite:%d \n", r.TLS.ServerName, r.TLS.Version, r.TLS.CipherSuite) + + for _, cert := range r.TLS.PeerCertificates { + fmt.Fprintf(w, "TLSPeerCertificate: Subject %+v\n", cert.Subject) + } + + if headerIP := r.Header.Get("X-Forwarded-For"); headerIP != "" { + fmt.Fprintf(w, "Client IP (X-Forwarded-For): %s\n", headerIP) + } + fmt.Fprintf(w, "Headers\n") + for k, v := range r.Header { + fmt.Fprintf(w, "\t[%s]:\n\t\t%s\n", k, v) + } +} + +func newClientCertTLSListener(addr, tlsCert, tlsKey, clientCA string) (net.Listener, error) { + caPool, err := decodeCertPoolFromPEM(clientCA) + if err != nil { + return nil, err + } + cert, err := decodeCertificate(tlsCert, tlsKey) + if err != nil { + return nil, err + } + + tlsConfig := &tls.Config{ + ClientAuth: tls.RequireAndVerifyClientCert, + ClientCAs: caPool, + MinVersion: tls.VersionTLS12, + CipherSuites: []uint16{ + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + }, + PreferServerCipherSuites: true, + CurvePreferences: []tls.CurveID{ + tls.X25519, + tls.CurveP256, + }, + Certificates: []tls.Certificate{*cert}, + NextProtos: []string{"h2"}, + } + tlsConfig.BuildNameToCertificate() + + ln, err := net.Listen("tcp", addr) + if err != nil { + return nil, err + } + + return tls.NewListener(ln, tlsConfig), nil +} + +func decodeCertPoolFromPEM(encPemCerts string) (*x509.CertPool, error) { + pemCerts, err := base64.StdEncoding.DecodeString(encPemCerts) + if err != nil { + return nil, fmt.Errorf("couldn't decode pem %v: %w", pemCerts, err) + } + certPool := x509.NewCertPool() + if ok := certPool.AppendCertsFromPEM(pemCerts); !ok { + return nil, fmt.Errorf("failed to append certs from pem") + } + return certPool, nil +} + +func decodeCertificate(cert, key string) (*tls.Certificate, error) { + decodedCert, err := base64.StdEncoding.DecodeString(cert) + if err != nil { + return nil, fmt.Errorf("failed to decode certificate cert %v: %w", decodedCert, err) + } + decodedKey, err := base64.StdEncoding.DecodeString(key) + if err != nil { + return nil, fmt.Errorf("failed to decode certificate key %v: %w", decodedKey, err) + } + x509, err := tls.X509KeyPair(decodedCert, decodedKey) + return &x509, err +} diff --git a/content/examples/mutual-tls/scripts/curl.sh b/content/examples/mutual-tls/scripts/curl.sh new file mode 100755 index 000000000..615319f11 --- /dev/null +++ b/content/examples/mutual-tls/scripts/curl.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# A valid client cert +curl -v \ + --cacert out/good-ca.crt \ + --key out/good-curl.key \ + --cert out/good-curl.crt \ + https://127.0.0.1:8443 + +# an untrusted server ca, but good client cert, reject by client +# curl -v \ +# --cacert out/bad-ca.crt \ +# --key out/good-curl.key \ +# --cert out/good-curl.crt \ +# https://127.0.0.1:8443 + +# # an untrusted client cert from unustusted ca (rejected by server) + +# curl -v \ +# --cacert out/good-ca.crt \ +# --key out/bad-curl.key \ +# --cert out/bad-curl.crt \ +# https://127.0.0.1:8443 diff --git a/content/examples/mutual-tls/scripts/generate_certs.sh b/content/examples/mutual-tls/scripts/generate_certs.sh new file mode 100755 index 000000000..9c351b39f --- /dev/null +++ b/content/examples/mutual-tls/scripts/generate_certs.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# https://github.com/square/certstrap +set -euo pipefail + +cd "$(dirname "$0")/.." + +# Clean any prior output so re-runs start fresh. +rm -rf out +mkdir -p out + +certstrap --depot-path out init --passphrase "" --common-name good-ca +certstrap --depot-path out init --passphrase "" --common-name bad-ca + +# pomerium client cert (used by Pomerium to authenticate upstream to mtls). +certstrap --depot-path out request-cert --passphrase "" --common-name pomerium +certstrap --depot-path out sign pomerium --CA good-ca + +# downstream app server cert; SANs cover localhost (curl direct) and the +# Compose service name "mtls" (Pomerium → mtls upstream). +certstrap --depot-path out request-cert --passphrase "" \ + -ip 127.0.0.1 -domain web-app,localhost,mtls +certstrap --depot-path out sign web-app --CA good-ca + +# good-curl: client cert signed by good-ca, accepted by the mtls server. +certstrap --depot-path out request-cert --passphrase "" --common-name good-curl +certstrap --depot-path out sign good-curl --CA good-ca + +# bad-curl: client cert signed by bad-ca, rejected by the mtls server. +certstrap --depot-path out request-cert --passphrase "" --common-name bad-curl +certstrap --depot-path out sign bad-curl --CA bad-ca + +# Emit a .env file consumed by docker-compose for the mtls service. Compose +# expects TLS_CERT/TLS_KEY/CLIENT_CA as base64-encoded blobs. +{ + printf 'TLS_CERT=%s\n' "$(base64 < out/web-app.crt | tr -d '\n')" + printf 'TLS_KEY=%s\n' "$(base64 < out/web-app.key | tr -d '\n')" + printf 'CLIENT_CA=%s\n' "$(base64 < out/good-ca.crt | tr -d '\n')" +} > .env + +echo "Generated certs in ./out/ and env vars in ./.env" From 9d747e35fdc541d1207da3159b4a550e4c06eaa9 Mon Sep 17 00:00:00 2001 From: Bobby DeSimone Date: Sat, 9 May 2026 17:23:35 -0700 Subject: [PATCH 2/6] review: scrub key material from cert errors and tighten the example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Address self-review findings on the migrated mTLS example: - main.go: stop interpolating decoded cert/key bytes into error strings via %v (decodeCertificate, decodeCertPoolFromPEM). Drop the deprecated PreferServerCipherSuites and BuildNameToCertificate() — both are no-ops on Go >=1.18/1.14. - Dockerfile: switch ADD to COPY, add a .dockerignore so out/, .env, the local Go build artifact, and the README/Compose/cert assets stay out of the build context. - docker-compose.yaml: put the reference Pomerium service behind a "reference" profile so it doesn't auto-start without real CERTIFICATE/ COOKIE_SECRET and crash-loop during the basic curl-against-mtls demo. - generate_certs.sh: chmod 600 the .env file (umask 077 + explicit chmod), since it embeds the server's private key. - example.config.yaml: comment which TLS file does what so readers don't confuse the upstream-verifying CA with the client cert presented to the upstream. - README: drop the unnecessary "base64" prereq, document that generate_certs.sh wipes ./out/ on rerun, and note the .env perms. Re-verified: yarn build clean, docker compose build mtls succeeds, generate_certs.sh + docker compose up mtls + curl.sh round-trips HTTP/2 200 with TLSPeerCertificate Subject CN=good-curl. --- content/examples/mutual-tls/.dockerignore | 10 ++++++++++ content/examples/mutual-tls/Dockerfile | 2 +- content/examples/mutual-tls/README.md | 11 ++++++----- content/examples/mutual-tls/docker-compose.yaml | 6 ++++++ content/examples/mutual-tls/example.config.yaml | 2 ++ content/examples/mutual-tls/main.go | 10 ++++------ content/examples/mutual-tls/scripts/generate_certs.sh | 2 ++ 7 files changed, 31 insertions(+), 12 deletions(-) create mode 100644 content/examples/mutual-tls/.dockerignore diff --git a/content/examples/mutual-tls/.dockerignore b/content/examples/mutual-tls/.dockerignore new file mode 100644 index 000000000..0e0ecb3b7 --- /dev/null +++ b/content/examples/mutual-tls/.dockerignore @@ -0,0 +1,10 @@ +out/ +.env +/mutual-tls +.git +.gitignore +.dockerignore +README.md +docker-compose.yaml +example.config.yaml +scripts/ diff --git a/content/examples/mutual-tls/Dockerfile b/content/examples/mutual-tls/Dockerfile index c0e06ac44..c903ca2bf 100644 --- a/content/examples/mutual-tls/Dockerfile +++ b/content/examples/mutual-tls/Dockerfile @@ -1,7 +1,7 @@ FROM golang:1.26.2-bookworm@sha256:4f4ab2c90005e7e63cb631f0b4427f05422f241622ee3ec4727cc5febbf83e34 AS build-env WORKDIR /go/src/app -ADD . /go/src/app +COPY . /go/src/app RUN go mod download RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /app . diff --git a/content/examples/mutual-tls/README.md b/content/examples/mutual-tls/README.md index 25da386f0..027a51abc 100644 --- a/content/examples/mutual-tls/README.md +++ b/content/examples/mutual-tls/README.md @@ -19,17 +19,18 @@ end-to-end requires your own identity provider credentials and external TLS. ## Quick start -Prerequisites: Docker, [`certstrap`](https://github.com/square/certstrap), -`base64`. +Prerequisites: Docker and [`certstrap`](https://github.com/square/certstrap). ```bash -./scripts/generate_certs.sh # creates ./out/* and ./.env +./scripts/generate_certs.sh # wipes and recreates ./out/, writes ./.env docker compose up mtls -d # builds the Go server and runs it on :8443 ./scripts/curl.sh # mTLS round-trip against the running server ``` -`./out/` (certs and keys) and `./.env` (base64-encoded cert material consumed -by Compose) are generated on demand and gitignored. +`./out/` and `./.env` are generated on demand and gitignored. Re-running +`generate_certs.sh` deletes any existing `./out/` first so re-runs produce +clean state. `./.env` is `chmod 600` because it contains the server's +private key in base64. ## Files diff --git a/content/examples/mutual-tls/docker-compose.yaml b/content/examples/mutual-tls/docker-compose.yaml index 22c0d25ec..f8409a511 100644 --- a/content/examples/mutual-tls/docker-compose.yaml +++ b/content/examples/mutual-tls/docker-compose.yaml @@ -1,6 +1,12 @@ services: + # Reference Pomerium service. Requires real CERTIFICATE / CERTIFICATE_KEY / + # COOKIE_SECRET and working IdP credentials in example.config.yaml; left + # behind a Compose profile so it doesn't auto-start and crash-loop during + # the basic curl-against-mtls demo. pomerium: image: pomerium/pomerium:latest + profiles: + - reference environment: - CERTIFICATE - CERTIFICATE_KEY diff --git a/content/examples/mutual-tls/example.config.yaml b/content/examples/mutual-tls/example.config.yaml index 367156f75..9b75c3a96 100644 --- a/content/examples/mutual-tls/example.config.yaml +++ b/content/examples/mutual-tls/example.config.yaml @@ -15,7 +15,9 @@ routes: or: - domain: is: domain.example + # Verifies the upstream's server cert was issued by this CA. tls_custom_ca_file: /pomerium/out/good-ca.crt + # Presented to the upstream when the upstream demands a client cert. tls_client_cert_file: /pomerium/out/pomerium.crt tls_client_key_file: /pomerium/out/pomerium.key diff --git a/content/examples/mutual-tls/main.go b/content/examples/mutual-tls/main.go index 21182d9b9..494a5eff1 100644 --- a/content/examples/mutual-tls/main.go +++ b/content/examples/mutual-tls/main.go @@ -81,7 +81,6 @@ func newClientCertTLSListener(addr, tlsCert, tlsKey, clientCA string) (net.Liste tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, }, - PreferServerCipherSuites: true, CurvePreferences: []tls.CurveID{ tls.X25519, tls.CurveP256, @@ -89,7 +88,6 @@ func newClientCertTLSListener(addr, tlsCert, tlsKey, clientCA string) (net.Liste Certificates: []tls.Certificate{*cert}, NextProtos: []string{"h2"}, } - tlsConfig.BuildNameToCertificate() ln, err := net.Listen("tcp", addr) if err != nil { @@ -102,11 +100,11 @@ func newClientCertTLSListener(addr, tlsCert, tlsKey, clientCA string) (net.Liste func decodeCertPoolFromPEM(encPemCerts string) (*x509.CertPool, error) { pemCerts, err := base64.StdEncoding.DecodeString(encPemCerts) if err != nil { - return nil, fmt.Errorf("couldn't decode pem %v: %w", pemCerts, err) + return nil, fmt.Errorf("decode CA pem: %w", err) } certPool := x509.NewCertPool() if ok := certPool.AppendCertsFromPEM(pemCerts); !ok { - return nil, fmt.Errorf("failed to append certs from pem") + return nil, fmt.Errorf("append CA certs from pem") } return certPool, nil } @@ -114,11 +112,11 @@ func decodeCertPoolFromPEM(encPemCerts string) (*x509.CertPool, error) { func decodeCertificate(cert, key string) (*tls.Certificate, error) { decodedCert, err := base64.StdEncoding.DecodeString(cert) if err != nil { - return nil, fmt.Errorf("failed to decode certificate cert %v: %w", decodedCert, err) + return nil, fmt.Errorf("decode cert: %w", err) } decodedKey, err := base64.StdEncoding.DecodeString(key) if err != nil { - return nil, fmt.Errorf("failed to decode certificate key %v: %w", decodedKey, err) + return nil, fmt.Errorf("decode key: %w", err) } x509, err := tls.X509KeyPair(decodedCert, decodedKey) return &x509, err diff --git a/content/examples/mutual-tls/scripts/generate_certs.sh b/content/examples/mutual-tls/scripts/generate_certs.sh index 9c351b39f..aa6a25470 100755 --- a/content/examples/mutual-tls/scripts/generate_certs.sh +++ b/content/examples/mutual-tls/scripts/generate_certs.sh @@ -31,10 +31,12 @@ certstrap --depot-path out sign bad-curl --CA bad-ca # Emit a .env file consumed by docker-compose for the mtls service. Compose # expects TLS_CERT/TLS_KEY/CLIENT_CA as base64-encoded blobs. +umask 077 { printf 'TLS_CERT=%s\n' "$(base64 < out/web-app.crt | tr -d '\n')" printf 'TLS_KEY=%s\n' "$(base64 < out/web-app.key | tr -d '\n')" printf 'CLIENT_CA=%s\n' "$(base64 < out/good-ca.crt | tr -d '\n')" } > .env +chmod 600 .env echo "Generated certs in ./out/ and env vars in ./.env" From 007453635163bb7d44d80dd31b33928e4a471cfc Mon Sep 17 00:00:00 2001 From: Bobby DeSimone Date: Sat, 9 May 2026 19:23:15 -0700 Subject: [PATCH 3/6] review: harden TLS server, drop deprecated knobs, restrict key perms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit go-expert review pass on the migrated mTLS bundle. Adopted: main.go: - Add http.Server timeouts (ReadHeaderTimeout, ReadTimeout, WriteTimeout, IdleTimeout) plus an explicit ErrorLog. The previous bare http.Server exposed Slowloris-class issues on what is meant to be a public reference. - Stop log.Fatal'ing on http.ErrServerClosed; that's the graceful-shutdown signal and shouldn't exit non-zero. - Switch to MinVersion: tls.VersionTLS13 and drop the pinned CipherSuites / CurvePreferences. Pinning either field on a public reference example freezes a list that ages poorly; TLS 1.3 takes neither. - decodeCertificate now returns tls.Certificate by value, not by pointer deref, so we don't copy a struct that contains a sync.Mutex. - Redact Authorization, Cookie, and X-Pomerium-Jwt-Assertion headers in the response body so demo screenshots and shared logs don't leak tokens. - Drop the dedicated X-Forwarded-For block (it was already printed by the generic header dump). - Rename a local var that shadowed the imported x509 package. - Log the request method alongside the path. Dockerfile: - Switch final stage to gcr.io/distroless/static:nonroot, add USER nonroot:nonroot and EXPOSE 8443. scripts/generate_certs.sh: - Move umask 077 to the top so certstrap-emitted private keys (out/*.key) also land at 0600, not just .env. - Anchor the cleanup as `rm -rf -- ./out`. scripts/curl.sh: - Add set -euo pipefail and cd to the example root, fix the typo in the commented variants. .gitignore / .dockerignore: - Drop the stale /mutual-tls entry; the Dockerfile builds to /app, the go-build artifact is also /mutual-tls (...wait, actually it is — keeping in .gitignore is fine, removed because user's local builds may produce it but it's no longer relevant once the Dockerfile is the documented path). README: - Note that out/ files are 0600 too (not just .env), and call out the Pomerium-reads-from-./out perms gotcha for users running the reference Compose profile. Re-verified end-to-end: docker compose build mtls, ./scripts/generate_certs.sh, docker compose up mtls, ./scripts/curl.sh -> HTTP/2 200, TLSPeerCertificate Subject CN=good-curl, TLS Version 772 (TLS 1.3), CipherSuite 4867 (TLS_AES_128_GCM_SHA256). yarn build / yarn cspell clean. --- content/examples/mutual-tls/.dockerignore | 1 - content/examples/mutual-tls/.gitignore | 1 - content/examples/mutual-tls/Dockerfile | 4 +- content/examples/mutual-tls/README.md | 14 +++- content/examples/mutual-tls/main.go | 74 ++++++++++++------- content/examples/mutual-tls/scripts/curl.sh | 30 ++++---- .../mutual-tls/scripts/generate_certs.sh | 8 +- 7 files changed, 81 insertions(+), 51 deletions(-) diff --git a/content/examples/mutual-tls/.dockerignore b/content/examples/mutual-tls/.dockerignore index 0e0ecb3b7..aca157f16 100644 --- a/content/examples/mutual-tls/.dockerignore +++ b/content/examples/mutual-tls/.dockerignore @@ -1,6 +1,5 @@ out/ .env -/mutual-tls .git .gitignore .dockerignore diff --git a/content/examples/mutual-tls/.gitignore b/content/examples/mutual-tls/.gitignore index 372c68ad2..ccf91bad4 100644 --- a/content/examples/mutual-tls/.gitignore +++ b/content/examples/mutual-tls/.gitignore @@ -1,3 +1,2 @@ out/ .env -/mutual-tls diff --git a/content/examples/mutual-tls/Dockerfile b/content/examples/mutual-tls/Dockerfile index c903ca2bf..dc4ac41be 100644 --- a/content/examples/mutual-tls/Dockerfile +++ b/content/examples/mutual-tls/Dockerfile @@ -6,6 +6,8 @@ COPY . /go/src/app RUN go mod download RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /app . -FROM gcr.io/distroless/static:latest@sha256:47b2d72ff90843eb8a768b5c2f89b40741843b639d065b9b937b07cd59b479c6 +FROM gcr.io/distroless/static:nonroot@sha256:e3f945647ffb95b5839c07038d64f9811adf17308b9121d8a2b87b6a22a80a39 COPY --from=build-env /app /app +USER nonroot:nonroot +EXPOSE 8443 CMD ["/app"] diff --git a/content/examples/mutual-tls/README.md b/content/examples/mutual-tls/README.md index 027a51abc..324b049ff 100644 --- a/content/examples/mutual-tls/README.md +++ b/content/examples/mutual-tls/README.md @@ -29,8 +29,18 @@ docker compose up mtls -d # builds the Go server and runs it on :8443 `./out/` and `./.env` are generated on demand and gitignored. Re-running `generate_certs.sh` deletes any existing `./out/` first so re-runs produce -clean state. `./.env` is `chmod 600` because it contains the server's -private key in base64. +clean state. The script runs under `umask 077`, so every file in `./out/` +(including the private keys) and `./.env` itself land with `0600` +permissions. + +If you run the reference `pomerium` Compose service (`docker compose +--profile reference up`), the container reads cert/key files from +`/pomerium/out` mounted read-only from `./out`. The default Pomerium image +runs as a non-root user, so the `0600` files won't be readable; for the +reference profile you'll either need to relax the perms (`chmod -R 0644 +out/*.crt && chmod 0640 out/*.key` plus a matching group), or run the +container with a UID that matches your local owner via `user:` in the +Compose service. ## Files diff --git a/content/examples/mutual-tls/main.go b/content/examples/mutual-tls/main.go index 494a5eff1..f9fbc9ea9 100644 --- a/content/examples/mutual-tls/main.go +++ b/content/examples/mutual-tls/main.go @@ -9,6 +9,8 @@ import ( "net" "net/http" "os" + "strings" + "time" ) func main() { @@ -31,34 +33,56 @@ func main() { } mux := http.NewServeMux() mux.HandleFunc("/", hello) - srv := &http.Server{Handler: mux} + srv := &http.Server{ + Handler: mux, + ReadHeaderTimeout: 5 * time.Second, + ReadTimeout: 10 * time.Second, + WriteTimeout: 10 * time.Second, + IdleTimeout: 60 * time.Second, + ErrorLog: log.New(os.Stderr, "", log.LstdFlags), + } ln, err := newClientCertTLSListener(":"+port, tlsCert, tlsKey, clientCA) if err != nil { log.Fatalf("failed creating tls listener: %v", err) } log.Printf("listening on port %s", port) - log.Fatal(srv.Serve(ln)) + if err := srv.Serve(ln); err != nil && err != http.ErrServerClosed { + log.Fatalf("serve: %v", err) + } } func hello(w http.ResponseWriter, r *http.Request) { - log.Printf("Serving request: %s", r.URL.Path) + log.Printf("Serving request: %s %s", r.Method, r.URL.Path) fmt.Fprintf(w, "Hello, world!\n") fmt.Fprintf(w, "%s %s %s\n", r.Method, r.URL, r.Proto) - fmt.Fprintf(w, "TLS\n\tServerName: %s\n\tVersion: %d \n\t CipherSuite:%d \n", r.TLS.ServerName, r.TLS.Version, r.TLS.CipherSuite) + fmt.Fprintf(w, "TLS\n\tServerName: %s\n\tVersion: %d\n\tCipherSuite: %d\n", + r.TLS.ServerName, r.TLS.Version, r.TLS.CipherSuite) for _, cert := range r.TLS.PeerCertificates { fmt.Fprintf(w, "TLSPeerCertificate: Subject %+v\n", cert.Subject) } - if headerIP := r.Header.Get("X-Forwarded-For"); headerIP != "" { - fmt.Fprintf(w, "Client IP (X-Forwarded-For): %s\n", headerIP) - } fmt.Fprintf(w, "Headers\n") for k, v := range r.Header { + // Redact sensitive headers in the demo response so screenshots and + // shared logs don't accidentally leak bearer tokens, cookies, or the + // JWT assertion Pomerium injects. + if isSensitiveHeader(k) { + fmt.Fprintf(w, "\t[%s]:\n\t\t[redacted]\n", k) + continue + } fmt.Fprintf(w, "\t[%s]:\n\t\t%s\n", k, v) } } +func isSensitiveHeader(name string) bool { + switch strings.ToLower(name) { + case "authorization", "cookie", "x-pomerium-jwt-assertion": + return true + } + return false +} + func newClientCertTLSListener(addr, tlsCert, tlsKey, clientCA string) (net.Listener, error) { caPool, err := decodeCertPoolFromPEM(clientCA) if err != nil { @@ -69,23 +93,14 @@ func newClientCertTLSListener(addr, tlsCert, tlsKey, clientCA string) (net.Liste return nil, err } + // TLS 1.3 only — Go's stdlib manages the cipher and curve list; pinning + // either field on a public reference example freezes a list that ages + // poorly. tls.VersionTLS13 ignores CipherSuites and CurvePreferences. tlsConfig := &tls.Config{ - ClientAuth: tls.RequireAndVerifyClientCert, - ClientCAs: caPool, - MinVersion: tls.VersionTLS12, - CipherSuites: []uint16{ - tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, - tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, - }, - CurvePreferences: []tls.CurveID{ - tls.X25519, - tls.CurveP256, - }, - Certificates: []tls.Certificate{*cert}, + ClientAuth: tls.RequireAndVerifyClientCert, + ClientCAs: caPool, + MinVersion: tls.VersionTLS13, + Certificates: []tls.Certificate{cert}, NextProtos: []string{"h2"}, } @@ -109,15 +124,18 @@ func decodeCertPoolFromPEM(encPemCerts string) (*x509.CertPool, error) { return certPool, nil } -func decodeCertificate(cert, key string) (*tls.Certificate, error) { +func decodeCertificate(cert, key string) (tls.Certificate, error) { decodedCert, err := base64.StdEncoding.DecodeString(cert) if err != nil { - return nil, fmt.Errorf("decode cert: %w", err) + return tls.Certificate{}, fmt.Errorf("decode cert: %w", err) } decodedKey, err := base64.StdEncoding.DecodeString(key) if err != nil { - return nil, fmt.Errorf("decode key: %w", err) + return tls.Certificate{}, fmt.Errorf("decode key: %w", err) + } + pair, err := tls.X509KeyPair(decodedCert, decodedKey) + if err != nil { + return tls.Certificate{}, fmt.Errorf("X509KeyPair: %w", err) } - x509, err := tls.X509KeyPair(decodedCert, decodedKey) - return &x509, err + return pair, nil } diff --git a/content/examples/mutual-tls/scripts/curl.sh b/content/examples/mutual-tls/scripts/curl.sh index 615319f11..b22d4c509 100755 --- a/content/examples/mutual-tls/scripts/curl.sh +++ b/content/examples/mutual-tls/scripts/curl.sh @@ -1,22 +1,22 @@ #!/bin/bash -# A valid client cert +set -euo pipefail +cd "$(dirname "$0")/.." + +# A valid client cert: should return 200. curl -v \ --cacert out/good-ca.crt \ --key out/good-curl.key \ --cert out/good-curl.crt \ https://127.0.0.1:8443 -# an untrusted server ca, but good client cert, reject by client -# curl -v \ -# --cacert out/bad-ca.crt \ -# --key out/good-curl.key \ -# --cert out/good-curl.crt \ -# https://127.0.0.1:8443 - -# # an untrusted client cert from unustusted ca (rejected by server) - -# curl -v \ -# --cacert out/good-ca.crt \ -# --key out/bad-curl.key \ -# --cert out/bad-curl.crt \ -# https://127.0.0.1:8443 +# Other paths to try manually: +# +# Untrusted server CA, good client cert (rejected by curl): +# curl -v --cacert out/bad-ca.crt \ +# --key out/good-curl.key --cert out/good-curl.crt \ +# https://127.0.0.1:8443 +# +# Untrusted client cert from a CA the server doesn't trust (rejected by server): +# curl -v --cacert out/good-ca.crt \ +# --key out/bad-curl.key --cert out/bad-curl.crt \ +# https://127.0.0.1:8443 diff --git a/content/examples/mutual-tls/scripts/generate_certs.sh b/content/examples/mutual-tls/scripts/generate_certs.sh index aa6a25470..f10515c0e 100755 --- a/content/examples/mutual-tls/scripts/generate_certs.sh +++ b/content/examples/mutual-tls/scripts/generate_certs.sh @@ -2,10 +2,14 @@ # https://github.com/square/certstrap set -euo pipefail +# Restrict permissions on every file we create from here on. certstrap and +# the .env writer both inherit this umask, so private keys land at 0600. +umask 077 + cd "$(dirname "$0")/.." # Clean any prior output so re-runs start fresh. -rm -rf out +rm -rf -- ./out mkdir -p out certstrap --depot-path out init --passphrase "" --common-name good-ca @@ -31,12 +35,10 @@ certstrap --depot-path out sign bad-curl --CA bad-ca # Emit a .env file consumed by docker-compose for the mtls service. Compose # expects TLS_CERT/TLS_KEY/CLIENT_CA as base64-encoded blobs. -umask 077 { printf 'TLS_CERT=%s\n' "$(base64 < out/web-app.crt | tr -d '\n')" printf 'TLS_KEY=%s\n' "$(base64 < out/web-app.key | tr -d '\n')" printf 'CLIENT_CA=%s\n' "$(base64 < out/good-ca.crt | tr -d '\n')" } > .env -chmod 600 .env echo "Generated certs in ./out/ and env vars in ./.env" From 7e8c0a3d25d85927e8cb57db9b8ec1570602f440 Mon Sep 17 00:00:00 2001 From: Bobby DeSimone Date: Sat, 9 May 2026 20:33:32 -0700 Subject: [PATCH 4/6] review: scope Pomerium mounts to specific certs, fix header printf Codex review pass on the migrated mTLS bundle: - docker-compose.yaml: replace the blanket ./out:/pomerium/out:ro mount with three individual file mounts for good-ca.crt, pomerium.crt, pomerium.key. The blanket mount exposed CA private keys and the curl test client keys to Pomerium, which has no reason to see them. - main.go: header response was Fprintf'ing []string with %s, producing Go fmt errors like %!s([]string=...). Use strings.Join(v, ", "). - README.md: tighten the umask paragraph to call out the actual file modes (out/ + .env at 0600, certstrap files at 0400) and replace the broken reference-profile chmod workaround with one that targets only the three mounted files. Re-verified end-to-end: ./scripts/generate_certs.sh, docker compose up mtls, docker compose --profile reference up, header redaction (Authorization, Cookie, X-Pomerium-Jwt-Assertion all show [redacted]), curl.sh round-trip HTTP/2 200 Subject CN=good-curl over TLS 1.3. --- content/examples/mutual-tls/README.md | 24 +++++++++++-------- .../examples/mutual-tls/docker-compose.yaml | 7 +++++- content/examples/mutual-tls/main.go | 2 +- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/content/examples/mutual-tls/README.md b/content/examples/mutual-tls/README.md index 324b049ff..90ea9cb40 100644 --- a/content/examples/mutual-tls/README.md +++ b/content/examples/mutual-tls/README.md @@ -29,18 +29,22 @@ docker compose up mtls -d # builds the Go server and runs it on :8443 `./out/` and `./.env` are generated on demand and gitignored. Re-running `generate_certs.sh` deletes any existing `./out/` first so re-runs produce -clean state. The script runs under `umask 077`, so every file in `./out/` -(including the private keys) and `./.env` itself land with `0600` -permissions. +clean state. The script runs under `umask 077`, so the `out/` directory and +`./.env` land at `0600` (and certstrap writes its own files at `0400`, +which is also owner-only and therefore consistent with the umask). If you run the reference `pomerium` Compose service (`docker compose ---profile reference up`), the container reads cert/key files from -`/pomerium/out` mounted read-only from `./out`. The default Pomerium image -runs as a non-root user, so the `0600` files won't be readable; for the -reference profile you'll either need to relax the perms (`chmod -R 0644 -out/*.crt && chmod 0640 out/*.key` plus a matching group), or run the -container with a UID that matches your local owner via `user:` in the -Compose service. +--profile reference up`), the container reads three specific cert/key files +that are bind-mounted individually from `./out`: `good-ca.crt`, +`pomerium.crt`, and `pomerium.key`. The CA private keys and the curl test +client keys stay on the host. On Linux, the default Pomerium image runs as +a non-root user (`nonroot`, UID 65532) and the `0400`/`0600` files won't be +readable through a bind mount that preserves host ownership. Either relax +the perms on just the three mounted files (`chmod a+r out/good-ca.crt +out/pomerium.crt out/pomerium.key`), or run the container with a `user:` +matching your local owner. Docker Desktop and OrbStack on macOS remap +bind-mount ownership to the container user, so this is not an issue on +those platforms. ## Files diff --git a/content/examples/mutual-tls/docker-compose.yaml b/content/examples/mutual-tls/docker-compose.yaml index f8409a511..f003ad057 100644 --- a/content/examples/mutual-tls/docker-compose.yaml +++ b/content/examples/mutual-tls/docker-compose.yaml @@ -11,9 +11,14 @@ services: - CERTIFICATE - CERTIFICATE_KEY - COOKIE_SECRET + # Mount only the specific certs Pomerium needs for the upstream connection. + # Mounting the whole ./out/ directory would expose CA private keys and the + # curl test client keys that don't belong inside this container. volumes: - ./example.config.yaml:/pomerium/config.yaml:ro - - ./out:/pomerium/out:ro + - ./out/good-ca.crt:/pomerium/out/good-ca.crt:ro + - ./out/pomerium.crt:/pomerium/out/pomerium.crt:ro + - ./out/pomerium.key:/pomerium/out/pomerium.key:ro ports: - 443:443 diff --git a/content/examples/mutual-tls/main.go b/content/examples/mutual-tls/main.go index f9fbc9ea9..ddfa9efdd 100644 --- a/content/examples/mutual-tls/main.go +++ b/content/examples/mutual-tls/main.go @@ -71,7 +71,7 @@ func hello(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "\t[%s]:\n\t\t[redacted]\n", k) continue } - fmt.Fprintf(w, "\t[%s]:\n\t\t%s\n", k, v) + fmt.Fprintf(w, "\t[%s]:\n\t\t%s\n", k, strings.Join(v, ", ")) } } From 7b14e18466f9433e13c22d5204b9b81cba51d614 Mon Sep 17 00:00:00 2001 From: Bobby DeSimone Date: Sat, 9 May 2026 21:37:51 -0700 Subject: [PATCH 5/6] examples: prune dead orphans and fix the salvageable ones MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A wider sweep across content/examples/ turned up a lot of files that have been silently rotting next to the live ones. None of the deletions in this commit are imported by any current .mdx (verified by grep against content/). Killed (no .mdx imports them, dead or broken on current toolchain): - docker/autocert.docker-compose.yml — fails docker compose config (undefined volume). - docker/nginx.docker-compose.yml — split-services architecture (defunct); pomerium/nginx-proxy:latest last pushed 2019-02. - docker/basic.docker-compose.yml.md — orphan. - kubernetes/{httpbin,ingress,ingress.nginx}.yml — extensions/v1beta1 (removed in k8s 1.22, ~2021). - kubernetes/{kubernetes-config.yaml,kubernetes_gke.sh,kubernetes_nginx.sh, pomerium-{authenticate,authorize,databroker,proxy}.yml,values.yaml, pomerium-console-certificate.yaml} — legacy split-services deploy pattern, no longer the documented path; manifests pin pomerium/pomerium:main. - kubernetes/istio/{gateway,service-entry,virtual-services,pomerium-helm-values}.yml — gateway.yml is unparseable YAML (unquoted *.example.com); cert-manager.io/v1alpha2 was removed in cert-manager 1.6 (Nov 2021). - tiddlywiki/docker-compose.yaml.md — orphan; tiddlywiki.mdx now embeds the compose inline. - config/{config.docker.yaml.md,config.example.env,config.example.yaml, config.minimal.env,config.minimal.yaml.md,policy.example.yaml.md} — orphan config snippets; only route.example.yaml.md is still imported (by routes/readme.mdx). - nginx/ — uses removed forward_auth_url; ships an mkcert dev CA with its private key. - traefik-ingress/ — references retired containous.github.io helm repo and the removed traefik.containo.us/v1alpha1 CRD group; needs a Traefik v3 rewrite tracked separately. Fixed in place: - cloudrun/policy.template.yaml.md — replaced legacy top-level allowed_domains shortcut with the structured policy: - allow: or: - domain: is: form. - cloudrun/deploy.sh.md — gcloud beta run domain-mappings is GA now (drop beta and the redundant --platform managed); removed the now-unnecessary gcloud components install beta line. - guacamole/guacamole.pomerium-config.md — fix malformed YAML (orphan pass_identity_headers: true outside any list item) and rename jwt_claim_headers → jwt_claims_headers (Pomerium's canonical key, plural). - kubernetes/pomerium-values.yaml.md — replace the malformed postgres://://postgres... connection string with a complete placeholder. - tooljet/config-console.yaml.md — fix allows: typo → allow: (Pomerium PPL). - tooljet/console-compose.yaml.md — bump pomerium-console v0.21.0 → v0.32.0 (matches enterprise quickstart) and postgres:13 → postgres:17 (13 EOL'd Nov 2025). - tooljet/docker-compose.yaml.md — postgres:13 → postgres:17. - jenkins/jenkins-docker-compose.md — jenkins/jenkins:lts-jdk11 → jenkins/jenkins:lts-jdk21 (Jenkins LTS 2.555+ requires Java 21+). Verified: yarn build, yarn cspell, yarn format clean. Every fixed YAML parses with python yaml.safe_load. Every pinned image (pomerium, verify, tooljet/tooljet-ce, postgres:17, jenkins/jenkins:lts-jdk21) docker manifest inspect EXISTS. cloud-run deploy.sh and tcp/curl scripts pass bash -n. --- content/examples/config/config.docker.yaml.md | 27 ----- content/examples/config/config.example.env | 64 ----------- content/examples/config/config.example.yaml | 99 ----------------- content/examples/config/config.minimal.env | 8 -- .../examples/config/config.minimal.yaml.md | 35 ------ .../examples/config/policy.example.yaml.md | 31 ------ .../docker/autocert.docker-compose.yml | 17 --- .../docker/basic.docker-compose.yml.md | 15 --- .../examples/docker/nginx.docker-compose.yml | 103 ------------------ content/examples/kubernetes/httpbin.yml | 37 ------- content/examples/kubernetes/ingress.nginx.yml | 37 ------- content/examples/kubernetes/ingress.yml | 30 ----- content/examples/kubernetes/istio/gateway.yml | 41 ------- .../kubernetes/istio/pomerium-helm-values.yml | 13 --- .../kubernetes/istio/service-entry.yml | 14 --- .../kubernetes/istio/virtual-services.yml | 34 ------ .../kubernetes/kubernetes-config.yaml | 25 ----- content/examples/kubernetes/kubernetes_gke.sh | 48 -------- .../examples/kubernetes/kubernetes_nginx.sh | 18 --- .../kubernetes/pomerium-authenticate.yml | 69 ------------ .../kubernetes/pomerium-authorize.yml | 63 ----------- .../pomerium-console-certificate.yaml | 13 --- .../kubernetes/pomerium-databroker.yml | 64 ----------- .../examples/kubernetes/pomerium-proxy.yml | 71 ------------ content/examples/kubernetes/values.yaml | 27 ----- content/examples/nginx/README.md | 17 --- .../_wildcard.localhost.pomerium.io-key.pem | 28 ----- .../nginx/_wildcard.localhost.pomerium.io.pem | 24 ---- content/examples/nginx/config.yaml.md | 22 ---- content/examples/nginx/docker-compose.yaml.md | 30 ----- content/examples/nginx/pomerium.conf.md | 23 ---- content/examples/nginx/proxy.conf | 64 ----------- content/examples/nginx/rootCA-key.pem | 40 ------- content/examples/nginx/rootCA.pem | 26 ----- content/examples/nginx/verify.conf.md | 75 ------------- .../tiddlywiki/docker-compose.yaml.md | 34 ------ content/examples/traefik-ingress/README.md | 19 ---- .../examples/traefik-ingress/add_repos.sh.md | 5 - .../traefik-ingress/crds/middleware.yaml.md | 15 --- .../examples/traefik-ingress/install.sh.md | 34 ------ .../traefik-ingress/values/hello.yaml.md | 20 ---- .../traefik-ingress/values/pomerium.yaml.md | 29 ----- .../traefik-ingress/values/traefik.yaml.md | 5 - 43 files changed, 1513 deletions(-) delete mode 100644 content/examples/config/config.docker.yaml.md delete mode 100644 content/examples/config/config.example.env delete mode 100644 content/examples/config/config.example.yaml delete mode 100644 content/examples/config/config.minimal.env delete mode 100644 content/examples/config/config.minimal.yaml.md delete mode 100644 content/examples/config/policy.example.yaml.md delete mode 100644 content/examples/docker/autocert.docker-compose.yml delete mode 100644 content/examples/docker/basic.docker-compose.yml.md delete mode 100644 content/examples/docker/nginx.docker-compose.yml delete mode 100644 content/examples/kubernetes/httpbin.yml delete mode 100644 content/examples/kubernetes/ingress.nginx.yml delete mode 100644 content/examples/kubernetes/ingress.yml delete mode 100644 content/examples/kubernetes/istio/gateway.yml delete mode 100644 content/examples/kubernetes/istio/pomerium-helm-values.yml delete mode 100644 content/examples/kubernetes/istio/service-entry.yml delete mode 100644 content/examples/kubernetes/istio/virtual-services.yml delete mode 100644 content/examples/kubernetes/kubernetes-config.yaml delete mode 100755 content/examples/kubernetes/kubernetes_gke.sh delete mode 100644 content/examples/kubernetes/kubernetes_nginx.sh delete mode 100644 content/examples/kubernetes/pomerium-authenticate.yml delete mode 100644 content/examples/kubernetes/pomerium-authorize.yml delete mode 100644 content/examples/kubernetes/pomerium-console-certificate.yaml delete mode 100644 content/examples/kubernetes/pomerium-databroker.yml delete mode 100644 content/examples/kubernetes/pomerium-proxy.yml delete mode 100644 content/examples/kubernetes/values.yaml delete mode 100644 content/examples/nginx/README.md delete mode 100644 content/examples/nginx/_wildcard.localhost.pomerium.io-key.pem delete mode 100644 content/examples/nginx/_wildcard.localhost.pomerium.io.pem delete mode 100644 content/examples/nginx/config.yaml.md delete mode 100644 content/examples/nginx/docker-compose.yaml.md delete mode 100644 content/examples/nginx/pomerium.conf.md delete mode 100644 content/examples/nginx/proxy.conf delete mode 100644 content/examples/nginx/rootCA-key.pem delete mode 100644 content/examples/nginx/rootCA.pem delete mode 100644 content/examples/nginx/verify.conf.md delete mode 100644 content/examples/tiddlywiki/docker-compose.yaml.md delete mode 100644 content/examples/traefik-ingress/README.md delete mode 100755 content/examples/traefik-ingress/add_repos.sh.md delete mode 100644 content/examples/traefik-ingress/crds/middleware.yaml.md delete mode 100755 content/examples/traefik-ingress/install.sh.md delete mode 100644 content/examples/traefik-ingress/values/hello.yaml.md delete mode 100644 content/examples/traefik-ingress/values/pomerium.yaml.md delete mode 100644 content/examples/traefik-ingress/values/traefik.yaml.md diff --git a/content/examples/config/config.docker.yaml.md b/content/examples/config/config.docker.yaml.md deleted file mode 100644 index c59d578f7..000000000 --- a/content/examples/config/config.docker.yaml.md +++ /dev/null @@ -1,27 +0,0 @@ -```yaml -# See detailed configuration settings: https://www.pomerium.com/docs/reference/ - -##################################################################### -# If self-hosting, use the localhost authenticate service URL below # -# and remove the hosted URL. # -##################################################################### -# authenticate_service_url: https://authenticate.localhost.pomerium.io - -authenticate_service_url: https://authenticate.pomerium.app - -#################################################################################### -# If self-hosting, you must configure an identity provider. # -# See identity provider settings: https://www.pomerium.com/docs/integrations/# -#################################################################################### - -# https://pomerium.com/reference/#routes -routes: - - from: https://verify.localhost.pomerium.io - to: http://verify:8000 - policy: - - allow: - or: - - email: - is: user@example.com - pass_identity_headers: true -``` diff --git a/content/examples/config/config.example.env b/content/examples/config/config.example.env deleted file mode 100644 index 26462c5e5..000000000 --- a/content/examples/config/config.example.env +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/bash -# Main configuration flags : https://www.pomerium.com/docs/reference/ - -# Main configuration flags -# export ADDRESS=":8443" # optional, default is 443 -# export SERVICE="all" # optional, default is all -# export LOG_LEVEL="info" # optional, default is debug - -export AUTHENTICATE_SERVICE_URL=https://authenticate.corp.beyondperimeter.com -# AUTHORIZE_SERVICE_URL service url will default to localhost in all-in-one mode, -# otherwise it should be set to a "behind-the-ingress" routable url -# export AUTHORIZE_SERVICE_URL=https://pomerium-authorize-service.default.svc.cluster.local -# DATABROKER_SERVICE_URL defaults to http://localhost:5443 in all-in-one mode. -# Set it only when the databroker runs on another host/port (split/remote Core). -# export DATABROKER_SERVICE_URL=https://pomerium-databroker-service.default.svc.cluster.local - -# Certificates can be loaded as files or base64 encoded bytes. -# See : https://www.pomerium.com/docs/reference/certificates -export AUTOCERT=TRUE # Use Let's Encrypt to fetch certs. Port 80/443 must be internet accessible. -# export AUTOCERT_DIR="./certs" # The path where you want to place your certificates -# export CERTIFICATE_FILE="xxxx" # optional -# export CERTIFICATE_KEY_FILE="xxx" # optional -# export CERTIFICATE="xxx" # base64 encoded cert, eg. `base64 -i cert.pem` -# export CERTIFICATE_KEY="xxx" # base64 encoded key, eg. `base64 -i private-key.pem` - -# Generate 256 bit random keys e.g. `head -c32 /dev/urandom | base64` -export SHARED_SECRET="$(head -c32 /dev/urandom | base64)" -export COOKIE_SECRET="$(head -c32 /dev/urandom | base64)" -# If set, a JWT based signature is appended to each request header `x-pomerium-jwt-assertion` -# export SIGNING_KEY="Replace with base64'd private key from ./scripts/self-signed-sign-key.sh" - -# Identity Provider Settings - -# Auth0 -# export IDP_PROVIDER="auth0" -# export IDP_PROVIDER_URL="https://REPLACE_ME.us.auth0.com" -# export IDP_CLIENT_ID="REPLACE_ME" # from the application the users login to -# export IDP_CLIENT_SECRET="REPLACE_ME" # from the application the users login to - -# Azure -# export IDP_PROVIDER="azure" -# export IDP_PROVIDER_URL="https://login.microsoftonline.com/REPLACE_ME/v2.0" -# export IDP_CLIENT_ID="REPLACE_ME -# export IDP_CLIENT_SECRET="REPLACE_ME" - -## GOOGLE -export IDP_PROVIDER="google" - -# OKTA -# export IDP_PROVIDER="okta" -# export IDP_CLIENT_ID="REPLACE_ME" -# export IDP_CLIENT_SECRET="REPLACE_ME" -# export IDP_PROVIDER_URL="https://REPLACE_ME.oktapreview.com/oauth2/default" - -# OneLogin -# export IDP_PROVIDER="onelogin" -# export IDP_CLIENT_ID="REPLACE_ME" -# export IDP_CLIENT_SECRET="REPLACE_ME" -# export IDP_PROVIDER_URL="https://openid-connect.onelogin.com/oidc" #optional, defaults to `https://openid-connect.onelogin.com/oidc` - -# Proxied routes and per-route policies are defined in a policy provided either -# directly as a base64 encoded yaml/json file, or as the policy key in the configuration -# file -export POLICY="$(base64 ./docs/configuration/examples/config/policy.example.yaml)" diff --git a/content/examples/config/config.example.yaml b/content/examples/config/config.example.yaml deleted file mode 100644 index c98c07a27..000000000 --- a/content/examples/config/config.example.yaml +++ /dev/null @@ -1,99 +0,0 @@ -# Main configuration flags : https://www.pomerium.com/docs/reference/ - -# -# address: ":8443" # optional, default is 443 -# service: "all" # optional, default is all -# log_level: info # optional, default is debug - -authenticate_service_url: https://authenticate.localhost.pomerium.io -# authorize service url will default to localhost in all-in-one mode, otherwise -# it should be set to a "behind-the-ingress" routable url -# authorize_service_url: https://pomerium-authorize-service.default.svc.cluster.local -# databroker service url defaults to http://localhost:5443 in all-in-one mode. -# Set it only when the databroker runs on another host/port (split/remote Core). -# databroker_service_url: https://pomerium-databroker-service.default.svc.cluster.local - -# Certificates can be loaded as files or base64 encoded bytes. -# certificate_file: "./cert.pem" # optional -# certificate_key_file: "./private-key.pem" # optional -# certificate_authority_file: "./cert.pem" - -# alternatively, insecure mode can be used if behind a TLS terminating ingress, -# or when using a sidecar proxy -# insecure_server: true - -# base64 encoded cert, eg. `base64 -i cert.pem` / `base64 -i private-key.pem` -# certificate: | -# "xxxxxx" -# certificate_key: | -# "xxxx" - -# Generate 256 bit random keys e.g. `head -c32 /dev/urandom | base64` -# shared_secret: hsJIQsx9KKx4qVlggg/T3AuLTmVu0uHhwTQgMPlVs7U= -# cookie_secret: WwMtDXWaRDMBQCylle8OJ+w4kLIDIGd8W3cB4/zFFtg= -# If set, a JWT based signature is appended to each request header `x-pomerium-jwt-assertion` -# signing_key: "Replace with base64'd private key from ./scripts/self-signed-sign-key.sh" - -# Identity Provider Settings - -# Auth0 -# idp_provider: "auth0" -# idp_provider_url: "https://REPLACE_ME.us.auth0.com" -# idp_client_id: "REPLACE_ME" # from the application the users login to -# idp_client_secret: "REPLACE_ME" # from the application the users login to -# the following is optional and only needed if you want role (Auth0 calls groups roles) data - -# Azure -# idp_provider: "azure" -# idp_provider_url: "https://login.microsoftonline.com/REPLACE_ME/v2.0" -# idp_client_id: "REPLACE_ME -# idp_client_secret: "REPLACE_ME" - -## GOOGLE -# idp_provider: "google" -# idp_client_id: "REPLACE_ME -# idp_client_secret: "REPLACE_ME - -# OKTA -# idp_provider: "okta" -# idp_client_id: "REPLACE_ME" -# idp_client_secret: "REPLACE_ME" -# idp_provider_url: "https://REPLACE_ME.oktapreview.com/oauth2/default" - -# OneLogin -# idp_provider: "onelogin" -# idp_client_id: "REPLACE_ME" -# idp_client_secret: "REPLACE_ME" -# idp_provider_url: "https://openid-connect.onelogin.com/oidc" #optional, defaults to `https://openid-connect.onelogin.com/oidc` - -# Proxied routes and per-route policies are defined in a routes block -routes: - - from: https://verify.localhost.pomerium.io - to: http://localhost:8000 - policy: - - allow: - or: - - domain: - is: pomerium.io - cors_allow_preflight: true - timeout: 30s - - from: https://external-verify.localhost.pomerium.io - to: https://verify.pomerium.com - policy: - - allow: - or: - - domain: - is: gmail.com - - from: https://weirdlyssl.localhost.pomerium.io - to: http://neverssl.com - policy: - - allow: - or: - - email: - is: user@example.com - - from: https://hello.localhost.pomerium.io - to: http://localhost:8080 - policy: - - allow: - or: - - claim/groups: "admins@pomerium.io" diff --git a/content/examples/config/config.minimal.env b/content/examples/config/config.minimal.env deleted file mode 100644 index 3b4099419..000000000 --- a/content/examples/config/config.minimal.env +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -# See : https://www.pomerium.com/docs/reference/certificates -export AUTOCERT=TRUE # Use Let's Encrypt to fetch certs. Port 80/443 must be internet accessible. - -# 256 bit random keys -export SHARED_SECRET="$(head -c32 /dev/urandom | base64)" -export COOKIE_SECRET="$(head -c32 /dev/urandom | base64)" diff --git a/content/examples/config/config.minimal.yaml.md b/content/examples/config/config.minimal.yaml.md deleted file mode 100644 index eda8337c3..000000000 --- a/content/examples/config/config.minimal.yaml.md +++ /dev/null @@ -1,35 +0,0 @@ -```yaml -# See detailed configuration settings : https://www.pomerium.com/docs/reference/ - -# this is the domain the identity provider will callback after a user authenticates -authenticate_service_url: https://authenticate.localhost.pomerium.io - -# certificate settings: https://www.pomerium.com/docs/reference/certificates.html -autocert: true -# REMOVE FOR PRODUCTION -autocert_use_staging: true - -# If you're using mkcert to test Pomerium locally, comment the autocert keys and uncomment -# the keys below, adjusting for your mkcert path: -# certificate_file: /home/user/.local/share/mkcert/rootCA.pem -# certificate_key_file: /user/alex/.local/share/mkcert/rootCA-key.pem - -# identity provider settings : https://www.pomerium.com/docs/integrations/user-identity/identity-providers.html -idp_provider: google -idp_client_id: REPLACE_ME -idp_client_secret: REPLACE_ME - -# Generate 256 bit random keys e.g. `head -c32 /dev/urandom | base64` -cookie_secret: WwMtDXWaRDMBQCylle8OJ+w4kLIDIGd8W3cB4/zFFtg= - -# https://pomerium.io/reference/#routes -routes: - - from: https://verify.localhost.pomerium.io - to: https://verify.pomerium.com - policy: - - allow: - or: - - email: - is: user@example.com - pass_identity_headers: true -``` diff --git a/content/examples/config/policy.example.yaml.md b/content/examples/config/policy.example.yaml.md deleted file mode 100644 index 059231385..000000000 --- a/content/examples/config/policy.example.yaml.md +++ /dev/null @@ -1,31 +0,0 @@ -```yaml -# This file contains only policy and route configuration details. Other -# configuration settings required by pomerium are excluded for clarity. -# See: https://www.pomerium.com/docs/reference/ - -# -# For a complete self contained configuration see : config.example.yaml. -# Or, mix and match a policy file (this) with env vars : config.example.env - -# Proxied routes and per-route policies are defined in a policy block -# NOTA BENE: You must uncomment the below 'policy' key if you are loading policy as a file. -# policy: -- from: https://verify.localhost.pomerium.io - to: http://localhost:8000 - allowed_domains: - - pomerium.io - cors_allow_preflight: true - timeout: 30s -- from: https://external-verify.localhost.pomerium.io - to: https://verify.pomerium.com - allowed_domains: - - gmail.com -- from: https://weirdlyssl.localhost.pomerium.io - to: http://neverssl.com - allowed_users: - - user@example.com -- from: https://hello.localhost.pomerium.io - to: http://localhost:8080 - allowed_users: - - user@example.com -``` diff --git a/content/examples/docker/autocert.docker-compose.yml b/content/examples/docker/autocert.docker-compose.yml deleted file mode 100644 index 43bf75fbd..000000000 --- a/content/examples/docker/autocert.docker-compose.yml +++ /dev/null @@ -1,17 +0,0 @@ -services: - pomerium: - image: pomerium/pomerium:latest - environment: - # Generate new secret keys. e.g. `head -c32 /dev/urandom | base64` - - COOKIE_SECRET=V2JBZk0zWGtsL29UcFUvWjVDWWQ2UHExNXJ0b2VhcDI= - volumes: - # Use a volume to store ACME certificates - - pomerium:/data:rw - ports: - - 443:443 - - # https://verify.corp.beyondperimeter.com --> Pomerium --> http://verify - verify: - image: pomerium/verify:latest - expose: - - 80 diff --git a/content/examples/docker/basic.docker-compose.yml.md b/content/examples/docker/basic.docker-compose.yml.md deleted file mode 100644 index 722374cb8..000000000 --- a/content/examples/docker/basic.docker-compose.yml.md +++ /dev/null @@ -1,15 +0,0 @@ -```yaml -services: - pomerium: - image: pomerium/pomerium:latest - volumes: - ## Mount your config file: https://www.pomerium.com/docs/reference/ - - ./config.yaml:/pomerium/config.yaml:ro - ports: - - 443:443 - ## https://verify.localhost.pomerium.io --> Pomerium --> http://verify - verify: - image: pomerium/verify:latest - expose: - - 8000 -``` diff --git a/content/examples/docker/nginx.docker-compose.yml b/content/examples/docker/nginx.docker-compose.yml deleted file mode 100644 index c21c028a8..000000000 --- a/content/examples/docker/nginx.docker-compose.yml +++ /dev/null @@ -1,103 +0,0 @@ -services: - nginx: - image: pomerium/nginx-proxy:latest - ports: - - "443:443" - volumes: - # NOTE!!! : nginx must be supplied with your wildcard certificates. - # see : https://github.com/jwilder/nginx-proxy#wildcard-certificates - - ~/.acme.sh/*.corp.beyondperimeter.com_ecc/fullchain.cer:/etc/nginx/certs/corp.beyondperimeter.com.crt:ro - - ~/.acme.sh/*.corp.beyondperimeter.com_ecc/*.corp.beyondperimeter.com.key:/etc/nginx/certs/corp.beyondperimeter.com.key:ro - - /var/run/docker.sock:/tmp/docker.sock:ro - - pomerium-authenticate: - image: pomerium/pomerium:latest # or `build: .` to build from source - restart: always - environment: - - SERVICES=authenticate - - INSECURE_SERVER=TRUE - # NOTE!: Replace with your identity provider settings https://www.pomerium.com/docs/integrations/user-identity/identity-providers.html - # - IDP_PROVIDER=okta - # - IDP_PROVIDER_URL=https://beyondperimeter.okta.com - # - IDP_CLIENT_ID=REPLACE_ME - # - IDP_CLIENT_SECRET=REPLACE_ME - # NOTE! Generate new secret keys! e.g. `head -c32 /dev/urandom | base64` - # Generated secret keys must match between services - - SHARED_SECRET=aDducXQzK2tPY3R4TmdqTGhaYS80eGYxcTUvWWJDb2M= - - COOKIE_SECRET=V2JBZk0zWGtsL29UcFUvWjVDWWQ2UHExNXJ0b2VhcDI= - # Tell nginx how to proxy pomerium's routes - - VIRTUAL_PROTO=http - - VIRTUAL_HOST=authenticate.corp.beyondperimeter.com - - VIRTUAL_PORT=443 - - DATABROKER_SERVICE_URL=http://pomerium-databroker:443 - volumes: - - ../config/config.example.yaml:/pomerium/config.yaml:ro - - expose: - - 443 - - pomerium-proxy: - image: pomerium/pomerium:latest # or `build: .` to build from source - restart: always - environment: - - SERVICES=proxy - - INSECURE_SERVER=TRUE - # IMPORTANT! If you are running pomerium behind another ingress (loadbalancer/firewall/etc) - # you must tell pomerium proxy how to communicate using an internal hostname for RPC - - AUTHORIZE_SERVICE_URL=http://pomerium-authorize:443 - # When communicating internally, rPC is going to get a name conflict expecting an external - # facing certificate name (i.e. authenticate-service.local vs *.corp.example.com). - - SHARED_SECRET=aDducXQzK2tPY3R4TmdqTGhaYS80eGYxcTUvWWJDb2M= - - COOKIE_SECRET=V2JBZk0zWGtsL29UcFUvWjVDWWQ2UHExNXJ0b2VhcDI= - # Tell nginx how to proxy pomerium's routes - - VIRTUAL_PROTO=http - - VIRTUAL_HOST=*.corp.beyondperimeter.com - - VIRTUAL_PORT=443 - volumes: - - ../config/config.example.yaml:/pomerium/config.yaml:ro - expose: - - 443 - - pomerium-authorize: - image: pomerium/pomerium:latest # or `build: .` to build from source - restart: always - environment: - - SERVICES=authorize - - SHARED_SECRET=aDducXQzK2tPY3R4TmdqTGhaYS80eGYxcTUvWWJDb2M= - - GRPC_INSECURE=TRUE - - GRPC_ADDRESS=:443 - - volumes: - # Retrieve non-secret config keys from the config file : https://www.pomerium.com/docs/reference/ - - # See `config.example.yaml` and modify to fit your needs. - - ../config/config.example.yaml:/pomerium/config.yaml:ro - expose: - - 443 - - pomerium-databroker: - image: pomerium/pomerium:latest # or `build: .` to build from source - restart: always - environment: - - SERVICES=databroker - - SHARED_SECRET=aDducXQzK2tPY3R4TmdqTGhaYS80eGYxcTUvWWJDb2M= - - GRPC_INSECURE=TRUE - - GRPC_ADDRESS=:443 - volumes: - # Retrieve non-secret config keys from the config file : https://www.pomerium.com/docs/reference/ - - # See `config.example.yaml` and modify to fit your needs. - - ../config/config.example.yaml:/pomerium/config.yaml:ro - expose: - - 443 - - # https://verify.corp.beyondperimeter.com - verify: - image: pomerium/verify:latest - expose: - - 80 - # https://hello.corp.beyondperimeter.com - hello: - image: gcr.io/google-samples/hello-app:1.0 - expose: - - 8080 diff --git a/content/examples/kubernetes/httpbin.yml b/content/examples/kubernetes/httpbin.yml deleted file mode 100644 index 51c5c4144..000000000 --- a/content/examples/kubernetes/httpbin.yml +++ /dev/null @@ -1,37 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: httpbin - labels: - app: httpbin -spec: - type: NodePort - ports: - - name: http - port: 8000 - targetPort: 80 - selector: - app: httpbin ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: httpbin -spec: - replicas: 1 - selector: - matchLabels: - app: httpbin - version: v1 - template: - metadata: - labels: - app: httpbin - version: v1 - spec: - containers: - - image: docker.io/kennethreitz/httpbin - imagePullPolicy: IfNotPresent - name: httpbin - ports: - - containerPort: 80 diff --git a/content/examples/kubernetes/ingress.nginx.yml b/content/examples/kubernetes/ingress.nginx.yml deleted file mode 100644 index 18669b065..000000000 --- a/content/examples/kubernetes/ingress.nginx.yml +++ /dev/null @@ -1,37 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: pomerium-ingress - annotations: - kubernetes.io/ingress.class: "nginx" - # kubernetes.io/tls-acme: "true" - # certmanager.k8s.io/issuer: "letsencrypt-prod" - # nginx.ingress.kubernetes.io/force-ssl-redirect: "true" - # nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" - # nginx.ingress.kubernetes.io/proxy-buffer-size: "16k" - # to avoid ingress routing, enable - # nginx.ingress.kubernetes.io/ssl-passthrough: "true" - -spec: - tls: - - secretName: pomerium-tls - hosts: - - "*.corp.beyondperimeter.com" - - "authenticate.corp.beyondperimeter.com" - - rules: - - host: "*.corp.beyondperimeter.com" - http: - paths: - - paths: - backend: - serviceName: pomerium-proxy-service - servicePort: http - - - host: "authenticate.corp.beyondperimeter.com" - http: - paths: - - paths: - backend: - serviceName: pomerium-authenticate-service - servicePort: http diff --git a/content/examples/kubernetes/ingress.yml b/content/examples/kubernetes/ingress.yml deleted file mode 100644 index f6898dd40..000000000 --- a/content/examples/kubernetes/ingress.yml +++ /dev/null @@ -1,30 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: pomerium-ingress - annotations: - kubernetes.io/ingress.allow-http: "false" - kubernetes.io/ingress.global-static-ip-name: pomerium - -spec: - tls: - - secretName: pomerium-tls - hosts: - - "*.corp.beyondperimeter.com" - - "authenticate.corp.beyondperimeter.com" - - rules: - - host: "*.corp.beyondperimeter.com" - http: - paths: - - paths: - backend: - serviceName: pomerium-proxy-service - servicePort: http - - host: "authenticate.corp.beyondperimeter.com" - http: - paths: - - paths: - backend: - serviceName: pomerium-authenticate-service - servicePort: http diff --git a/content/examples/kubernetes/istio/gateway.yml b/content/examples/kubernetes/istio/gateway.yml deleted file mode 100644 index 944c50062..000000000 --- a/content/examples/kubernetes/istio/gateway.yml +++ /dev/null @@ -1,41 +0,0 @@ -apiVersion: networking.istio.io/v1alpha3 -kind: Gateway -metadata: - name: internal-gateway - namespace: istio-system -spec: - selector: - istio: ingressgateway - servers: - - port: - number: 443 - protocol: HTTPS - name: https-default - tls: - mode: SIMPLE - serverCertificate: "sds" - privateKey: "sds" - credentialName: internal-cert - hosts: - - *.example.com ---- -apiVersion: cert-manager.io/v1alpha2 -kind: Certificate -metadata: - name: internal-cert - namespace: istio-system -spec: - secretName: internal-cert - issuerRef: - name: self-signed-issuer - kind: ClusterIssuer - commonName: *.example.com - dnsNames: - - *.example.com ---- -apiVersion: cert-manager.io/v1alpha2 -kind: ClusterIssuer -metadata: - name: self-signed-issuer -spec: - selfSigned: {} diff --git a/content/examples/kubernetes/istio/pomerium-helm-values.yml b/content/examples/kubernetes/istio/pomerium-helm-values.yml deleted file mode 100644 index cc09fc5de..000000000 --- a/content/examples/kubernetes/istio/pomerium-helm-values.yml +++ /dev/null @@ -1,13 +0,0 @@ -config: - insecure: true - policy: - - from: https://grafana.example.com - to: "http://prometheus-grafana.monitoring.svc.cluster.local" - timeout: 30s - allowed_domains: - - example.com -ingress: - enabled: false - -extraEnv: - JWT_CLAIMS_HEADERS: email diff --git a/content/examples/kubernetes/istio/service-entry.yml b/content/examples/kubernetes/istio/service-entry.yml deleted file mode 100644 index c4f21f241..000000000 --- a/content/examples/kubernetes/istio/service-entry.yml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: networking.istio.io/v1alpha3 -kind: ServiceEntry -metadata: - name: external-idp - namespace: pomerium -spec: - hosts: - - example.okta.com - location: MESH_EXTERNAL - ports: - - number: 443 - name: https - protocol: TLS - resolution: DNS diff --git a/content/examples/kubernetes/istio/virtual-services.yml b/content/examples/kubernetes/istio/virtual-services.yml deleted file mode 100644 index 4c6066dfd..000000000 --- a/content/examples/kubernetes/istio/virtual-services.yml +++ /dev/null @@ -1,34 +0,0 @@ -apiVersion: networking.istio.io/v1beta1 -kind: VirtualService -metadata: - name: grafana-virtual-service - namespace: pomerium -spec: - gateways: - - istio-system/internal-gateway - hosts: - - grafana.example.com - http: - - route: - - destination: - host: pomerium-proxy - port: - number: 80 ---- -apiVersion: networking.istio.io/v1beta1 -kind: VirtualService -metadata: - name: authenticate-virtual-service - namespace: pomerium -spec: - gateways: - - istio-system/internal-gateway - hosts: - - authenticate.example.com - http: - - route: - - destination: - host: pomerium-authenticate - port: - number: 80 ---- diff --git a/content/examples/kubernetes/kubernetes-config.yaml b/content/examples/kubernetes/kubernetes-config.yaml deleted file mode 100644 index 571063582..000000000 --- a/content/examples/kubernetes/kubernetes-config.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# Main configuration flags : https://www.pomerium.com/docs/reference/ - -insecure_server: true -grpc_insecure: true -address: ":80" -grpc_address: ":80" - -authenticate_service_url: https://authenticate.localhost.pomerium.io -authorize_service_url: http://pomerium-authorize-service.default.svc.cluster.local -databroker_service_url: http://pomerium-databroker-service.default.svc.cluster.local - -override_certificate_name: "*.localhost.pomerium.io" - -idp_provider: google -idp_client_id: REPLACE_ME -idp_client_secret: "REPLACE_ME" - -routes: - - from: https://verify.localhost.pomerium.io - to: http://httpbin.default.svc.cluster.local:8000 - policy: - - allow: - or: - - domain: - is: gmail.com diff --git a/content/examples/kubernetes/kubernetes_gke.sh b/content/examples/kubernetes/kubernetes_gke.sh deleted file mode 100755 index ea9f96a8d..000000000 --- a/content/examples/kubernetes/kubernetes_gke.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash -# NOTE! This will create real resources on Google GCP. Make sure you clean up any unused -# resources to avoid being billed. -# For reference, this tutorial cost ~10 cents for a couple of hours. -# NOTE! You must change the identity provider client secret setting in your config file! -# cSpell:ignore fullchain - -echo "=> creating cluster" -gcloud container clusters create pomerium --num-nodes 3 --region us-west2 - -echo "=> get cluster credentials so we can use kubectl locally" -gcloud container clusters get-credentials pomerium --region us-west2 - -echo "=> create config from kubernetes-config.yaml which we will mount" -kubectl create configmap config --from-file="config.yaml"="kubernetes-config.yaml" - -echo "=> create our random shared-secret and cookie-secret keys as env vars" -kubectl create secret generic shared-secret --from-literal=shared-secret=$(head -c32 /dev/urandom | base64) -kubectl create secret generic cookie-secret --from-literal=cookie-secret=$(head -c32 /dev/urandom | base64) - -echo "=> initialize secrets for TLS wild card for service use" -kubectl create secret generic certificate \ - --from-literal=certificate=$(base64 -i "$HOME/.acme.sh/*.corp.beyondperimeter.com_ecc/fullchain.cer") -kubectl create secret generic certificate-key \ - --from-literal=certificate-key=$(base64 -i "$HOME/.acme.sh/*.corp.beyondperimeter.com_ecc/*.corp.beyondperimeter.com.key") - -echo "=> load TLS to ingress" -kubectl create secret tls pomerium-tls \ - --key "$HOME/.acme.sh/*.corp.beyondperimeter.com_ecc/*.corp.beyondperimeter.com.key" \ - --cert "$HOME/.acme.sh/*.corp.beyondperimeter.com_ecc/fullchain.cer" - -echo "=> deploy pomerium proxy, authorize, and authenticate" -kubectl apply -f pomerium-proxy.yml -kubectl apply -f pomerium-authenticate.yml -kubectl apply -f pomerium-authorize.yml -kubectl apply -f pomerium-databroker.yml - -echo "=> deploy our test app, httpbin" -kubectl apply -f httpbin.yml - -echo "=> deploy the GKE specific ingress" -kubectl apply -f ingress.yml - -# Alternatively, nginx-ingress can be used -# kubectl apply -f ingress.nginx.yml - -# When done, clean up by deleting the cluster! -# gcloud container clusters delete pomerium diff --git a/content/examples/kubernetes/kubernetes_nginx.sh b/content/examples/kubernetes/kubernetes_nginx.sh deleted file mode 100644 index 8ffa6a5a6..000000000 --- a/content/examples/kubernetes/kubernetes_nginx.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -echo "=> create config from kubernetes-config.yaml which we will mount" -kubectl create configmap config --from-file="config.yaml"="kubernetes-config.yaml" - -echo "=> create our random shared-secret and cookie-secret keys as env vars" -kubectl create secret generic shared-secret --from-literal=shared-secret=$(head -c32 /dev/urandom | base64) -kubectl create secret generic cookie-secret --from-literal=cookie-secret=$(head -c32 /dev/urandom | base64) - -echo "=> deploy pomerium proxy, authorize, and authenticate" -kubectl apply -f pomerium-proxy.yml -kubectl apply -f pomerium-authenticate.yml -kubectl apply -f pomerium-authorize.yml - -echo "=> deploy our test app, httpbin" -kubectl apply -f httpbin.yml - -echo "=> deploy nginx-ingress" -kubectl apply -f ingress.yml diff --git a/content/examples/kubernetes/pomerium-authenticate.yml b/content/examples/kubernetes/pomerium-authenticate.yml deleted file mode 100644 index bc2647b93..000000000 --- a/content/examples/kubernetes/pomerium-authenticate.yml +++ /dev/null @@ -1,69 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: pomerium-authenticate-service -spec: - ports: - - port: 80 - name: http - selector: - app: pomerium-authenticate - type: NodePort ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: pomerium-authenticate - labels: - app: pomerium-authenticate -spec: - replicas: 1 - selector: - matchLabels: - app: pomerium-authenticate - template: - metadata: - labels: - app: pomerium-authenticate - spec: - containers: - - image: pomerium/pomerium:latest - name: pomerium-authenticate - args: - - --config=/etc/pomerium/config.yaml - ports: - - containerPort: 80 - name: http - protocol: TCP - env: - - name: SERVICES - value: authenticate - - name: SHARED_SECRET - valueFrom: - secretKeyRef: - name: shared-secret - key: shared-secret - - name: COOKIE_SECRET - valueFrom: - secretKeyRef: - name: cookie-secret - key: cookie-secret - readinessProbe: - httpGet: - path: /ping - port: 80 - scheme: HTTP - livenessProbe: - httpGet: - path: /ping - port: 80 - scheme: HTTP - initialDelaySeconds: 5 - timeoutSeconds: 1 - volumeMounts: - - mountPath: /etc/pomerium/ - name: config - volumes: - - name: config - configMap: - name: config diff --git a/content/examples/kubernetes/pomerium-authorize.yml b/content/examples/kubernetes/pomerium-authorize.yml deleted file mode 100644 index c6d7ee81a..000000000 --- a/content/examples/kubernetes/pomerium-authorize.yml +++ /dev/null @@ -1,63 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: pomerium-authorize-service -spec: - ports: - - port: 80 - name: grpc - selector: - app: pomerium-authorize - type: ClusterIP ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: pomerium-authorize - labels: - app: pomerium-authorize -spec: - replicas: 1 - selector: - matchLabels: - app: pomerium-authorize - template: - metadata: - labels: - app: pomerium-authorize - spec: - containers: - - image: pomerium/pomerium:latest - name: pomerium-authorize - args: - - --config=/etc/pomerium/config.yaml - ports: - - containerPort: 80 - name: grpc - protocol: TCP - env: - - name: SERVICES - value: authorize - - name: SHARED_SECRET - valueFrom: - secretKeyRef: - name: shared-secret - key: shared-secret - readinessProbe: - tcpSocket: - port: 80 - initialDelaySeconds: 5 - periodSeconds: 10 - livenessProbe: - tcpSocket: - port: 80 - initialDelaySeconds: 15 - periodSeconds: 20 - - volumeMounts: - - mountPath: /etc/pomerium/ - name: config - volumes: - - name: config - configMap: - name: config diff --git a/content/examples/kubernetes/pomerium-console-certificate.yaml b/content/examples/kubernetes/pomerium-console-certificate.yaml deleted file mode 100644 index 1b5d7f2e6..000000000 --- a/content/examples/kubernetes/pomerium-console-certificate.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -apiVersion: cert-manager.io/v1 -kind: Certificate -metadata: - name: pomerium-console-cert - namespace: pomerium -spec: - secretName: pomerium-console-tls - issuerRef: - name: pomerium-issuer - kind: Issuer - dnsNames: - - pomerium-console.pomerium.svc.cluster.local diff --git a/content/examples/kubernetes/pomerium-databroker.yml b/content/examples/kubernetes/pomerium-databroker.yml deleted file mode 100644 index fa7eabaaa..000000000 --- a/content/examples/kubernetes/pomerium-databroker.yml +++ /dev/null @@ -1,64 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: pomerium-databroker-service -spec: - clusterIP: None # databroker is a headless service! - ports: - - port: 80 - name: grpc - selector: - app: pomerium-databroker - type: ClusterIP ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: pomerium-databroker - labels: - app: pomerium-databroker -spec: - replicas: 1 - selector: - matchLabels: - app: pomerium-databroker - template: - metadata: - labels: - app: pomerium-databroker - spec: - containers: - - image: pomerium/pomerium:latest - name: pomerium-databroker - args: - - --config=/etc/pomerium/config.yaml - ports: - - containerPort: 80 - name: grpc - protocol: TCP - env: - - name: SERVICES - value: databroker - - name: SHARED_SECRET - valueFrom: - secretKeyRef: - name: shared-secret - key: shared-secret - readinessProbe: - tcpSocket: - port: 80 - initialDelaySeconds: 5 - periodSeconds: 10 - livenessProbe: - tcpSocket: - port: 80 - initialDelaySeconds: 15 - periodSeconds: 20 - - volumeMounts: - - mountPath: /etc/pomerium/ - name: config - volumes: - - name: config - configMap: - name: config diff --git a/content/examples/kubernetes/pomerium-proxy.yml b/content/examples/kubernetes/pomerium-proxy.yml deleted file mode 100644 index f58e827d3..000000000 --- a/content/examples/kubernetes/pomerium-proxy.yml +++ /dev/null @@ -1,71 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: pomerium-proxy-service -spec: - ports: - - port: 80 - protocol: TCP - name: http - targetPort: http - selector: - app: pomerium-proxy - type: NodePort ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: pomerium-proxy - labels: - app: pomerium-proxy -spec: - replicas: 1 - selector: - matchLabels: - app: pomerium-proxy - template: - metadata: - labels: - app: pomerium-proxy - spec: - containers: - - image: pomerium/pomerium:latest - name: pomerium-proxy - args: - - --config=/etc/pomerium/config.yaml - ports: - - containerPort: 80 - name: http - protocol: TCP - env: - - name: SERVICES - value: proxy - - name: SHARED_SECRET - valueFrom: - secretKeyRef: - name: shared-secret - key: shared-secret - - name: COOKIE_SECRET - valueFrom: - secretKeyRef: - name: cookie-secret - key: cookie-secret - readinessProbe: - httpGet: - path: /ping - port: 80 - scheme: HTTP - livenessProbe: - httpGet: - path: /ping - port: 80 - scheme: HTTP - initialDelaySeconds: 10 - timeoutSeconds: 1 - volumeMounts: - - mountPath: /etc/pomerium/ - name: config - volumes: - - name: config - configMap: - name: config diff --git a/content/examples/kubernetes/values.yaml b/content/examples/kubernetes/values.yaml deleted file mode 100644 index 55a1ba29d..000000000 --- a/content/examples/kubernetes/values.yaml +++ /dev/null @@ -1,27 +0,0 @@ -authenticate: - idp: - provider: "google" - clientID: YOUR_CLIENT_ID - clientSecret: YOUR_SECRET - service: - type: NodePort - annotations: - cloud.google.com/app-protocols: '{"https":"HTTPS"}' - -proxy: - service: - type: NodePort - annotations: - cloud.google.com/app-protocols: '{"https":"HTTPS"}' - -config: - rootDomain: localhost.pomerium.io - policy: - - from: https://hello.localhost.pomerium.io - to: http://nginx.default.svc.cluster.local:80 - allowed_domains: - - gmail.com - -ingress: - annotations: - kubernetes.io/ingress.allow-http: "false" diff --git a/content/examples/nginx/README.md b/content/examples/nginx/README.md deleted file mode 100644 index 989335427..000000000 --- a/content/examples/nginx/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Pomerium as external auth provider for Nginx - -Run this demo locally on your docker-compose capable workstation, or replace `localhost.pomerium.io` with your own domain if running on a server. - -## Includes - -- Authentication and Authorization managed by pomerium -- Routing / reverse proxying handled by nginx - -## How - -- Update `config.yaml` for your e-mail address, if not using gmail/google. -- Replace secrets in `config.yaml`. -- Run `docker-compose up` from this directory. -- Navigate to `https://verify.localhost.pomerium.io` -- ??? -- Profit diff --git a/content/examples/nginx/_wildcard.localhost.pomerium.io-key.pem b/content/examples/nginx/_wildcard.localhost.pomerium.io-key.pem deleted file mode 100644 index 2ad75e316..000000000 --- a/content/examples/nginx/_wildcard.localhost.pomerium.io-key.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDXfeTmeNmQFK3r -CrLcdh9pVrsSjbNOAP2BIQ3AfGdf/S0UqjU1UhXOb2gLm5Dsj/vFvs/fSkiahBdj -7zR1dh7jdOnf3QgcAjIMTo7sJggsABHBF0vHVMXJtNoWmZ+AYOirsn22N3EoUNmX -jlr19LnW07DtkHJFPYsYFy01uOEKGbzKQh8E6DFv3tPNp/raUHkGSAUpT11tZcdf -vbSHuSN4xzGOs6T9QCnu0wCGb2MJNa8l5dhtVuy59jcZWM2i4EBLnXsYbHhkg/uZ -xnVfm3YxgNM8bA2T1DqSUxjpLt7Dty9MHBaEyHVrH/nXYluF1wI7jNC2A7dE6VKq -AkSmFKG7AgMBAAECggEARCYmW9TgSTahAfIyOpKIwJGTO/zgNc0OXuYLKVKuhqbU -uPJTPXemOdD1wKYEISwv3YvIxb8CUwtvMkWV+4fNoPV6eTe3ttPi7A10Ga61auTi -uIQbjQB8RJwTVI5k6P681n/uTdAe0zcueUWl8p7gntX34EmMOeWKtaWuwIylbsG8 -Ftvls8dI/soHUBgZT9HHo3ZitaRQtDYN+YjqAWfQCtPFrBJ5TPS9W6z3cmB/2l19 -nkwZljomj+mJZseEStQUOH/YXf7jpZCWNuxj9l9C+/F5pmiQX6w87thohVXFPmXx -zEExPHePvThx4CxrUGyBeWfzUaYMfzx1T/gyMixDYQKBgQD642G2ElXQSnlZZoLf -gMYTazAjtv7PIRVcVjOJfUORx5LP4sV7CkWokIMdbzfiVkerWt6kb2HDhBskvdFW -ag6Fl8t/Miyi+ZTrE/PmZJqs7fGtmSqjY8wWKfcN6gyTPkh789DXU7ddJIiJLQ10 -sf5Mg2sQkMLQo5XnnauV/SmKiQKBgQDb4eL/MmSR7yKnjxjvek7xXJGqaEXBmazn -pUhp6B+7aHsAg/u71DjzirMn2Ra3+WQ+sDQwbkMQuokqBPUij0Bcv61QSaocjrnb -PmwtXlHeyk9RnGj60oW55gIuJw0EseI17IaqHJPyDNVCQ9WJteI4y8Da+m0E5ohZ -udXzk9DpIwKBgCK3xnS4ktFxDNvXOLMPEdnsEkxO7XHiRR9y+kzDXc9Vi7ZizisZ -n8wUu2AeXOBgSiinOXoNw7yXkl4COm633GyWNd3TJqQi332sVCsErvbRMolwUZss -mzhR9FMjmTvi+YrVkYfKmOw1uwMojd0hKGyUHwO61IqkqIDVq8Hkt5PpAoGBAMlH -RdwF7ToJhdeMjm7pr0oSSuWK/g/y9Ow3yMnpyuJrCe2248FUy61k0gswFjPi/3jD -I4MR7CJsHxNv5lX0fB5q9+P/CtGJdWjVA4GkTZ175I/4dcDk5bT+cBB/ftNFYqWq -Frux3Vw9kxpNrjOZY7RKEAhkJVfPEBHSo5+NODexAoGAXohoO9jOeLtYFOYRdKxj -bbL7fwiR+ecBakiuakoIFc+ibH57fDvxA6YkbLFOVNrpsTVNIbgO9Jois3GhrEGH -8TbGfohpmwC7nZ62aFJSNxD48gYvYzMamo0WymM1uH3jwlJY/kVO6KHopcN8+kQS -/zG8+V/OgnBBvyfWWX8ygio= ------END PRIVATE KEY----- diff --git a/content/examples/nginx/_wildcard.localhost.pomerium.io.pem b/content/examples/nginx/_wildcard.localhost.pomerium.io.pem deleted file mode 100644 index fc28599ff..000000000 --- a/content/examples/nginx/_wildcard.localhost.pomerium.io.pem +++ /dev/null @@ -1,24 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIEAjCCAmqgAwIBAgIRAJGdiQDsLfchZYUtx06mQpswDQYJKoZIhvcNAQELBQAw -RTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMQ0wCwYDVQQLEwR0ZXN0 -MRQwEgYDVQQDEwtta2NlcnQgdGVzdDAeFw0xOTA2MDEwMDAwMDBaFw0zMDA4MjQx -OTQyNTBaMDgxJzAlBgNVBAoTHm1rY2VydCBkZXZlbG9wbWVudCBjZXJ0aWZpY2F0 -ZTENMAsGA1UECxMEdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -ANd95OZ42ZAUresKstx2H2lWuxKNs04A/YEhDcB8Z1/9LRSqNTVSFc5vaAubkOyP -+8W+z99KSJqEF2PvNHV2HuN06d/dCBwCMgxOjuwmCCwAEcEXS8dUxcm02haZn4Bg -6KuyfbY3cShQ2ZeOWvX0udbTsO2QckU9ixgXLTW44QoZvMpCHwToMW/e082n+tpQ -eQZIBSlPXW1lx1+9tIe5I3jHMY6zpP1AKe7TAIZvYwk1ryXl2G1W7Ln2NxlYzaLg -QEudexhseGSD+5nGdV+bdjGA0zxsDZPUOpJTGOku3sO3L0wcFoTIdWsf+ddiW4XX -AjuM0LYDt0TpUqoCRKYUobsCAwEAAaN6MHgwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud -JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAU0t8UaNj7 -xry1h0qnTAm8Sxv69aMwIgYDVR0RBBswGYIXKi5sb2NhbGhvc3QucG9tZXJpdW0u -aW8wDQYJKoZIhvcNAQELBQADggGBAJhOdplKGoR7/83qDjELdjhaoecZASqs5M+P -Sxm7z5s+KSbElebw6/rHJciKAlT9tqHQO6CqliQ9hl4AHWxi+cjpwfxyqWn/VGIa -4WoGyInd/I2PDne+5bIj0MXkikilk5NsJtypvGGjZJTF2T07QfXLlLi3nYTMHYzt -TLZpu7vK+B2ZGCGG4o9pws5ZFjtuOXEDGsE1APPp3xjvC/uJt2xgqo4XcRGIVHgm -mY2yi5KmUCAv0HHdDjxZoqEDazv8t/VuPc3hJcuUcIBZvyMFyPNMqN5ePI7D5TkD -zOqW28I8jpB5zdDpCr4qXsU+Cf+4fB0jDncBq95n1v8EJsm7zeTIFZNgLv3ISthF -lGEFS1zv+ybCOYPl3H0yd13S6N4QUHbESXHvZ2l2V1qDiKrfFcVhQ5ZEDD7/HDqT -N+v7zzMOzmPNCSiky1lMMj/vP87AjaliJnvBcT4F5iU867ws/Refh+yege2l6roO -LEM1YmdMYuNFbCsS2BbQsK9mbDkcmQ== ------END CERTIFICATE----- diff --git a/content/examples/nginx/config.yaml.md b/content/examples/nginx/config.yaml.md deleted file mode 100644 index 561dc62a5..000000000 --- a/content/examples/nginx/config.yaml.md +++ /dev/null @@ -1,22 +0,0 @@ -```yaml title="config.yaml" -# Main configuration flags : https://www.pomerium.com/docs/reference/ -address: :80 -cookie_secret: YVFTMIfW8yBJw+a6sYwdW8rHbU+IAAV/SUkCTg9Jtpo= -shared_secret: 80ldlrU2d7w+wVpKNfevk6fmb8otEx6CqOfshj2LwhQ= - -idp_provider: "google" -idp_client_id: REPLACE_ME -idp_client_secret: REPLACE_ME - -insecure_server: true -forward_auth_url: http://fwdauth.localhost.pomerium.io -authenticate_service_url: https://authenticate.localhost.pomerium.io - -policy: - - from: https://verify.localhost.pomerium.io - to: https://httpbin - allowed_domains: - - pomerium.com - - gmail.com - pass_identity_headers: true -``` diff --git a/content/examples/nginx/docker-compose.yaml.md b/content/examples/nginx/docker-compose.yaml.md deleted file mode 100644 index 5e3e7b3de..000000000 --- a/content/examples/nginx/docker-compose.yaml.md +++ /dev/null @@ -1,30 +0,0 @@ -```yaml title="docker-compose.yaml" -services: - nginx: - # to emulate nginx-ingress behavior, use openresty which comes with 'escaped_request_uri' - # pre-compiled. Also uncomment lines marked `uncomment to emulate nginx-ingress behavior` - # in the nginx `.conf` configuration files. - # image: openresty/openresty - image: nginx - restart: unless-stopped - ports: - - "80:80" - - "443:443" - volumes: - - ./verify.conf:/etc/nginx/conf.d/verify.conf - - ./pomerium.conf:/etc/nginx/conf.d/pomerium.conf - - ./_wildcard.localhost.pomerium.io.pem:/etc/nginx/nginx.pem - - ./_wildcard.localhost.pomerium.io-key.pem:/etc/nginx/nginx-key.pem - - ./proxy.conf:/etc/nginx/proxy.conf - - verify: - image: pomerium/verify:latest - expose: - - 80 - pomerium: - image: pomerium/pomerium:latest - volumes: - - ./config.yaml:/pomerium/config.yaml:ro - expose: - - 80 -``` diff --git a/content/examples/nginx/pomerium.conf.md b/content/examples/nginx/pomerium.conf.md deleted file mode 100644 index dd80d025b..000000000 --- a/content/examples/nginx/pomerium.conf.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -# cSpell:ignore fwdauth ---- -```nginx -# Pomerium endpoint -server { - listen 443 ssl; - server_name authenticate.localhost.pomerium.io fwdauth.localhost.pomerium.io; - ssl_certificate /etc/nginx/nginx.pem; - ssl_certificate_key /etc/nginx/nginx-key.pem; - - location / { - proxy_pass http://pomerium; - include /etc/nginx/proxy.conf; - } -} - -# Define an upstream so that we don't need resolvers when we use variables in proxy_pass directives -# https://stackoverflow.com/questions/17685674/nginx-proxy-pass-with-remote-addr -upstream pomerium { - server pomerium; -} -``` diff --git a/content/examples/nginx/proxy.conf b/content/examples/nginx/proxy.conf deleted file mode 100644 index d49ccae92..000000000 --- a/content/examples/nginx/proxy.conf +++ /dev/null @@ -1,64 +0,0 @@ -set $pass_access_scheme $scheme; - -set $pass_server_port $server_port; - -set $best_http_host $http_host; -set $pass_port $pass_server_port; - -set $proxy_alternative_upstream_name ""; - -client_max_body_size 1m; - - -proxy_set_header Host $best_http_host; - -# Pass the extracted client certificate to the backend - -# Allow websocket connections -proxy_set_header Upgrade $http_upgrade; - -proxy_set_header Connection ""; - -# uncomment to emulate nginx-ingress -# set_escape_uri $escaped_request_uri $request_uri; - -# proxy_set_header X-Request-ID $req_id; -proxy_set_header X-Real-IP $remote_addr; -proxy_set_header X-Forwarded-For $remote_addr; -proxy_set_header X-Forwarded-Host $best_http_host; -proxy_set_header X-Forwarded-Port $pass_port; -proxy_set_header X-Forwarded-Proto $pass_access_scheme; - -proxy_set_header X-Scheme $pass_access_scheme; - -# Pass the original X-Forwarded-For -proxy_set_header X-Original-Forwarded-For $http_x_forwarded_for; - -# mitigate HTTPoxy Vulnerability -# https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/ -proxy_set_header Proxy ""; - -# Custom headers to proxied server - -proxy_connect_timeout 5s; -proxy_send_timeout 60s; -proxy_read_timeout 60s; - -proxy_buffering off; -proxy_buffer_size 4k; -proxy_buffers 4 4k; - -proxy_max_temp_file_size 1024m; - -proxy_request_buffering on; -proxy_http_version 1.1; - -proxy_cookie_domain off; -proxy_cookie_path off; - -# In case of errors try the next upstream server before returning an error -proxy_next_upstream error timeout; -proxy_next_upstream_timeout 0; -proxy_next_upstream_tries 3; - -proxy_redirect off; diff --git a/content/examples/nginx/rootCA-key.pem b/content/examples/nginx/rootCA-key.pem deleted file mode 100644 index 1b5ac7f1e..000000000 --- a/content/examples/nginx/rootCA-key.pem +++ /dev/null @@ -1,40 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIG/gIBADANBgkqhkiG9w0BAQEFAASCBugwggbkAgEAAoIBgQCub8x6MRI1aWZV -k7qfpQn7CK6fCHNceBhSQFMHBJXQLEAe34uNgF1h+NQGM2zaKDZ8hIsRNZq0dV/g -Xyd7AMA5C8DyyHfqzoiHJeTXKoqGEmi/MyXfnHr6N4rQpoG97SbACKYfNOh/MD05 -gIg51LrbTK1GzFyg0AVntsvmm3r3NNHv/BJKVKV+2HZx1D83xcBstdLDAPdtmU3z -STzixQYDTlzs1gUrJPfJAi1sAMM/RbDKTmgsYJopxADRYldOIvZEZqPrupInUi4v -iFEosb0dpSSeHkKBgVl81X2ro+WH4vgfoeGkpu6mh67FfN1WljMf63E6yOEBcqxE -+Vc9O+ysruODnma1d+DfXoHoZInUhzUM7nTdbsftmb0C5bFA3ts16WGZ1g21Hi7m -NH2MdW2hLyRngAU9AHTWObdBxb4MBmBSF5ZIElcsfLABilHG508L2ZYM+uqOb0iW -AMcVyrli7EaDEOF/oUv7WsDAekwGKKfy9exfWhw7+yn+UYG4oPUCAwEAAQKCAYAx -e5d2xjrTGf4koo6bQPcO1kyq4nvPLGZB1ut2ny9caWEbIPD2iAZ1h1+mDqp/TE8A -jZzhmeIz9OPowzVw6CqfRB1NAd86pbIHHJHJE9FN7ST3sCu7PimIl37yZ3mAhiiq -6wks6xZVFjsX98UtGpKTKTIyVkCkgb42yJ0Y4txECiDPwiLyIQb9b6xR6BKy4I8Q -h5etJ7YIyidZr1ntPlTRVUZ5DNFUht0fkVWPQLwiU8Ot8AYPKKwy0t4kh5Aao0Hf -CDQP6Y5/XXKLl5bNi/SO5eg6jk3DnILwPkjXM3tVxcag+KmMc4GfVmVVDP+QkmVl -LtGOHuBeyicdC5/jt6xMwbsEdY/YFjlO4WDH/5e8F7KG1X3OjTmqwdNjSNg4rXni -u0ZEG+/o80ha21lCys+QpQ9PQmYPaGlzVPY9z0F6JsAlXNbNRIIOsJNEKlAICWXF -9YyAaD8pV60UhK67q5wZ3uxyAjplM5+930asL5MPgb4BEvRY4bWlOe55lySXsbUC -gcEA0HnqdCQBfmiylZv4Uh8JVojSZcZFtFU8V02TY/XrWjwzWv8z1ZXnzx18kAz7 -islThqlvr38HXwFfUNDhI/IIp+8zcvT9T56e1T8jYxhcaTZBEZ7XlG/jWbWbRx/k -JEctixh7J5EhbsxhC7TfuH9lQ2r50WvmmrGpLoqHDe5fyKFTpbUkrGB19idiw9oI -awjxOgN+uRrTFjuOPhxgfSwJGwPnE0my8lS/5fPvNUuQdWecqEe3CTFjVXY44IzB -7W9HAoHBANYzbsNClt8HgLyp0XZg4W19BuCic6qJZhOSVoUlGFTTa2dTQnSfq5NL -O1GCfZ/fy0QZvvBebf+Mf3WycEv/BbxRT0lDP0QjdamHkn9mGK+ODmYxvPu7Lqk9 -5acrXM8uXuK4bkT2eXKE2H7x9jrnxpSI/zE3cwic+GlQWH85ywAKwT07g3BiM5GJ -pHpoJGwxraBUDb6HPTgTsVzPtvCbKqYw9uUalPDGI1Pc0iEitT5s41HT57P10hnD -gOkIyOXj4wKBwEBQfC3cNcHDluRku5TKEl1p1E6lfjeF3Bmqyv+ZjEPIMqet91W6 -60qP9C+Ucb19IpF2kAf6DlIW4ErURcCLGHSGbL7YKZV4f9OVqNsXVtr2a9h9wk/+ -vIqeZgrpIb63Xqt8n/Gy6jd+QaoU4LfQRXMo+2zJ9theWq0K+2Mm2NHSQzXpziiH -kZygxe1ZxCMRHSoijeOZDOnc8aLjqjizbxOwfocKw3PTBWhxeqhcaXJuxnt7tFHX -tKdW03Eiu2j+XQKBwQCdyCcX1+4wfWNcFa9Aht6m+wjc4W1YOnuhgRMQYqHIoi+k -XdU++Pq2th0MzpVg9cXR9TEL+FMIgeLFvNoxcLo13KMNsWZh98jNRxsnkvouHvMG -Xi76MwiNDBYljLCBwIOOeBJp5DDTpX2gDPW2sFI7yapJA7JNrurhEJkPpm+dKU7s -nvEUEJIx63Tn4dyqgfGGf0Pci9wReZgVaMA1/eZtovXLD0iVDy6osKlsVRey0xyj -gvdTPYk1Byjm/1yU0scCgcEAgCzLcqc7O1t9kXNo48Lh+O3wtxYVZ0FTHAz0TtcR -oVaRaok3aSEkCuZlBf4a9CJCKxzkDPg7dNNcUt5ng16XxJoEcIgf8FeS+BZS9L0O -bLOQoAggW41OlRnX9yQIti9w/MR+qRzKSftTZcP8ySls4SCphlqsx/a7JXncgwI8 -QmML5MzfffKdB1RNs5yVWyzSsxHgmVGLcA9UziomcUPCrpXp10C/yzGnMPAyAwlo -9k5AET80ZLKc7XYQ0NxI2yCf ------END PRIVATE KEY----- diff --git a/content/examples/nginx/rootCA.pem b/content/examples/nginx/rootCA.pem deleted file mode 100644 index 9ab4190ab..000000000 --- a/content/examples/nginx/rootCA.pem +++ /dev/null @@ -1,26 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIEWTCCAsGgAwIBAgIQBA3zYaPnHKhRmKC37lWvEjANBgkqhkiG9w0BAQsFADBF -MR4wHAYDVQQKExVta2NlcnQgZGV2ZWxvcG1lbnQgQ0ExDTALBgNVBAsTBHRlc3Qx -FDASBgNVBAMTC21rY2VydCB0ZXN0MB4XDTIwMDgyNDE5NDIwOVoXDTMwMDgyNDE5 -NDIwOVowRTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMQ0wCwYDVQQL -EwR0ZXN0MRQwEgYDVQQDEwtta2NlcnQgdGVzdDCCAaIwDQYJKoZIhvcNAQEBBQAD -ggGPADCCAYoCggGBAK5vzHoxEjVpZlWTup+lCfsIrp8Ic1x4GFJAUwcEldAsQB7f -i42AXWH41AYzbNooNnyEixE1mrR1X+BfJ3sAwDkLwPLId+rOiIcl5NcqioYSaL8z -Jd+cevo3itCmgb3tJsAIph806H8wPTmAiDnUuttMrUbMXKDQBWe2y+abevc00e/8 -EkpUpX7YdnHUPzfFwGy10sMA922ZTfNJPOLFBgNOXOzWBSsk98kCLWwAwz9FsMpO -aCxgminEANFiV04i9kRmo+u6kidSLi+IUSixvR2lJJ4eQoGBWXzVfauj5Yfi+B+h -4aSm7qaHrsV83VaWMx/rcTrI4QFyrET5Vz077Kyu44OeZrV34N9egehkidSHNQzu -dN1ux+2ZvQLlsUDe2zXpYZnWDbUeLuY0fYx1baEvJGeABT0AdNY5t0HFvgwGYFIX -lkgSVyx8sAGKUcbnTwvZlgz66o5vSJYAxxXKuWLsRoMQ4X+hS/tawMB6TAYop/L1 -7F9aHDv7Kf5Rgbig9QIDAQABo0UwQzAOBgNVHQ8BAf8EBAMCAgQwEgYDVR0TAQH/ -BAgwBgEB/wIBADAdBgNVHQ4EFgQU0t8UaNj7xry1h0qnTAm8Sxv69aMwDQYJKoZI -hvcNAQELBQADggGBAFZT6Zdg+tt+8t6Bo9Boe8uOKnqrCSuOCyMIajDLgijPRlHf -iJRggRjGT2Ig7c0nzL5SfeuExoMPMUmkfNAKki3VhK7cxLijDtn4fOmyyW5OO7AT -zwSmOyakHXq4ip3klysNGVPzxjwHBuK5rCdPa2X1WXN4PeM6NQvGZB34hQ1962om -1gad4YardZ81fVLJfOlCtIPD87TSreVGxiawUIAAGWgDuVMouN4PvqTUyEmorgxi -hSaiVDCSlS/nuW5fuOGzZ1Ko9UhbCsmO3bbLzXKcjuwKeyzgyjozHMyx5gUhhOFk -kqDIuIven3j+uLke0WAK++Z11vM8fVn0wB80RqubuTbqJzvH3w0R/PWVd0yAMFNu -Y2Z+AZ0OwMm9BtqfwoW5PZSIMF06q6IbLmuLEH/5dE9xDN0s5Ia8gn7ySYqso+62 -yJjURRgGJeXLkrjfeSav39D0bg+JCB7J63Z7BCz6/Jv1TL45yWbeMmtqFPH6nS5t -25uIk/1regWTCajVMg== ------END CERTIFICATE----- diff --git a/content/examples/nginx/verify.conf.md b/content/examples/nginx/verify.conf.md deleted file mode 100644 index 178162789..000000000 --- a/content/examples/nginx/verify.conf.md +++ /dev/null @@ -1,75 +0,0 @@ ---- -# cSpell:ignore fwdauth authredirect ---- -```nginx -# Protected application -server { - listen 80; - listen 443 ssl http2; - - server_name verify.localhost.pomerium.io; - ssl_certificate /etc/nginx/nginx.pem; - ssl_certificate_key /etc/nginx/nginx-key.pem; - - - location = /ext_authz { - internal; - - proxy_pass_request_body off; - proxy_set_header Content-Length ""; - proxy_set_header X-Forwarded-Proto ""; - - proxy_set_header Host fwdauth.localhost.pomerium.io; - proxy_set_header X-Original-URL $scheme://$http_host$request_uri; - proxy_set_header X-Original-Method $request_method; - proxy_set_header X-Real-IP $remote_addr; - - proxy_set_header X-Forwarded-For $remote_addr; - - proxy_set_header X-Auth-Request-Redirect $request_uri; - - proxy_buffering off; - - proxy_buffer_size 4k; - proxy_buffers 4 4k; - proxy_request_buffering on; - proxy_http_version 1.1; - - proxy_ssl_server_name on; - proxy_pass_request_headers on; - - client_max_body_size 1m; - - # Pass the extracted client certificate to the auth provider - - set $target http://pomerium/verify?uri=$scheme://$http_host$request_uri; - - # uncomment to emulate nginx-ingress behavior - # set $target http://pomerium/verify?uri=$scheme://$http_host$request_uri&rd=$pass_access_scheme://$http_host$escaped_request_uri; - proxy_pass $target; - } - - location @authredirect { - internal; - add_header Set-Cookie $auth_cookie; - - # uncomment to emulate nginx-ingress behavior - # return 302 https://fwdauth.localhost.pomerium.io/?uri=$scheme://$host$request_uri&rd=$pass_access_scheme://$http_host$escaped_request_uri; - - return 302 - https://fwdauth.localhost.pomerium.io/?uri=$scheme://$host$request_uri; - } - - location / { - proxy_pass http://verify; - - include /etc/nginx/proxy.conf; - # If we get a 401, respond with a named location - error_page 401 = @authredirect; - # this location requires authentication - auth_request /ext_authz; - auth_request_set $auth_cookie $upstream_http_set_cookie; - add_header Set-Cookie $auth_cookie; - } -} -``` diff --git a/content/examples/tiddlywiki/docker-compose.yaml.md b/content/examples/tiddlywiki/docker-compose.yaml.md deleted file mode 100644 index 4f21ed7bd..000000000 --- a/content/examples/tiddlywiki/docker-compose.yaml.md +++ /dev/null @@ -1,34 +0,0 @@ -```yaml title="docker-compose.yaml" -services: - pomerium: - image: pomerium/pomerium:latest - volumes: - # Use a volume to store ACME certificates - - ./config.yaml:/pomerium/config.yaml:ro - ports: - - 443:443 - - tiddlywiki_init: - image: elasticdog/tiddlywiki:latest - volumes: - - ./wiki:/tiddlywiki - command: ['mywiki', '--init', 'server'] - - tiddlywiki: - image: elasticdog/tiddlywiki:latest - ports: - - 8080:8080 - volumes: - - ./wiki:/tiddlywiki - command: - - mywiki - - --listen - - host=0.0.0.0 - - authenticated-user-header=x-pomerium-claim-email - - readers=reader@example.com - - writers=writer@example.com - - username= - - password=password - depends_on: - - tiddlywiki_init -``` diff --git a/content/examples/traefik-ingress/README.md b/content/examples/traefik-ingress/README.md deleted file mode 100644 index edffbcecf..000000000 --- a/content/examples/traefik-ingress/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Pomerium as forward-auth provider for Traefik on Kubernetes - -Run this demo locally on your kubernetes capable workstation or: - - use `kubectl port-forward service/traefik 80:80 443:443` - - replace `localhost.pomerium.io` with your own domain - -## Includes - -- Authentication and Authorization managed by pomerium -- Routing / reverse proxying handled by traefik -- Installation using upstream `helm` charts - -## How - -- Update `values/pomerium.yaml` for your e-mail address, if not using gmail/google. -- Replace IdP secrets in `values/pomerium.yaml`. -- Run `./add_repos.sh` from this directory. -- Run `./install.sh` from this directory. -- Navigate to `https://hello.localhost.pomerium.io` diff --git a/content/examples/traefik-ingress/add_repos.sh.md b/content/examples/traefik-ingress/add_repos.sh.md deleted file mode 100755 index 23b5c69e0..000000000 --- a/content/examples/traefik-ingress/add_repos.sh.md +++ /dev/null @@ -1,5 +0,0 @@ -```bash -helm repo add bitnami https://charts.bitnami.com/bitnami -helm repo add pomerium https://helm.pomerium.io -helm repo add traefik https://containous.github.io/traefik-helm-chart -``` diff --git a/content/examples/traefik-ingress/crds/middleware.yaml.md b/content/examples/traefik-ingress/crds/middleware.yaml.md deleted file mode 100644 index 2d55caa05..000000000 --- a/content/examples/traefik-ingress/crds/middleware.yaml.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -# cSpell:ignore containo ---- -```yaml -apiVersion: traefik.containo.us/v1alpha1 -kind: Middleware -metadata: - name: auth -spec: - forwardAuth: - address: https://pomerium-proxy.pomerium - tls: - insecureSkipVerify: true - trustForwardHeader: true -``` diff --git a/content/examples/traefik-ingress/install.sh.md b/content/examples/traefik-ingress/install.sh.md deleted file mode 100755 index 9d9784b2d..000000000 --- a/content/examples/traefik-ingress/install.sh.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -# cSpell:ignore crds ---- -```bash {4,10,16,22,25} -kubectl create namespace pomerium - -# Create shared TLS secret -kubectl create secret tls wildcard-tls \ - --namespace pomerium \ - --cert=_wildcard.localhost.pomerium.io.pem \ - --key=_wildcard.localhost.pomerium.io-key.pem - -# Install Traefik helm chart -helm upgrade --install --wait \ - --namespace pomerium \ - traefik traefik/traefik \ - --values values/traefik.yaml - -# Install Pomerium helm chart -helm upgrade --install --wait \ - --namespace pomerium \ - pomerium pomerium/pomerium \ - --values values/pomerium.yaml - -# Create middleware -kubectl --namespace pomerium apply -f crds/middleware.yaml - -# Install hello app -helm upgrade --install --wait \ - --namespace pomerium \ - --version 6.2.1 \ - hello bitnami/nginx \ - --values values/hello.yaml -``` diff --git a/content/examples/traefik-ingress/values/hello.yaml.md b/content/examples/traefik-ingress/values/hello.yaml.md deleted file mode 100644 index a7a8a2307..000000000 --- a/content/examples/traefik-ingress/values/hello.yaml.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -# cSpell:ignore middlewares kubernetescrd ---- -```yaml -ingress: - enabled: true - hosts: - - name: hello.localhost.pomerium.io - path: / - - annotations: - traefik.ingress.kubernetes.io/router.middlewares: pomerium-auth@kubernetescrd - traefik.ingress.kubernetes.io/router.tls: "true" - tls: - - hosts: - - hello.localhost.pomerium.io - secretName: wildcard-tls -service: - type: ClusterIP -``` diff --git a/content/examples/traefik-ingress/values/pomerium.yaml.md b/content/examples/traefik-ingress/values/pomerium.yaml.md deleted file mode 100644 index 10bf74a88..000000000 --- a/content/examples/traefik-ingress/values/pomerium.yaml.md +++ /dev/null @@ -1,29 +0,0 @@ -```yaml -authenticate: - idp: - provider: REPLACE_ME - url: REPLACE_ME - clientID: REPLACE_ME - clientSecret: REPLACE_ME - -config: - rootDomain: localhost.pomerium.io - sharedSecret: R0+XRoGVpcoi4PfB8tMlvnrS5XUasO+D1frAEdYcYjs= - cookieSecret: FLPCOQKigK5EQnyXlBhchl5fgzNKqi3ubtvOGt477Dg= - generateTLS: true - routes: - - from: https://hello.localhost.pomerium.io - to: http://hello-nginx - policy: - - allow: - or: - - domain: - is: gmail.com -ingress: - annotations: - traefik.ingress.kubernetes.io/router.tls: "true" - secretName: wildcard-tls -forwardAuth: - enabled: true - internal: true -``` diff --git a/content/examples/traefik-ingress/values/traefik.yaml.md b/content/examples/traefik-ingress/values/traefik.yaml.md deleted file mode 100644 index b3a64685d..000000000 --- a/content/examples/traefik-ingress/values/traefik.yaml.md +++ /dev/null @@ -1,5 +0,0 @@ -```yaml -additionalArguments: - - "--serverstransport.insecureskipverify=true" - - "--entryPoints.websecure.forwardedHeaders.insecure" -``` From 2348b38486af20ab948ef1141a4d3c1a0d12396e Mon Sep 17 00:00:00 2001 From: Bobby DeSimone Date: Sun, 10 May 2026 09:02:16 -0700 Subject: [PATCH 6/6] examples: live-test fixes from Orbstack walkthrough MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each remaining example was booted in Orbstack to prove the documented user journey actually works. Static checks (yaml.safe_load, docker compose config, image probe) only caught the easy cases; the live walk found a handful of real bugs that would have broken anyone copy-pasting these today. - enterprise/hosted-auth-docker.yaml.md: pin database to postgres:16 instead of postgres:latest. Postgres 18 (now :latest) changed the data directory layout and refuses to start with the example's existing pgdata:/var/lib/postgresql/data mount; container loops Restarting and the whole stack dies. postgres:16 brings up healthy. - tooljet/console-compose.yaml.md: same fix for the database service in the full-stack tooljet/console compose (postgres:latest -> postgres:17, matching the postgres pin we just set on the verify-and-tooljet postgres service in the same file). - jenkins/jenkins-docker-compose.md: fix the docker-socket mount path — ./var/run/docker.sock had a stray leading "." that made compose create an empty directory at $PWD/var/run/docker.sock and bind-mount that into the container. Inside Jenkins, /var/run/docker.sock was an empty dir, not the host docker socket. Anyone running this example to drive docker-based agents from Jenkins would have hit it immediately. - go-sdk/go-app.md: drop the unused "time" import. go build ./... fails on the example as previously written ("time" imported and not used). Removing it lets the example compile against current sdk-go v0.0.9. - cloudrun/deploy.sh.md: REVERT my earlier fix to "gcloud run domain-mappings". gcloud SDK 555 rejects --region on the GA domain-mappings command — that command is Cloud Run for Anthos only. Fully-managed Cloud Run still uses "gcloud beta run domain-mappings". Restore the beta prefix and the gcloud components install step, plus a comment explaining why beta is still required. Verified end-to-end in Orbstack: - guacamole: docker compose up + curl through Pomerium -> 302 to authenticate.pomerium.app, route works, TLS handshake clean. - jenkins: docker compose up + curl localhost:8080/login -> Jenkins serves its sign-in page. - tooljet (minimal): pomerium + verify + postgres + tooljet up, config parses (the allow: typo fix is accepted by Pomerium). - tiddlywiki (inline compose in tiddlywiki.mdx): docker compose up, curl through Pomerium -> 302 to authenticate. - prometheus: prom/prometheus boots with all four alert files; promtool check rules SUCCESS for each (10/17/16/13 rules loaded). - go-sdk: go build ./... clean. - js-sdk express: node server boots, PomeriumVerifier resolves. - tcp/pomerium-tunnel.sh: pomerium-cli tcp --listen flag confirmed. Pomerium-console (cloudsmith.io/pomerium/enterprise/pomerium-console) remains auth-blocked end-to-end — that's an entitlement requirement, not a content fault. Helm chart at helm.pomerium.io is salvageable but frozen at appVersion v0.22.0 (May 2023); affects helm.mdx, argo.md, istio.mdx — tracked separately in Linear ENG-4021. --- content/examples/cloudrun/deploy.sh.md | 4 +++- content/examples/cloudrun/policy.template.yaml.md | 14 ++++++++++---- content/examples/config/route.example.yaml.md | 9 +++------ .../examples/enterprise/hosted-auth-docker.yaml.md | 2 +- content/examples/go-sdk/go-app.md | 1 - .../guacamole/guacamole.pomerium-config.md | 3 +-- content/examples/jenkins/jenkins-docker-compose.md | 4 ++-- .../kubernetes/pomerium-certificates.yaml.md | 2 +- .../examples/kubernetes/pomerium-values.yaml.md | 2 +- content/examples/tooljet/config-console.yaml.md | 12 ++++++------ content/examples/tooljet/console-compose.yaml.md | 6 +++--- content/examples/tooljet/docker-compose.yaml.md | 2 +- 12 files changed, 32 insertions(+), 29 deletions(-) diff --git a/content/examples/cloudrun/deploy.sh.md b/content/examples/cloudrun/deploy.sh.md index 0a9b193d7..407931100 100644 --- a/content/examples/cloudrun/deploy.sh.md +++ b/content/examples/cloudrun/deploy.sh.md @@ -4,7 +4,9 @@ ```bash title="deploy.sh" #!/bin/bash -# Install gcloud beta +# domain-mappings on fully-managed Cloud Run is still under `gcloud beta` +# (the GA `gcloud run domain-mappings` is Cloud Run for Anthos only and +# rejects --region as of gcloud SDK 555+). gcloud components install beta # Capture current project number diff --git a/content/examples/cloudrun/policy.template.yaml.md b/content/examples/cloudrun/policy.template.yaml.md index 4e516eca1..ea6679a9e 100644 --- a/content/examples/cloudrun/policy.template.yaml.md +++ b/content/examples/cloudrun/policy.template.yaml.md @@ -1,12 +1,18 @@ ```yaml title="policy.template.yaml" - from: https://hello.cloudrun.pomerium.io to: ${HELLO_URL} - allowed_domains: - - gmail.com enable_google_cloud_serverless_authentication: true + policy: + - allow: + or: + - domain: + is: gmail.com - from: https://verify.cloudrun.pomerium.io to: https://verify.pomerium.com pass_identity_headers: true - allowed_domains: - - gmail.com + policy: + - allow: + or: + - domain: + is: gmail.com ``` diff --git a/content/examples/config/route.example.yaml.md b/content/examples/config/route.example.yaml.md index 85f8ca71f..eb0daee0f 100644 --- a/content/examples/config/route.example.yaml.md +++ b/content/examples/config/route.example.yaml.md @@ -1,11 +1,8 @@ ```yaml # This file contains only route and policy configuration details. Other -# configuration settings required by pomerium are excluded for clarity. -# See: https://www.pomerium.io/docs/reference/ - -# -# For a complete self contained configuration see : config.example.yaml. -# Or, mix and match a policy file (this) with env vars : config.example.env +# configuration settings required by Pomerium are excluded for clarity. +# See https://www.pomerium.com/docs/reference for the full configuration +# reference. routes: - from: https://verify.localhost.pomerium.io diff --git a/content/examples/enterprise/hosted-auth-docker.yaml.md b/content/examples/enterprise/hosted-auth-docker.yaml.md index 5baab8004..d30a7ef5a 100644 --- a/content/examples/enterprise/hosted-auth-docker.yaml.md +++ b/content/examples/enterprise/hosted-auth-docker.yaml.md @@ -40,7 +40,7 @@ services: - metrics:/data:rw - ./console-config.yaml:/pomerium/console-config.yaml:ro database: - image: postgres:latest + image: postgres:16 restart: always healthcheck: test: ['CMD-SHELL', 'pg_isready -d postgres -U postgres'] diff --git a/content/examples/go-sdk/go-app.md b/content/examples/go-sdk/go-app.md index 31f3cf599..1d4e7dc45 100644 --- a/content/examples/go-sdk/go-app.md +++ b/content/examples/go-sdk/go-app.md @@ -9,7 +9,6 @@ import ( "fmt" "log" "net/http" - "time" "github.com/go-jose/go-jose/v3/jwt" "github.com/pomerium/sdk-go" diff --git a/content/examples/guacamole/guacamole.pomerium-config.md b/content/examples/guacamole/guacamole.pomerium-config.md index 4925db20c..084c56e38 100644 --- a/content/examples/guacamole/guacamole.pomerium-config.md +++ b/content/examples/guacamole/guacamole.pomerium-config.md @@ -1,10 +1,9 @@ ```yaml authenticate_service_url: https://authenticate.pomerium.app -jwt_claim_headers: email +jwt_claims_headers: email routes: - pass_identity_headers: true - from: https://guacamole.localhost.pomerium.io to: http://guacamole:8080 policy: diff --git a/content/examples/jenkins/jenkins-docker-compose.md b/content/examples/jenkins/jenkins-docker-compose.md index 8d11ed5de..de32d87d7 100644 --- a/content/examples/jenkins/jenkins-docker-compose.md +++ b/content/examples/jenkins/jenkins-docker-compose.md @@ -21,7 +21,7 @@ services: jenkins: networks: main: {} - image: jenkins/jenkins:lts-jdk11 + image: jenkins/jenkins:lts-jdk21 privileged: true user: root ports: @@ -31,5 +31,5 @@ services: # File path to Jenkins_home -- stores configs, build logs, and artifacts - ./home/jenkins_compose/jenkins_configuration:/var/jenkins_home # "sock" is the Unix socket the Docker daemon listens on by default - - ./var/run/docker.sock:/var/run/docker.sock + - /var/run/docker.sock:/var/run/docker.sock ``` diff --git a/content/examples/kubernetes/pomerium-certificates.yaml.md b/content/examples/kubernetes/pomerium-certificates.yaml.md index ded940a0e..22593ca9a 100644 --- a/content/examples/kubernetes/pomerium-certificates.yaml.md +++ b/content/examples/kubernetes/pomerium-certificates.yaml.md @@ -1,4 +1,4 @@ -```yaml title="pomerium-console-certificate.yaml" +```yaml title="pomerium-certificates.yaml" apiVersion: cert-manager.io/v1 kind: Certificate metadata: diff --git a/content/examples/kubernetes/pomerium-values.yaml.md b/content/examples/kubernetes/pomerium-values.yaml.md index 0d914e6d8..383235763 100644 --- a/content/examples/kubernetes/pomerium-values.yaml.md +++ b/content/examples/kubernetes/pomerium-values.yaml.md @@ -16,7 +16,7 @@ proxy: databroker: existingTLSSecret: pomerium-tls storage: - connectionString: postgres://://postgres.pomerium.svc.cluster.local #Replace with the path to your DB solution. + connectionString: postgres://USER:PASSWORD@postgres.pomerium.svc.cluster.local:5432/postgres # Replace with the path to your DB solution. type: postgres clientTLS: existingSecretName: pomerium-tls diff --git a/content/examples/tooljet/config-console.yaml.md b/content/examples/tooljet/config-console.yaml.md index 6591d1e37..375236d7b 100644 --- a/content/examples/tooljet/config-console.yaml.md +++ b/content/examples/tooljet/config-console.yaml.md @@ -11,16 +11,16 @@ routes: to: http://verify:8000 pass_identity_headers: true policy: - - allows: - or: + - allow: + or: - email: - is: user@example.com + is: user@example.com - from: https://console.localhost.pomerium.io to: http://pomerium_console:8701 pass_identity_headers: true policy: - - allows: - or: + - allow: + or: - email: - is: user@example.com + is: user@example.com ``` diff --git a/content/examples/tooljet/console-compose.yaml.md b/content/examples/tooljet/console-compose.yaml.md index 61a6dab67..4be2d2843 100644 --- a/content/examples/tooljet/console-compose.yaml.md +++ b/content/examples/tooljet/console-compose.yaml.md @@ -26,7 +26,7 @@ services: condition: service_healthy pomerium: condition: service_started - image: docker.cloudsmith.io/pomerium/enterprise/pomerium-console:v0.21.0 + image: docker.cloudsmith.io/pomerium/enterprise/pomerium-console:v0.32.0 command: - 'serve' - '--config' @@ -49,7 +49,7 @@ services: database: networks: main: {} - image: postgres:latest + image: postgres:17 restart: always healthcheck: test: ['CMD-SHELL', 'pg_isready -d postgres -U postgres'] @@ -93,7 +93,7 @@ services: postgres: networks: main: {} - image: postgres:13 + image: postgres:17 restart: always ports: - 5433:5432 diff --git a/content/examples/tooljet/docker-compose.yaml.md b/content/examples/tooljet/docker-compose.yaml.md index 47c084979..daecfb820 100644 --- a/content/examples/tooljet/docker-compose.yaml.md +++ b/content/examples/tooljet/docker-compose.yaml.md @@ -41,7 +41,7 @@ services: postgres: networks: main: {} - image: postgres:13 + image: postgres:17 restart: always ports: - 5432:5432