The tutorial below targets Pomerium Core, the open-source/self-managed edition, using the current v0.33 stable generation as the baseline. Pomeriumโs documentation also has a rolling main version, so features appearing there may occasionally be newer than stable. Pomerium Core is Apache-2.0 licensed. (Pomerium)
1. What Is Pomerium?
Pomerium is an open-source identity-aware access proxy based on BeyondCorp and Zero Trust principles.
Instead of deciding whether someone should access an application based primarily on where they are connected fromโoffice network, VPN, trusted subnet, static IPโPomerium asks:
Who is this user or workload, and is this specific request authorized right now?
It sits between users and protected applications:
User
โ
โ HTTPS
โผ
Pomerium
โ
โโโ Authenticate user
โโโ Verify session
โโโ Evaluate policy
โโโ Add identity context
โ
โผ
Private ApplicationCode language: PHP (php)
Pomerium can protect internal websites, dashboards, APIs, Kubernetes applications, SSH servers, databases and other TCP/UDP services without giving every user broad network-level access. For ordinary web applications, users normally need nothing more than their browser. (Pomerium)
A useful one-line definition is:
Pomerium is an identity-aware reverse proxy that converts application access from network-based trust to per-request identity-based authorization.
2. The Problem Pomerium Solves
Consider a company with these internal systems:
Grafana
Argo CD
Kibana
Jenkins
Internal admin portal
Kubernetes dashboards
PostgreSQL
Redis
SSH servers
Internal APIs
The traditional design often looks like:
Internet
โ
โผ
Corporate VPN
โ
โผ
Private Network
โ
โโโ Grafana
โโโ Jenkins
โโโ Database
โโโ SSH
โโโ Admin applicationsCode language: PHP (php)
Once someone obtains VPN access, they may receive network connectivity to far more resources than they actually need.
The security decision is essentially:
Are you on the trusted network?
YES
โ
You can reach lots of things.
Pomerium changes the model.
Internet
โ
โผ
Pomerium
โ
โโโ Who are you?
โโโ Did the IdP authenticate you?
โโโ What claims do you have?
โโโ Which application are you requesting?
โโโ What policy applies?
โโโ Is this request permitted?
โ
โโโโโโโดโโโโโโ
โผ โผ
Allow Deny
โ
โผ
ApplicationCode language: JavaScript (javascript)
Authorization happens at the resource boundary rather than merely at the network boundary. Pomerium evaluates policy continuously as requests pass through it. (Pomerium)
3. Pomerium Is Not an Identity Provider
This is one of the most important concepts to understand.
Pomerium does not normally maintain your users and passwords.
Instead, it integrates with your existing Identity Provider.
Examples include:
Microsoft Entra ID
Google
Okta
Auth0
GitHub
GitLab
AWS Cognito
Keycloak
Ping Identity
OneLogin
Other OAuth/OIDC providers
Pomerium uses OAuth 2.0/OIDC integrations and can work with major SSO providers. A normal integration requires a client ID, client secret and redirect URI. (Pomerium)
Think of the responsibilities this way:
Identity Provider
โ
โ "This is Alice"
โผ
Pomerium
โ
โ "Alice may access Grafana,
โ but not Production Admin"
โผ
ApplicationCode language: PHP (php)
The IdP answers:
Who are you?
Pomerium answers:
Given who you are, may you access this resource?
4. Pomerium vs VPN
Pomerium can eliminate the need for a VPN for many application-access use cases, but it should not be confused with a general Layer-3 network VPN.
A VPN usually grants network connectivity:
Laptop
โ
VPN
โผ
10.0.0.0/8
Laptop can potentially discover/reach:
โโโ host A
โโโ host B
โโโ database
โโโ printers
โโโ services
โโโ anything routing/firewalls permit
Pomerium instead grants access to explicitly configured resources:
Alice
โ
โโโ Grafana ALLOW
Alice
โ
โโโ Production DB DENY
Bob
โ
โโโ Production DB ALLOW
That dramatically reduces implicit network trust.
5. Pomerium vs Traditional Reverse Proxy
A normal reverse proxy generally performs:
TLS termination
routing
load balancing
headers
Pomerium adds an identity-aware security layer:
TLS
+
Routing
+
Authentication
+
Authorization
+
SSO
+
Identity-aware policy
+
Signed identity propagation
+
TCP/SSH access
In other words:
NGINX / HAProxy / Envoy
+
Identity-aware access control
โ
Pomerium conceptually
Pomerium itself uses Envoy in its data-plane architecture.
6. When Should You Use Pomerium?
Pomerium becomes especially attractive when you have resources that should be reachable remotely but should not simply become publicly accessible after login logic is bolted onto each application.
Excellent use cases include:
| Use case | Example |
|---|---|
| Internal applications | Admin portals |
| Observability | Grafana, Kibana |
| Deployment tooling | Argo CD, Jenkins |
| Infrastructure consoles | Kubernetes dashboards |
| Developer tools | Jupyter, internal IDEs |
| APIs | Internal REST/gRPC APIs |
| SSH | Linux servers |
| Databases | PostgreSQL/MySQL |
| Caches | Redis |
| Kubernetes services | Internal Ingress |
| Contractors | Restricted application access |
| Multi-cloud environments | AWS + GCP + on-prem |
| Machine identities | GitHub Actions/Kubernetes workloads |
| MCP/AI services | Restricted internal MCP endpoints |
7. When Pomerium May Not Be the Right Tool
Do not force Pomerium into every networking problem.
If you need arbitrary IP routing such as:
entire subnet access
legacy broadcast protocols
arbitrary workstation networking
site-to-site connectivity
general Layer-3 connectivity
a VPN, SD-WAN or network overlay may still be appropriate.
Pomerium shines when the requirement can be expressed as:
Identity X should be able to access resource Y under policy Z.
8. Pomerium Product Editions
Understanding the editions avoids a lot of confusion.
| Product | Control Plane | Data Plane | Primary Use |
|---|---|---|---|
| Pomerium Core | You manage it | Your infrastructure | Open-source/self-managed |
| Pomerium Zero | Pomerium-managed | Your infrastructure | Easier managed control plane |
| Pomerium Enterprise | Self-hosted | Your infrastructure | Enterprise governance |
Pomerium Core is the open-source engine beneath the other deployment models.
Zero adds a managed control plane.
Enterprise adds capabilities such as centralized configuration, directory synchronization, RBAC/namespaces, audit/deployment history, service accounts and additional governance functionality while retaining the control plane in your environment. (Pomerium)
For this tutorial, the primary focus is:
Pomerium Core โ fully self-managed.
9. Pomerium Architecture
Pomerium logically consists of four major services:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ POMERIUM โ
โ โ
โ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโ โ
โ โ Proxy โโโโโโโโบโ Authorize โ โ
โ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโ โ
โ โ โ โ
โ โ โโโโโโโโผโโโโโโโโ โ
โ โ โ Databroker โ โ
โ โ โโโโโโโโโโโโโโโโ โ
โ โ โฒ โ
โ โโโโโโโโโผโโโโโโโ โ โ
โ โ Authenticate โโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโCode language: JavaScript (javascript)
Pomerium documents these as Proxy, Authenticate, Authorize and Databroker services. They can run together in one process or, for specialized architectures, separately. (Pomerium)
10. Proxy Service
The Proxy is the front door.
User
โ
โผ
Proxy
โ
โผ
ApplicationCode language: JavaScript (javascript)
It:
- terminates user connections,
- selects routes,
- requests authorization decisions,
- forwards approved traffic,
- injects configured identity information,
- handles redirects and sessions.
Users normally interact with Proxy rather than directly with the other Pomerium services.
11. Authenticate Service
Authenticate handles user authentication.
User
โ
โผ
Pomerium Authenticate
โ
โผ
Identity Provider
โ
โผ
Google / Entra / Okta / Keycloak
It performs the OAuth/OIDC authentication flow and obtains identity information that Pomerium can use to establish the session. (Pomerium)
12. Authorize Service
Authorize evaluates the access policy.
Suppose:
Alice
email = alice@example.com
groups = engineering
and the route policy is:
allow Engineering
deny everyone elseCode language: JavaScript (javascript)
Authorize decides whether the request is permitted.
Importantly, Pomerium’s model evaluates authorization on requests rather than assuming that an authenticated user is universally trusted.
13. Databroker
Databroker maintains state required by the Pomerium services, including session-related information.
Conceptually:
Authenticate
โ
โผ
Databroker
โฒ
โ
Authorize
Storage choices include:
Memory
File
PostgreSQL
The default memory backend is convenient but loses state after restart. File storage provides persistence for a single instance. PostgreSQL supports persistent multi-replica deployments. (Pomerium)
14. Complete Authentication Flow
Suppose a user visits:
https://grafana.access.example.comCode language: JavaScript (javascript)
The flow looks like this:
1. Browser
โ
โผ
2. Pomerium Proxy
โ
โ No valid session
โผ
3. Authenticate Service
โ
โผ
4. Identity Provider
โ
โ User signs in
โผ
5. Authenticate
โ
โ Session information
โผ
6. Databroker
โ
โผ
7. Proxy
โ
โผ
8. Authorize
โ
โ Evaluate policy
โผ
9. ALLOW
โ
โผ
10. GrafanaCode language: JavaScript (javascript)
On subsequent requests, the complete IdP login normally does not repeat. The existing Pomerium session is used and the authorization decision is reevaluated. (Pomerium)
15. Core Pomerium Concepts
Before installing anything, understand these five objects:
Identity Provider
Route
Policy
Session
Upstream
A Pomerium route connects an externally visible resource to an upstream:
from:
https://grafana.example.com
to:
http://grafana.internal:3000Code language: JavaScript (javascript)
A policy then determines who may traverse that route.
16. Routes
A minimal route resembles:
routes:
- from: https://grafana.access.example.com
to: http://grafana:3000
policy:
- allow:
and:
- authenticated_user: trueCode language: JavaScript (javascript)
from means:
Where users connect.
to means:
Where Pomerium sends authorized traffic.
A route needs a destination such as to, redirect, or response, plus authorization logic before it becomes useful for protected traffic. (Pomerium)
17. Pomerium Policy Language โ PPL
Authorization is usually expressed using Pomerium Policy Language, or PPL.
PPL supports:
allow
deny
and
or
not
nor
For example:
policy:
- allow:
and:
- domain:
is: example.comCode language: CSS (css)
Users whose authenticated email belongs to example.com are allowed.
Pomerium’s important rule is:
A request needs an applicable allow, while a matching deny takes precedence. (Pomerium)
18. Policy Example: Any Authenticated User
policy:
- allow:
and:
- authenticated_user: trueCode language: JavaScript (javascript)
Use this for relatively low-risk internal applications where simply belonging to your IdP is sufficient.
19. Policy Example: Corporate Domain
policy:
- allow:
and:
- domain:
is: example.comCode language: CSS (css)
Good for company-wide applications.
20. Policy Example: Specific Users
policy:
- allow:
or:
- email:
is: alice@example.com
- email:
is: bob@example.comCode language: CSS (css)
Useful for highly restricted services.
21. Policy Example: Group Claim
If your IdP supplies an appropriate claim:
policy:
- allow:
and:
- claim/groups: engineering
This uses the group claim already present in the authenticated token.
Do not confuse this with Pomerium Enterprise’s dedicated groups criterion, which uses directory synchronization. Core can authorize against claims supplied by the IdP via claim/.... (Pomerium)
22. Combined Policy
A more realistic policy:
policy:
- allow:
and:
- domain:
is: example.com
- claim/groups: sre
Meaning:
email domain = example.com
AND
group claim contains/matches sre
23. Explicit Deny
You can also implement guardrails:
policy:
- allow:
and:
- domain:
is: example.com
- deny:
or:
- email:
is: suspended-user@example.comCode language: CSS (css)
The deny wins over an allow. (Pomerium)
24. Recommended DNS Architecture
A clean deployment might use:
access.example.comCode language: CSS (css)
with services beneath it:
authenticate.access.example.com
grafana.access.example.com
argocd.access.example.com
jenkins.access.example.com
admin.access.example.com
ssh.access.example.comCode language: CSS (css)
DNS points the protected route hostnames toward Pomerium:
*.access.example.com
โ
โผ
Load Balancer
โ
โผ
PomeriumCode language: CSS (css)
The applications themselves can remain private.
25. Recommended Network Architecture
For a production cloud environment:
Internet
โ
โผ
โโโโโโโโโโโโโโโโโ
โ L4 Load โ
โ Balancer โ
โโโโโโโโโฌโโโโโโโโ
โ
โโโโโโโโโโโดโโโโโโโโโโ
โผ โผ
Pomerium AZ-A Pomerium AZ-B
โ โ
โโโโโโโโโโโฌโโโโโโโโโโ
โ
PostgreSQL
โ
โโโโโโโโโโโโโโผโโโโโโโโโโโโโโ
โผ โผ โผ
Grafana Argo CD Internal API
Pomerium recommends multiple replicas for production and recommends Layer-4 load balancing in front of Proxy. Multiple all-in-one or Databroker replicas require shared/appropriate external storage; PostgreSQL is the conventional production choice. (Pomerium)
26. Installation Method Choices
Pomerium Core can be installed using:
| Method | Best use |
|---|---|
| Docker | Testing / simple servers |
| Docker Compose | Labs / smaller deployments |
| Linux package | VM production |
| Standalone binary | Controlled VM deployments |
| Kubernetes Ingress Controller | Kubernetes |
| Source build | Development |
Official Linux packages are available in DEB/RPM forms, and official container images and binaries are published as well. (Pomerium)
For learning Pomerium, Docker Compose is the easiest starting point.
27. End-to-End Lab
We will build:
Browser
โ
โผ
Pomerium
โ
โผ
Verify Application
Use a real domain in production.
Example:
authenticate.access.example.com
verify.access.example.comCode language: CSS (css)
28. Prerequisites
You need:
Linux VM/server
Docker
Docker Compose
Domain you control
DNS access
TCP 443 reachable
TCP 80 reachable for ACME when required
Pomerium’s Core quickstart uses a public server, controllable DNS and ports 80/443 for the Autocert-based scenario. (Pomerium)
29. Create the Project
mkdir pomerium
cd pomerium
Our directory becomes:
pomerium/
โโโ config.yaml
โโโ docker-compose.yaml
30. Generate Secrets
Generate a Pomerium shared secret:
head -c32 /dev/urandom | base64
Generate another independent secret for cookies:
head -c32 /dev/urandom | base64
The shared secret is used for mutual authentication between Pomerium services. Cookie secrets protect the Pomerium session cookie. (Pomerium)
Do not reuse the examples from documentation.
31. Initial config.yaml
For an initial test:
address: ":443"
autocert: true
databroker_storage_type: file
databroker_storage_connection_string: file:///data/databroker
routes:
- from: https://verify.access.example.com
to: http://verify:8000
policy:
- allow:
and:
- email:
is: your.email@example.comCode language: JavaScript (javascript)
For the quickest trial, Pomerium currently provides a Hosted Authenticate Service, meaning you can test Core before configuring your own IdP. (Pomerium)
32. Docker Compose
services:
pomerium:
image: pomerium/pomerium:v0.33.0
ports:
- "80:80"
- "443:443"
volumes:
- ./config.yaml:/pomerium/config.yaml:ro
- pomerium-data:/data
environment:
SHARED_SECRET: "REPLACE_WITH_SHARED_SECRET"
COOKIE_SECRET: "REPLACE_WITH_COOKIE_SECRET"
restart: unless-stopped
verify:
image: pomerium/verify:latest
expose:
- "8000"
restart: unless-stopped
volumes:
pomerium-data:Code language: PHP (php)
For a production build, pin every image to a version that you have tested rather than relying on latest.
33. Configure DNS
Create:
verify.access.example.com
โ
โผ
Pomerium public IPCode language: CSS (css)
If you will self-host Authenticate, also create:
authenticate.access.example.com
โ
โผ
PomeriumCode language: CSS (css)
A wildcard record is convenient:
*.access.example.comCode language: CSS (css)
but explicit DNS records can provide tighter control.
34. Start Pomerium
docker compose up -d
Inspect:
docker compose ps
and:
docker compose logs -f pomerium
Now browse to:
https://verify.access.example.comCode language: JavaScript (javascript)
Expected workflow:
Verify URL
โ
Pomerium
โ
Authentication
โ
Policy evaluation
โ
Verify application
At this point you have a working identity-aware proxy.
35. Moving to Your Own Identity Provider
The hosted authentication option is excellent for learning.
For a serious fully controlled environment, integrate Pomerium with your organization’s IdP.
Create an OAuth/OIDC client with this redirect URI pattern:
https://authenticate.access.example.com/oauth2/callbackCode language: JavaScript (javascript)
Pomerium standardizes the callback path on /oauth2/callback. (Pomerium)
36. Generic OIDC Configuration
Update config.yaml:
authenticate_service_url: https://authenticate.access.example.com
idp_provider: oidc
idp_provider_url: YOUR_OIDC_ISSUER
idp_scopes:
- openid
- profile
- emailCode language: HTTP (http)
Provide secrets through your secret mechanism:
IDP_CLIENT_ID
IDP_CLIENT_SECRET
rather than embedding them directly in Git.
37. Example Architecture with Keycloak
For Keycloak:
Browser
โ
โผ
Pomerium
โ
โผ
Keycloak
โ
โผ
User authentication
The Pomerium OIDC configuration pattern is:
authenticate_service_url: https://authenticate.access.example.com
idp_provider: oidc
idp_provider_url: YOUR_KEYCLOAK_REALM
idp_client_id: YOUR_CLIENT_ID
idp_client_secret: YOUR_CLIENT_SECRETCode language: HTTP (http)
Pomerium’s current Keycloak integration uses the standard OIDC provider mode and the same callback pattern. (Pomerium)
38. Protect Grafana
Suppose Grafana runs privately at:
grafana.internal:3000Code language: CSS (css)
Add:
routes:
- from: https://grafana.access.example.com
to: http://grafana.internal:3000
policy:
- allow:
and:
- claim/groups: sreCode language: JavaScript (javascript)
Now Grafana does not need to be publicly exposed.
The network becomes:
Internet
Xโโโโโโโโโโโโโโโโโโโโโโโบ Grafana
โ
โผ
Pomerium
โ
โ authorized only
โผ
Grafana
39. Passing User Identity to the Application
Sometimes the upstream application needs to know who Pomerium authenticated.
Enable:
pass_identity_headers: trueCode language: JavaScript (javascript)
Pomerium can send:
X-Pomerium-Jwt-Assertion
X-Pomerium-Claim-*
to upstream services. The JWT assertion provides a cryptographically signed identity artifact that the upstream can verify. (Pomerium)
Example:
routes:
- from: https://app.access.example.com
to: http://app:8080
pass_identity_headers: true
policy:
- allow:
and:
- authenticated_user: trueCode language: JavaScript (javascript)
40. Important Identity-Header Security Rule
Do not blindly trust:
X-Email
X-Username
X-Pomerium-Claim-*
merely because they exist.
A malicious client could potentially send fake headers if the application remains reachable through another path.
The stronger pattern is:
Internet
โ
โผ
Pomerium
โ
โผ
Application
with the application firewall allowing requests only from Pomerium, combined with verification of X-Pomerium-Jwt-Assertion where appropriate.
41. Signed JWT Flow
The design looks like:
User
โ
โผ
Pomerium
โ
โ signed JWT
โผ
Application
โ
โผ
Pomerium JWKS
The application fetches Pomerium’s public keys from its JWKS endpoint and verifies:
signature
issuer
audience
expiration
This is substantially stronger than blindly trusting an unsigned X-User header. (Pomerium)
42. Pomerium Internal Discovery Endpoints
Useful internal endpoints include:
/ping
/healthz
/.well-known/pomerium
/.well-known/pomerium/jwks.json
/.pomerium/
/.pomerium/user
/.pomerium/sign_outCode language: JavaScript (javascript)
/ping and /healthz provide basic health checks, while the JWKS endpoint exposes the public keys required to verify Pomerium-issued JWTs. (Pomerium)
43. Protecting Multiple Applications
One Pomerium deployment can front many applications:
routes:
- from: https://grafana.access.example.com
to: http://grafana:3000
policy:
- allow:
and:
- claim/groups: sre
- from: https://argocd.access.example.com
to: http://argocd:8080
policy:
- allow:
and:
- claim/groups: platform
- from: https://admin.access.example.com
to: http://admin:9000
policy:
- allow:
or:
- email:
is: security-admin@example.comCode language: JavaScript (javascript)
That is one of Pomerium’s strongest design properties: centralized access enforcement without requiring each application to implement the same OAuth integration.
44. TCP Applications
Pomerium is not limited to HTTP.
For TCP services it uses an authenticated tunnel through pomerium-cli.
For example:
routes:
- from: tcp+https://redis.access.example.com:6379
to: tcp://redis.internal:6379
policy:
- allow:
and:
- claim/groups: platformCode language: JavaScript (javascript)
A user then connects with Pomerium CLI.
Conceptually:
Redis Client
โ
localhost
โ
โผ
pomerium-cli
โ
HTTPS tunnel
โผ
Pomerium
โ
โผ
Redis
Pomerium supports this approach for protocols such as SSH, databases and Redis, and also supports UDP-over-HTTP patterns. (Pomerium)
45. SSH
There are two important SSH models.
Model A โ TCP Tunnel
SSH Client
โ
โผ
pomerium-cli
โ
โผ
Pomerium
โ
โผ
SSH Server
This is convenient because the SSH server requires relatively little modification.
Model B โ Native SSH
Modern Pomerium releases also support Native SSH access with OAuth-based login and ephemeral certificates.
This produces a better long-term production UX but requires configuring SSH servers to trust the appropriate Pomerium CA. Native SSH was significantly expanded in the v0.32 generation. (Pomerium)
46. Machine-to-Machine Access
Zero Trust cannot stop at human users.
Examples:
GitHub Action
Kubernetes Pod
CI/CD runner
service
automation process
SPIFFE workload
These cannot complete browser authentication.
Pomerium therefore supports bearer-token authentication.
A request might contain:
Authorization: Bearer <JWT>Code language: HTML, XML (xml)
Pomerium can verify JWTs from explicitly trusted issuers such as:
Kubernetes
GitHub Actions OIDC
SPIFFE
OIDC-compatible issuers
and then apply normal policy to the verified claims. (Pomerium)
Example:
identity_providers:
ci:
issuer: YOUR_CI_ISSUER
audiences:
- internal-api
routes:
- from: https://api.access.example.com
to: http://internal-api:8080
bearer_token_format: jwt
identity_providers:
- ci
policy:
- allow:
and:
- claim/sub: deployment-jobCode language: JavaScript (javascript)
This is a very powerful pattern:
Human access
+
Machine identity
+
Same policy enforcement layer
47. TLS Architecture
There are two distinct TLS relationships:
Client
โ
โ Downstream TLS
โผ
Pomerium
โ
โ Upstream TLS
โผ
Application
For strong Zero Trust architecture, protect both.
48. Downstream TLS
This protects:
User โ Pomerium
Use publicly trusted certificates where the service is internet accessible.
Pomerium can work with supplied certificates or certificate automation. (Pomerium)
49. Upstream TLS
This protects:
Pomerium โ Application
Instead of:
Pomerium โโโ HTTP โโโโบ Application
production-sensitive environments can use:
Pomerium โโโ HTTPS โโโโบ Application
or even:
Pomerium โโโ mTLS โโโโบ Application
Pomerium supports custom certificate authorities, upstream server-name validation and client certificates for mutual TLS. (Pomerium)
50. Never Normalize tls_skip_verify
Pomerium supports:
tls_skip_verify: trueCode language: JavaScript (javascript)
but official documentation explicitly warns that doing so disables certificate chain and hostname verification and exposes the connection to man-in-the-middle risk. It should be considered a troubleshooting/test option rather than a normal production solution. (Pomerium)
Instead, fix trust correctly:
Valid internal certificate
or
Custom internal CA
or
mTLS
51. Upstream Load Balancing
Pomerium can route to multiple upstream servers:
to:
- http://app-1:8080
- http://app-2:8080
- http://app-3:8080Code language: JavaScript (javascript)
Supported load-balancing selections include strategies such as:
ROUND_ROBIN
LEAST_REQUEST
RANDOM
RING_HASH
MAGLEV
It also supports HTTP, TCP and gRPC health checks so unhealthy upstream instances can be removed from service. (Pomerium)
52. Example Upstream Health Check
routes:
- from: https://app.access.example.com
to:
- http://app-1:8080
- http://app-2:8080
health_checks:
- timeout: 3s
interval: 10s
healthy_threshold: 2
unhealthy_threshold: 3
http_health_check:
path: /health
policy:
- allow:
and:
- authenticated_user: trueCode language: PHP (php)
Now Pomerium provides both:
identity-aware authorization
+
upstream availability checking
53. Pomerium on Kubernetes
Pomerium has an official Kubernetes Ingress Controller.
Instead of maintaining routes exclusively in one central config.yaml, Kubernetes applications can define routes using Kubernetes resources. (Pomerium)
Architecture:
Internet
โ
โผ
Cloud Load Balancer
โ
โผ
Pomerium Ingress Controller
โ
โโโโโโบ Service A
โ
โโโโโโบ Service B
โ
โโโโโโบ Service C
54. Kubernetes Installation
For the current v0.33 controller generation:
kubectl apply -k \
github.com/pomerium/ingress-controller/config/default?ref=0-33-0Code language: JavaScript (javascript)
The standard installation creates the Pomerium namespace, controller/Core deployment, Proxy LoadBalancer service, metrics service, bootstrap secret generation, CRDs, RBAC and the pomerium IngressClass. (Pomerium)
A great production practice from Pomerium’s own documentation is:
Pin the installation reference to a known version rather than tracking
main. (Pomerium)
55. Kubernetes Application Example
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: grafana
annotations:
ingress.pomerium.io/policy: |
allow:
and:
- claim/groups: sre
ingress.pomerium.io/pass_identity_headers: "true"
spec:
ingressClassName: pomerium
rules:
- host: grafana.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: grafana
port:
number: 3000Code language: HTTP (http)
Now application access policy lives next to the application’s Kubernetes configuration.
That makes GitOps possible:
Developer
โ
โผ
Pull Request
โ
โผ
Review policy
โ
โผ
Merge
โ
โผ
Kubernetes
โ
โผ
Pomerium route automatically updated
56. Gateway API
Pomerium also supports Kubernetes Gateway API integration.
However, as of the current v0.33 documentation, Gateway API support remains described as experimental/partial, so I would not automatically choose it over the mature Ingress Controller for a critical production environment without validating the required features. (Pomerium)
57. High Availability
A production deployment should avoid:
Internet
โ
โผ
One Pomerium VM
because the identity gateway itself becomes the single point of failure.
Instead:
Load Balancer
โ
โโโโโโโโโโโดโโโโโโโโโโ
โผ โผ
Pomerium A Pomerium B
AZ-A AZ-B
โ โ
โโโโโโโโโโโฌโโโโโโโโโโ
โผ
PostgreSQL
Pomerium recommends multiple instances separated across failure domains for resilient deployments. (Pomerium)
58. Storage for Production
The useful rule is simple:
Single lab
โ
Memory
Single persistent instance
โ
File
Multiple production replicas
โ
PostgreSQL
For example:
databroker_storage_type: postgres
databroker_storage_connection_string: YOUR_POSTGRES_CONNECTIONCode language: HTTP (http)
PostgreSQL provides persistence and support for multiple Pomerium replicas. Pomerium recommends a dedicated database and recommends encryption at rest because Databroker record values are not themselves encrypted by the application storage layer. (Pomerium)
59. All-in-One vs Split Services
Pomerium can run:
All-in-One
where Proxy, Authenticate, Authorize and Databroker run together.
Or:
Proxy cluster
Authenticate cluster
Authorize cluster
Databroker clusterCode language: JavaScript (javascript)
Pomerium’s current guidance is interesting: all-in-one is desirable for most deployments because it lowers complexity and resource footprint. Split-service architecture makes sense for specialized security constraints, very large environments or cases requiring independent scaling/blast-radius boundaries. (Pomerium)
Do not split services just because the diagram has four boxes.
Complexity is not automatically architecture maturity.
60. Production Load Balancer Choice
For Pomerium Proxy, the recommended architecture is:
Layer 4 / TCP Load Balancer
rather than inserting another generic Layer-7 reverse proxy in front of it.
This becomes particularly important when using TCP tunneling because Pomerium uses CONNECT semantics and expects the connection path to preserve them. (Pomerium)
61. Monitoring Pomerium
A Zero Trust gateway should itself be heavily monitored.
Pomerium exposes Prometheus-compatible metrics covering areas such as:
HTTP traffic
authorization
storage
Databroker
database connection pools
cache behavior
Envoy
Pomerium also supports Prometheus scraping in Kubernetes. (Pomerium)
Architecture:
Pomerium
โ
โผ
Prometheus
โ
โผ
Grafana
62. OpenTelemetry
Current Pomerium versions use OpenTelemetry for tracing rather than the older OpenCensus tracing path. (Pomerium)
A mature environment can therefore implement:
Pomerium
โ
โโโ Logs
โโโ Metrics
โโโ Traces
โ
โผ
OpenTelemetry Collector
โ
โผ
Observability Backend
That becomes extremely useful when investigating authentication latency, upstream latency or unexpected authorization behavior.
63. Access Logging
Pomerium logs structured information for proxied HTTP requests.
Useful fields can include:
method
authority
path
response-code
duration
request-id
user-agent
forwarded-for
upstream-cluster
Pomerium warns that logging query parameters can expose sensitive data, so enabling query logging should be done deliberately. (Pomerium)
For security teams, these logs are especially valuable because they provide an identity-aware record of access activity.
64. Monitor Pomerium Externally Too
Do not monitor Pomerium only from inside the same cluster.
Use synthetic monitoring against:
/healthz
/ping
critical protected route
actual login journey where practicalCode language: PHP (php)
A good design:
External Monitor
โ
โผ
Pomerium
โ
โผ
Critical Application
This detects the exact failure your users would experience.
65. Production Security Best Practices
A strong Pomerium deployment should follow these principles:
- Default deny. Create explicit access rules rather than broad global allowances.
- Use your real IdP. Hosted authentication is excellent for learning, but serious environments should integrate with their organizational identity source.
- Enable MFA at the IdP. Pomerium benefits from stronger authentication upstream.
- Keep applications private. If the application remains directly internet-accessible, users may simply bypass Pomerium.
- Use signed identity assertions when applications rely on Pomerium identity.
- Never broadly enable
tls_skip_verify. - Use TLS or mTLS upstream for sensitive systems.
- Store secrets outside Git. Use Vault, AWS Secrets Manager, Kubernetes Secrets + External Secrets, cloud secret stores or equivalent.
- Use PostgreSQL for multi-replica production deployments.
- Deploy multiple Pomerium replicas across failure domains.
- Use L4 load balancing where possible, especially if non-HTTP tunnels are required.
- Pin Pomerium versions rather than using floating container or Kubernetes references.
- Monitor metrics, logs and health endpoints.
- Encrypt Databroker persistence at rest.
- Regularly review policies. Access rules tend to accumulate just like firewall rules.
- Restrict Pomerium’s network access. It should reach only the upstream systems, IdPs, databases and infrastructure required for its operation.
- Protect administrative/debug interfaces. Never casually expose Envoy’s administration endpoint publicly.
- Test upgrades in staging. Pomerium publishes upgrade notes and security fixes; review them before production rollout. (Pomerium)
66. Common Troubleshooting Flow
When Pomerium does not work, debug it in layers.
DNS
โ
TLS
โ
Pomerium listener
โ
Authentication
โ
Session
โ
Authorization
โ
Route matching
โ
Upstream DNS
โ
Upstream TLS
โ
Application
Do not immediately assume every 403 or 502 is an identity problem.
67. Common Errors
| Symptom | Likely area |
|---|---|
| Domain doesn’t resolve | DNS |
| Certificate warning | TLS/certificate |
| Endless authentication loop | Cookie/IdP/callback |
| OAuth callback error | IdP redirect URI |
401 | Authentication/bearer token |
403 | Policy authorization |
502/503 | Upstream connectivity |
| x509 error | Upstream certificate/CA |
| Sessions vanish after restart | Nonpersistent Databroker |
| Different replicas behave inconsistently | Storage/shared-secret issue |
| TCP tunnel fails | L7 proxy/WAF in front |
| Group policy never matches | IdP claim not present |
| App sees no identity | pass_identity_headers disabled |
For Kubernetes:
kubectl describe pomerium
and:
kubectl describe ingress <name>Code language: HTML, XML (xml)
are particularly useful because the controller publishes status/events to Kubernetes resources. (Pomerium)
68. A Gold-Standard Production Architecture
For a company running Kubernetes across AWS, this is the type of design I would aim for:
USERS
โ
โ HTTPS
โผ
โโโโโโโโโโโโโโโโโโโโ
โ Route53 / DNS โ
โโโโโโโโโโฌโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโ
โ AWS NLB โ
โ Layer 4 โ
โโโโโโโโโโฌโโโโโโโโโโ
โ
โโโโโโโโโโโโโดโโโโโโโโโโโโ
โ โ
โผ โผ
Pomerium Replica A Pomerium Replica B
AZ-A AZ-C
โ โ
โโโโโโโโโโโโโฌโโโโโโโโโโโโ
โ
PostgreSQL
โ
โโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโ
โผ โผ โผ
Grafana Argo CD Admin API
private private private
โฒ
โ
Authentication
โ
โผ
Enterprise IdP
Entra / Google / Okta
Add:
Prometheus
OpenTelemetry
central logs
synthetic health checks
secrets manager
certificate management
around that architecture.
The important property is:
The upstream applications do not need to trust the internet. They trust the controlled Pomerium path.
69. Gold-Standard Kubernetes Pattern
For Kubernetes:
Git Repository
โ
โผ
Ingress + Pomerium Policy
โ
โผ
Argo CD / Flux
โ
โผ
Kubernetes API
โ
โผ
Pomerium Ingress Controller
โ
โผ
Protected ServiceCode language: PHP (php)
This gives you something traditional VPN access rarely provides:
Access change
=
Pull request
=
Code review
=
Audit trail
=
Git history
That is a major operational benefit.
70. Recommended Adoption Strategy
Do not start by replacing every VPN use case on day one.
A safer migration looks like:
Phase 1
Low-risk internal websites
Grafana / dashboards
โ
Phase 2
Admin applications
Argo CD / Jenkins
โ
Phase 3
Internal APIs
Machine-to-machine access
โ
Phase 4
SSH and databases
โ
Phase 5
Reduce VPN dependency
This gives the team time to establish:
IdP integration
policy conventions
logging
monitoring
HA
incident procedures
access reviews
before Pomerium becomes business-critical infrastructure.
71. Suggested Policy Model
Avoid hundreds of policies based on named individuals.
Prefer:
Identity Provider
โ
โผ
Role / group claims
โ
โผ
Pomerium policies
โ
โผ
Applications
For example:
employees
developers
sre
security
finance
production-admin
contractor
Then:
Grafana
โ sre
Argo CD staging
โ developers + sre
Argo CD production
โ production-admin
Billing portal
โ finance
Security tooling
โ security
This scales far better than individual-email allowlists.
72. Pomerium’s Biggest Strength
The real power of Pomerium is not SSO.
SSO has existed for decades.
The valuable architectural change is:
OLD MODEL
authenticated once
โ
trusted network
โ
broad access
versus:
POMERIUM MODEL
authenticate identity
โ
request resource
โ
evaluate explicit policy
โ
authorize request
โ
forward only to that resource
That is the core Zero Trust idea.
73. Pomerium’s Biggest Operational Risk
Pomerium becomes a critical dependency.
If everything is protected by:
Pomerium
then:
Pomerium down
=
Internal applications unavailable
So mature deployments require the same engineering discipline as any other Tier-0 access system:
HA
multi-AZ
persistent storage
backups
monitoring
synthetic checks
capacity planning
upgrade testing
disaster recovery
IdP availability
DNS reliability
certificate lifecycle management
Treat Pomerium as security infrastructure, not merely another reverse proxy container.
74. Final Decision Guide
Use Pomerium Core when you want:
Open source
Self-hosting
Configuration as code
Full operational controlCode language: PHP (php)
Use Pomerium Zero when you want:
Pomerium-managed control plane
+
Core running in your environment
+
simpler operations
Use Pomerium Enterprise when you need:
Self-hosted control plane
Directory sync
RBAC
Namespaces
Governance
Centralized administration
Audit/deployment history
Enterprise managementCode language: PHP (php)
Pomerium’s own current architecture follows exactly this separation between Core, Zero and Enterprise. (Pomerium)
75. The Final Mental Model
If you remember only one diagram, remember this:
Identity Provider
โฒ
โ
Authentication
โ
โ
USER โโโโโ HTTPS โโโโโโบ POMERIUM
โ
Authorization
โ
Policy evaluation
โ
โโโโโโโโโโดโโโโโโโโโ
โ โ
ALLOW DENY
โ
โผ
PRIVATE SERVICE
โ
Grafana / API /
SSH / DB / Kubernetes
Pomerium turns:
"Are you inside my network?"Code language: JSON / JSON with Comments (json)
into:
"Who are you,
what exactly are you trying to access,
and does policy permit this request?"Code language: PHP (php)
That is why Pomerium is much more interesting than simply being another reverse proxy.
It represents a shift from:
network-centric access
to:
identity-centric access.
And when deployed correctlyโwith a strong IdP, private upstreams, explicit policies, signed identity propagation, encrypted traffic, persistent storage, HA, observability and configuration-as-codeโit can become an extremely effective foundation for Zero Trust access to internal applications, Kubernetes workloads, APIs, SSH, databases and machine-to-machine services. (Pomerium)
Primary technical references
The tutorial is based mainly on Pomerium’s current Core architecture, configuration, deployment, policy, Kubernetes and security documentation. The currently published documentation identifies v0.33 as the latest stable documentation line. (Pomerium) Pomerium’s official repository is Apache-2.0 licensed, while the current release train includes security-maintenance updates to the underlying Envoy stack, which is another good reason to treat upgrades as part of the operational lifecycle rather than โinstall once and forget.โ (GitHub)
I’m Rajesh Kumar, a DevOps, SRE, DevSecOps, Cloud, and Platform Engineering expert passionate about sharing practical knowledge, real-world experiences, and industry best practices. I have worked at Cotocus and regularly write about technology, travel, investing, health, product reviews, and digital marketing through my various platforms.
I publish technical articles at DevOps School, travel stories at Holiday Landmark, stock market insights at Stocks Mantra, health and fitness guidance at My Medic Plus, product reviews at TrueReviewNow, and SEO and digital marketing strategies at Wizbrand.
Find Trusted Cardiac Hospitals
Compare heart hospitals by city and services โ all in one place.
Explore Hospitals