Find the Best Cosmetic Hospitals

Explore trusted cosmetic hospitals and make a confident choice for your transformation.

“Invest in yourself — your confidence is always worth it.”

Explore Cosmetic Hospitals

Start your journey today — compare options in one place.

The Complete Pomerium Tutorial: From Absolute Beginner to Advanced Zero Trust Access Engineering

Course overview

Pomerium is an open-source, identity-aware proxy that helps organizations securely provide access to internal applications and services. It combines identity verification, access policies, and reverse-proxy capabilities to control who can reach protected resources.

This tutorial teaches the underlying technology first, then Pomerium, then hands-on implementation.

Beginner → Advanced

28 Chapters

Practical labs

Primary technology

Zero Trust Network Access (ZTNA), Identity-Aware Proxy (IAP), Access Management

Learning environment

Windows, Ubuntu, macOS, Docker, and applicable Linux distributions

Learning approach

Concepts, diagrams, experiments, configurations, labs, troubleshooting, and assessments

Final outcome

Design, deploy, secure, operate, and troubleshoot Pomerium independently

Research and version baseline

Official documentation and release information checked: October 28, 2026.

The latest stable Pomerium Core release found in the official GitHub releases was v0.33.4, published October 2, 2026. Its security updates include an Envoy upgrade and a fix addressing potential denial-of-service or performance issues with many distinct clients. Pomerium Core v0.33.0 also removed native macOS Intel (darwin/amd64) binary support. GitHub+1

The course primarily uses:

  • Pomerium Core for self-managed, open-source experiments.
  • Docker Compose for a consistent local environment.
  • Pomerium’s hosted authentication service for the first experiments, avoiding the need to configure your own identity provider immediately.
  • Realistic access policies and private demo applications.
  • Enterprise and cloud-managed deployment models when discussing larger environments.

The local examples are educational rather than production-ready defaults. Production changes are introduced separately and explicitly.

Part I — Understand the World Before the Tool

Chapter 1. The Big Picture

1.1 Imagine a company with many internal applications

Suppose a company has 500 employees using several internal systems:

ApplicationPurposeWho should access it?
GrafanaMonitoring dashboardsDevOps and SRE teams
JenkinsContinuous Integration/Continuous DeliveryAuthorized developers
Internal Admin PortalCompany administrationAdministrators
Kubernetes DashboardCluster managementPlatform engineers
Internal WikiDocumentationEmployees
Database Management UIDatabase administrationDatabase administrators

These applications might run on company servers, Amazon Web Services (AWS), Microsoft Azure, Google Cloud, or Kubernetes clusters.

The company must answer some important questions:

  • How can employees access these applications securely from home, an office, or while traveling?
  • How does the company know who is connecting?
  • How can it allow developers to access Jenkins but not the finance administration portal?
  • How can it remove access when an employee leaves?
  • How can it establish a central record of application access?
  • Can it avoid giving employees access to an entire private network?

These are identity, access management, and application security problems.

1.2 The traditional approach: Virtual Private Networks

Historically, many companies used a Virtual Private Network (VPN).

A VPN creates an encrypted connection between a user’s device and a private network.

Imagine the company’s private network as an office building.

A VPN is somewhat like giving an employee a special tunnel into the building. Once inside, they may be able to reach multiple rooms, depending on how the network and access controls are configured.

Traditional remote-access concept

EmployeeRemote laptop

VPNNetwork tunnel

Private networkInternal resources

A VPN provides network connectivity. Additional controls are still necessary to restrict which resources the user can reach.

VPNs are useful, but several operational challenges can arise:

  1. Users typically need VPN client software.
  2. Administrators must manage VPN connectivity and client configurations.
  3. Network access may be broader than necessary.
  4. Applications may each have separate login systems.
  5. Security teams need additional mechanisms to manage fine-grained application permissions.
  6. A compromised device may gain access to network services that were not intended for that user.

A properly configured VPN can implement strong authentication, segmentation, and fine-grained controls. The limitation is not that VPNs are inherently insecure; it is that network connectivity and application authorization are different problems.

1.3 The modern approach: Zero Trust

Zero Trust is a security approach in which access is not automatically trusted just because a user or device is connected to a particular network.

Instead, access decisions consider identity, permissions, and other relevant conditions.

For example, a user wants to open an internal dashboard.

The system can ask:

  • Who is the user?
  • Has the user authenticated?
  • Is the user allowed to access this application?
  • Is the session still valid?
  • Do any additional access restrictions apply?

The National Institute of Standards and Technology (NIST) describes these principles in Special Publication 800-207, Zero Trust Architecture. CSRC

1.4 The office security analogy

Compare two ways of securing an office building.

Traditional perimeter security: A guard checks someone at the front entrance. Inside, additional permissions depend on locks and other controls.

Zero Trust-oriented application security: Every sensitive room has its own access check. A person allowed into the engineering room is not automatically allowed into the finance room.

Pomerium acts like a central access checkpoint for the applications it protects.

The actual technology is more precise than the analogy: Pomerium validates user sessions, evaluates configured policies, and forwards authorized requests to the correct service.

1.5 Where Pomerium fits

#chatgpt-mermaid-_r_1e3_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;fill:rgb(13, 13, 13);}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#chatgpt-mermaid-_r_1e3_ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_1e3_ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_1e3_ .error-icon{fill:rgb(243, 243, 243);}#chatgpt-mermaid-_r_1e3_ .error-text{fill:rgb(13, 13, 13);stroke:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1e3_ .edge-thickness-normal{stroke-width:1px;}#chatgpt-mermaid-_r_1e3_ .edge-thickness-thick{stroke-width:3.5px;}#chatgpt-mermaid-_r_1e3_ .edge-pattern-solid{stroke-dasharray:0;}#chatgpt-mermaid-_r_1e3_ .edge-thickness-invisible{stroke-width:0;fill:none;}#chatgpt-mermaid-_r_1e3_ .edge-pattern-dashed{stroke-dasharray:3;}#chatgpt-mermaid-_r_1e3_ .edge-pattern-dotted{stroke-dasharray:2;}#chatgpt-mermaid-_r_1e3_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1e3_ .marker.cross{stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1e3_ svg{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;}#chatgpt-mermaid-_r_1e3_ p{margin:0;}#chatgpt-mermaid-_r_1e3_ .label{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1e3_ .cluster-label text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1e3_ .cluster-label span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1e3_ .cluster-label span p{background-color:transparent;}#chatgpt-mermaid-_r_1e3_ .label text,#chatgpt-mermaid-_r_1e3_ span{fill:rgb(13, 13, 13);color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1e3_ .node rect,#chatgpt-mermaid-_r_1e3_ .node circle,#chatgpt-mermaid-_r_1e3_ .node ellipse,#chatgpt-mermaid-_r_1e3_ .node polygon,#chatgpt-mermaid-_r_1e3_ .node path{fill:rgb(222, 234, 251);stroke:rgb(83, 154, 248);stroke-width:1px;}#chatgpt-mermaid-_r_1e3_ .rough-node .label text,#chatgpt-mermaid-_r_1e3_ .node .label text,#chatgpt-mermaid-_r_1e3_ .image-shape .label,#chatgpt-mermaid-_r_1e3_ .icon-shape .label{text-anchor:middle;}#chatgpt-mermaid-_r_1e3_ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#chatgpt-mermaid-_r_1e3_ .rough-node .label,#chatgpt-mermaid-_r_1e3_ .node .label,#chatgpt-mermaid-_r_1e3_ .image-shape .label,#chatgpt-mermaid-_r_1e3_ .icon-shape .label{text-align:center;}#chatgpt-mermaid-_r_1e3_ .node.clickable{cursor:pointer;}#chatgpt-mermaid-_r_1e3_ .root .anchor path{fill:rgb(143, 143, 143)!important;stroke-width:0;stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1e3_ .arrowheadPath{fill:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1e3_ .edgePath .path{stroke:rgb(143, 143, 143);stroke-width:1px;}#chatgpt-mermaid-_r_1e3_ .flowchart-link{stroke:rgb(143, 143, 143);fill:none;}#chatgpt-mermaid-_r_1e3_ .edgeLabel{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_1e3_ .edgeLabel p{background-color:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1e3_ .edgeLabel rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1e3_ .labelBkg{background-color:rgba(252, 252, 252, 0.5);}#chatgpt-mermaid-_r_1e3_ .cluster rect{fill:rgb(243, 243, 243);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_1e3_ .cluster text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1e3_ .cluster span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1e3_ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:12px;background:rgb(243, 243, 243);border:1px solid rgba(0, 0, 0, 0.1);border-radius:2px;pointer-events:none;z-index:100;}#chatgpt-mermaid-_r_1e3_ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1e3_ rect.text{fill:none;stroke-width:0;}#chatgpt-mermaid-_r_1e3_ .icon-shape,#chatgpt-mermaid-_r_1e3_ .image-shape{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_1e3_ .icon-shape p,#chatgpt-mermaid-_r_1e3_ .image-shape p{background-color:rgb(252, 252, 252);padding:2px;}#chatgpt-mermaid-_r_1e3_ .icon-shape .label rect,#chatgpt-mermaid-_r_1e3_ .image-shape .label rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1e3_ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#chatgpt-mermaid-_r_1e3_ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#chatgpt-mermaid-_r_1e3_ .node .neo-node{stroke:rgb(83, 154, 248);}#chatgpt-mermaid-_r_1e3_ [data-look=”neo”].node rect,#chatgpt-mermaid-_r_1e3_ [data-look=”neo”].cluster rect,#chatgpt-mermaid-_r_1e3_ [data-look=”neo”].node polygon{stroke:url(#chatgpt-mermaid-_r_1e3_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1e3_ [data-look=”neo”].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_1e3_ [data-look=”neo”].node path{stroke:url(#chatgpt-mermaid-_r_1e3_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_1e3_ [data-look=”neo”].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1e3_ [data-look=”neo”].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_1e3_ [data-look=”neo”].node circle{stroke:url(#chatgpt-mermaid-_r_1e3_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1e3_ [data-look=”neo”].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_1e3_ [data-look=”neo”].icon-shape .icon{fill:url(#chatgpt-mermaid-_r_1e3_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1e3_ [data-look=”neo”].icon-shape .icon-neo path{stroke:url(#chatgpt-mermaid-_r_1e3_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1e3_ .node text{font-size:14px;font-weight:600;letter-spacing:normal;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_1e3_ .edgeLabels text{font-size:13px;font-weight:600;letter-spacing:-0.08px;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_1e3_ .node tspan[font-weight=”normal”],#chatgpt-mermaid-_r_1e3_ .edgeLabels tspan[font-weight=”normal”]{font-weight:600;}#chatgpt-mermaid-_r_1e3_ .edgeLabel .label rect{opacity:1;rx:13px;ry:13px;fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-width:1px;}#chatgpt-mermaid-_r_1e3_ .node rect,#chatgpt-mermaid-_r_1e3_ .node circle,#chatgpt-mermaid-_r_1e3_ .node ellipse,#chatgpt-mermaid-_r_1e3_ .node polygon,#chatgpt-mermaid-_r_1e3_ .node path{fill:rgb(229, 243, 255);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_1e3_ .node rect{rx:16px;ry:16px;}#chatgpt-mermaid-_r_1e3_ .mermaid-decision .label-container{fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-dasharray:2,2;}#chatgpt-mermaid-_r_1e3_ .edgePaths .flowchart-link{stroke:rgb(143, 143, 143);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;}#chatgpt-mermaid-_r_1e3_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1e3_ :root{–mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;}Employee opens an internalweb applicationPomerium receives therequestIdentity is verifiedIs access permitted?Application receives therequestAccess deniedYesNo

What happens here?

The employee requests an application through a Pomerium-protected address. Pomerium establishes or validates the user’s identity and evaluates an authorization policy.

Only an authorized request is forwarded to the protected application.

This allows access decisions to focus on the individual application rather than granting general network connectivity.

1.6 Who uses Pomerium?

Pomerium is particularly relevant to platform engineering, DevOps, Site Reliability Engineering (SRE), cybersecurity, identity and access management, and internal application development teams.

It is useful for protecting web-based tools, internal administrative interfaces, developer services, monitoring tools, and other supported services.

What You Should Understand Before Moving On

Pomerium addresses application access rather than simply providing network connectivity.

The central idea is:

Verify identity, evaluate permission, and grant access only to the requested resource.

Chapter 2. Prerequisite Concepts

Before learning Pomerium itself, understand the concepts that make its behavior possible.

2.1 Authentication versus authorization

These two concepts are fundamental.

Authentication answers:

Who are you?

Examples include signing in with a password, using a security key, or completing multifactor authentication.

Authorization answers:

What are you allowed to access or do?

An authenticated employee might be allowed to read internal documentation but forbidden from accessing production administration tools.

ConceptSimple definitionAnalogyPractical exampleImportance
AuthenticationProving identityShowing an ID cardSigning in with GoogleEssential
AuthorizationChecking permissionChecking room accessAllowing only administrators into GrafanaEssential
Identity ProviderSystem that authenticates usersID issuing officeMicrosoft Entra ID, OktaEssential
Single Sign-OnReusing one login across applicationsOne identity badgeCorporate login for several toolsEssential
Reverse ProxyServer that receives requests and forwards them to other serversReception deskPomerium forwarding traffic to GrafanaEssential
Zero TrustAvoiding implicit trust based only on network positionCheck each protected doorwayVerify access to every protected applicationEssential
Access policyRules determining accessEntry requirementsAllow selected email addressesEssential
TLSEncryption and server authentication for network connectionsProtected communication channelHTTPSEssential
DNSResolves names to network addressesAddress directoryFinding an application’s server IPEssential
ContainerPackaged application running in an isolated environmentSeparate application workspaceDocker containerHelpful
KubernetesPlatform for running and managing containerized applicationsAutomated operations coordinatorManaging Pomerium replicasAdvanced

2.2 How a website request works

When someone types an address such as https://dashboard.example.com, several things happen.

First, the browser resolves the hostname to an Internet Protocol (IP) address, normally through the Domain Name System (DNS).

Next, the browser establishes a network connection.

For HTTPS, the browser also establishes a Transport Layer Security (TLS) connection, verifies the server certificate, and sends an encrypted Hypertext Transfer Protocol (HTTP) request.

Finally, the server processes the request and returns an HTTP response.

Pomerium can sit between the browser and the actual application server.

2.3 Forward proxy versus reverse proxy

A forward proxy usually acts on behalf of clients that want to connect to other systems.

A reverse proxy acts as the entry point to one or more backend services.

Pomerium is primarily a reverse proxy, with additional identity and policy enforcement functionality.

For example:

Browser
   |
   | HTTPS request
   v
Pomerium
   |
   | Authorized upstream request
   v
Grafana

The word upstream refers to the service behind Pomerium. Downstream refers to the client side of the connection.

2.4 Identity providers and Single Sign-On

An Identity Provider (IdP) is a trusted system that authenticates users.

Examples include:

  • Microsoft Entra ID
  • Okta
  • Google identity services
  • Authentik
  • Keycloak

A user can authenticate through the identity provider rather than managing an independent password inside every protected application.

Pomerium then uses identity information to evaluate access policies.

There is an important distinction: the identity provider establishes user identity, while Pomerium evaluates whether the identity satisfies the access policy for the requested service.

2.5 OAuth 2.0 and OpenID Connect

Two standards frequently appear in Pomerium documentation.

OAuth 2.0 is an authorization framework for delegated access. It enables applications to obtain access tokens with defined permissions.

OpenID Connect (OIDC) is an identity layer built on OAuth 2.0. It provides a standardized way for applications to authenticate users and obtain identity information.

For example:

  1. The browser attempts to access a protected service.
  2. The user is redirected to an identity provider.
  3. The user signs in.
  4. The identity provider returns the appropriate authentication result through the protocol.
  5. Pomerium establishes a session and evaluates access policy.

The learner does not need to implement OAuth 2.0 manually to complete the first Pomerium laboratory.

2.6 Cookies, sessions, and tokens

These concepts are related but different.

A cookie is a small piece of information stored by a browser and sent to a website according to cookie rules.

A session represents the ongoing authenticated relationship between a user and a system.

A token is information used to represent identity, authorization, or other claims.

One common token format is a JavaScript Object Notation Web Token, normally abbreviated as JSON Web Token (JWT).

JWTs can contain digitally signed claims, such as the issuer, intended audience, identity, or expiration.

A signed JWT is not automatically encrypted. Systems must validate its signature and important claims before trusting it.

Pomerium uses sessions and identity information as part of its access decision workflow.

2.7 Docker and Docker Compose

A Docker image is a packaged definition of application software and its environment.

A container is a running instance of an image.

Docker Compose lets you describe multiple cooperating containers in one configuration file.

For example, our laboratory will use separate containers for Pomerium and a demo application.

Docker Compose allows us to start both without manually installing a web server into the host operating system.

2.8 Essential versus optional prerequisites

For the first laboratory, you only need basic computer skills, a browser, a terminal, and the ability to install Docker.

Understanding DNS, HTTPS, authentication, and YAML configuration is essential conceptually, but the examples below will teach them as they are used.

Kubernetes, PostgreSQL, custom identity-provider administration, public certificates, and distributed deployment are advanced topics. They are not prerequisites for first success.

Chapter 3. Essential Terminology and Glossary

3.1 Beginner terminology

TermFull formSimple meaningExampleWhy it matters
IAPIdentity-Aware ProxyProxy that uses identity to control accessPomeriumMain tool category
ZTNAZero Trust Network AccessIdentity- and policy-based access to resourcesRestricted internal appsSecurity design
IdPIdentity ProviderService responsible for authenticating usersOktaEstablishes identity
SSOSingle Sign-OnLogin reused across servicesCorporate loginSimplifies access
MFAMultifactor AuthenticationMultiple ways of proving identityPassword plus passkeyStronger authentication
HTTPHypertext Transfer ProtocolWeb request protocolGET requestApplication communication
HTTPSHTTP SecureHTTP over TLSSecure web applicationEncrypted communication
TLSTransport Layer SecuritySecure network communication protocolHTTPS connectionProtects data in transit
DNSDomain Name SystemMaps hostnames to addressesapp.example.comRouting
URLUniform Resource LocatorAddress identifying a resourcehttps://app.example.comRoute identification
ProxyIntermediary serverReceives and forwards requestsPomeriumMain traffic component
UpstreamBackend receiving proxied trafficProtected applicationGrafanaRouting destination
RouteMapping from an external address to a backendApplication mappingApp URL → serviceEssential configuration
PolicyRule controlling permitted accessAllow selected usersEmail restrictionCore security function
SessionAuthenticated interaction stateLogged-in browser sessionLogin sessionTracks authentication
YAMLYAML Ain’t Markup LanguageHuman-readable configuration formatconfig.yamlConfiguration
CLICommand-Line InterfaceText-based interaction with softwaredocker composeOperations
ContainerIsolated application environmentRunning Docker imagePomerium containerLocal deployment

3.2 Intermediate and advanced terminology

| Term | Full form | Simple meaning | Example | Why it matters |
|—|—|—|—|—|
| OIDC | OpenID Connect | Standard identity protocol | Corporate SSO | Authentication |
| OAuth 2.0 | OAuth authorization framework | Delegated authorization protocol | Token-based integration | Identity integrations |
| JWT | JSON Web Token | Structured claims in a token | Signed identity assertion | Identity validation |
| JWKS | JSON Web Key Set | Published cryptographic verification keys | JWT signature verification | Application trust |
| PPL | Pomerium Policy Language | Language for access policies | Email or group rule | Authorization |
| RBAC | Role-Based Access Control | Permissions based on roles | Admin versus viewer | Governance |
| ABAC | Attribute-Based Access Control | Permissions based on attributes | Team and device conditions | Fine-grained policies |
| gRPC | Google-originated Remote Procedure Call framework | Protocol for service communication | Proxy to Authorize | Internal architecture |
| Databroker | Pomerium state-management component | Stores sessions and related data | User session records | State management |
| Envoy | High-performance proxy software | Handles network proxy traffic | Pomerium’s proxy engine | Underlying architecture |
| mTLS | Mutual Transport Layer Security | Both peers authenticate with certificates | Secure service connections | Stronger transport trust |
| CA | Certificate Authority | Entity that issues trusted certificates | Internal CA | TLS certificate trust |
| HA | High Availability | Design that tolerates component failure | Multiple replicas | Production reliability |
| Observability | Understanding system behavior through telemetry | Logs and metrics | Debugging failed logins | Operations |
| Data plane | Components processing application traffic | Pomerium Core proxy services | Request processing |
| Control plane | System managing configuration and policy | Pomerium Zero | Configuration management |

3.3 Commonly confused terms

These are differentMain distinction
Authentication vs authorizationIdentity verification vs permission checking
VPN vs IAPNetwork connectivity vs application-aware access gateway
Identity Provider vs PomeriumAuthenticates identities vs enforces application access
HTTP vs HTTPSWeb protocol vs its TLS-protected form
Session vs JWTAuthenticated state vs a token format
Proxy vs load balancerRequest interception and processing vs traffic distribution; functions can overlap
Pomerium Core vs Pomerium ZeroSelf-managed data plane and configuration vs managed control plane
Container vs virtual machineApplication-level isolation vs virtualized operating-system environments

A useful habit is to distinguish identity, permission, network connectivity, and application behavior when diagnosing an access problem. They are different layers.

Chapter 4. How the Technology Domain Works Without Pomerium

4.1 A company builds its own access architecture

Imagine a small engineering team running an internal dashboard.

Without Pomerium, the team might implement access control using the dashboard’s own authentication system, a VPN, an application gateway, or several individually managed security components.

A basic system could look like this:

#chatgpt-mermaid-_r_1ef_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;fill:rgb(13, 13, 13);}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#chatgpt-mermaid-_r_1ef_ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_1ef_ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_1ef_ .error-icon{fill:rgb(243, 243, 243);}#chatgpt-mermaid-_r_1ef_ .error-text{fill:rgb(13, 13, 13);stroke:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1ef_ .edge-thickness-normal{stroke-width:1px;}#chatgpt-mermaid-_r_1ef_ .edge-thickness-thick{stroke-width:3.5px;}#chatgpt-mermaid-_r_1ef_ .edge-pattern-solid{stroke-dasharray:0;}#chatgpt-mermaid-_r_1ef_ .edge-thickness-invisible{stroke-width:0;fill:none;}#chatgpt-mermaid-_r_1ef_ .edge-pattern-dashed{stroke-dasharray:3;}#chatgpt-mermaid-_r_1ef_ .edge-pattern-dotted{stroke-dasharray:2;}#chatgpt-mermaid-_r_1ef_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1ef_ .marker.cross{stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1ef_ svg{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;}#chatgpt-mermaid-_r_1ef_ p{margin:0;}#chatgpt-mermaid-_r_1ef_ .label{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1ef_ .cluster-label text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1ef_ .cluster-label span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1ef_ .cluster-label span p{background-color:transparent;}#chatgpt-mermaid-_r_1ef_ .label text,#chatgpt-mermaid-_r_1ef_ span{fill:rgb(13, 13, 13);color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1ef_ .node rect,#chatgpt-mermaid-_r_1ef_ .node circle,#chatgpt-mermaid-_r_1ef_ .node ellipse,#chatgpt-mermaid-_r_1ef_ .node polygon,#chatgpt-mermaid-_r_1ef_ .node path{fill:rgb(222, 234, 251);stroke:rgb(83, 154, 248);stroke-width:1px;}#chatgpt-mermaid-_r_1ef_ .rough-node .label text,#chatgpt-mermaid-_r_1ef_ .node .label text,#chatgpt-mermaid-_r_1ef_ .image-shape .label,#chatgpt-mermaid-_r_1ef_ .icon-shape .label{text-anchor:middle;}#chatgpt-mermaid-_r_1ef_ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#chatgpt-mermaid-_r_1ef_ .rough-node .label,#chatgpt-mermaid-_r_1ef_ .node .label,#chatgpt-mermaid-_r_1ef_ .image-shape .label,#chatgpt-mermaid-_r_1ef_ .icon-shape .label{text-align:center;}#chatgpt-mermaid-_r_1ef_ .node.clickable{cursor:pointer;}#chatgpt-mermaid-_r_1ef_ .root .anchor path{fill:rgb(143, 143, 143)!important;stroke-width:0;stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1ef_ .arrowheadPath{fill:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1ef_ .edgePath .path{stroke:rgb(143, 143, 143);stroke-width:1px;}#chatgpt-mermaid-_r_1ef_ .flowchart-link{stroke:rgb(143, 143, 143);fill:none;}#chatgpt-mermaid-_r_1ef_ .edgeLabel{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_1ef_ .edgeLabel p{background-color:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1ef_ .edgeLabel rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1ef_ .labelBkg{background-color:rgba(252, 252, 252, 0.5);}#chatgpt-mermaid-_r_1ef_ .cluster rect{fill:rgb(243, 243, 243);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_1ef_ .cluster text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1ef_ .cluster span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1ef_ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:12px;background:rgb(243, 243, 243);border:1px solid rgba(0, 0, 0, 0.1);border-radius:2px;pointer-events:none;z-index:100;}#chatgpt-mermaid-_r_1ef_ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1ef_ rect.text{fill:none;stroke-width:0;}#chatgpt-mermaid-_r_1ef_ .icon-shape,#chatgpt-mermaid-_r_1ef_ .image-shape{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_1ef_ .icon-shape p,#chatgpt-mermaid-_r_1ef_ .image-shape p{background-color:rgb(252, 252, 252);padding:2px;}#chatgpt-mermaid-_r_1ef_ .icon-shape .label rect,#chatgpt-mermaid-_r_1ef_ .image-shape .label rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1ef_ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#chatgpt-mermaid-_r_1ef_ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#chatgpt-mermaid-_r_1ef_ .node .neo-node{stroke:rgb(83, 154, 248);}#chatgpt-mermaid-_r_1ef_ [data-look=”neo”].node rect,#chatgpt-mermaid-_r_1ef_ [data-look=”neo”].cluster rect,#chatgpt-mermaid-_r_1ef_ [data-look=”neo”].node polygon{stroke:url(#chatgpt-mermaid-_r_1ef_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1ef_ [data-look=”neo”].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_1ef_ [data-look=”neo”].node path{stroke:url(#chatgpt-mermaid-_r_1ef_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_1ef_ [data-look=”neo”].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1ef_ [data-look=”neo”].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_1ef_ [data-look=”neo”].node circle{stroke:url(#chatgpt-mermaid-_r_1ef_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1ef_ [data-look=”neo”].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_1ef_ [data-look=”neo”].icon-shape .icon{fill:url(#chatgpt-mermaid-_r_1ef_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1ef_ [data-look=”neo”].icon-shape .icon-neo path{stroke:url(#chatgpt-mermaid-_r_1ef_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1ef_ .node text{font-size:14px;font-weight:600;letter-spacing:normal;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_1ef_ .edgeLabels text{font-size:13px;font-weight:600;letter-spacing:-0.08px;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_1ef_ .node tspan[font-weight=”normal”],#chatgpt-mermaid-_r_1ef_ .edgeLabels tspan[font-weight=”normal”]{font-weight:600;}#chatgpt-mermaid-_r_1ef_ .edgeLabel .label rect{opacity:1;rx:13px;ry:13px;fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-width:1px;}#chatgpt-mermaid-_r_1ef_ .node rect,#chatgpt-mermaid-_r_1ef_ .node circle,#chatgpt-mermaid-_r_1ef_ .node ellipse,#chatgpt-mermaid-_r_1ef_ .node polygon,#chatgpt-mermaid-_r_1ef_ .node path{fill:rgb(229, 243, 255);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_1ef_ .node rect{rx:16px;ry:16px;}#chatgpt-mermaid-_r_1ef_ .mermaid-decision .label-container{fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-dasharray:2,2;}#chatgpt-mermaid-_r_1ef_ .edgePaths .flowchart-link{stroke:rgb(143, 143, 143);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;}#chatgpt-mermaid-_r_1ef_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1ef_ :root{–mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;}EmployeeVPN or network gatewayInternal applicationIdentity providerApplication permissionsApplication data

The diagram represents a possible architecture, not a claim that every VPN deployment works exactly this way.

The employee first obtains connectivity to the internal network. The application then authenticates the employee and decides whether to allow the requested operation.

If the organization has ten applications, each may need its own identity integration, session handling, and authorization model.

This can become operationally complicated, especially when some applications lack modern authentication features.

4.2 How an application determines access

Suppose an employee wants to view a monitoring dashboard.

The process may involve:

  1. Resolving the dashboard hostname.
  2. Establishing network connectivity.
  3. Connecting to the application’s HTTPS endpoint.
  4. Providing login credentials or using SSO.
  5. Establishing an authenticated session.
  6. Evaluating application-specific permissions.
  7. Returning the requested dashboard data.

If any stage fails, the application cannot complete the request successfully.

4.3 What a centralized application access gateway changes

Now introduce the idea of a centralized gateway without focusing on a particular product.

#chatgpt-mermaid-_r_1em_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;fill:rgb(13, 13, 13);}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#chatgpt-mermaid-_r_1em_ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_1em_ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_1em_ .error-icon{fill:rgb(243, 243, 243);}#chatgpt-mermaid-_r_1em_ .error-text{fill:rgb(13, 13, 13);stroke:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1em_ .edge-thickness-normal{stroke-width:1px;}#chatgpt-mermaid-_r_1em_ .edge-thickness-thick{stroke-width:3.5px;}#chatgpt-mermaid-_r_1em_ .edge-pattern-solid{stroke-dasharray:0;}#chatgpt-mermaid-_r_1em_ .edge-thickness-invisible{stroke-width:0;fill:none;}#chatgpt-mermaid-_r_1em_ .edge-pattern-dashed{stroke-dasharray:3;}#chatgpt-mermaid-_r_1em_ .edge-pattern-dotted{stroke-dasharray:2;}#chatgpt-mermaid-_r_1em_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1em_ .marker.cross{stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1em_ svg{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;}#chatgpt-mermaid-_r_1em_ p{margin:0;}#chatgpt-mermaid-_r_1em_ .label{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1em_ .cluster-label text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1em_ .cluster-label span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1em_ .cluster-label span p{background-color:transparent;}#chatgpt-mermaid-_r_1em_ .label text,#chatgpt-mermaid-_r_1em_ span{fill:rgb(13, 13, 13);color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1em_ .node rect,#chatgpt-mermaid-_r_1em_ .node circle,#chatgpt-mermaid-_r_1em_ .node ellipse,#chatgpt-mermaid-_r_1em_ .node polygon,#chatgpt-mermaid-_r_1em_ .node path{fill:rgb(222, 234, 251);stroke:rgb(83, 154, 248);stroke-width:1px;}#chatgpt-mermaid-_r_1em_ .rough-node .label text,#chatgpt-mermaid-_r_1em_ .node .label text,#chatgpt-mermaid-_r_1em_ .image-shape .label,#chatgpt-mermaid-_r_1em_ .icon-shape .label{text-anchor:middle;}#chatgpt-mermaid-_r_1em_ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#chatgpt-mermaid-_r_1em_ .rough-node .label,#chatgpt-mermaid-_r_1em_ .node .label,#chatgpt-mermaid-_r_1em_ .image-shape .label,#chatgpt-mermaid-_r_1em_ .icon-shape .label{text-align:center;}#chatgpt-mermaid-_r_1em_ .node.clickable{cursor:pointer;}#chatgpt-mermaid-_r_1em_ .root .anchor path{fill:rgb(143, 143, 143)!important;stroke-width:0;stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1em_ .arrowheadPath{fill:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1em_ .edgePath .path{stroke:rgb(143, 143, 143);stroke-width:1px;}#chatgpt-mermaid-_r_1em_ .flowchart-link{stroke:rgb(143, 143, 143);fill:none;}#chatgpt-mermaid-_r_1em_ .edgeLabel{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_1em_ .edgeLabel p{background-color:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1em_ .edgeLabel rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1em_ .labelBkg{background-color:rgba(252, 252, 252, 0.5);}#chatgpt-mermaid-_r_1em_ .cluster rect{fill:rgb(243, 243, 243);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_1em_ .cluster text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1em_ .cluster span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1em_ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:12px;background:rgb(243, 243, 243);border:1px solid rgba(0, 0, 0, 0.1);border-radius:2px;pointer-events:none;z-index:100;}#chatgpt-mermaid-_r_1em_ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1em_ rect.text{fill:none;stroke-width:0;}#chatgpt-mermaid-_r_1em_ .icon-shape,#chatgpt-mermaid-_r_1em_ .image-shape{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_1em_ .icon-shape p,#chatgpt-mermaid-_r_1em_ .image-shape p{background-color:rgb(252, 252, 252);padding:2px;}#chatgpt-mermaid-_r_1em_ .icon-shape .label rect,#chatgpt-mermaid-_r_1em_ .image-shape .label rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1em_ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#chatgpt-mermaid-_r_1em_ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#chatgpt-mermaid-_r_1em_ .node .neo-node{stroke:rgb(83, 154, 248);}#chatgpt-mermaid-_r_1em_ [data-look=”neo”].node rect,#chatgpt-mermaid-_r_1em_ [data-look=”neo”].cluster rect,#chatgpt-mermaid-_r_1em_ [data-look=”neo”].node polygon{stroke:url(#chatgpt-mermaid-_r_1em_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1em_ [data-look=”neo”].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_1em_ [data-look=”neo”].node path{stroke:url(#chatgpt-mermaid-_r_1em_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_1em_ [data-look=”neo”].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1em_ [data-look=”neo”].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_1em_ [data-look=”neo”].node circle{stroke:url(#chatgpt-mermaid-_r_1em_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1em_ [data-look=”neo”].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_1em_ [data-look=”neo”].icon-shape .icon{fill:url(#chatgpt-mermaid-_r_1em_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1em_ [data-look=”neo”].icon-shape .icon-neo path{stroke:url(#chatgpt-mermaid-_r_1em_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1em_ .node text{font-size:14px;font-weight:600;letter-spacing:normal;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_1em_ .edgeLabels text{font-size:13px;font-weight:600;letter-spacing:-0.08px;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_1em_ .node tspan[font-weight=”normal”],#chatgpt-mermaid-_r_1em_ .edgeLabels tspan[font-weight=”normal”]{font-weight:600;}#chatgpt-mermaid-_r_1em_ .edgeLabel .label rect{opacity:1;rx:13px;ry:13px;fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-width:1px;}#chatgpt-mermaid-_r_1em_ .node rect,#chatgpt-mermaid-_r_1em_ .node circle,#chatgpt-mermaid-_r_1em_ .node ellipse,#chatgpt-mermaid-_r_1em_ .node polygon,#chatgpt-mermaid-_r_1em_ .node path{fill:rgb(229, 243, 255);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_1em_ .node rect{rx:16px;ry:16px;}#chatgpt-mermaid-_r_1em_ .mermaid-decision .label-container{fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-dasharray:2,2;}#chatgpt-mermaid-_r_1em_ .edgePaths .flowchart-link{stroke:rgb(143, 143, 143);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;}#chatgpt-mermaid-_r_1em_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1em_ :root{–mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;}Employee browserIdentity-aware accessgatewayCorporate identity providerCentral access policyPrivate applicationRequests applicationAuthenticate identityIdentity resultEvaluate permissionAllow or denyOnly authorized requests

This architecture moves an important part of the access decision out of each application and into a shared gateway.

The application can remain on a private network, provided users cannot bypass the gateway to reach it directly.

However, the application may still need its own authorization controls. A gateway granting access to Grafana does not automatically determine which Grafana dashboards or administrative operations that user may perform.

4.4 Universal concepts versus product-specific implementation

The following ideas are not unique to Pomerium:

  • Identity-based authentication
  • Access policies
  • HTTPS and TLS
  • Reverse proxies
  • User sessions
  • Zero Trust principles
  • Application-level access enforcement

Pomerium implements these ideas through its own architecture, configuration model, policy language, and integrations.

That distinction matters because understanding the domain lets you evaluate Pomerium intelligently rather than learning a collection of commands without knowing why they exist.

Part II — Understand Pomerium

Chapter 5. What Is Pomerium?

5.1 One-sentence definition

Pomerium is an identity-aware reverse proxy that authenticates users, evaluates access policies, and securely connects authorized clients to protected applications and services.

5.2 Beginner-friendly definition

Pomerium is a security gateway you place in front of applications.

Instead of letting everyone connect directly to your internal Grafana, Jenkins, or administration portal, you make Pomerium the controlled entry point.

Pomerium determines whether a user has a valid identity and permission to access the requested application.

When access is allowed, Pomerium forwards the request to the application.

5.3 Technical definition

Pomerium is an identity- and context-aware reverse proxy built around Zero Trust principles.

Its core architecture includes a proxy, authentication service, authorization service, and state-management service called the Databroker. The proxy layer uses Envoy, while OAuth 2.0 and OpenID Connect support identity integration. Pomerium+1

Pomerium can be run as one integrated instance or as multiple cooperating service components.

5.4 What category does Pomerium belong to?

Pomerium belongs to several overlapping technology categories.

CategoryRelationship to Pomerium
Identity-Aware ProxyPrimary product category
Zero Trust Network AccessProvides resource-specific access capabilities
Reverse ProxyForwards authorized traffic to backend services
Identity and Access ManagementIntegrates with IAM systems to make access decisions
Application Access GatewayCentralizes access to protected applications
Security Policy EnforcementEvaluates permissions before forwarding traffic
Cloud-native infrastructureDeployable with containers and Kubernetes

Pomerium is not itself a complete identity provider or a general replacement for all network security controls.

5.5 Pomerium editions and deployment models

One important distinction is that Pomerium Core, Pomerium Zero, and Pomerium Enterprise are not identical products with identical management capabilities.

OfferingWhat it isManagement modelMain audience
Pomerium CoreOpen-source proxy and servicesSelf-managedDevelopers, DevOps, platform teams
Pomerium ZeroHosted control plane managing Core clustersCloud-managed configuration; self-hosted proxyIndividuals and teams wanting easier management
Pomerium EnterpriseSelf-hosted control plane with additional governance featuresOrganization-managedLarger organizations with advanced operational requirements

Pomerium Core is available under the Apache 2.0 open-source license. Zero and Enterprise add management and operational capabilities, some subject to commercial plans and licensing. GitHub+2

5.6 Where does it run?

Pomerium Core supports several deployment methods.

[macOS] 개발환경 구축 – Docker, Colima 설치

Docker containers

The easiest starting environment for beginners. Pomerium and the applications it protects run in separate containers.

Se simplifier Kubernetes avec Helm et les Charts

Kubernetes

Suitable for orchestrated environments, ingress management, automated deployments, and scaling.

Linux Logo, Tux, Linux Kernel, Ubuntu, Free Software, Linux Mint, MX Linux, Bird transparent background PNG clipart | HiClipart

Linux servers and virtual machines

Pomerium can also run using official packages or prebuilt binaries.

The installation chapters explain operating-system differences in detail.

5.7 What Pomerium does not do

Understanding limitations prevents architecture mistakes.

Pomerium does not automatically provide:

  • A complete corporate user directory.
  • A replacement for application-specific business permissions.
  • An antivirus or endpoint detection system.
  • A Web Application Firewall (WAF) covering every attack category.
  • Database backup, disaster recovery, or application data protection.
  • General-purpose network connectivity equivalent to every VPN use case.
  • Protection against an application being accessed through a separate, unprotected network path.

Its job is to enforce an access boundary for the resources routed through it.

Chapter 6. Why Does Pomerium Exist?

6.1 The problem of inconsistent access controls

Consider an organization with 30 internal applications.

Some applications use local passwords. Others support corporate SSO. Some are accessible only through VPN. Others have been exposed through reverse proxies.

Administrators may need to update several systems whenever someone joins, changes teams, or leaves.

Pomerium provides a way to standardize an important layer of application access.

6.2 Three real-world scenarios

ScenarioWithout PomeriumWith PomeriumMain benefit
Internal GrafanaConfigure a VPN or separate authentication for dashboard accessProtect Grafana with an identity-based route and policyCentralized application access
Developer toolsManage different access approaches for Jenkins, documentation, and utilitiesConfigure protected routes with distinct permissionsConsistent enforcement
Contractor accessProvision broader connectivity or application-specific credentialsGrant access to specifically approved protected applicationsReduced unnecessary access

These benefits are conditional on correct deployment, identity integration, and network isolation.

6.3 Why not use only a VPN?

VPNs are useful for private networking, especially where applications require general IP connectivity.

However, a VPN does not inherently provide the same application-level authorization model as Pomerium.

Conversely, Pomerium is not always the right tool for access to arbitrary network protocols or complete private networks.

Organizations can use both technologies together.

6.4 What trade-offs does Pomerium introduce?

Pomerium adds a security enforcement component to the request path.

That introduces responsibilities:

  • Deploying and maintaining a reliable gateway.
  • Managing TLS certificates and access policies.
  • Ensuring identity-provider availability.
  • Controlling session and state storage.
  • Preventing direct access that bypasses the proxy.
  • Monitoring gateway health and response latency.

An access gateway becomes part of the application’s availability architecture. If it is unavailable, legitimate users may also be unable to access the protected application.

6.5 When is Pomerium unnecessary?

You may not need Pomerium when an application already has strong corporate SSO, appropriate authorization, reliable audit capabilities, and an acceptable network security architecture.

It may also be excessive for a small local-only tool used by one person.

The decision should depend on actual security and operational requirements, not on the desire to add another infrastructure component.

Chapter 7. How Pomerium Works

7.1 The four logical components

Pomerium contains four main logical services.

ComponentResponsibilityEveryday analogy
ProxyAccepts and forwards trafficReception desk
AuthenticateEstablishes user identity and login sessionIdentity verification counter
AuthorizeChecks whether the request is permittedAccess-control officer
DatabrokerManages state, sessions, and identity-related recordsSecure records office

These are logical services. They do not necessarily require four separately deployed servers.

In the beginner deployment, the Core components run together, while the first login experience uses Pomerium’s external hosted authentication service.

7.2 End-to-end request architecture

#chatgpt-mermaid-_r_1fm_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;fill:rgb(13, 13, 13);}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#chatgpt-mermaid-_r_1fm_ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_1fm_ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_1fm_ .error-icon{fill:rgb(243, 243, 243);}#chatgpt-mermaid-_r_1fm_ .error-text{fill:rgb(13, 13, 13);stroke:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1fm_ .edge-thickness-normal{stroke-width:1px;}#chatgpt-mermaid-_r_1fm_ .edge-thickness-thick{stroke-width:3.5px;}#chatgpt-mermaid-_r_1fm_ .edge-pattern-solid{stroke-dasharray:0;}#chatgpt-mermaid-_r_1fm_ .edge-thickness-invisible{stroke-width:0;fill:none;}#chatgpt-mermaid-_r_1fm_ .edge-pattern-dashed{stroke-dasharray:3;}#chatgpt-mermaid-_r_1fm_ .edge-pattern-dotted{stroke-dasharray:2;}#chatgpt-mermaid-_r_1fm_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1fm_ .marker.cross{stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1fm_ svg{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;}#chatgpt-mermaid-_r_1fm_ p{margin:0;}#chatgpt-mermaid-_r_1fm_ .label{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1fm_ .cluster-label text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1fm_ .cluster-label span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1fm_ .cluster-label span p{background-color:transparent;}#chatgpt-mermaid-_r_1fm_ .label text,#chatgpt-mermaid-_r_1fm_ span{fill:rgb(13, 13, 13);color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1fm_ .node rect,#chatgpt-mermaid-_r_1fm_ .node circle,#chatgpt-mermaid-_r_1fm_ .node ellipse,#chatgpt-mermaid-_r_1fm_ .node polygon,#chatgpt-mermaid-_r_1fm_ .node path{fill:rgb(222, 234, 251);stroke:rgb(83, 154, 248);stroke-width:1px;}#chatgpt-mermaid-_r_1fm_ .rough-node .label text,#chatgpt-mermaid-_r_1fm_ .node .label text,#chatgpt-mermaid-_r_1fm_ .image-shape .label,#chatgpt-mermaid-_r_1fm_ .icon-shape .label{text-anchor:middle;}#chatgpt-mermaid-_r_1fm_ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#chatgpt-mermaid-_r_1fm_ .rough-node .label,#chatgpt-mermaid-_r_1fm_ .node .label,#chatgpt-mermaid-_r_1fm_ .image-shape .label,#chatgpt-mermaid-_r_1fm_ .icon-shape .label{text-align:center;}#chatgpt-mermaid-_r_1fm_ .node.clickable{cursor:pointer;}#chatgpt-mermaid-_r_1fm_ .root .anchor path{fill:rgb(143, 143, 143)!important;stroke-width:0;stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1fm_ .arrowheadPath{fill:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1fm_ .edgePath .path{stroke:rgb(143, 143, 143);stroke-width:1px;}#chatgpt-mermaid-_r_1fm_ .flowchart-link{stroke:rgb(143, 143, 143);fill:none;}#chatgpt-mermaid-_r_1fm_ .edgeLabel{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_1fm_ .edgeLabel p{background-color:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1fm_ .edgeLabel rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1fm_ .labelBkg{background-color:rgba(252, 252, 252, 0.5);}#chatgpt-mermaid-_r_1fm_ .cluster rect{fill:rgb(243, 243, 243);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_1fm_ .cluster text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1fm_ .cluster span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1fm_ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:12px;background:rgb(243, 243, 243);border:1px solid rgba(0, 0, 0, 0.1);border-radius:2px;pointer-events:none;z-index:100;}#chatgpt-mermaid-_r_1fm_ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1fm_ rect.text{fill:none;stroke-width:0;}#chatgpt-mermaid-_r_1fm_ .icon-shape,#chatgpt-mermaid-_r_1fm_ .image-shape{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_1fm_ .icon-shape p,#chatgpt-mermaid-_r_1fm_ .image-shape p{background-color:rgb(252, 252, 252);padding:2px;}#chatgpt-mermaid-_r_1fm_ .icon-shape .label rect,#chatgpt-mermaid-_r_1fm_ .image-shape .label rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1fm_ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#chatgpt-mermaid-_r_1fm_ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#chatgpt-mermaid-_r_1fm_ .node .neo-node{stroke:rgb(83, 154, 248);}#chatgpt-mermaid-_r_1fm_ [data-look=”neo”].node rect,#chatgpt-mermaid-_r_1fm_ [data-look=”neo”].cluster rect,#chatgpt-mermaid-_r_1fm_ [data-look=”neo”].node polygon{stroke:url(#chatgpt-mermaid-_r_1fm_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1fm_ [data-look=”neo”].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_1fm_ [data-look=”neo”].node path{stroke:url(#chatgpt-mermaid-_r_1fm_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_1fm_ [data-look=”neo”].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1fm_ [data-look=”neo”].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_1fm_ [data-look=”neo”].node circle{stroke:url(#chatgpt-mermaid-_r_1fm_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1fm_ [data-look=”neo”].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_1fm_ [data-look=”neo”].icon-shape .icon{fill:url(#chatgpt-mermaid-_r_1fm_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1fm_ [data-look=”neo”].icon-shape .icon-neo path{stroke:url(#chatgpt-mermaid-_r_1fm_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1fm_ .node text{font-size:14px;font-weight:600;letter-spacing:normal;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_1fm_ .edgeLabels text{font-size:13px;font-weight:600;letter-spacing:-0.08px;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_1fm_ .node tspan[font-weight=”normal”],#chatgpt-mermaid-_r_1fm_ .edgeLabels tspan[font-weight=”normal”]{font-weight:600;}#chatgpt-mermaid-_r_1fm_ .edgeLabel .label rect{opacity:1;rx:13px;ry:13px;fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-width:1px;}#chatgpt-mermaid-_r_1fm_ .node rect,#chatgpt-mermaid-_r_1fm_ .node circle,#chatgpt-mermaid-_r_1fm_ .node ellipse,#chatgpt-mermaid-_r_1fm_ .node polygon,#chatgpt-mermaid-_r_1fm_ .node path{fill:rgb(229, 243, 255);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_1fm_ .node rect{rx:16px;ry:16px;}#chatgpt-mermaid-_r_1fm_ .mermaid-decision .label-container{fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-dasharray:2,2;}#chatgpt-mermaid-_r_1fm_ .edgePaths .flowchart-link{stroke:rgb(143, 143, 143);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;}#chatgpt-mermaid-_r_1fm_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1fm_ :root{–mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;}User browserPomerium ProxyAuthorization serviceAuthentication serviceIdentity providerDatabrokerProtected applicationHTTPS requestCheck accessIf login requiredOIDC authenticationSession establishedSession informationAccess decisionAuthorized trafficResponseHTTPS response

This diagram summarizes the logical interactions; the browser also participates in authentication redirects.

7.3 Step-by-step execution

Step 1 — The browser requests an application.

An employee opens a Pomerium-protected URL.

Step 2 — The proxy receives the request.

Pomerium identifies the matching route and initiates an authorization check.

Step 3 — Authentication is checked.

If the request lacks a valid session, the user is directed into the authentication process.

Step 4 — The identity provider authenticates the user.

This may involve a password, passkey, or another factor according to the identity-provider configuration.

Step 5 — Session information is established.

Pomerium manages the session using its authentication and Databroker components.

Step 6 — Authorization evaluates the request.

The service evaluates the policy using relevant authenticated identity and request context.

Step 7 — Pomerium either allows or denies access.

If the request is permitted, Pomerium forwards it to the upstream application.

Step 8 — The application responds.

The response returns through Pomerium to the browser.

Pomerium’s documented architecture uses gRPC communication among relevant internal components and evaluates HTTP authorization on a per-request basis. Pomerium+1

7.4 Authentication does not equal authorization

Suppose two employees successfully authenticate.

The first employee is a platform engineer. The second is a marketing analyst.

Both may have valid corporate identities.

However, a production administration route might permit only the first employee.

Authentication succeeds for both, but authorization produces different decisions.

That is the central distinction behind Pomerium’s access-control model.

7.5 Understanding state

Pomerium maintains data about users and sessions.

Its Databroker supports different storage approaches, including memory, local file storage, and PostgreSQL.

The choice affects session persistence and high availability.

We will explore those differences when designing production architecture.

Chapter 8. Core Features Explained Simply

8.1 Essential features

FeatureWhat it doesProblem solvedExampleLevel
Identity-aware reverse proxyAccepts and controls application requestsUncontrolled application entryProtect GrafanaBeginner
Authentication integrationConnects user login to an identity providerRepeated login systemsCorporate SSOBeginner
Access policiesControls who can access a routeExcessive accessAllow specific usersBeginner
Application routingMaps external URLs to backend servicesComplex access pathsDashboard hostname to GrafanaBeginner
Session handlingMaintains authenticated interactionsRepeated authenticationBrowser login sessionBeginner
TLS supportSecures transport connectionsUnencrypted communicationHTTPSBeginner

8.2 Everyday operational features

FeatureSimple explanationPractical exampleLevel
Configuration filesDefine how Pomerium behavesYAML configurationBeginner
Environment variablesSupply configuration outside the fileSecrets injected at runtimeIntermediate
LogsShow significant operational eventsDiagnose login errorsBeginner
Health checksReport whether services are ready and healthyContainer health probeIntermediate
MetricsExpose operational measurementsPrometheus monitoringIntermediate
Hot configuration reloadApply supported configuration changes without restarting the processUpdate a route policyIntermediate

8.3 Integration features

FeaturePractical purposeTypical environmentLevel
OIDC integrationAuthenticate through existing identity providersCorporate IAMIntermediate
Signed identity assertionsAllow applications to verify identity information sent by PomeriumCustom applicationsIntermediate
Kubernetes integrationProtect services in Kubernetes environmentsEKS or other Kubernetes clustersAdvanced
TCP connectivity clientsAccess supported non-HTTP services through PomeriumDeveloper servicesAdvanced
Terraform integrationsManage supported configuration declarativelyInfrastructure as CodeAdvanced

8.4 Security features

FeatureProblem addressedExample
Per-route authorizationUsers getting access to applications outside their roleOnly SREs can access monitoring
Deny policiesExplicitly blocked identities or conditionsDeny a named user
Identity assertionsApplications need trustworthy identity informationVerify signed JWT
Session restrictionsLong-lived or inappropriate sessionsConfigure session expiration
Certificate validationUntrusted network connectionsValidate upstream TLS
Mutual TLSNeed for certificate-based authenticationClient-to-gateway certificate authentication
Contextual policiesDecisions require additional conditionsPolicy using available device or request attributes

Contextual policy support depends on the availability of the relevant attributes, provider integrations, and product configuration. Installing Core alone does not automatically supply every device or directory signal.

8.5 Advanced and production features

FeatureAvailability or dependencyMain value
Multiple Pomerium replicasCore with appropriate shared stateAvailability and capacity
Split-service deploymentCoreIndependent component placement
PostgreSQL-backed DatabrokerCorePersistent shared state
Pomerium Policy LanguageCoreDeclarative authorization
Kubernetes Ingress ControllerSeparate Pomerium Kubernetes integrationKubernetes-native routes
Service accountsZero and Enterprise featureMachine authentication
Centralized management consoleZero or EnterpriseEasier multi-application management
Directory synchronizationEnterprise featureOrganization-scale identity management
Namespace-based governanceEnterprise featureDelegated administration
Enterprise APIEnterpriseProgrammatic administration
Advanced Rego policiesEnterpriseMore expressive policy logic

The official Pomerium product documentation distinguishes these capabilities across Core, Zero, and Enterprise. Pomerium+2

Chapter 9. Similar Tools and Alternatives

Pomerium is one of several technologies that address application access.

The correct alternative depends on whether you primarily need application authentication, cloud-managed access, general private networking, or infrastructure access.

9.1 Comparison

ToolPrimary purposeMain strengthMain limitation or trade-offBest use caseRelationship to Pomerium
PomeriumIdentity-aware application accessOpen-source proxy with route-level policiesRequires gateway operations and configurationSelf-hosted protected web appsReference tool
OAuth2 ProxyOAuth/OIDC authentication proxyFocused authentication integrationAdvanced authorization designs may require additional componentsAdd SSO to existing web appsDirect alternative for some use cases
Cloudflare AccessManaged identity-aware application accessManaged service with device and identity policiesDependence on Cloudflare service and architectureCloud-managed application accessDirect alternative
AuthentikIdentity provider and proxy authenticationIntegrated identity and application access featuresManaging the broader identity platform adds responsibilitySelf-hosted identity and app accessAlternative or complementary
AutheliaAuthentication and authorization portalSelf-hosted authentication alongside reverse proxiesRequires compatible integration and operationsProtect self-hosted servicesAlternative architecture
TeleportInfrastructure and application accessStrong SSH, Kubernetes, database, and session-oriented capabilitiesBroader infrastructure platform with different operational modelInfrastructure access governanceOverlapping alternative
TailscaleIdentity-based private networkingSimple private device and network connectivityDifferent focus from per-request HTTP proxy enforcementDevices, private networks, remote connectivityOften complementary
NGINX with external authenticationReverse proxy with external access checksFlexible integration into existing proxy stacksRequires separate identity and authorization designOrganizations already using NGINXComponent alternative

Cloudflare Access, Authentik, Teleport, and Tailscale provide substantially different technical models despite their overlapping access-security goals. Cloudflare One docs+3

9.2 Pomerium versus OAuth2 Proxy

OAuth2 Proxy is particularly relevant when you have a web application that needs authentication and you want to reuse an existing OAuth 2.0 or OIDC provider.

Pomerium is attractive when you also want a unified identity-aware routing gateway with a dedicated authorization architecture.

This is a design distinction, not an absolute statement that one product is always more secure.

9.3 Pomerium versus Cloudflare Access

Cloudflare Access offers a managed, identity-aware access layer.

Pomerium Core allows organizations to operate the proxy and configuration within their own environment.

Pomerium Zero provides a middle ground by retaining the self-hosted data plane while using a hosted management service.

Choose based on control-plane location, trust boundaries, networking requirements, cost, operational skills, and the features needed.

9.4 Pomerium versus Authentik

Authentik can function as an identity provider and can also protect applications through proxy or forward-authentication integrations.

Pomerium focuses on the identity-aware access gateway.

These tools can sometimes work together, with Authentik supplying identity and Pomerium enforcing access to protected applications.

9.5 Pomerium versus Tailscale

Tailscale is more naturally suited to secure device and network connectivity.

Pomerium is more naturally suited to application access through an identity-aware proxy.

A team might use Tailscale for private connectivity between environments while Pomerium enforces access to specific web applications.

Which Tool Should You Choose and Why?

Interactive technology selection guideSelf-host a central identity-aware gateway for internal web applicationsUse a managed service for protecting web applicationsOperate a self-hosted identity provider and application access systemConnect remote devices and private networksControl SSH, Kubernetes, and database infrastructure access

Start by evaluating Pomerium Core.

Its identity-aware routing and policy model directly match this requirement.

Part III — Architecture and Workflows

Chapter 10. Architecture Explained from Simple to Advanced

10.1 Architecture level 1: The smallest working setup

The first architecture uses one Pomerium instance and one web application.

#chatgpt-mermaid-_r_1gs_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;fill:rgb(13, 13, 13);}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#chatgpt-mermaid-_r_1gs_ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_1gs_ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_1gs_ .error-icon{fill:rgb(243, 243, 243);}#chatgpt-mermaid-_r_1gs_ .error-text{fill:rgb(13, 13, 13);stroke:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1gs_ .edge-thickness-normal{stroke-width:1px;}#chatgpt-mermaid-_r_1gs_ .edge-thickness-thick{stroke-width:3.5px;}#chatgpt-mermaid-_r_1gs_ .edge-pattern-solid{stroke-dasharray:0;}#chatgpt-mermaid-_r_1gs_ .edge-thickness-invisible{stroke-width:0;fill:none;}#chatgpt-mermaid-_r_1gs_ .edge-pattern-dashed{stroke-dasharray:3;}#chatgpt-mermaid-_r_1gs_ .edge-pattern-dotted{stroke-dasharray:2;}#chatgpt-mermaid-_r_1gs_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1gs_ .marker.cross{stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1gs_ svg{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;}#chatgpt-mermaid-_r_1gs_ p{margin:0;}#chatgpt-mermaid-_r_1gs_ .label{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1gs_ .cluster-label text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1gs_ .cluster-label span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1gs_ .cluster-label span p{background-color:transparent;}#chatgpt-mermaid-_r_1gs_ .label text,#chatgpt-mermaid-_r_1gs_ span{fill:rgb(13, 13, 13);color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1gs_ .node rect,#chatgpt-mermaid-_r_1gs_ .node circle,#chatgpt-mermaid-_r_1gs_ .node ellipse,#chatgpt-mermaid-_r_1gs_ .node polygon,#chatgpt-mermaid-_r_1gs_ .node path{fill:rgb(222, 234, 251);stroke:rgb(83, 154, 248);stroke-width:1px;}#chatgpt-mermaid-_r_1gs_ .rough-node .label text,#chatgpt-mermaid-_r_1gs_ .node .label text,#chatgpt-mermaid-_r_1gs_ .image-shape .label,#chatgpt-mermaid-_r_1gs_ .icon-shape .label{text-anchor:middle;}#chatgpt-mermaid-_r_1gs_ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#chatgpt-mermaid-_r_1gs_ .rough-node .label,#chatgpt-mermaid-_r_1gs_ .node .label,#chatgpt-mermaid-_r_1gs_ .image-shape .label,#chatgpt-mermaid-_r_1gs_ .icon-shape .label{text-align:center;}#chatgpt-mermaid-_r_1gs_ .node.clickable{cursor:pointer;}#chatgpt-mermaid-_r_1gs_ .root .anchor path{fill:rgb(143, 143, 143)!important;stroke-width:0;stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1gs_ .arrowheadPath{fill:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1gs_ .edgePath .path{stroke:rgb(143, 143, 143);stroke-width:1px;}#chatgpt-mermaid-_r_1gs_ .flowchart-link{stroke:rgb(143, 143, 143);fill:none;}#chatgpt-mermaid-_r_1gs_ .edgeLabel{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_1gs_ .edgeLabel p{background-color:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1gs_ .edgeLabel rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1gs_ .labelBkg{background-color:rgba(252, 252, 252, 0.5);}#chatgpt-mermaid-_r_1gs_ .cluster rect{fill:rgb(243, 243, 243);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_1gs_ .cluster text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1gs_ .cluster span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1gs_ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:12px;background:rgb(243, 243, 243);border:1px solid rgba(0, 0, 0, 0.1);border-radius:2px;pointer-events:none;z-index:100;}#chatgpt-mermaid-_r_1gs_ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1gs_ rect.text{fill:none;stroke-width:0;}#chatgpt-mermaid-_r_1gs_ .icon-shape,#chatgpt-mermaid-_r_1gs_ .image-shape{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_1gs_ .icon-shape p,#chatgpt-mermaid-_r_1gs_ .image-shape p{background-color:rgb(252, 252, 252);padding:2px;}#chatgpt-mermaid-_r_1gs_ .icon-shape .label rect,#chatgpt-mermaid-_r_1gs_ .image-shape .label rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1gs_ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#chatgpt-mermaid-_r_1gs_ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#chatgpt-mermaid-_r_1gs_ .node .neo-node{stroke:rgb(83, 154, 248);}#chatgpt-mermaid-_r_1gs_ [data-look=”neo”].node rect,#chatgpt-mermaid-_r_1gs_ [data-look=”neo”].cluster rect,#chatgpt-mermaid-_r_1gs_ [data-look=”neo”].node polygon{stroke:url(#chatgpt-mermaid-_r_1gs_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1gs_ [data-look=”neo”].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_1gs_ [data-look=”neo”].node path{stroke:url(#chatgpt-mermaid-_r_1gs_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_1gs_ [data-look=”neo”].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1gs_ [data-look=”neo”].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_1gs_ [data-look=”neo”].node circle{stroke:url(#chatgpt-mermaid-_r_1gs_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1gs_ [data-look=”neo”].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_1gs_ [data-look=”neo”].icon-shape .icon{fill:url(#chatgpt-mermaid-_r_1gs_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1gs_ [data-look=”neo”].icon-shape .icon-neo path{stroke:url(#chatgpt-mermaid-_r_1gs_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1gs_ .node text{font-size:14px;font-weight:600;letter-spacing:normal;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_1gs_ .edgeLabels text{font-size:13px;font-weight:600;letter-spacing:-0.08px;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_1gs_ .node tspan[font-weight=”normal”],#chatgpt-mermaid-_r_1gs_ .edgeLabels tspan[font-weight=”normal”]{font-weight:600;}#chatgpt-mermaid-_r_1gs_ .edgeLabel .label rect{opacity:1;rx:13px;ry:13px;fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-width:1px;}#chatgpt-mermaid-_r_1gs_ .node rect,#chatgpt-mermaid-_r_1gs_ .node circle,#chatgpt-mermaid-_r_1gs_ .node ellipse,#chatgpt-mermaid-_r_1gs_ .node polygon,#chatgpt-mermaid-_r_1gs_ .node path{fill:rgb(229, 243, 255);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_1gs_ .node rect{rx:16px;ry:16px;}#chatgpt-mermaid-_r_1gs_ .mermaid-decision .label-container{fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-dasharray:2,2;}#chatgpt-mermaid-_r_1gs_ .edgePaths .flowchart-link{stroke:rgb(143, 143, 143);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;}#chatgpt-mermaid-_r_1gs_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1gs_ :root{–mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;}BrowserPomerium CorePrivate web applicationHosted authenticationHTTPSAuthorized HTTPAuthentication

Pomerium receives browser requests, handles the required authorization process, and forwards permitted traffic to the private application.

This is the setup we will build locally.

10.2 Architecture level 2: Inside Pomerium Core

#chatgpt-mermaid-_r_1h3_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;fill:rgb(13, 13, 13);}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#chatgpt-mermaid-_r_1h3_ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_1h3_ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_1h3_ .error-icon{fill:rgb(243, 243, 243);}#chatgpt-mermaid-_r_1h3_ .error-text{fill:rgb(13, 13, 13);stroke:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1h3_ .edge-thickness-normal{stroke-width:1px;}#chatgpt-mermaid-_r_1h3_ .edge-thickness-thick{stroke-width:3.5px;}#chatgpt-mermaid-_r_1h3_ .edge-pattern-solid{stroke-dasharray:0;}#chatgpt-mermaid-_r_1h3_ .edge-thickness-invisible{stroke-width:0;fill:none;}#chatgpt-mermaid-_r_1h3_ .edge-pattern-dashed{stroke-dasharray:3;}#chatgpt-mermaid-_r_1h3_ .edge-pattern-dotted{stroke-dasharray:2;}#chatgpt-mermaid-_r_1h3_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1h3_ .marker.cross{stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1h3_ svg{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;}#chatgpt-mermaid-_r_1h3_ p{margin:0;}#chatgpt-mermaid-_r_1h3_ .label{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1h3_ .cluster-label text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1h3_ .cluster-label span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1h3_ .cluster-label span p{background-color:transparent;}#chatgpt-mermaid-_r_1h3_ .label text,#chatgpt-mermaid-_r_1h3_ span{fill:rgb(13, 13, 13);color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1h3_ .node rect,#chatgpt-mermaid-_r_1h3_ .node circle,#chatgpt-mermaid-_r_1h3_ .node ellipse,#chatgpt-mermaid-_r_1h3_ .node polygon,#chatgpt-mermaid-_r_1h3_ .node path{fill:rgb(222, 234, 251);stroke:rgb(83, 154, 248);stroke-width:1px;}#chatgpt-mermaid-_r_1h3_ .rough-node .label text,#chatgpt-mermaid-_r_1h3_ .node .label text,#chatgpt-mermaid-_r_1h3_ .image-shape .label,#chatgpt-mermaid-_r_1h3_ .icon-shape .label{text-anchor:middle;}#chatgpt-mermaid-_r_1h3_ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#chatgpt-mermaid-_r_1h3_ .rough-node .label,#chatgpt-mermaid-_r_1h3_ .node .label,#chatgpt-mermaid-_r_1h3_ .image-shape .label,#chatgpt-mermaid-_r_1h3_ .icon-shape .label{text-align:center;}#chatgpt-mermaid-_r_1h3_ .node.clickable{cursor:pointer;}#chatgpt-mermaid-_r_1h3_ .root .anchor path{fill:rgb(143, 143, 143)!important;stroke-width:0;stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1h3_ .arrowheadPath{fill:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1h3_ .edgePath .path{stroke:rgb(143, 143, 143);stroke-width:1px;}#chatgpt-mermaid-_r_1h3_ .flowchart-link{stroke:rgb(143, 143, 143);fill:none;}#chatgpt-mermaid-_r_1h3_ .edgeLabel{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_1h3_ .edgeLabel p{background-color:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1h3_ .edgeLabel rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1h3_ .labelBkg{background-color:rgba(252, 252, 252, 0.5);}#chatgpt-mermaid-_r_1h3_ .cluster rect{fill:rgb(243, 243, 243);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_1h3_ .cluster text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1h3_ .cluster span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1h3_ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:12px;background:rgb(243, 243, 243);border:1px solid rgba(0, 0, 0, 0.1);border-radius:2px;pointer-events:none;z-index:100;}#chatgpt-mermaid-_r_1h3_ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1h3_ rect.text{fill:none;stroke-width:0;}#chatgpt-mermaid-_r_1h3_ .icon-shape,#chatgpt-mermaid-_r_1h3_ .image-shape{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_1h3_ .icon-shape p,#chatgpt-mermaid-_r_1h3_ .image-shape p{background-color:rgb(252, 252, 252);padding:2px;}#chatgpt-mermaid-_r_1h3_ .icon-shape .label rect,#chatgpt-mermaid-_r_1h3_ .image-shape .label rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1h3_ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#chatgpt-mermaid-_r_1h3_ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#chatgpt-mermaid-_r_1h3_ .node .neo-node{stroke:rgb(83, 154, 248);}#chatgpt-mermaid-_r_1h3_ [data-look=”neo”].node rect,#chatgpt-mermaid-_r_1h3_ [data-look=”neo”].cluster rect,#chatgpt-mermaid-_r_1h3_ [data-look=”neo”].node polygon{stroke:url(#chatgpt-mermaid-_r_1h3_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1h3_ [data-look=”neo”].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_1h3_ [data-look=”neo”].node path{stroke:url(#chatgpt-mermaid-_r_1h3_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_1h3_ [data-look=”neo”].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1h3_ [data-look=”neo”].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_1h3_ [data-look=”neo”].node circle{stroke:url(#chatgpt-mermaid-_r_1h3_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1h3_ [data-look=”neo”].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_1h3_ [data-look=”neo”].icon-shape .icon{fill:url(#chatgpt-mermaid-_r_1h3_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1h3_ [data-look=”neo”].icon-shape .icon-neo path{stroke:url(#chatgpt-mermaid-_r_1h3_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1h3_ .node text{font-size:14px;font-weight:600;letter-spacing:normal;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_1h3_ .edgeLabels text{font-size:13px;font-weight:600;letter-spacing:-0.08px;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_1h3_ .node tspan[font-weight=”normal”],#chatgpt-mermaid-_r_1h3_ .edgeLabels tspan[font-weight=”normal”]{font-weight:600;}#chatgpt-mermaid-_r_1h3_ .edgeLabel .label rect{opacity:1;rx:13px;ry:13px;fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-width:1px;}#chatgpt-mermaid-_r_1h3_ .node rect,#chatgpt-mermaid-_r_1h3_ .node circle,#chatgpt-mermaid-_r_1h3_ .node ellipse,#chatgpt-mermaid-_r_1h3_ .node polygon,#chatgpt-mermaid-_r_1h3_ .node path{fill:rgb(229, 243, 255);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_1h3_ .node rect{rx:16px;ry:16px;}#chatgpt-mermaid-_r_1h3_ .mermaid-decision .label-container{fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-dasharray:2,2;}#chatgpt-mermaid-_r_1h3_ .edgePaths .flowchart-link{stroke:rgb(143, 143, 143);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;}#chatgpt-mermaid-_r_1h3_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1h3_ :root{–mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;}Pomerium Core — all-in-oneProxyAuthorizeAuthenticateDatabrokerBrowserIdentity providerUpstream applicationLogin redirects

An all-in-one deployment contains the logical Pomerium services in one running process.

Why this is useful: It reduces configuration and deployment complexity while preserving the main Pomerium architecture.

Pomerium officially recommends all-in-one mode for its simplicity, and notes that it can also be used in large production environments. Pomerium

10.3 Architecture level 3: Split-service deployment

In a split-service deployment, components are separated so that they can be deployed and operated independently.

#chatgpt-mermaid-_r_1he_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;fill:rgb(13, 13, 13);}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#chatgpt-mermaid-_r_1he_ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_1he_ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_1he_ .error-icon{fill:rgb(243, 243, 243);}#chatgpt-mermaid-_r_1he_ .error-text{fill:rgb(13, 13, 13);stroke:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1he_ .edge-thickness-normal{stroke-width:1px;}#chatgpt-mermaid-_r_1he_ .edge-thickness-thick{stroke-width:3.5px;}#chatgpt-mermaid-_r_1he_ .edge-pattern-solid{stroke-dasharray:0;}#chatgpt-mermaid-_r_1he_ .edge-thickness-invisible{stroke-width:0;fill:none;}#chatgpt-mermaid-_r_1he_ .edge-pattern-dashed{stroke-dasharray:3;}#chatgpt-mermaid-_r_1he_ .edge-pattern-dotted{stroke-dasharray:2;}#chatgpt-mermaid-_r_1he_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1he_ .marker.cross{stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1he_ svg{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;}#chatgpt-mermaid-_r_1he_ p{margin:0;}#chatgpt-mermaid-_r_1he_ .label{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1he_ .cluster-label text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1he_ .cluster-label span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1he_ .cluster-label span p{background-color:transparent;}#chatgpt-mermaid-_r_1he_ .label text,#chatgpt-mermaid-_r_1he_ span{fill:rgb(13, 13, 13);color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1he_ .node rect,#chatgpt-mermaid-_r_1he_ .node circle,#chatgpt-mermaid-_r_1he_ .node ellipse,#chatgpt-mermaid-_r_1he_ .node polygon,#chatgpt-mermaid-_r_1he_ .node path{fill:rgb(222, 234, 251);stroke:rgb(83, 154, 248);stroke-width:1px;}#chatgpt-mermaid-_r_1he_ .rough-node .label text,#chatgpt-mermaid-_r_1he_ .node .label text,#chatgpt-mermaid-_r_1he_ .image-shape .label,#chatgpt-mermaid-_r_1he_ .icon-shape .label{text-anchor:middle;}#chatgpt-mermaid-_r_1he_ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#chatgpt-mermaid-_r_1he_ .rough-node .label,#chatgpt-mermaid-_r_1he_ .node .label,#chatgpt-mermaid-_r_1he_ .image-shape .label,#chatgpt-mermaid-_r_1he_ .icon-shape .label{text-align:center;}#chatgpt-mermaid-_r_1he_ .node.clickable{cursor:pointer;}#chatgpt-mermaid-_r_1he_ .root .anchor path{fill:rgb(143, 143, 143)!important;stroke-width:0;stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1he_ .arrowheadPath{fill:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1he_ .edgePath .path{stroke:rgb(143, 143, 143);stroke-width:1px;}#chatgpt-mermaid-_r_1he_ .flowchart-link{stroke:rgb(143, 143, 143);fill:none;}#chatgpt-mermaid-_r_1he_ .edgeLabel{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_1he_ .edgeLabel p{background-color:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1he_ .edgeLabel rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1he_ .labelBkg{background-color:rgba(252, 252, 252, 0.5);}#chatgpt-mermaid-_r_1he_ .cluster rect{fill:rgb(243, 243, 243);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_1he_ .cluster text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1he_ .cluster span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1he_ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:12px;background:rgb(243, 243, 243);border:1px solid rgba(0, 0, 0, 0.1);border-radius:2px;pointer-events:none;z-index:100;}#chatgpt-mermaid-_r_1he_ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1he_ rect.text{fill:none;stroke-width:0;}#chatgpt-mermaid-_r_1he_ .icon-shape,#chatgpt-mermaid-_r_1he_ .image-shape{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_1he_ .icon-shape p,#chatgpt-mermaid-_r_1he_ .image-shape p{background-color:rgb(252, 252, 252);padding:2px;}#chatgpt-mermaid-_r_1he_ .icon-shape .label rect,#chatgpt-mermaid-_r_1he_ .image-shape .label rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1he_ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#chatgpt-mermaid-_r_1he_ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#chatgpt-mermaid-_r_1he_ .node .neo-node{stroke:rgb(83, 154, 248);}#chatgpt-mermaid-_r_1he_ [data-look=”neo”].node rect,#chatgpt-mermaid-_r_1he_ [data-look=”neo”].cluster rect,#chatgpt-mermaid-_r_1he_ [data-look=”neo”].node polygon{stroke:url(#chatgpt-mermaid-_r_1he_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1he_ [data-look=”neo”].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_1he_ [data-look=”neo”].node path{stroke:url(#chatgpt-mermaid-_r_1he_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_1he_ [data-look=”neo”].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1he_ [data-look=”neo”].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_1he_ [data-look=”neo”].node circle{stroke:url(#chatgpt-mermaid-_r_1he_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1he_ [data-look=”neo”].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_1he_ [data-look=”neo”].icon-shape .icon{fill:url(#chatgpt-mermaid-_r_1he_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1he_ [data-look=”neo”].icon-shape .icon-neo path{stroke:url(#chatgpt-mermaid-_r_1he_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1he_ .node text{font-size:14px;font-weight:600;letter-spacing:normal;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_1he_ .edgeLabels text{font-size:13px;font-weight:600;letter-spacing:-0.08px;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_1he_ .node tspan[font-weight=”normal”],#chatgpt-mermaid-_r_1he_ .edgeLabels tspan[font-weight=”normal”]{font-weight:600;}#chatgpt-mermaid-_r_1he_ .edgeLabel .label rect{opacity:1;rx:13px;ry:13px;fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-width:1px;}#chatgpt-mermaid-_r_1he_ .node rect,#chatgpt-mermaid-_r_1he_ .node circle,#chatgpt-mermaid-_r_1he_ .node ellipse,#chatgpt-mermaid-_r_1he_ .node polygon,#chatgpt-mermaid-_r_1he_ .node path{fill:rgb(229, 243, 255);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_1he_ .node rect{rx:16px;ry:16px;}#chatgpt-mermaid-_r_1he_ .mermaid-decision .label-container{fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-dasharray:2,2;}#chatgpt-mermaid-_r_1he_ .edgePaths .flowchart-link{stroke:rgb(143, 143, 143);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;}#chatgpt-mermaid-_r_1he_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1he_ :root{–mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;}BrowserLoad balancerPomerium Proxy servicePomerium Authorize servicePomerium AuthenticateservicePomerium DatabrokerserviceIdentity providerPersistent storagePrivate applications

Separating services can provide more deployment control, but it also introduces operational complexity.

Administrators must explicitly configure inter-service communication, addresses, credentials, and appropriate transport security.

More components do not automatically mean higher availability. Reliability depends on replica counts, state storage, dependencies, and failure handling.

10.4 Understanding the Databroker storage options

Storage typePersistenceMulti-replica suitabilityBest use
MemoryNo persistence across process restartsNot suitable for independent memory-backed Databroker replicasInitial experiments
FilePersistent local storageNormally single-instance; clustered Databroker is a separate advanced capabilitySmall self-managed installations
PostgreSQLPersistent databaseSuitable for shared-state multi-replica deploymentsConventional production HA architecture

Pomerium also documents an experimental clustered Databroker capability. Treat that as an architecture requiring independent evaluation rather than assuming that local file storage automatically provides cluster-wide redundancy. Pomerium+1

10.5 Architecture level 4: Production deployment

A production deployment might use multiple Pomerium instances, a load balancer, private upstream services, centralized monitoring, and persistent database storage.

#chatgpt-mermaid-_r_1hp_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;fill:rgb(13, 13, 13);}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#chatgpt-mermaid-_r_1hp_ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_1hp_ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_1hp_ .error-icon{fill:rgb(243, 243, 243);}#chatgpt-mermaid-_r_1hp_ .error-text{fill:rgb(13, 13, 13);stroke:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1hp_ .edge-thickness-normal{stroke-width:1px;}#chatgpt-mermaid-_r_1hp_ .edge-thickness-thick{stroke-width:3.5px;}#chatgpt-mermaid-_r_1hp_ .edge-pattern-solid{stroke-dasharray:0;}#chatgpt-mermaid-_r_1hp_ .edge-thickness-invisible{stroke-width:0;fill:none;}#chatgpt-mermaid-_r_1hp_ .edge-pattern-dashed{stroke-dasharray:3;}#chatgpt-mermaid-_r_1hp_ .edge-pattern-dotted{stroke-dasharray:2;}#chatgpt-mermaid-_r_1hp_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1hp_ .marker.cross{stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1hp_ svg{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;}#chatgpt-mermaid-_r_1hp_ p{margin:0;}#chatgpt-mermaid-_r_1hp_ .label{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1hp_ .cluster-label text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1hp_ .cluster-label span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1hp_ .cluster-label span p{background-color:transparent;}#chatgpt-mermaid-_r_1hp_ .label text,#chatgpt-mermaid-_r_1hp_ span{fill:rgb(13, 13, 13);color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1hp_ .node rect,#chatgpt-mermaid-_r_1hp_ .node circle,#chatgpt-mermaid-_r_1hp_ .node ellipse,#chatgpt-mermaid-_r_1hp_ .node polygon,#chatgpt-mermaid-_r_1hp_ .node path{fill:rgb(222, 234, 251);stroke:rgb(83, 154, 248);stroke-width:1px;}#chatgpt-mermaid-_r_1hp_ .rough-node .label text,#chatgpt-mermaid-_r_1hp_ .node .label text,#chatgpt-mermaid-_r_1hp_ .image-shape .label,#chatgpt-mermaid-_r_1hp_ .icon-shape .label{text-anchor:middle;}#chatgpt-mermaid-_r_1hp_ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#chatgpt-mermaid-_r_1hp_ .rough-node .label,#chatgpt-mermaid-_r_1hp_ .node .label,#chatgpt-mermaid-_r_1hp_ .image-shape .label,#chatgpt-mermaid-_r_1hp_ .icon-shape .label{text-align:center;}#chatgpt-mermaid-_r_1hp_ .node.clickable{cursor:pointer;}#chatgpt-mermaid-_r_1hp_ .root .anchor path{fill:rgb(143, 143, 143)!important;stroke-width:0;stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1hp_ .arrowheadPath{fill:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1hp_ .edgePath .path{stroke:rgb(143, 143, 143);stroke-width:1px;}#chatgpt-mermaid-_r_1hp_ .flowchart-link{stroke:rgb(143, 143, 143);fill:none;}#chatgpt-mermaid-_r_1hp_ .edgeLabel{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_1hp_ .edgeLabel p{background-color:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1hp_ .edgeLabel rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1hp_ .labelBkg{background-color:rgba(252, 252, 252, 0.5);}#chatgpt-mermaid-_r_1hp_ .cluster rect{fill:rgb(243, 243, 243);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_1hp_ .cluster text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1hp_ .cluster span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1hp_ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:12px;background:rgb(243, 243, 243);border:1px solid rgba(0, 0, 0, 0.1);border-radius:2px;pointer-events:none;z-index:100;}#chatgpt-mermaid-_r_1hp_ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1hp_ rect.text{fill:none;stroke-width:0;}#chatgpt-mermaid-_r_1hp_ .icon-shape,#chatgpt-mermaid-_r_1hp_ .image-shape{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_1hp_ .icon-shape p,#chatgpt-mermaid-_r_1hp_ .image-shape p{background-color:rgb(252, 252, 252);padding:2px;}#chatgpt-mermaid-_r_1hp_ .icon-shape .label rect,#chatgpt-mermaid-_r_1hp_ .image-shape .label rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1hp_ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#chatgpt-mermaid-_r_1hp_ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#chatgpt-mermaid-_r_1hp_ .node .neo-node{stroke:rgb(83, 154, 248);}#chatgpt-mermaid-_r_1hp_ [data-look=”neo”].node rect,#chatgpt-mermaid-_r_1hp_ [data-look=”neo”].cluster rect,#chatgpt-mermaid-_r_1hp_ [data-look=”neo”].node polygon{stroke:url(#chatgpt-mermaid-_r_1hp_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1hp_ [data-look=”neo”].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_1hp_ [data-look=”neo”].node path{stroke:url(#chatgpt-mermaid-_r_1hp_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_1hp_ [data-look=”neo”].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1hp_ [data-look=”neo”].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_1hp_ [data-look=”neo”].node circle{stroke:url(#chatgpt-mermaid-_r_1hp_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1hp_ [data-look=”neo”].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_1hp_ [data-look=”neo”].icon-shape .icon{fill:url(#chatgpt-mermaid-_r_1hp_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1hp_ [data-look=”neo”].icon-shape .icon-neo path{stroke:url(#chatgpt-mermaid-_r_1hp_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1hp_ .node text{font-size:14px;font-weight:600;letter-spacing:normal;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_1hp_ .edgeLabels text{font-size:13px;font-weight:600;letter-spacing:-0.08px;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_1hp_ .node tspan[font-weight=”normal”],#chatgpt-mermaid-_r_1hp_ .edgeLabels tspan[font-weight=”normal”]{font-weight:600;}#chatgpt-mermaid-_r_1hp_ .edgeLabel .label rect{opacity:1;rx:13px;ry:13px;fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-width:1px;}#chatgpt-mermaid-_r_1hp_ .node rect,#chatgpt-mermaid-_r_1hp_ .node circle,#chatgpt-mermaid-_r_1hp_ .node ellipse,#chatgpt-mermaid-_r_1hp_ .node polygon,#chatgpt-mermaid-_r_1hp_ .node path{fill:rgb(229, 243, 255);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_1hp_ .node rect{rx:16px;ry:16px;}#chatgpt-mermaid-_r_1hp_ .mermaid-decision .label-container{fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-dasharray:2,2;}#chatgpt-mermaid-_r_1hp_ .edgePaths .flowchart-link{stroke:rgb(143, 143, 143);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;}#chatgpt-mermaid-_r_1hp_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1hp_ :root{–mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;}Application access layerPomerium Replica 1Pomerium Replica 2Employees and approvedclientsHTTPS load balancerCorporate Identity ProviderPostgreSQLPrivate applicationsLogging and monitoring

The diagram deliberately simplifies internal Pomerium communications to focus on deployment topology.

In a real architecture, the Databroker and its database dependencies need an explicit availability design. The identity provider and protected applications also remain separate failure domains.

10.6 Control plane versus data plane

This distinction is important when considering Pomerium Zero and Enterprise.

Data plane: Components processing the actual application requests.

Control plane: Components managing configuration, routes, policies, and operational settings.

With Pomerium Core, the organization manages both configuration and runtime infrastructure.

With Pomerium Zero, the management control plane is hosted, while the Pomerium proxy data plane runs in the organization’s environment.

With Pomerium Enterprise, the organization can operate the additional management control plane itself.

Chapter 11. The Complete Workflow

11.1 Authentication, authorization, and application access

A more detailed workflow includes both success and failure paths.

#chatgpt-mermaid-_r_1i0_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;fill:rgb(13, 13, 13);}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#chatgpt-mermaid-_r_1i0_ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_1i0_ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_1i0_ .error-icon{fill:rgb(243, 243, 243);}#chatgpt-mermaid-_r_1i0_ .error-text{fill:rgb(13, 13, 13);stroke:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1i0_ .edge-thickness-normal{stroke-width:1px;}#chatgpt-mermaid-_r_1i0_ .edge-thickness-thick{stroke-width:3.5px;}#chatgpt-mermaid-_r_1i0_ .edge-pattern-solid{stroke-dasharray:0;}#chatgpt-mermaid-_r_1i0_ .edge-thickness-invisible{stroke-width:0;fill:none;}#chatgpt-mermaid-_r_1i0_ .edge-pattern-dashed{stroke-dasharray:3;}#chatgpt-mermaid-_r_1i0_ .edge-pattern-dotted{stroke-dasharray:2;}#chatgpt-mermaid-_r_1i0_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1i0_ .marker.cross{stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1i0_ svg{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;}#chatgpt-mermaid-_r_1i0_ p{margin:0;}#chatgpt-mermaid-_r_1i0_ .label{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1i0_ .cluster-label text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1i0_ .cluster-label span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1i0_ .cluster-label span p{background-color:transparent;}#chatgpt-mermaid-_r_1i0_ .label text,#chatgpt-mermaid-_r_1i0_ span{fill:rgb(13, 13, 13);color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1i0_ .node rect,#chatgpt-mermaid-_r_1i0_ .node circle,#chatgpt-mermaid-_r_1i0_ .node ellipse,#chatgpt-mermaid-_r_1i0_ .node polygon,#chatgpt-mermaid-_r_1i0_ .node path{fill:rgb(222, 234, 251);stroke:rgb(83, 154, 248);stroke-width:1px;}#chatgpt-mermaid-_r_1i0_ .rough-node .label text,#chatgpt-mermaid-_r_1i0_ .node .label text,#chatgpt-mermaid-_r_1i0_ .image-shape .label,#chatgpt-mermaid-_r_1i0_ .icon-shape .label{text-anchor:middle;}#chatgpt-mermaid-_r_1i0_ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#chatgpt-mermaid-_r_1i0_ .rough-node .label,#chatgpt-mermaid-_r_1i0_ .node .label,#chatgpt-mermaid-_r_1i0_ .image-shape .label,#chatgpt-mermaid-_r_1i0_ .icon-shape .label{text-align:center;}#chatgpt-mermaid-_r_1i0_ .node.clickable{cursor:pointer;}#chatgpt-mermaid-_r_1i0_ .root .anchor path{fill:rgb(143, 143, 143)!important;stroke-width:0;stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1i0_ .arrowheadPath{fill:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1i0_ .edgePath .path{stroke:rgb(143, 143, 143);stroke-width:1px;}#chatgpt-mermaid-_r_1i0_ .flowchart-link{stroke:rgb(143, 143, 143);fill:none;}#chatgpt-mermaid-_r_1i0_ .edgeLabel{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_1i0_ .edgeLabel p{background-color:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1i0_ .edgeLabel rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1i0_ .labelBkg{background-color:rgba(252, 252, 252, 0.5);}#chatgpt-mermaid-_r_1i0_ .cluster rect{fill:rgb(243, 243, 243);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_1i0_ .cluster text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1i0_ .cluster span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1i0_ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:12px;background:rgb(243, 243, 243);border:1px solid rgba(0, 0, 0, 0.1);border-radius:2px;pointer-events:none;z-index:100;}#chatgpt-mermaid-_r_1i0_ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1i0_ rect.text{fill:none;stroke-width:0;}#chatgpt-mermaid-_r_1i0_ .icon-shape,#chatgpt-mermaid-_r_1i0_ .image-shape{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_1i0_ .icon-shape p,#chatgpt-mermaid-_r_1i0_ .image-shape p{background-color:rgb(252, 252, 252);padding:2px;}#chatgpt-mermaid-_r_1i0_ .icon-shape .label rect,#chatgpt-mermaid-_r_1i0_ .image-shape .label rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1i0_ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#chatgpt-mermaid-_r_1i0_ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#chatgpt-mermaid-_r_1i0_ .node .neo-node{stroke:rgb(83, 154, 248);}#chatgpt-mermaid-_r_1i0_ [data-look=”neo”].node rect,#chatgpt-mermaid-_r_1i0_ [data-look=”neo”].cluster rect,#chatgpt-mermaid-_r_1i0_ [data-look=”neo”].node polygon{stroke:url(#chatgpt-mermaid-_r_1i0_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1i0_ [data-look=”neo”].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_1i0_ [data-look=”neo”].node path{stroke:url(#chatgpt-mermaid-_r_1i0_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_1i0_ [data-look=”neo”].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1i0_ [data-look=”neo”].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_1i0_ [data-look=”neo”].node circle{stroke:url(#chatgpt-mermaid-_r_1i0_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1i0_ [data-look=”neo”].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_1i0_ [data-look=”neo”].icon-shape .icon{fill:url(#chatgpt-mermaid-_r_1i0_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1i0_ [data-look=”neo”].icon-shape .icon-neo path{stroke:url(#chatgpt-mermaid-_r_1i0_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1i0_ .node text{font-size:14px;font-weight:600;letter-spacing:normal;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_1i0_ .edgeLabels text{font-size:13px;font-weight:600;letter-spacing:-0.08px;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_1i0_ .node tspan[font-weight=”normal”],#chatgpt-mermaid-_r_1i0_ .edgeLabels tspan[font-weight=”normal”]{font-weight:600;}#chatgpt-mermaid-_r_1i0_ .edgeLabel .label rect{opacity:1;rx:13px;ry:13px;fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-width:1px;}#chatgpt-mermaid-_r_1i0_ .node rect,#chatgpt-mermaid-_r_1i0_ .node circle,#chatgpt-mermaid-_r_1i0_ .node ellipse,#chatgpt-mermaid-_r_1i0_ .node polygon,#chatgpt-mermaid-_r_1i0_ .node path{fill:rgb(229, 243, 255);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_1i0_ .node rect{rx:16px;ry:16px;}#chatgpt-mermaid-_r_1i0_ .mermaid-decision .label-container{fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-dasharray:2,2;}#chatgpt-mermaid-_r_1i0_ .edgePaths .flowchart-link{stroke:rgb(143, 143, 143);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;}#chatgpt-mermaid-_r_1i0_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1i0_ :root{–mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;}Browser requests protectedURLPomerium matches routeValid session?Start authenticationLogin succeeds?Establish sessionEvaluate route policyAccess allowed?Forward request toapplicationReturn application responseAuthentication failureAccess deniedReturn upstream or gatewayerrorNoYesNoYesYesNoUpstream respondsUpstream failure

11.2 Example: Accessing an engineering dashboard

An employee opens the dashboard URL.

Pomerium determines whether the employee has an authenticated session. If not, the browser follows the login process.

After authentication, Pomerium evaluates the policy associated with the dashboard route.

If the employee satisfies the policy, Pomerium forwards the request to the dashboard.

If the employee does not satisfy the policy, the request is denied before reaching the dashboard.

11.3 How to recognize the results

OutcomeWhat it meansExpected observation
Successful authorizationUser satisfies the route policyApplication content loads
Authentication requiredNo valid session is availableBrowser enters login process
Authentication failureLogin is not completed successfullyAuthentication error or failed login
Authorization failureAuthenticated user lacks permissionAccess denied
Upstream failureBackend is unavailable or incorrectly configuredProxy or upstream error
TLS failureSecure connection cannot be validated or establishedBrowser or TLS diagnostic error

An HTTP status code alone may not tell you exactly which condition occurred. Redirects, application responses, and gateway-generated errors must be interpreted together.

Chapter 12. Where Pomerium Fits into a Larger System

12.1 A realistic enterprise technology stack

Consider a software engineering organization using:

  • An identity provider for employee identities.
  • Kubernetes for application deployment.
  • Grafana for monitoring.
  • Jenkins for continuous integration.
  • Terraform for infrastructure configuration.
  • Prometheus for monitoring metrics.

Pomerium can be the access layer protecting the relevant internal applications.

#chatgpt-mermaid-_r_1i7_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;fill:rgb(13, 13, 13);}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#chatgpt-mermaid-_r_1i7_ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_1i7_ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_1i7_ .error-icon{fill:rgb(243, 243, 243);}#chatgpt-mermaid-_r_1i7_ .error-text{fill:rgb(13, 13, 13);stroke:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1i7_ .edge-thickness-normal{stroke-width:1px;}#chatgpt-mermaid-_r_1i7_ .edge-thickness-thick{stroke-width:3.5px;}#chatgpt-mermaid-_r_1i7_ .edge-pattern-solid{stroke-dasharray:0;}#chatgpt-mermaid-_r_1i7_ .edge-thickness-invisible{stroke-width:0;fill:none;}#chatgpt-mermaid-_r_1i7_ .edge-pattern-dashed{stroke-dasharray:3;}#chatgpt-mermaid-_r_1i7_ .edge-pattern-dotted{stroke-dasharray:2;}#chatgpt-mermaid-_r_1i7_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1i7_ .marker.cross{stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1i7_ svg{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;}#chatgpt-mermaid-_r_1i7_ p{margin:0;}#chatgpt-mermaid-_r_1i7_ .label{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1i7_ .cluster-label text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1i7_ .cluster-label span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1i7_ .cluster-label span p{background-color:transparent;}#chatgpt-mermaid-_r_1i7_ .label text,#chatgpt-mermaid-_r_1i7_ span{fill:rgb(13, 13, 13);color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1i7_ .node rect,#chatgpt-mermaid-_r_1i7_ .node circle,#chatgpt-mermaid-_r_1i7_ .node ellipse,#chatgpt-mermaid-_r_1i7_ .node polygon,#chatgpt-mermaid-_r_1i7_ .node path{fill:rgb(222, 234, 251);stroke:rgb(83, 154, 248);stroke-width:1px;}#chatgpt-mermaid-_r_1i7_ .rough-node .label text,#chatgpt-mermaid-_r_1i7_ .node .label text,#chatgpt-mermaid-_r_1i7_ .image-shape .label,#chatgpt-mermaid-_r_1i7_ .icon-shape .label{text-anchor:middle;}#chatgpt-mermaid-_r_1i7_ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#chatgpt-mermaid-_r_1i7_ .rough-node .label,#chatgpt-mermaid-_r_1i7_ .node .label,#chatgpt-mermaid-_r_1i7_ .image-shape .label,#chatgpt-mermaid-_r_1i7_ .icon-shape .label{text-align:center;}#chatgpt-mermaid-_r_1i7_ .node.clickable{cursor:pointer;}#chatgpt-mermaid-_r_1i7_ .root .anchor path{fill:rgb(143, 143, 143)!important;stroke-width:0;stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1i7_ .arrowheadPath{fill:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1i7_ .edgePath .path{stroke:rgb(143, 143, 143);stroke-width:1px;}#chatgpt-mermaid-_r_1i7_ .flowchart-link{stroke:rgb(143, 143, 143);fill:none;}#chatgpt-mermaid-_r_1i7_ .edgeLabel{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_1i7_ .edgeLabel p{background-color:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1i7_ .edgeLabel rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1i7_ .labelBkg{background-color:rgba(252, 252, 252, 0.5);}#chatgpt-mermaid-_r_1i7_ .cluster rect{fill:rgb(243, 243, 243);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_1i7_ .cluster text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1i7_ .cluster span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1i7_ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:12px;background:rgb(243, 243, 243);border:1px solid rgba(0, 0, 0, 0.1);border-radius:2px;pointer-events:none;z-index:100;}#chatgpt-mermaid-_r_1i7_ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1i7_ rect.text{fill:none;stroke-width:0;}#chatgpt-mermaid-_r_1i7_ .icon-shape,#chatgpt-mermaid-_r_1i7_ .image-shape{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_1i7_ .icon-shape p,#chatgpt-mermaid-_r_1i7_ .image-shape p{background-color:rgb(252, 252, 252);padding:2px;}#chatgpt-mermaid-_r_1i7_ .icon-shape .label rect,#chatgpt-mermaid-_r_1i7_ .image-shape .label rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1i7_ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#chatgpt-mermaid-_r_1i7_ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#chatgpt-mermaid-_r_1i7_ .node .neo-node{stroke:rgb(83, 154, 248);}#chatgpt-mermaid-_r_1i7_ [data-look=”neo”].node rect,#chatgpt-mermaid-_r_1i7_ [data-look=”neo”].cluster rect,#chatgpt-mermaid-_r_1i7_ [data-look=”neo”].node polygon{stroke:url(#chatgpt-mermaid-_r_1i7_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1i7_ [data-look=”neo”].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_1i7_ [data-look=”neo”].node path{stroke:url(#chatgpt-mermaid-_r_1i7_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_1i7_ [data-look=”neo”].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1i7_ [data-look=”neo”].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_1i7_ [data-look=”neo”].node circle{stroke:url(#chatgpt-mermaid-_r_1i7_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1i7_ [data-look=”neo”].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_1i7_ [data-look=”neo”].icon-shape .icon{fill:url(#chatgpt-mermaid-_r_1i7_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1i7_ [data-look=”neo”].icon-shape .icon-neo path{stroke:url(#chatgpt-mermaid-_r_1i7_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1i7_ .node text{font-size:14px;font-weight:600;letter-spacing:normal;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_1i7_ .edgeLabels text{font-size:13px;font-weight:600;letter-spacing:-0.08px;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_1i7_ .node tspan[font-weight=”normal”],#chatgpt-mermaid-_r_1i7_ .edgeLabels tspan[font-weight=”normal”]{font-weight:600;}#chatgpt-mermaid-_r_1i7_ .edgeLabel .label rect{opacity:1;rx:13px;ry:13px;fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-width:1px;}#chatgpt-mermaid-_r_1i7_ .node rect,#chatgpt-mermaid-_r_1i7_ .node circle,#chatgpt-mermaid-_r_1i7_ .node ellipse,#chatgpt-mermaid-_r_1i7_ .node polygon,#chatgpt-mermaid-_r_1i7_ .node path{fill:rgb(229, 243, 255);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_1i7_ .node rect{rx:16px;ry:16px;}#chatgpt-mermaid-_r_1i7_ .mermaid-decision .label-container{fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-dasharray:2,2;}#chatgpt-mermaid-_r_1i7_ .edgePaths .flowchart-link{stroke:rgb(143, 143, 143);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;}#chatgpt-mermaid-_r_1i7_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1i7_ :root{–mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;}Private infrastructureGrafanaJenkinsInternal Admin PortalEmployeesCorporate Identity ProviderPomerium Access GatewayObservability platformInfrastructure configurationDeployment and configuration

12.2 Who owns each component?

ComponentTypical responsible teamResponsibility
Identity providerIAM or IT securityUser identities, authentication, MFA
PomeriumPlatform engineering or security engineeringGateway deployment and access enforcement
ApplicationApplication development teamApplication correctness and internal permissions
DNS and certificatesInfrastructure or platform teamDomain routing and TLS lifecycle
Databroker storageInfrastructure or database operationsAvailability and recovery
MonitoringSRE or observability teamMetrics, alerts, incident diagnosis
Access policiesApplication owners and security teamsApproval and lifecycle of permissions

12.3 The most important architectural security rule

The protected application must not be independently accessible through an uncontrolled path that bypasses Pomerium.

For example, if Grafana is protected at one hostname but remains publicly available through an unprotected IP address, the access boundary is incomplete.

This is why production network isolation matters just as much as writing the right access policy.

Part IV — Installation and First Success

Chapter 13. Prerequisites and Environment Preparation

Our first working environment will run entirely on your local computer, except for the external hosted authentication service used to sign in.

You do not need to purchase a domain, create a cloud server, or operate an identity provider for this experiment.

13.1 What you need

RequirementNeeded for first lab?Notes
Windows, macOS, or LinuxYesMust support the selected Docker installation
Docker Engine or Docker DesktopYesRuns the containers
Docker ComposeYesStarts Pomerium and the demo service together
Internet connectionYesDownloads images and supports hosted authentication
Web browserYesCompletes authentication
A usable email identityYesUsed in the access policy and login
Text editorYesCreates YAML files
mkcertRecommended for this labCreates locally trusted TLS certificates
Domain registrationNoWe use a special localhost domain
KubernetesNoIntroduced later
PostgreSQLNoIntroduced for persistent and replicated deployments
Pomerium commercial licenceNoWe use Pomerium Core

13.2 Hardware recommendations

For a basic two-container demonstration, a modern laptop with several gigabytes of available memory is usually sufficient.

A comfortable learning setup would have approximately 8 GB or more of system memory and several gigabytes of free storage, particularly when using Docker Desktop.

These are practical classroom recommendations, not officially published minimum Pomerium server requirements.

Actual production capacity must be measured against requests per second, connection counts, authentication load, policy complexity, and dependencies.

13.3 Network requirements

Our first lab uses these connections:

ConnectionPortPurpose
Browser → local PomeriumTCP 443HTTPS access
Pomerium → demo Verify containerTCP 8000Private Docker-network traffic
Browser → hosted authenticationHTTPS/TCP 443User sign-in
Container environment → external dependenciesAs requiredImage download and authentication-related services

Only Pomerium’s HTTPS endpoint needs to be published on the host.

The demo application should not expose a separate host port.

13.4 What is localhost.pomerium.io?

Pomerium documentation uses hostnames such as:

verify.localhost.pomerium.ioCode language: CSS (css)

This special local development domain resolves to the loopback address 127.0.0.1.

That means the browser reaches a service on your own computer.

It avoids the need to manually register a production domain for the local example.

Corporate DNS restrictions, proxy settings, or DNS-rebinding protection may interfere with this special domain. We will account for that during troubleshooting. Pomerium

13.5 Pre-installation checklist

Environment readiness

0 of 6Docker can be installed on my operating systemI can use a terminal and edit text filesTCP port 443 is available locallyI have a working Internet connectionI can authenticate with an email identityI understand this is a local learning environment

Chapter 14. Install Pomerium on Supported Operating Systems

The recommended beginner approach is to install Docker on the host and run the official Pomerium Linux container image.

This keeps the actual Pomerium deployment nearly identical across Windows, Ubuntu, and macOS.

14.1 Operating-system compatibility

Operating systemRecommended beginner methodNative Pomerium Core server
Windows 10/11, subject to Docker prerequisitesDocker Desktop with a Linux-container backendNo official native Windows server binary documented
UbuntuDocker Engine and ComposeLinux binary or .deb package available
macOS Apple SiliconDocker DesktopNative ARM64 binary available
macOS IntelCompatible Docker Linux-container environmentNative darwin/amd64 removed in Pomerium v0.33
DebianDocker EngineLinux binary or .deb package
FedoraDocker EngineLinux binary or compatible .rpm package
RHEL and compatible distributionsSupported container runtimeLinux binary or applicable .rpm package

Native binary support, package support, and container support are distinct. Do not infer one from another. Pomerium+1

A. Windows Installation

Step 1 — Prepare Windows

Use a supported Windows installation that meets Docker Desktop’s current system requirements.

For a typical Windows 11 setup, Docker Desktop can use Windows Subsystem for Linux 2 (WSL 2).

If WSL is not installed, open PowerShell as Administrator and run:

wsl --install

This installs or enables the necessary WSL components on supported systems. Restart the computer if prompted.

Verify:

wsl --status

If WSL installation fails because virtualization is unavailable, check firmware virtualization settings and the official Microsoft documentation.

Step 2 — Install Docker Desktop

Download Docker Desktop from the official installation page:Docker Desktop for Windows — Official installation instructions

Run the installer and select the WSL 2-based backend where appropriate.

Start Docker Desktop, complete its setup, and wait until the Docker engine is running.

Docker’s official instructions provide the current Windows requirements and supported backends. Docker Docs

Step 3 — Verify Docker

Open a new PowerShell window:

docker --version
docker compose version
docker run --rm hello-world

The hello-world image should print a message indicating that Docker successfully ran a container.

If the Docker engine is unavailable, start Docker Desktop and confirm that Linux containers are enabled.

Step 4 — Install mkcert

If Windows Package Manager is available:

winget install -e --id FiloSottile.mkcertCode language: CSS (css)

Alternatively, use the installation methods documented by the official mkcert project, including Chocolatey or Scoop.

Open a new PowerShell terminal and verify:

mkcert -version

The installation guidance and binaries are available in the official mkcert project.

B. Ubuntu Installation

The following procedure uses Docker’s official APT repository rather than an arbitrary installation script.

Step 1 — Check the Ubuntu version

cat /etc/os-release
uname -m

Verify your operating-system release and CPU architecture are supported by Docker.

For an existing installation, first review whether older Docker packages conflict with the official repository packages.

Step 2 — Install repository prerequisites

sudo apt update
sudo apt install -y ca-certificates curl

ca-certificates provides trusted certificate authorities. curl downloads resources over HTTP or HTTPS.

Step 3 — Add Docker’s official package signing key

sudo install -m 0755 -d /etc/apt/keyrings

sudo curl -fsSL \
  https://download.docker.com/linux/ubuntu/gpg \
  -o /etc/apt/keyrings/docker.asc

sudo chmod a+r /etc/apt/keyrings/docker.ascCode language: JavaScript (javascript)

The signing key enables APT to verify packages from the configured repository.

Step 4 — Add the Docker package repository

sudo tee /etc/apt/sources.list.d/docker.sources > /dev/null <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOFCode language: JavaScript (javascript)

This creates the repository configuration corresponding to your Ubuntu release.

Step 5 — Install Docker and Compose

sudo apt update

sudo apt install -y \
  docker-ce \
  docker-ce-cli \
  containerd.io \
  docker-buildx-plugin \
  docker-compose-pluginCode language: CSS (css)

These are the packages specified by Docker’s Ubuntu installation guide. Docker Docs

Step 6 — Start Docker

sudo systemctl enable --now docker
sudo systemctl status docker

The service should report an active state.

Verify container execution:

sudo docker run --rm hello-world
sudo docker compose version

On a standard Docker Engine installation, you may need to prefix Docker commands with sudo.

Adding users to the docker group grants powerful Docker daemon permissions, effectively root-equivalent access in a typical rootful Docker installation. Do not make this change casually.

Step 7 — Install mkcert

First install its certificate-store dependency:

sudo apt install -y libnss3-tools

For an x86_64 Ubuntu computer, the mkcert project’s documented prebuilt-binary method is:

curl -JLO \
  "https://dl.filippo.io/mkcert/latest?for=linux/amd64"

chmod +x mkcert-v*-linux-amd64

sudo install -m 0755 \
  mkcert-v*-linux-amd64 \
  /usr/local/bin/mkcertCode language: JavaScript (javascript)

Verify:

mkcert -version

For ARM64 or other architectures, select the matching binary from the project’s official releases rather than using an AMD64 binary.

C. macOS Installation

Step 1 — Check the architecture

Open Terminal:

uname -m
sw_vers

Common architecture values include:

  • arm64: Apple Silicon
  • x86_64: Intel Mac

Choose Docker Desktop for the correct architecture.

Step 2 — Install Docker Desktop

Download Docker Desktop from:Docker Desktop for macOS — Official instructions

Open the .dmg installer, move Docker into Applications, and start it.

Complete the initial configuration.

Docker Desktop may require specific macOS versions, system resources, privileges, and licensing depending on the environment and commercial use. Docker Docs

Step 3 — Verify Docker

docker --version
docker compose version
docker run --rm hello-world

If Docker commands cannot communicate with the engine, make sure Docker Desktop has started.

Step 4 — Install mkcert

If Homebrew is installed:

brew install mkcert

For Firefox integration, the official mkcert instructions also recommend:

brew install nss

Verify:

mkcert -version

Optional — Native macOS installation

For a supported Apple Silicon environment, Pomerium’s release documentation provides standalone macOS ARM64 binaries.

For the course’s pinned release, the documented release-artifact naming convention gives:

curl -fL -o pomerium.tar.gz \
  https://github.com/pomerium/pomerium/releases/download/v0.33.4/pomerium-darwin-arm64.tar.gz

tar -xzf pomerium.tar.gzCode language: JavaScript (javascript)

After supplying a valid config.yaml, the native binary can be started with:

./pomerium -config config.yaml

Verify the archive’s release assets and integrity before relying on them. This is an alternative deployment method, not a requirement for the Docker lab.

D. Debian, Fedora, RHEL, Rocky Linux, and AlmaLinux

For these systems, first identify the distribution and architecture.

cat /etc/os-release
uname -m

Debian uses APT repositories, while Fedora, RHEL, and related distributions commonly use RPM packages with DNF.

For example, on a Docker-supported Fedora release, the official repository installation is:

sudo dnf config-manager addrepo \
  --from-repofile \
  https://download.docker.com/linux/fedora/docker-ce.repo

sudo dnf install -y \
  docker-ce \
  docker-ce-cli \
  containerd.io \
  docker-buildx-plugin \
  docker-compose-plugin

sudo systemctl enable --now docker
sudo docker run --rm hello-worldCode language: JavaScript (javascript)

This assumes the prerequisite repository-management command is available.

Use the distribution-specific official guides for other systems. In particular, do not blindly use Fedora repository instructions on Rocky Linux, AlmaLinux, or RHEL.

Relevant resources:

Pomerium’s native Linux binaries and package repositories are documented separately in Pomerium Core deployment documentation.

Installation verification summary

EnvironmentKey verificationSuccessful result
WindowsDocker Desktop running; Docker and Compose commands succeedDocker engine responds
UbuntuDocker systemd service running; hello-world succeedsContainers can run
macOSDocker Desktop running; hello-world succeedsContainers can run
Other LinuxAppropriate container runtime and Compose installedContainer execution works
All systemsmkcert version command worksCertificate utility available

At this point, you have installed the tools needed to run Pomerium, but Pomerium itself has not yet been deployed.

Chapter 15. Your First Working Pomerium Example

We will now protect an application using Pomerium Core.

15.1 What we are going to build

We will use Pomerium’s demo Verify application.

The application is designed to help confirm identity information and test whether the gateway is working.

Our local deployment will contain:

  • One Pomerium container.
  • One Verify application container.
  • An explicit email-based access policy.
  • A locally trusted TLS certificate.
  • A private Docker network.

This follows Pomerium’s official Core fundamentals approach while adding local TLS certificate management. Pomerium+1

15.2 Target architecture

#chatgpt-mermaid-_r_1ol_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;fill:rgb(13, 13, 13);}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#chatgpt-mermaid-_r_1ol_ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_1ol_ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_1ol_ .error-icon{fill:rgb(243, 243, 243);}#chatgpt-mermaid-_r_1ol_ .error-text{fill:rgb(13, 13, 13);stroke:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1ol_ .edge-thickness-normal{stroke-width:1px;}#chatgpt-mermaid-_r_1ol_ .edge-thickness-thick{stroke-width:3.5px;}#chatgpt-mermaid-_r_1ol_ .edge-pattern-solid{stroke-dasharray:0;}#chatgpt-mermaid-_r_1ol_ .edge-thickness-invisible{stroke-width:0;fill:none;}#chatgpt-mermaid-_r_1ol_ .edge-pattern-dashed{stroke-dasharray:3;}#chatgpt-mermaid-_r_1ol_ .edge-pattern-dotted{stroke-dasharray:2;}#chatgpt-mermaid-_r_1ol_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1ol_ .marker.cross{stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1ol_ svg{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;}#chatgpt-mermaid-_r_1ol_ p{margin:0;}#chatgpt-mermaid-_r_1ol_ .label{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1ol_ .cluster-label text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1ol_ .cluster-label span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1ol_ .cluster-label span p{background-color:transparent;}#chatgpt-mermaid-_r_1ol_ .label text,#chatgpt-mermaid-_r_1ol_ span{fill:rgb(13, 13, 13);color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1ol_ .node rect,#chatgpt-mermaid-_r_1ol_ .node circle,#chatgpt-mermaid-_r_1ol_ .node ellipse,#chatgpt-mermaid-_r_1ol_ .node polygon,#chatgpt-mermaid-_r_1ol_ .node path{fill:rgb(222, 234, 251);stroke:rgb(83, 154, 248);stroke-width:1px;}#chatgpt-mermaid-_r_1ol_ .rough-node .label text,#chatgpt-mermaid-_r_1ol_ .node .label text,#chatgpt-mermaid-_r_1ol_ .image-shape .label,#chatgpt-mermaid-_r_1ol_ .icon-shape .label{text-anchor:middle;}#chatgpt-mermaid-_r_1ol_ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#chatgpt-mermaid-_r_1ol_ .rough-node .label,#chatgpt-mermaid-_r_1ol_ .node .label,#chatgpt-mermaid-_r_1ol_ .image-shape .label,#chatgpt-mermaid-_r_1ol_ .icon-shape .label{text-align:center;}#chatgpt-mermaid-_r_1ol_ .node.clickable{cursor:pointer;}#chatgpt-mermaid-_r_1ol_ .root .anchor path{fill:rgb(143, 143, 143)!important;stroke-width:0;stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1ol_ .arrowheadPath{fill:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1ol_ .edgePath .path{stroke:rgb(143, 143, 143);stroke-width:1px;}#chatgpt-mermaid-_r_1ol_ .flowchart-link{stroke:rgb(143, 143, 143);fill:none;}#chatgpt-mermaid-_r_1ol_ .edgeLabel{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_1ol_ .edgeLabel p{background-color:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1ol_ .edgeLabel rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1ol_ .labelBkg{background-color:rgba(252, 252, 252, 0.5);}#chatgpt-mermaid-_r_1ol_ .cluster rect{fill:rgb(243, 243, 243);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_1ol_ .cluster text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1ol_ .cluster span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1ol_ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:12px;background:rgb(243, 243, 243);border:1px solid rgba(0, 0, 0, 0.1);border-radius:2px;pointer-events:none;z-index:100;}#chatgpt-mermaid-_r_1ol_ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_1ol_ rect.text{fill:none;stroke-width:0;}#chatgpt-mermaid-_r_1ol_ .icon-shape,#chatgpt-mermaid-_r_1ol_ .image-shape{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_1ol_ .icon-shape p,#chatgpt-mermaid-_r_1ol_ .image-shape p{background-color:rgb(252, 252, 252);padding:2px;}#chatgpt-mermaid-_r_1ol_ .icon-shape .label rect,#chatgpt-mermaid-_r_1ol_ .image-shape .label rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_1ol_ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#chatgpt-mermaid-_r_1ol_ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#chatgpt-mermaid-_r_1ol_ .node .neo-node{stroke:rgb(83, 154, 248);}#chatgpt-mermaid-_r_1ol_ [data-look=”neo”].node rect,#chatgpt-mermaid-_r_1ol_ [data-look=”neo”].cluster rect,#chatgpt-mermaid-_r_1ol_ [data-look=”neo”].node polygon{stroke:url(#chatgpt-mermaid-_r_1ol_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1ol_ [data-look=”neo”].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_1ol_ [data-look=”neo”].node path{stroke:url(#chatgpt-mermaid-_r_1ol_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_1ol_ [data-look=”neo”].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1ol_ [data-look=”neo”].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_1ol_ [data-look=”neo”].node circle{stroke:url(#chatgpt-mermaid-_r_1ol_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1ol_ [data-look=”neo”].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_1ol_ [data-look=”neo”].icon-shape .icon{fill:url(#chatgpt-mermaid-_r_1ol_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1ol_ [data-look=”neo”].icon-shape .icon-neo path{stroke:url(#chatgpt-mermaid-_r_1ol_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1ol_ .node text{font-size:14px;font-weight:600;letter-spacing:normal;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_1ol_ .edgeLabels text{font-size:13px;font-weight:600;letter-spacing:-0.08px;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_1ol_ .node tspan[font-weight=”normal”],#chatgpt-mermaid-_r_1ol_ .edgeLabels tspan[font-weight=”normal”]{font-weight:600;}#chatgpt-mermaid-_r_1ol_ .edgeLabel .label rect{opacity:1;rx:13px;ry:13px;fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-width:1px;}#chatgpt-mermaid-_r_1ol_ .node rect,#chatgpt-mermaid-_r_1ol_ .node circle,#chatgpt-mermaid-_r_1ol_ .node ellipse,#chatgpt-mermaid-_r_1ol_ .node polygon,#chatgpt-mermaid-_r_1ol_ .node path{fill:rgb(229, 243, 255);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_1ol_ .node rect{rx:16px;ry:16px;}#chatgpt-mermaid-_r_1ol_ .mermaid-decision .label-container{fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-dasharray:2,2;}#chatgpt-mermaid-_r_1ol_ .edgePaths .flowchart-link{stroke:rgb(143, 143, 143);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;}#chatgpt-mermaid-_r_1ol_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_1ol_ :root{–mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;}Browser on your computerPomerium Core containerPomerium hostedauthenticationVerify demo containerhttps://verify.localhost.pomerium.ioSign-in flowAuthorized request

15.3 Create the project directory

Choose the commands matching your operating system.

macOS or Linux Terminal:

mkdir -p ~/pomerium-lab/certs
cd ~/pomerium-labCode language: JavaScript (javascript)

Windows PowerShell:

New-Item -ItemType Directory -Force `
  -Path "$HOME\pomerium-lab\certs"

Set-Location "$HOME\pomerium-lab"Code language: PHP (php)

Our initial project structure will be:

pomerium-lab/
├── compose.yaml
├── config.yaml
└── certs/

15.4 Generate locally trusted TLS certificates

We need HTTPS because authentication sessions and browser security depend on secure connections.

mkcert makes local development certificates that your computer can trust.

macOS or Linux Terminal:

cd ~/pomerium-lab/certs

mkcert -install

mkcert "*.localhost.pomerium.io"

cd ..Code language: JavaScript (javascript)

Windows PowerShell:

Set-Location "$HOME\pomerium-lab\certs"

mkcert -install

mkcert "*.localhost.pomerium.io"

Set-Location ..Code language: JavaScript (javascript)

You should now have files resembling:

certs/
├── _wildcard.localhost.pomerium.io.pem
└── _wildcard.localhost.pomerium.io-key.pem

The first file contains the local server certificate. The second contains its private key.

The certificate is for local development only. Do not publish the private key, and do not share mkcert’s local root certificate authority private key.

15.5 Create the Pomerium configuration

Create config.yaml in the project root using your text editor.

# config.yaml

# Development authentication service.
authenticate_service_url: https://authenticate.pomerium.app

# Locally trusted TLS certificate.
certificate_file: /pomerium/certs/_wildcard.localhost.pomerium.io.pem
certificate_key_file: /pomerium/certs/_wildcard.localhost.pomerium.io-key.pem

# Protected application routes.
routes:
  - from: https://verify.localhost.pomerium.io
    to: http://verify:8000

    pass_identity_headers: true

    policy:
      - allow:
          or:
            - email:
                is: learner@example.comCode language: PHP (php)

Important: Replace learner@example.com with the email address you will actually use to authenticate.

Understanding the configuration

SettingExplanation
authenticate_service_urlSpecifies the hosted authentication service used in this demonstration
certificate_filePath to the server certificate inside the Pomerium container
certificate_key_filePath to the corresponding private key
routesCollection of protected application routes
fromAddress users open in their browsers
toDestination to which Pomerium forwards authorized requests
pass_identity_headersEnables forwarding of Pomerium identity assertion headers
policyDefines authorization rules
allowSpecifies conditions that grant access
emailChecks the authenticated user’s email identity
isRequires an exact value match

The Verify app will be reachable through Pomerium, not through a separately published application port.

15.6 Create Docker Compose configuration

Create compose.yaml:

services:
  pomerium:
    image: pomerium/pomerium:v0.33.4

    ports:
      - "127.0.0.1:443:443"

    volumes:
      - ./config.yaml:/pomerium/config.yaml:ro
      - ./certs:/pomerium/certs:ro

    networks:
      - private

  verify:
    image: pomerium/verify:latest

    expose:
      - "8000"

    networks:
      - private

networks:
  private: {}Code language: PHP (php)

What the file does

pomerium service: Runs the official Pomerium Core image.

verify service: Runs the official demo application.

Port mapping: Binds Pomerium’s HTTPS listener to the local machine’s loopback interface on port 443.

Volumes: Mounts configuration and certificates from the host computer into the container.

Read-only mounts: The :ro suffix prevents the container from writing to those mounted host paths.

Private network: Allows the two containers to communicate.

expose: Documents the Verify service’s internal port without publishing that port to the host.

This uses a pinned Pomerium Core version to make the tutorial reproducible. The demo image follows the official example’s latest pattern; pin that dependency to a tested version or image digest for a reproducible production build.

15.7 Validate the Compose file

Open Terminal or PowerShell inside pomerium-lab.

docker compose config --quiet

This checks the Compose configuration.

If the command succeeds, it normally produces no output.

It does not fully validate Pomerium’s own configuration, certificates, or access policies.

15.8 Start the application stack

docker compose up -d

The command downloads images when necessary, creates the Docker network, and starts the services.

The -d option means detached mode: the containers run without occupying the current terminal.

15.9 Check container status

docker compose ps

Both services should show a running state.

To inspect Pomerium’s output:

docker compose logs --tail=100 pomerium

Look for successful startup and configuration messages.

Do not assume that a container being listed as running means the full authentication process works. We must test it.

15.10 Run Pomerium’s health check

docker compose exec pomerium pomerium health

Pomerium’s official container includes a health subcommand. It returns success when its applicable health checks pass.

For more detail:

docker compose exec pomerium pomerium health -v

Pomerium supports health reporting for components such as its proxy, authorization service, configuration, and storage. Pomerium

15.11 Open the application

Your local protected application

https://verify.localhost.pomerium.io

Open local Verify applicationThis URL only works after you have deployed the local lab successfully.

Your browser should reach Pomerium and enter the authentication flow.

Sign in using the email identity configured in config.yaml.

Once your identity is verified and the route policy is satisfied, you should reach the Pomerium Verify application.

Depending on the Verify image and assertion configuration, the application may display available identity and session details.

If your route is denied, confirm the configured email exactly matches the authenticated identity.

15.12 Test authorization

To understand why Pomerium is valuable, perform a small access-control experiment.

Open config.yaml and temporarily replace the permitted email address with a different address that you do not own.

For example:

policy:
  - allow:
      or:
        - email:
            is: another-user@example.comCode language: CSS (css)

Save the file.

Pomerium supports hot reloading of several configuration settings, but for a simple reproducible lab, explicitly restart its container:

docker compose restart pomerium

Return to the Verify application in your browser and refresh.

Your authenticated identity should no longer satisfy the route policy, so access should be denied.

Restore your actual email address in the configuration and restart Pomerium again.

This experiment demonstrates the difference between being authenticated and being authorized.

15.13 Test application isolation

Observe that the Verify container has no host-published application port.

For example, opening http://localhost:8000 should not reach this Verify service through the normal host network, assuming no unrelated application is listening there.

The Verify service is reached by Pomerium through the Docker network.

This is only a local demonstration of network isolation, not a complete container-hardening or production network-security design.

15.14 Shut down safely

When finished:

docker compose down

This stops and removes the containers and the Compose network.

Your configuration files and certificates remain in your project directory.

Do not add --volumes to a cleanup command casually in later projects, because named volumes may hold persistent data.

15.15 First-lab troubleshooting

SymptomLikely causeFirst action
Docker command failsDocker engine unavailableStart Docker Desktop or Docker service
Port binding errorPort 443 already usedIdentify the competing listener
Browser certificate warningmkcert certificate not trustedCheck mkcert installation and trust
Login repeatedly failsAuthentication or browser session problemInspect logs and browser redirects
Access deniedEmail does not match policyVerify authenticated email
Proxy errorVerify container not reachableCheck Compose network and service status
Nothing loadsContainer not running, port problem, or DNS issueCheck docker compose ps and logs

15.16 Success criteria

You have completed your first Pomerium deployment when you can demonstrate all of the following:

  • Pomerium starts in Docker.
  • The Verify application is reachable through the Pomerium HTTPS route.
  • Authentication completes successfully.
  • The authorized identity can access the application.
  • An identity that does not meet the policy is denied.
  • The application is not independently published on the host’s port 8000.
  • Pomerium logs and health checks can be inspected.
  • You can stop the environment safely.

You have now built a working identity-aware application access gateway.

Part V — Commands, Configuration, and Daily Usage

Chapter 16. Essential Commands and Operations

Pomerium Core is primarily a service rather than an interactive command-line application.

In our Docker deployment, most daily operations use Docker Compose. The Pomerium server binary also supports operational commands such as health checks.

Do not confuse the Pomerium server binary with the separate pomerium-cli client used for certain non-HTTP connections.

16.1 Docker Compose command reference

CommandPurposeWhen to use itWarning
docker compose up -dStart the stackInitial startupStarts configured services
docker compose psShow service statusRoutine inspectionRunning does not prove application health
docker compose logsShow logsTroubleshootingLogs can contain sensitive data
docker compose logs -fFollow logsLive diagnosisRuns until interrupted
docker compose restart pomeriumRestart PomeriumApply restart-requiring changesInterrupts active connections
docker compose pullDownload configured imagesPreparing upgradesMay download newer images for floating tags
docker compose config --quietValidate Compose configurationBefore deploymentDoes not validate Pomerium policies
docker compose exec pomerium pomerium healthCheck Pomerium healthRoutine verificationRequires running container
docker compose downStop and remove Compose servicesLab cleanupInterrupts access
docker compose down --volumesRemove containers and named volumesDestructive lab resetDeletes persisted volume data

16.2 Basic daily operations

Start the environment:

docker compose up -d

Inspect it:

docker compose ps

Read recent logs:

docker compose logs --tail=100 pomerium

Follow new log messages:

docker compose logs -f pomerium

Stop following logs with Ctrl+C. This does not stop the container.

16.3 Inspect container health

docker compose exec pomerium pomerium health

Verbose diagnostic output:

docker compose exec pomerium pomerium health -v

Pomerium’s health command uses process exit status to indicate success or failure. A successful check exits with code zero.

16.4 Check the running image

docker compose images

This helps identify which container images are associated with the current Compose project.

To inspect the pinned Pomerium image:

docker image inspect pomerium/pomerium:v0.33.4

Image inspection provides container-image metadata. It is not a substitute for checking Pomerium’s release notes and security advisories.

16.5 Native Pomerium commands

For users running a native server binary, the documented startup form is:

./pomerium -config config.yaml

The configuration path identifies the file to load.

Pomerium’s operational health command is:

pomerium health

For command-specific assistance:

pomerium health --help

16.6 The separate Pomerium client

The pomerium-cli tool is used for supported client-side connections such as TCP routes.

After installing the appropriate client from the official Pomerium client documentation, inspect its available commands:

pomerium-cli --help

For example, the client supports TCP access to correctly configured Pomerium TCP routes.

This is an advanced topic because it requires more than a browser-accessible HTTP route. Pomerium

Chapter 17. Configuration Explained

17.1 Pomerium’s configuration model

Pomerium Core supports configuration files and environment variables.

Common configuration formats include YAML, JSON, and TOML, although this tutorial uses YAML because it is widely used in infrastructure management.

When the same configuration key is specified in both the configuration file and the environment, the environment variable takes precedence. Pomerium

17.2 Global settings versus route settings

Global configuration affects the Pomerium deployment more broadly.

Route-specific configuration affects a particular protected application.

For example:

# Global setting
log_level: info

routes:
  # Route-specific settings
  - from: https://portal.localhost.pomerium.io
    to: http://portal:80

    policy:
      - allow:
          or:
            - email:
                is: learner@example.comCode language: PHP (php)

The logging setting is global.

The URL mapping and policy are specific to the portal route.

17.3 Understanding Pomerium Policy Language

Pomerium Policy Language (PPL) lets administrators describe authorization logic.

The major building blocks are:

ComponentMeaning
allowDefine circumstances granting access
denyDefine circumstances denying access
andRequire multiple conditions
orPermit matching any of several conditions
emailCompare an authenticated email
domainCompare the email’s domain
userCompare a user identifier
groupsEvaluate group-related identity data when available
claim/...Evaluate a particular identity claim

For example, to permit either of two users:

policy:
  - allow:
      or:
        - email:
            is: alice@example.com
        - email:
            is: bob@example.comCode language: CSS (css)

17.4 Combining allow and deny logic

Suppose everyone in example.com may access a portal except a specifically blocked user.

policy:
  allow:
    and:
      - domain:
          is: example.com

  deny:
    and:
      - email:
          is: blocked@example.comCode language: CSS (css)

Pomerium’s policy evaluation requires an applicable allow decision and no matching deny condition. Explicit deny takes precedence over allow. Pomerium

A policy requiring a corporate email domain is convenient, but sensitive production access may require stronger constraints, such as explicit user or group permission and suitable identity-provider controls.

17.5 Handling secrets correctly

Our first lab intentionally used minimal configuration.

For a more persistent setup, we should explicitly configure cryptographic secrets and state storage.

Pomerium uses important secrets such as:

  • Shared secret: Used for secure communication among Pomerium services.
  • Cookie secret: Used to protect session cookies.
  • Identity-provider credentials: Required when using a custom identity provider.
  • Signing key: Used when providing signed identity assertions to applications.

These have different purposes. Do not reuse the same secret for unrelated settings.

17.6 Generate cryptographically random secrets

A simple cross-platform approach is to use a temporary Alpine Linux container.

Run this command twice:

docker run --rm alpine:3.20 \
  sh -c "head -c 32 /dev/urandom | base64"Code language: JavaScript (javascript)

On Windows PowerShell, use the same command on one line:

docker run --rm alpine:3.20 sh -c "head -c 32 /dev/urandom | base64"Code language: JavaScript (javascript)

Each execution should produce a different Base64-encoded random value.

Use one value for SHARED_SECRET and another for COOKIE_SECRET.

17.7 Create a local environment file

In your project directory, create .env.

POMERIUM_SHARED_SECRET=REPLACE_WITH_FIRST_GENERATED_VALUE
POMERIUM_COOKIE_SECRET=REPLACE_WITH_SECOND_GENERATED_VALUE

Replace both placeholders.

Do not commit this file to a Git repository.

Create .gitignore:

.env

certs/*-key.pem
*.key
ec_private.pemCode language: CSS (css)

This file helps prevent accidental source-control commits, but it does not provide encryption or a production secrets-management system.

17.8 Enable persistent Databroker storage

Update config.yaml:

authenticate_service_url: https://authenticate.pomerium.app

certificate_file: /pomerium/certs/_wildcard.localhost.pomerium.io.pem
certificate_key_file: /pomerium/certs/_wildcard.localhost.pomerium.io-key.pem

# Persist session-related data locally.
databroker_storage_type: file
databroker_storage_connection_string: file:///data/pomerium

log_level: info

routes:
  - from: https://verify.localhost.pomerium.io
    to: http://verify:8000

    pass_identity_headers: true

    policy:
      - allow:
          or:
            - email:
                is: learner@example.comCode language: PHP (php)

Remember to replace the email.

Now replace compose.yaml with:

services:
  pomerium:
    image: pomerium/pomerium:v0.33.4

    ports:
      - "127.0.0.1:443:443"

    environment:
      SHARED_SECRET: ${POMERIUM_SHARED_SECRET}
      COOKIE_SECRET: ${POMERIUM_COOKIE_SECRET}

    volumes:
      - ./config.yaml:/pomerium/config.yaml:ro
      - ./certs:/pomerium/certs:ro
      - pomerium-data:/data

    networks:
      - private

  verify:
    image: pomerium/verify:latest

    expose:
      - "8000"

    networks:
      - private

networks:
  private: {}

volumes:
  pomerium-data:Code language: PHP (php)

The named volume stores the local Databroker files across ordinary container recreation.

This is a persistent, single-instance configuration—not a high-availability architecture.

17.9 Apply the changes

docker compose config --quiet
docker compose up -d

Recreating Pomerium after introducing new secrets may invalidate previously established sessions. Sign in again if necessary.

Verify health:

docker compose exec pomerium pomerium health -v

The file-backed Databroker should now be configured, provided the volume is mounted and writable.

The hosted authentication service still has its own session limitations. Persistent local storage does not remove those limitations.

17.10 Configuration precedence

SourceBehaviorTypical usage
YAML configuration fileDefines Core configurationRoutes, policies, runtime settings
Environment variablesOverride duplicate file keysRuntime secrets and deployment settings
Product-specific control planeManages supported configuration in Zero or EnterpriseCentralized administration
Bootstrap configurationInitializes important runtime settingsInternal service secrets and addresses

Pomerium can hot-reload several configuration categories, including routes and policies. Other changes may require service recreation or restart.

Always verify the effective behavior after a configuration update.

Chapter 18. Logs, Status, and Verification

18.1 Installation success is not operational success

A running container proves only that a process is running.

A fully working Pomerium deployment must also authenticate users, evaluate policies, connect to upstream applications, and return the correct responses.

18.2 Routine diagnostic commands

Inspect the deployment:

docker compose ps

Check Pomerium health:

docker compose exec pomerium pomerium health -v

Inspect recent logs:

docker compose logs --tail=200 pomerium

Inspect all service logs:

docker compose logs --tail=100

18.3 Understanding health endpoints

Pomerium exposes internal health checks, normally on 127.0.0.1:28080 within its runtime environment.

EndpointPurpose
/startupzStartup readiness
/readyzReadiness to receive traffic
/healthzLiveness
/statusHuman-readable component status

These are distinct from Pomerium’s public listener and routing endpoints.

The internal health port should not be exposed directly to the public Internet. Pomerium

18.4 HTTP connectivity check

On macOS or Linux:

curl -I https://verify.localhost.pomerium.io/pingCode language: JavaScript (javascript)

On Windows PowerShell:

curl.exe -I https://verify.localhost.pomerium.io/pingCode language: JavaScript (javascript)

Pomerium documents /ping as a special endpoint for basic connectivity and health checks.

A normal result is an HTTP success response such as 200 OK.

This proves basic HTTPS reachability to Pomerium, not that authentication or an upstream application is functioning.

18.5 Understanding HTTP status codes

StatusMeaningWhat to inspect
200Successful responseConfirm it is from the expected endpoint
301 / 302RedirectCheck login and destination URLs
401Authentication-related failureCredentials, tokens, session
403Access forbiddenPolicy and user identity
404Resource not foundHostname, route, application path
502Bad gatewayUpstream availability and connectivity
503Service unavailableGateway or backend health
504Gateway timeoutConnectivity, slow backend, timeout configuration

These are general HTTP meanings. The exact cause depends on the responding component.

18.6 Log levels

Pomerium supports logging levels such as info, warn, error, debug, and trace.

For routine operation:

log_level: infoCode language: HTTP (http)

For targeted troubleshooting:

log_level: debugCode language: HTTP (http)

Use more verbose levels temporarily when needed.

Verbose logs can increase data volume and expose sensitive operational context. Restrict access and return to the normal logging level after diagnosis.

18.7 A systematic troubleshooting method

#chatgpt-mermaid-_r_22g_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;fill:rgb(13, 13, 13);}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#chatgpt-mermaid-_r_22g_ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_22g_ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_22g_ .error-icon{fill:rgb(243, 243, 243);}#chatgpt-mermaid-_r_22g_ .error-text{fill:rgb(13, 13, 13);stroke:rgb(13, 13, 13);}#chatgpt-mermaid-_r_22g_ .edge-thickness-normal{stroke-width:1px;}#chatgpt-mermaid-_r_22g_ .edge-thickness-thick{stroke-width:3.5px;}#chatgpt-mermaid-_r_22g_ .edge-pattern-solid{stroke-dasharray:0;}#chatgpt-mermaid-_r_22g_ .edge-thickness-invisible{stroke-width:0;fill:none;}#chatgpt-mermaid-_r_22g_ .edge-pattern-dashed{stroke-dasharray:3;}#chatgpt-mermaid-_r_22g_ .edge-pattern-dotted{stroke-dasharray:2;}#chatgpt-mermaid-_r_22g_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_22g_ .marker.cross{stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_22g_ svg{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;}#chatgpt-mermaid-_r_22g_ p{margin:0;}#chatgpt-mermaid-_r_22g_ .label{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_22g_ .cluster-label text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_22g_ .cluster-label span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_22g_ .cluster-label span p{background-color:transparent;}#chatgpt-mermaid-_r_22g_ .label text,#chatgpt-mermaid-_r_22g_ span{fill:rgb(13, 13, 13);color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_22g_ .node rect,#chatgpt-mermaid-_r_22g_ .node circle,#chatgpt-mermaid-_r_22g_ .node ellipse,#chatgpt-mermaid-_r_22g_ .node polygon,#chatgpt-mermaid-_r_22g_ .node path{fill:rgb(222, 234, 251);stroke:rgb(83, 154, 248);stroke-width:1px;}#chatgpt-mermaid-_r_22g_ .rough-node .label text,#chatgpt-mermaid-_r_22g_ .node .label text,#chatgpt-mermaid-_r_22g_ .image-shape .label,#chatgpt-mermaid-_r_22g_ .icon-shape .label{text-anchor:middle;}#chatgpt-mermaid-_r_22g_ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#chatgpt-mermaid-_r_22g_ .rough-node .label,#chatgpt-mermaid-_r_22g_ .node .label,#chatgpt-mermaid-_r_22g_ .image-shape .label,#chatgpt-mermaid-_r_22g_ .icon-shape .label{text-align:center;}#chatgpt-mermaid-_r_22g_ .node.clickable{cursor:pointer;}#chatgpt-mermaid-_r_22g_ .root .anchor path{fill:rgb(143, 143, 143)!important;stroke-width:0;stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_22g_ .arrowheadPath{fill:rgb(143, 143, 143);}#chatgpt-mermaid-_r_22g_ .edgePath .path{stroke:rgb(143, 143, 143);stroke-width:1px;}#chatgpt-mermaid-_r_22g_ .flowchart-link{stroke:rgb(143, 143, 143);fill:none;}#chatgpt-mermaid-_r_22g_ .edgeLabel{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_22g_ .edgeLabel p{background-color:rgb(252, 252, 252);}#chatgpt-mermaid-_r_22g_ .edgeLabel rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_22g_ .labelBkg{background-color:rgba(252, 252, 252, 0.5);}#chatgpt-mermaid-_r_22g_ .cluster rect{fill:rgb(243, 243, 243);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_22g_ .cluster text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_22g_ .cluster span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_22g_ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:12px;background:rgb(243, 243, 243);border:1px solid rgba(0, 0, 0, 0.1);border-radius:2px;pointer-events:none;z-index:100;}#chatgpt-mermaid-_r_22g_ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_22g_ rect.text{fill:none;stroke-width:0;}#chatgpt-mermaid-_r_22g_ .icon-shape,#chatgpt-mermaid-_r_22g_ .image-shape{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_22g_ .icon-shape p,#chatgpt-mermaid-_r_22g_ .image-shape p{background-color:rgb(252, 252, 252);padding:2px;}#chatgpt-mermaid-_r_22g_ .icon-shape .label rect,#chatgpt-mermaid-_r_22g_ .image-shape .label rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_22g_ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#chatgpt-mermaid-_r_22g_ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#chatgpt-mermaid-_r_22g_ .node .neo-node{stroke:rgb(83, 154, 248);}#chatgpt-mermaid-_r_22g_ [data-look=”neo”].node rect,#chatgpt-mermaid-_r_22g_ [data-look=”neo”].cluster rect,#chatgpt-mermaid-_r_22g_ [data-look=”neo”].node polygon{stroke:url(#chatgpt-mermaid-_r_22g_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_22g_ [data-look=”neo”].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_22g_ [data-look=”neo”].node path{stroke:url(#chatgpt-mermaid-_r_22g_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_22g_ [data-look=”neo”].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_22g_ [data-look=”neo”].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_22g_ [data-look=”neo”].node circle{stroke:url(#chatgpt-mermaid-_r_22g_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_22g_ [data-look=”neo”].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_22g_ [data-look=”neo”].icon-shape .icon{fill:url(#chatgpt-mermaid-_r_22g_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_22g_ [data-look=”neo”].icon-shape .icon-neo path{stroke:url(#chatgpt-mermaid-_r_22g_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_22g_ .node text{font-size:14px;font-weight:600;letter-spacing:normal;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_22g_ .edgeLabels text{font-size:13px;font-weight:600;letter-spacing:-0.08px;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_22g_ .node tspan[font-weight=”normal”],#chatgpt-mermaid-_r_22g_ .edgeLabels tspan[font-weight=”normal”]{font-weight:600;}#chatgpt-mermaid-_r_22g_ .edgeLabel .label rect{opacity:1;rx:13px;ry:13px;fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-width:1px;}#chatgpt-mermaid-_r_22g_ .node rect,#chatgpt-mermaid-_r_22g_ .node circle,#chatgpt-mermaid-_r_22g_ .node ellipse,#chatgpt-mermaid-_r_22g_ .node polygon,#chatgpt-mermaid-_r_22g_ .node path{fill:rgb(229, 243, 255);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_22g_ .node rect{rx:16px;ry:16px;}#chatgpt-mermaid-_r_22g_ .mermaid-decision .label-container{fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-dasharray:2,2;}#chatgpt-mermaid-_r_22g_ .edgePaths .flowchart-link{stroke:rgb(143, 143, 143);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;}#chatgpt-mermaid-_r_22g_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_22g_ :root{–mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;}Application cannot beaccessedPomerium running?Inspect container logsLocal HTTPS reachable?Check DNS, port, and TLSAuthentication works?Check identity provider andsessionPolicy allows user?Check authorization rulesUpstream reachable?Check Docker network andbackendSuccessful applicationresponseNoYesNoYesNoYesNoYesNoYes

Always find which layer is failing before changing configuration.

Part VI — Real-World Applications

Chapter 19. Practical Use Cases

Pomerium becomes particularly useful when access to multiple protected resources must be controlled consistently.

Use case 1 — Protect a personal development dashboard

Problem: A developer has a private dashboard and does not want arbitrary visitors reaching it.

Environment: A small self-hosted server or container environment.

Implementation: Deploy Pomerium in front of the dashboard and allow only the developer’s authenticated identity.

Expected outcome: The dashboard is accessed through the approved route, while direct access is restricted.

Success measurements: Successful authorized access, expected denial for unauthorized identities, and absence of unprotected public backend routes.

Risk: The developer must still maintain the server, certificates, identity provider, and security updates.

Use case 2 — Centralize access for a development team

Problem: A team maintains Jenkins, Grafana, internal documentation, and several engineering tools.

Environment: Applications hosted in Docker or virtual machines.

Implementation: Configure separate Pomerium routes and policies for different tools.

For example:

Protected serviceExample access rule
Developer wikiApproved employee identities
JenkinsAuthorized engineering team
GrafanaEngineering and operations
Administration portalExplicit administrator identities

Expected outcome: Consistent, reviewable access policies across multiple applications.

Success measurements: Authorized versus denied requests, access-provisioning effort, and number of independently exposed services.

Risk: Incorrect policy scope could grant broader access than intended.

Use case 3 — Secure production administration tools

Problem: Production administration applications should not be freely reachable.

Environment: Private cloud networks or data centers.

Implementation: Deploy Pomerium as an enforced access boundary, integrate corporate authentication, require suitable MFA, and restrict routes to approved identities.

Expected outcome: Access to administration interfaces is controlled centrally.

Success measurements: Policy-test results, authentication success and failure trends, audit coverage, and gateway uptime.

Risk: A misconfigured network route could allow access around Pomerium. The administration application must also enforce its internal privileges.

Use case 4 — Protect applications running in Kubernetes

Problem: Teams need access to internal services running inside Kubernetes clusters.

Environment: Kubernetes with an ingress controller, internal services, and a corporate IdP.

Implementation: Deploy the supported Pomerium Kubernetes integration, configure routes, and enforce authorization policies.

Expected outcome: Developers reach approved applications through the protected ingress layer.

Success measurements: Valid ingress routing, successful allow/deny tests, deployment availability, and changes managed through version control.

Risk: Kubernetes networking, ingress configuration, TLS certificate issuance, and Pomerium access policies must be coordinated.

Use case 5 — Control contractor access

Problem: A contractor needs access to one project tool but should not receive unnecessary network or application permissions.

Environment: Corporate identity provider and internal project application.

Implementation: Establish a contractor identity, define a narrow route policy, and remove permission when work finishes.

Expected outcome: Access is limited to the approved service and duration.

Success measurements: Only approved identities succeed; access removal takes effect as expected.

Risk: Time-based access lifecycle and session revocation must be designed carefully. A route policy alone does not automatically implement every contract-expiration rule.

Use case 6 — Secure machine-to-machine access

Problem: An automated process needs to call a protected service without an interactive browser login.

Environment: Automated pipelines, scheduled jobs, or service integrations.

Implementation: Evaluate Pomerium Zero or Enterprise service accounts, or another supported token-based integration appropriate to the authentication model.

Expected outcome: An authorized machine identity can access the intended endpoint without sharing a human user’s password.

Success measurements: Successful token validation, least-privilege policy behavior, and safe credential rotation.

Risk: Exposed service-account tokens can be abused. Tokens require protection, expiration, and rotation.

Pomerium documents service-account creation for Zero and Enterprise, along with token-based access methods. Pomerium

Chapter 20. A Complete Hands-On Project

Project: Secure an Internal Operations Portal with Pomerium

We will now extend the first lab into a more realistic multi-application setup.

The project includes:

  • A private NGINX web portal.
  • The Pomerium Verify application.
  • Two protected routes.
  • Email-based authorization.
  • Local HTTPS certificates.
  • Persistent Pomerium state.
  • Runtime secrets separated from configuration.
  • A basic Pomerium health check.

20.1 Project objective

Build a private web portal that a permitted user can access through Pomerium, while unauthorized users are denied.

20.2 Architecture

#chatgpt-mermaid-_r_22r_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;fill:rgb(13, 13, 13);}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#chatgpt-mermaid-_r_22r_ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_22r_ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_22r_ .error-icon{fill:rgb(243, 243, 243);}#chatgpt-mermaid-_r_22r_ .error-text{fill:rgb(13, 13, 13);stroke:rgb(13, 13, 13);}#chatgpt-mermaid-_r_22r_ .edge-thickness-normal{stroke-width:1px;}#chatgpt-mermaid-_r_22r_ .edge-thickness-thick{stroke-width:3.5px;}#chatgpt-mermaid-_r_22r_ .edge-pattern-solid{stroke-dasharray:0;}#chatgpt-mermaid-_r_22r_ .edge-thickness-invisible{stroke-width:0;fill:none;}#chatgpt-mermaid-_r_22r_ .edge-pattern-dashed{stroke-dasharray:3;}#chatgpt-mermaid-_r_22r_ .edge-pattern-dotted{stroke-dasharray:2;}#chatgpt-mermaid-_r_22r_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_22r_ .marker.cross{stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_22r_ svg{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;}#chatgpt-mermaid-_r_22r_ p{margin:0;}#chatgpt-mermaid-_r_22r_ .label{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_22r_ .cluster-label text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_22r_ .cluster-label span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_22r_ .cluster-label span p{background-color:transparent;}#chatgpt-mermaid-_r_22r_ .label text,#chatgpt-mermaid-_r_22r_ span{fill:rgb(13, 13, 13);color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_22r_ .node rect,#chatgpt-mermaid-_r_22r_ .node circle,#chatgpt-mermaid-_r_22r_ .node ellipse,#chatgpt-mermaid-_r_22r_ .node polygon,#chatgpt-mermaid-_r_22r_ .node path{fill:rgb(222, 234, 251);stroke:rgb(83, 154, 248);stroke-width:1px;}#chatgpt-mermaid-_r_22r_ .rough-node .label text,#chatgpt-mermaid-_r_22r_ .node .label text,#chatgpt-mermaid-_r_22r_ .image-shape .label,#chatgpt-mermaid-_r_22r_ .icon-shape .label{text-anchor:middle;}#chatgpt-mermaid-_r_22r_ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#chatgpt-mermaid-_r_22r_ .rough-node .label,#chatgpt-mermaid-_r_22r_ .node .label,#chatgpt-mermaid-_r_22r_ .image-shape .label,#chatgpt-mermaid-_r_22r_ .icon-shape .label{text-align:center;}#chatgpt-mermaid-_r_22r_ .node.clickable{cursor:pointer;}#chatgpt-mermaid-_r_22r_ .root .anchor path{fill:rgb(143, 143, 143)!important;stroke-width:0;stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_22r_ .arrowheadPath{fill:rgb(143, 143, 143);}#chatgpt-mermaid-_r_22r_ .edgePath .path{stroke:rgb(143, 143, 143);stroke-width:1px;}#chatgpt-mermaid-_r_22r_ .flowchart-link{stroke:rgb(143, 143, 143);fill:none;}#chatgpt-mermaid-_r_22r_ .edgeLabel{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_22r_ .edgeLabel p{background-color:rgb(252, 252, 252);}#chatgpt-mermaid-_r_22r_ .edgeLabel rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_22r_ .labelBkg{background-color:rgba(252, 252, 252, 0.5);}#chatgpt-mermaid-_r_22r_ .cluster rect{fill:rgb(243, 243, 243);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_22r_ .cluster text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_22r_ .cluster span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_22r_ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:12px;background:rgb(243, 243, 243);border:1px solid rgba(0, 0, 0, 0.1);border-radius:2px;pointer-events:none;z-index:100;}#chatgpt-mermaid-_r_22r_ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_22r_ rect.text{fill:none;stroke-width:0;}#chatgpt-mermaid-_r_22r_ .icon-shape,#chatgpt-mermaid-_r_22r_ .image-shape{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_22r_ .icon-shape p,#chatgpt-mermaid-_r_22r_ .image-shape p{background-color:rgb(252, 252, 252);padding:2px;}#chatgpt-mermaid-_r_22r_ .icon-shape .label rect,#chatgpt-mermaid-_r_22r_ .image-shape .label rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_22r_ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#chatgpt-mermaid-_r_22r_ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#chatgpt-mermaid-_r_22r_ .node .neo-node{stroke:rgb(83, 154, 248);}#chatgpt-mermaid-_r_22r_ [data-look=”neo”].node rect,#chatgpt-mermaid-_r_22r_ [data-look=”neo”].cluster rect,#chatgpt-mermaid-_r_22r_ [data-look=”neo”].node polygon{stroke:url(#chatgpt-mermaid-_r_22r_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_22r_ [data-look=”neo”].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_22r_ [data-look=”neo”].node path{stroke:url(#chatgpt-mermaid-_r_22r_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_22r_ [data-look=”neo”].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_22r_ [data-look=”neo”].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_22r_ [data-look=”neo”].node circle{stroke:url(#chatgpt-mermaid-_r_22r_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_22r_ [data-look=”neo”].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_22r_ [data-look=”neo”].icon-shape .icon{fill:url(#chatgpt-mermaid-_r_22r_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_22r_ [data-look=”neo”].icon-shape .icon-neo path{stroke:url(#chatgpt-mermaid-_r_22r_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_22r_ .node text{font-size:14px;font-weight:600;letter-spacing:normal;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_22r_ .edgeLabels text{font-size:13px;font-weight:600;letter-spacing:-0.08px;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_22r_ .node tspan[font-weight=”normal”],#chatgpt-mermaid-_r_22r_ .edgeLabels tspan[font-weight=”normal”]{font-weight:600;}#chatgpt-mermaid-_r_22r_ .edgeLabel .label rect{opacity:1;rx:13px;ry:13px;fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-width:1px;}#chatgpt-mermaid-_r_22r_ .node rect,#chatgpt-mermaid-_r_22r_ .node circle,#chatgpt-mermaid-_r_22r_ .node ellipse,#chatgpt-mermaid-_r_22r_ .node polygon,#chatgpt-mermaid-_r_22r_ .node path{fill:rgb(229, 243, 255);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_22r_ .node rect{rx:16px;ry:16px;}#chatgpt-mermaid-_r_22r_ .mermaid-decision .label-container{fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-dasharray:2,2;}#chatgpt-mermaid-_r_22r_ .edgePaths .flowchart-link{stroke:rgb(143, 143, 143);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;}#chatgpt-mermaid-_r_22r_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_22r_ :root{–mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;}Private Docker networkVerify applicationNGINX operations portalBrowserPomerium CoreHosted authenticationPersistent Databroker filesHTTPSLoginRoute 1Route 2

20.3 Directory structure

Our completed project will look like this:

pomerium-lab/
├── .env
├── .gitignore
├── compose.yaml
├── config.yaml
├── certs/
│   ├── _wildcard.localhost.pomerium.io.pem
│   └── _wildcard.localhost.pomerium.io-key.pem
└── site/
    └── index.html

Use the secrets and certificates generated in the previous chapters.

20.4 Create the application directory

macOS/Linux:

cd ~/pomerium-lab
mkdir -p site

Windows PowerShell:

Set-Location "$HOME\pomerium-lab"
New-Item -ItemType Directory -Force siteCode language: JavaScript (javascript)

20.5 Build the private web application

Create site/index.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, initial-scale=1">

  <title>Internal Operations Portal</title>

  <style>
    body {
      font-family: Arial, sans-serif;
      background: #f5f7fa;
      margin: 0;
      padding: 40px 20px;
    }

    main {
      max-width: 700px;
      margin: 0 auto;
      padding: 32px;
      background: white;
      border-radius: 12px;
      box-shadow: 0 4px 20px #00000010;
    }

    h1 {
      color: #1e293b;
    }

    p {
      line-height: 1.7;
    }

    .status {
      display: inline-block;
      padding: 8px 14px;
      border-radius: 8px;
      background: #dcfce7;
      color: #166534;
    }
  </style>
</head>

<body>
  <main>
    <h1>Internal Operations Portal</h1>

    <p>
      This application is protected by Pomerium.
    </p>

    <p class="status">
      Application is reachable.
    </p>

    <h2>About this demonstration</h2>

    <p>
      Pomerium authenticates and authorizes requests
      before forwarding traffic to this private
      NGINX application.
    </p>

    <p>
      The NGINX container has no published host port.
    </p>
  </main>
</body>
</html>Code language: HTML, XML (xml)

This is intentionally a simple static application.

It does not implement its own login functionality. The access enforcement happens before traffic reaches it.

20.6 Create the final Pomerium configuration

Replace config.yaml with:

authenticate_service_url: https://authenticate.pomerium.app

certificate_file: /pomerium/certs/_wildcard.localhost.pomerium.io.pem
certificate_key_file: /pomerium/certs/_wildcard.localhost.pomerium.io-key.pem

databroker_storage_type: file
databroker_storage_connection_string: file:///data/pomerium

log_level: info

routes:
  # Route 1: Identity verification demonstration
  - from: https://verify.localhost.pomerium.io
    to: http://verify:8000

    pass_identity_headers: true

    policy:
      - allow:
          or:
            - email:
                is: learner@example.com

  # Route 2: Internal operations portal
  - from: https://portal.localhost.pomerium.io
    to: http://portal:80

    policy:
      - allow:
          or:
            - email:
                is: learner@example.comCode language: PHP (php)

Replace both occurrences of learner@example.com with your authenticated email.

The two routes have different from addresses and different upstream destinations.

Their policies are currently identical, but each can be changed independently.

20.7 Create the final Compose configuration

Replace compose.yaml:

services:
  pomerium:
    image: pomerium/pomerium:v0.33.4

    ports:
      - "127.0.0.1:443:443"

    environment:
      SHARED_SECRET: ${POMERIUM_SHARED_SECRET}
      COOKIE_SECRET: ${POMERIUM_COOKIE_SECRET}

    volumes:
      - ./config.yaml:/pomerium/config.yaml:ro
      - ./certs:/pomerium/certs:ro
      - pomerium-data:/data

    healthcheck:
      test: ["CMD", "pomerium", "health"]
      interval: 30s
      timeout: 5s
      retries: 5

    networks:
      - private

  verify:
    image: pomerium/verify:latest

    expose:
      - "8000"

    networks:
      - private

  portal:
    image: nginx:stable-alpine

    volumes:
      - ./site:/usr/share/nginx/html:ro

    expose:
      - "80"

    networks:
      - private

networks:
  private: {}

volumes:
  pomerium-data:Code language: PHP (php)

This Compose file defines three services.

Only Pomerium publishes a host port.

The Verify and NGINX applications are private within the Compose network.

20.8 Ensure secrets exist

Your .env file must contain real, randomly generated values for:

POMERIUM_SHARED_SECRET=REPLACE_WITH_GENERATED_VALUE
POMERIUM_COOKIE_SECRET=REPLACE_WITH_ANOTHER_GENERATED_VALUE

Do not leave the placeholders unchanged.

The file should remain local and excluded from version control.

20.9 Validate and start the project

docker compose config --quiet
docker compose up -d
docker compose ps

The services should start.

Pomerium should eventually report healthy.

Check:

docker compose exec pomerium pomerium health -v

20.10 Test both applications

Verify application

Identity and authorization testOpen Verify

Operations portal

Private NGINX applicationOpen Operations Portal

These are local lab addresses and will only work on a computer where the corresponding Pomerium stack is running.

After successful authentication, the Operations Portal should display the HTML page we created.

20.11 Experiment: Different application permissions

Change the portal route to permit a different email while leaving the Verify route unchanged:

  - from: https://portal.localhost.pomerium.io
    to: http://portal:80

    policy:
      - allow:
          or:
            - email:
                is: other-user@example.com

Restart Pomerium:

docker compose restart pomerium

Now test both routes.

Your original identity should still satisfy the Verify policy but should no longer satisfy the portal policy.

This demonstrates independent access rules for different applications.

Restore your original portal policy afterward.

20.12 Verify network exposure

Inspect published ports:

docker compose ps

Only the Pomerium service should show a published host port.

The NGINX container’s internal port 80 should not appear as a separately published host port.

Users with access to the Docker host, container runtime, or private Docker network may have other ways to contact it. Production isolation must consider those trust boundaries.

20.13 Failure experiment

Stop only the portal service:

docker compose stop portal

Try to access:

https://portal.localhost.pomerium.ioCode language: JavaScript (javascript)

Pomerium should remain available, but its portal upstream is now unavailable.

You may receive a gateway error such as a 502 or 503 response, depending on the failure state.

Restore the portal:

docker compose start portal

Verify that the application becomes reachable again.

This teaches the distinction between gateway availability and upstream application availability.

20.14 Cleanup

Stop the complete project:

docker compose down

This preserves the named volume and project files.

For an intentional complete lab reset, after confirming that no useful data remains in the named volumes:

docker compose down --volumes

The second command deletes Compose-managed named volumes associated with the project. Do not use it on production systems without reviewing the consequences.

20.15 Project completion criteria

Your project is complete when:

  • Both applications are reachable through separate Pomerium routes.
  • Unauthorized identities fail route authorization.
  • The upstream containers are not exposed through host-published ports.
  • Pomerium provides a successful health check.
  • You can inspect logs and change policies.
  • You understand how an upstream failure differs from a Pomerium failure.
  • You can stop and restore the environment safely.

20.16 Suggested improvements

Once the project works, extend it by integrating a custom identity provider, adding a second user with different permissions, issuing signed identity assertions, monitoring authorization results, and testing a production-oriented storage configuration.

These improvements form the bridge to the advanced chapters.

Part VII — Advanced Capabilities

Chapter 21. Advanced Pomerium Features

The following capabilities are not required for the first local laboratory. Learn them after becoming comfortable with routing, authentication, policies, and operations.

21.1 Advanced authorization policies

A basic policy might allow one authenticated email address.

Advanced policies can combine multiple conditions, such as identity attributes, group membership, request context, and other supported criteria.

For example:

policy:
  allow:
    or:
      - email:
          is: lead@example.com

      - domain:
          is: engineering.example.com

  deny:
    and:
      - email:
          is: suspended@example.comCode language: CSS (css)

This illustrative policy allows a named user or users with the specified email domain, except the explicitly denied identity.

Prerequisite: Understanding how allow, deny, and, and or interact.

Trade-off: More complex policies can create surprising access decisions if they are not tested.

For sensitive services, create a test matrix before deploying a policy:

IdentityShould access?Why?
Approved engineerYesMeets allow condition
Approved team leadYesMeets allow condition
Suspended employeeNoExplicit deny
External visitorNoNo matching allow
Missing identity dataNoRequired policy condition cannot be established

Pomerium Enterprise also supports Rego policies for advanced logic using Open Policy Agent’s policy language. Rego is not required for ordinary Core policies. Pomerium

21.2 Integrating a custom identity provider

Our beginner lab uses Pomerium’s hosted authentication service.

A production deployment will often use a corporate identity provider.

The architecture changes to:

ApplicationCorporate IdPPomeriumBrowserApplicationCorporate IdPPomeriumBrowser#chatgpt-mermaid-_r_26s_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;fill:rgb(13, 13, 13);}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#chatgpt-mermaid-_r_26s_ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_26s_ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_26s_ .error-icon{fill:rgb(243, 243, 243);}#chatgpt-mermaid-_r_26s_ .error-text{fill:rgb(13, 13, 13);stroke:rgb(13, 13, 13);}#chatgpt-mermaid-_r_26s_ .edge-thickness-normal{stroke-width:1px;}#chatgpt-mermaid-_r_26s_ .edge-thickness-thick{stroke-width:3.5px;}#chatgpt-mermaid-_r_26s_ .edge-pattern-solid{stroke-dasharray:0;}#chatgpt-mermaid-_r_26s_ .edge-thickness-invisible{stroke-width:0;fill:none;}#chatgpt-mermaid-_r_26s_ .edge-pattern-dashed{stroke-dasharray:3;}#chatgpt-mermaid-_r_26s_ .edge-pattern-dotted{stroke-dasharray:2;}#chatgpt-mermaid-_r_26s_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_26s_ .marker.cross{stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_26s_ svg{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;}#chatgpt-mermaid-_r_26s_ p{margin:0;}#chatgpt-mermaid-_r_26s_ .actor{stroke:rgb(83, 154, 248);fill:rgb(222, 234, 251);stroke-width:1;}#chatgpt-mermaid-_r_26s_ rect.actor.outer-path[data-look=”neo”]{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_26s_ rect.note[data-look=”neo”]{stroke:rgb(107, 198, 127);fill:rgb(243, 243, 243);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_26s_ text.actor>tspan{fill:rgb(13, 13, 13);stroke:none;}#chatgpt-mermaid-_r_26s_ .actor-line{stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_26s_ .innerArc{stroke-width:1.5;stroke-dasharray:none;}#chatgpt-mermaid-_r_26s_ .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_26s_ .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_26s_ [id$=”-arrowhead”] path{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_26s_ .sequenceNumber{fill:#707070;}#chatgpt-mermaid-_r_26s_ [id$=”-sequencenumber”]{fill:rgb(143, 143, 143);}#chatgpt-mermaid-_r_26s_ [id$=”-crosshead”] path{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_26s_ .messageText{fill:rgb(13, 13, 13);stroke:none;}#chatgpt-mermaid-_r_26s_ .labelBox{stroke:rgba(0, 0, 0, 0.1);fill:rgb(252, 252, 252);filter:none;}#chatgpt-mermaid-_r_26s_ .labelText,#chatgpt-mermaid-_r_26s_ .labelText>tspan{fill:rgb(13, 13, 13);stroke:none;}#chatgpt-mermaid-_r_26s_ .loopText,#chatgpt-mermaid-_r_26s_ .loopText>tspan{fill:rgb(13, 13, 13);stroke:none;}#chatgpt-mermaid-_r_26s_ .sectionTitle,#chatgpt-mermaid-_r_26s_ .sectionTitle>tspan{fill:rgb(13, 13, 13);stroke:none;}#chatgpt-mermaid-_r_26s_ .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:rgba(0, 0, 0, 0.1);fill:rgba(0, 0, 0, 0.1);}#chatgpt-mermaid-_r_26s_ .note{stroke:rgb(107, 198, 127);fill:rgb(243, 243, 243);}#chatgpt-mermaid-_r_26s_ .noteText,#chatgpt-mermaid-_r_26s_ .noteText>tspan{fill:rgb(13, 13, 13);stroke:none;font-weight:normal;}#chatgpt-mermaid-_r_26s_ .activation0{fill:rgb(243, 243, 243);stroke:hsl(0, 0%, 85.2941176471%);}#chatgpt-mermaid-_r_26s_ .activation1{fill:rgb(243, 243, 243);stroke:hsl(0, 0%, 85.2941176471%);}#chatgpt-mermaid-_r_26s_ .activation2{fill:rgb(243, 243, 243);stroke:hsl(0, 0%, 85.2941176471%);}#chatgpt-mermaid-_r_26s_ .actorPopupMenu{position:absolute;}#chatgpt-mermaid-_r_26s_ .actorPopupMenuPanel{position:absolute;fill:rgb(222, 234, 251);box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#chatgpt-mermaid-_r_26s_ .actor-man circle,#chatgpt-mermaid-_r_26s_ line{fill:rgb(222, 234, 251);stroke-width:2px;}#chatgpt-mermaid-_r_26s_ g rect.rect{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));stroke:rgb(83, 154, 248);}#chatgpt-mermaid-_r_26s_ .node .neo-node{stroke:rgb(83, 154, 248);}#chatgpt-mermaid-_r_26s_ [data-look=”neo”].node rect,#chatgpt-mermaid-_r_26s_ [data-look=”neo”].cluster rect,#chatgpt-mermaid-_r_26s_ [data-look=”neo”].node polygon{stroke:url(#chatgpt-mermaid-_r_26s_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_26s_ [data-look=”neo”].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_26s_ [data-look=”neo”].node path{stroke:url(#chatgpt-mermaid-_r_26s_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_26s_ [data-look=”neo”].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_26s_ [data-look=”neo”].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_26s_ [data-look=”neo”].node circle{stroke:url(#chatgpt-mermaid-_r_26s_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_26s_ [data-look=”neo”].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_26s_ [data-look=”neo”].icon-shape .icon{fill:url(#chatgpt-mermaid-_r_26s_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_26s_ [data-look=”neo”].icon-shape .icon-neo path{stroke:url(#chatgpt-mermaid-_r_26s_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_26s_ :root{–mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;}Request protected applicationInitiate authenticationAuthenticate through OIDCAuthentication redirectComplete authentication flowEstablish session and evaluate policyAuthorized requestApplication responseReturn response

For a custom OpenID Connect integration, typical setup involves registering an application with the identity provider.

The integration requires values such as the provider or issuer information, a client identifier, a client secret, and approved redirect addresses.

Pomerium exposes corresponding settings such as:

idp_provider: oidc
idp_client_id: REPLACE_WITH_CLIENT_ID
idp_client_secret: REPLACE_WITH_CLIENT_SECRETCode language: HTTP (http)

This is an illustrative configuration fragment, not a complete custom-IdP deployment. A real installation also requires the provider-specific discovery or endpoint settings, authentication-service configuration, and correctly registered redirect URIs.

Use the official instructions for the selected identity provider:Pomerium Authentication and SSO documentation

Do not commit identity-provider client secrets to version control.

21.3 Signed identity assertions and JWT verification

An internal application may need to know which user Pomerium authenticated.

Merely receiving an HTTP header containing a username is not sufficient proof of identity. Headers can be forged by a client unless the architecture establishes a trustworthy way to distinguish them.

Pomerium supports a signed identity assertion, commonly supplied through:

X-Pomerium-Jwt-Assertion: <SIGNED_JWT>Code language: HTML, XML (xml)

The application can verify the signature using Pomerium’s public key and validate important claims.

Generate a signing key

On a machine with OpenSSL installed:

openssl ecparam \
  -genkey \
  -name prime256v1 \
  -noout \
  -out ec_private.pem

openssl ec \
  -in ec_private.pem \
  -pubout \
  -out ec_public.pemCode language: CSS (css)

The private key must remain protected.

After securely mounting the private key in the Pomerium container, configure:

signing_key_file: /pomerium/ec_private.pemCode language: JavaScript (javascript)

On a protected route:

pass_identity_headers: trueCode language: JavaScript (javascript)

An upstream application can retrieve the corresponding verification information from Pomerium’s JSON Web Key Set endpoint.

/.well-known/pomerium/jwks.json

A correct JWT verifier must validate more than the signature: it should also validate the issuer, audience, expiration, and other claims appropriate to the application.

Do not paste production identity tokens into public debugging websites. Pomerium

21.4 TCP and UDP access

Pomerium also supports certain non-HTTP protocols through its client tools.

This is a different workflow from accessing a normal website.

For example, a TCP route may look like:

routes:
  - from: tcp+https://ssh.example.com:22
    to: tcp://ssh.internal.example.com:22

    policy:
      - allow:
          or:
            - email:
                is: engineer@example.comCode language: JavaScript (javascript)

This example assumes the named infrastructure exists and the upstream server is reachable.

A correctly configured client connection might use:

pomerium-cli tcp ssh.example.com:22 \
  --listen 127.0.0.1:2222Code language: CSS (css)

In another terminal, a user can connect through the local forwarded port:

ssh 127.0.0.1 -p 2222Code language: CSS (css)

Important: These commands are not part of the earlier local Verify lab. They require a corresponding TCP route, reachable SSH server, suitable authentication, and the separately installed pomerium-cli.

Pomerium also supports UDP tunneling using the appropriate client and route configuration.

There is a significant security distinction: Pomerium’s documentation states that long-lived TCP and WebSocket connections are authorized when established, and changing the policy does not automatically terminate an existing long-running connection. Plan session termination and revocation accordingly. Pomerium

21.5 Kubernetes integration

In Kubernetes, Pomerium can be deployed using its supported Kubernetes integration and Ingress Controller.

An Ingress resource describes how incoming traffic is routed to a service.

The Pomerium controller integrates protected routing with Kubernetes configuration workflows.

#chatgpt-mermaid-_r_291_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;fill:rgb(13, 13, 13);}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#chatgpt-mermaid-_r_291_ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_291_ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_291_ .error-icon{fill:rgb(243, 243, 243);}#chatgpt-mermaid-_r_291_ .error-text{fill:rgb(13, 13, 13);stroke:rgb(13, 13, 13);}#chatgpt-mermaid-_r_291_ .edge-thickness-normal{stroke-width:1px;}#chatgpt-mermaid-_r_291_ .edge-thickness-thick{stroke-width:3.5px;}#chatgpt-mermaid-_r_291_ .edge-pattern-solid{stroke-dasharray:0;}#chatgpt-mermaid-_r_291_ .edge-thickness-invisible{stroke-width:0;fill:none;}#chatgpt-mermaid-_r_291_ .edge-pattern-dashed{stroke-dasharray:3;}#chatgpt-mermaid-_r_291_ .edge-pattern-dotted{stroke-dasharray:2;}#chatgpt-mermaid-_r_291_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_291_ .marker.cross{stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_291_ svg{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;}#chatgpt-mermaid-_r_291_ p{margin:0;}#chatgpt-mermaid-_r_291_ .label{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_291_ .cluster-label text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_291_ .cluster-label span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_291_ .cluster-label span p{background-color:transparent;}#chatgpt-mermaid-_r_291_ .label text,#chatgpt-mermaid-_r_291_ span{fill:rgb(13, 13, 13);color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_291_ .node rect,#chatgpt-mermaid-_r_291_ .node circle,#chatgpt-mermaid-_r_291_ .node ellipse,#chatgpt-mermaid-_r_291_ .node polygon,#chatgpt-mermaid-_r_291_ .node path{fill:rgb(222, 234, 251);stroke:rgb(83, 154, 248);stroke-width:1px;}#chatgpt-mermaid-_r_291_ .rough-node .label text,#chatgpt-mermaid-_r_291_ .node .label text,#chatgpt-mermaid-_r_291_ .image-shape .label,#chatgpt-mermaid-_r_291_ .icon-shape .label{text-anchor:middle;}#chatgpt-mermaid-_r_291_ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#chatgpt-mermaid-_r_291_ .rough-node .label,#chatgpt-mermaid-_r_291_ .node .label,#chatgpt-mermaid-_r_291_ .image-shape .label,#chatgpt-mermaid-_r_291_ .icon-shape .label{text-align:center;}#chatgpt-mermaid-_r_291_ .node.clickable{cursor:pointer;}#chatgpt-mermaid-_r_291_ .root .anchor path{fill:rgb(143, 143, 143)!important;stroke-width:0;stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_291_ .arrowheadPath{fill:rgb(143, 143, 143);}#chatgpt-mermaid-_r_291_ .edgePath .path{stroke:rgb(143, 143, 143);stroke-width:1px;}#chatgpt-mermaid-_r_291_ .flowchart-link{stroke:rgb(143, 143, 143);fill:none;}#chatgpt-mermaid-_r_291_ .edgeLabel{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_291_ .edgeLabel p{background-color:rgb(252, 252, 252);}#chatgpt-mermaid-_r_291_ .edgeLabel rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_291_ .labelBkg{background-color:rgba(252, 252, 252, 0.5);}#chatgpt-mermaid-_r_291_ .cluster rect{fill:rgb(243, 243, 243);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_291_ .cluster text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_291_ .cluster span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_291_ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:12px;background:rgb(243, 243, 243);border:1px solid rgba(0, 0, 0, 0.1);border-radius:2px;pointer-events:none;z-index:100;}#chatgpt-mermaid-_r_291_ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_291_ rect.text{fill:none;stroke-width:0;}#chatgpt-mermaid-_r_291_ .icon-shape,#chatgpt-mermaid-_r_291_ .image-shape{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_291_ .icon-shape p,#chatgpt-mermaid-_r_291_ .image-shape p{background-color:rgb(252, 252, 252);padding:2px;}#chatgpt-mermaid-_r_291_ .icon-shape .label rect,#chatgpt-mermaid-_r_291_ .image-shape .label rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_291_ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#chatgpt-mermaid-_r_291_ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#chatgpt-mermaid-_r_291_ .node .neo-node{stroke:rgb(83, 154, 248);}#chatgpt-mermaid-_r_291_ [data-look=”neo”].node rect,#chatgpt-mermaid-_r_291_ [data-look=”neo”].cluster rect,#chatgpt-mermaid-_r_291_ [data-look=”neo”].node polygon{stroke:url(#chatgpt-mermaid-_r_291_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_291_ [data-look=”neo”].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_291_ [data-look=”neo”].node path{stroke:url(#chatgpt-mermaid-_r_291_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_291_ [data-look=”neo”].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_291_ [data-look=”neo”].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_291_ [data-look=”neo”].node circle{stroke:url(#chatgpt-mermaid-_r_291_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_291_ [data-look=”neo”].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_291_ [data-look=”neo”].icon-shape .icon{fill:url(#chatgpt-mermaid-_r_291_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_291_ [data-look=”neo”].icon-shape .icon-neo path{stroke:url(#chatgpt-mermaid-_r_291_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_291_ .node text{font-size:14px;font-weight:600;letter-spacing:normal;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_291_ .edgeLabels text{font-size:13px;font-weight:600;letter-spacing:-0.08px;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_291_ .node tspan[font-weight=”normal”],#chatgpt-mermaid-_r_291_ .edgeLabels tspan[font-weight=”normal”]{font-weight:600;}#chatgpt-mermaid-_r_291_ .edgeLabel .label rect{opacity:1;rx:13px;ry:13px;fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-width:1px;}#chatgpt-mermaid-_r_291_ .node rect,#chatgpt-mermaid-_r_291_ .node circle,#chatgpt-mermaid-_r_291_ .node ellipse,#chatgpt-mermaid-_r_291_ .node polygon,#chatgpt-mermaid-_r_291_ .node path{fill:rgb(229, 243, 255);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_291_ .node rect{rx:16px;ry:16px;}#chatgpt-mermaid-_r_291_ .mermaid-decision .label-container{fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-dasharray:2,2;}#chatgpt-mermaid-_r_291_ .edgePaths .flowchart-link{stroke:rgb(143, 143, 143);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;}#chatgpt-mermaid-_r_291_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_291_ :root{–mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;}UserKubernetes external entrypointPomeriumIdentity providerKubernetes ServiceApplication Pods

A realistic Kubernetes deployment must account for service discovery, cluster networking, ingress configuration, persistent state, TLS certificates, and operational monitoring.

The Pomerium Ingress Controller documentation lists Kubernetes, supported CPU architectures, PostgreSQL, and a certificate-management solution among its prerequisites.

Check the requirements for the exact controller release being deployed. Do not install obsolete Kubernetes or PostgreSQL versions simply because they meet an older documented minimum. Pomerium

Official guide:Pomerium Kubernetes installation

21.6 High availability

High availability means designing the system so that an individual component failure does not necessarily interrupt the entire service.

A typical high-availability design includes:

  • Multiple Pomerium replicas.
  • Shared and persistent state where required.
  • A load balancer.
  • Correctly configured health checks.
  • Consistent secrets across replicas.
  • Redundant networking and certificate management.
  • Monitoring and tested recovery procedures.

For a conventional multi-replica Core design, PostgreSQL-backed Databroker storage is an important option.

Simply starting multiple containers with independent in-memory Databrokers is not a correct substitute for shared session state.

21.7 Automatic certificate management

Public deployments can use automated certificate management.

Pomerium Core supports automatic certificates in suitable environments, including configurations using Let’s Encrypt.

A documented configuration key is:

autocert: trueCode language: JavaScript (javascript)

However, enabling that setting alone is not sufficient.

You also need a compatible deployment environment, correctly configured public DNS, certificate issuance connectivity, and the necessary network ports and storage behavior.

The first laboratory intentionally uses mkcert instead because it is local and does not require a publicly reachable server.

21.8 Managing machine access with service accounts

Human users commonly authenticate through interactive browser-based flows.

Automated jobs need a different authentication strategy.

Pomerium Zero and Enterprise provide service-account capabilities for supported machine-to-machine access.

A service account represents a non-human identity that can be authorized by policy.

Service-account credentials must be scoped carefully, stored securely, rotated, and revoked when no longer required.

21.9 Reverse tunneling

Pomerium also documents reverse-tunneling capabilities for situations where Pomerium cannot directly reach an upstream service.

In a reverse-tunnel architecture, an authenticated SSH client establishes an outbound connection to Pomerium and acts as an upstream endpoint.

This can help expose authorized access to services located behind restrictive network boundaries.

It introduces additional trust, key-management, and tunnel-availability responsibilities and should not be treated as a substitute for proper policy enforcement.

The official feature also has runtime configuration requirements and protocol limitations. Pomerium

21.10 Enterprise-scale management

When applications, teams, and policies multiply, management can become a larger challenge than proxying itself.

Pomerium Zero and Enterprise address different aspects of this complexity.

Important capabilities include centralized configuration, managed cluster settings, service accounts, operational visibility, and—depending on the offering—namespace governance, directory synchronization, and administration APIs.

Choose the management model based on organizational requirements rather than assuming that the largest edition is automatically necessary.

Chapter 22. Security Best Practices

Installing Pomerium does not automatically make all protected applications secure.

The complete security design depends on identity management, network architecture, configuration, application security, and operations.

22.1 The security model

Pomerium can enforce an important application access boundary, but the full security chain is broader.

#chatgpt-mermaid-_r_29o_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;fill:rgb(13, 13, 13);}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#chatgpt-mermaid-_r_29o_ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_29o_ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_29o_ .error-icon{fill:rgb(243, 243, 243);}#chatgpt-mermaid-_r_29o_ .error-text{fill:rgb(13, 13, 13);stroke:rgb(13, 13, 13);}#chatgpt-mermaid-_r_29o_ .edge-thickness-normal{stroke-width:1px;}#chatgpt-mermaid-_r_29o_ .edge-thickness-thick{stroke-width:3.5px;}#chatgpt-mermaid-_r_29o_ .edge-pattern-solid{stroke-dasharray:0;}#chatgpt-mermaid-_r_29o_ .edge-thickness-invisible{stroke-width:0;fill:none;}#chatgpt-mermaid-_r_29o_ .edge-pattern-dashed{stroke-dasharray:3;}#chatgpt-mermaid-_r_29o_ .edge-pattern-dotted{stroke-dasharray:2;}#chatgpt-mermaid-_r_29o_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_29o_ .marker.cross{stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_29o_ svg{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;}#chatgpt-mermaid-_r_29o_ p{margin:0;}#chatgpt-mermaid-_r_29o_ .label{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_29o_ .cluster-label text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_29o_ .cluster-label span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_29o_ .cluster-label span p{background-color:transparent;}#chatgpt-mermaid-_r_29o_ .label text,#chatgpt-mermaid-_r_29o_ span{fill:rgb(13, 13, 13);color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_29o_ .node rect,#chatgpt-mermaid-_r_29o_ .node circle,#chatgpt-mermaid-_r_29o_ .node ellipse,#chatgpt-mermaid-_r_29o_ .node polygon,#chatgpt-mermaid-_r_29o_ .node path{fill:rgb(222, 234, 251);stroke:rgb(83, 154, 248);stroke-width:1px;}#chatgpt-mermaid-_r_29o_ .rough-node .label text,#chatgpt-mermaid-_r_29o_ .node .label text,#chatgpt-mermaid-_r_29o_ .image-shape .label,#chatgpt-mermaid-_r_29o_ .icon-shape .label{text-anchor:middle;}#chatgpt-mermaid-_r_29o_ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#chatgpt-mermaid-_r_29o_ .rough-node .label,#chatgpt-mermaid-_r_29o_ .node .label,#chatgpt-mermaid-_r_29o_ .image-shape .label,#chatgpt-mermaid-_r_29o_ .icon-shape .label{text-align:center;}#chatgpt-mermaid-_r_29o_ .node.clickable{cursor:pointer;}#chatgpt-mermaid-_r_29o_ .root .anchor path{fill:rgb(143, 143, 143)!important;stroke-width:0;stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_29o_ .arrowheadPath{fill:rgb(143, 143, 143);}#chatgpt-mermaid-_r_29o_ .edgePath .path{stroke:rgb(143, 143, 143);stroke-width:1px;}#chatgpt-mermaid-_r_29o_ .flowchart-link{stroke:rgb(143, 143, 143);fill:none;}#chatgpt-mermaid-_r_29o_ .edgeLabel{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_29o_ .edgeLabel p{background-color:rgb(252, 252, 252);}#chatgpt-mermaid-_r_29o_ .edgeLabel rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_29o_ .labelBkg{background-color:rgba(252, 252, 252, 0.5);}#chatgpt-mermaid-_r_29o_ .cluster rect{fill:rgb(243, 243, 243);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_29o_ .cluster text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_29o_ .cluster span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_29o_ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:12px;background:rgb(243, 243, 243);border:1px solid rgba(0, 0, 0, 0.1);border-radius:2px;pointer-events:none;z-index:100;}#chatgpt-mermaid-_r_29o_ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_29o_ rect.text{fill:none;stroke-width:0;}#chatgpt-mermaid-_r_29o_ .icon-shape,#chatgpt-mermaid-_r_29o_ .image-shape{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_29o_ .icon-shape p,#chatgpt-mermaid-_r_29o_ .image-shape p{background-color:rgb(252, 252, 252);padding:2px;}#chatgpt-mermaid-_r_29o_ .icon-shape .label rect,#chatgpt-mermaid-_r_29o_ .image-shape .label rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_29o_ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#chatgpt-mermaid-_r_29o_ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#chatgpt-mermaid-_r_29o_ .node .neo-node{stroke:rgb(83, 154, 248);}#chatgpt-mermaid-_r_29o_ [data-look=”neo”].node rect,#chatgpt-mermaid-_r_29o_ [data-look=”neo”].cluster rect,#chatgpt-mermaid-_r_29o_ [data-look=”neo”].node polygon{stroke:url(#chatgpt-mermaid-_r_29o_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_29o_ [data-look=”neo”].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_29o_ [data-look=”neo”].node path{stroke:url(#chatgpt-mermaid-_r_29o_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_29o_ [data-look=”neo”].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_29o_ [data-look=”neo”].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_29o_ [data-look=”neo”].node circle{stroke:url(#chatgpt-mermaid-_r_29o_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_29o_ [data-look=”neo”].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_29o_ [data-look=”neo”].icon-shape .icon{fill:url(#chatgpt-mermaid-_r_29o_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_29o_ [data-look=”neo”].icon-shape .icon-neo path{stroke:url(#chatgpt-mermaid-_r_29o_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_29o_ .node text{font-size:14px;font-weight:600;letter-spacing:normal;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_29o_ .edgeLabels text{font-size:13px;font-weight:600;letter-spacing:-0.08px;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_29o_ .node tspan[font-weight=”normal”],#chatgpt-mermaid-_r_29o_ .edgeLabels tspan[font-weight=”normal”]{font-weight:600;}#chatgpt-mermaid-_r_29o_ .edgeLabel .label rect{opacity:1;rx:13px;ry:13px;fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-width:1px;}#chatgpt-mermaid-_r_29o_ .node rect,#chatgpt-mermaid-_r_29o_ .node circle,#chatgpt-mermaid-_r_29o_ .node ellipse,#chatgpt-mermaid-_r_29o_ .node polygon,#chatgpt-mermaid-_r_29o_ .node path{fill:rgb(229, 243, 255);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_29o_ .node rect{rx:16px;ry:16px;}#chatgpt-mermaid-_r_29o_ .mermaid-decision .label-container{fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-dasharray:2,2;}#chatgpt-mermaid-_r_29o_ .edgePaths .flowchart-link{stroke:rgb(143, 143, 143);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;}#chatgpt-mermaid-_r_29o_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_29o_ :root{–mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;}Trusted identity providerSecure user authenticationCorrect PomeriumauthorizationProtected applicationnetworkApplication-level permissionsMonitoring and incidentresponse

If the identity provider is compromised, permissions are overly broad, or an application has an unprotected alternative entry point, the overall system may still be vulnerable.

Pomerium’s published threat model explicitly identifies several responsibilities outside its protection scope, including the security of trusted third-party identity providers and upstream applications’ own access-control systems. Pomerium

22.2 Insecure practices versus safer alternatives

Insecure practiceRiskSafer alternative
Allow every authenticated user to reach sensitive routesExcessive permissionsExplicit least-privilege route policies
Publish the backend application directlyBypass of PomeriumRestrict backend network reachability
Use the hosted demo authentication service as an assumed production SLAAuthentication dependency riskEvaluate a production IdP and authentication architecture
Store secrets in public Git repositoriesCredential exposureSecret manager or protected runtime injection
Use weak or reused secretsCompromised sessions or servicesIndependent cryptographically random secrets
Disable TLS verificationSusceptibility to interceptionTrusted certificates and correct hostname validation
Use local development certificates in productionInappropriate certificate trustManaged production certificates
Run unreviewed floating container versionsUnexpected changesTested version or digest pinning
Expose metrics or administration endpoints publiclyInformation disclosure or attack surfacePrivate monitoring endpoints
Ignore authentication failuresMissed incidentsLogging, alerts, and investigation
Depend on one instance without recovery planningAvailability riskTested HA or recovery architecture
Rely only on Pomerium for all application permissionsInternal privilege errorsEnforce application-level authorization too

22.3 Protect authentication

Use the identity provider’s appropriate security controls.

Depending on the organization’s requirements, these may include phishing-resistant MFA, managed-device policies, credential lifecycle management, and timely account deprovisioning.

Pomerium’s policies should use identity attributes that are trustworthy and consistently populated.

22.4 Follow least privilege

A good policy grants access only to the people and services that need it.

For example, a production administration portal should not automatically become available to every person with a company email address.

Use specific groups, identities, or contextual conditions when appropriate.

22.5 Protect upstream applications

The gateway cannot protect traffic that bypasses it.

Use private networks, host firewalls, cloud security groups, Kubernetes NetworkPolicies where appropriate, and application-side validation.

If the application trusts Pomerium-supplied identity information, verify the signed assertion rather than blindly trusting arbitrary client-controlled headers.

22.6 Secure secrets and state

Protect:

  • Identity-provider credentials.
  • Shared and cookie secrets.
  • TLS private keys.
  • JWT signing keys.
  • Service-account tokens.
  • Databroker database credentials.

Use access restrictions, backup encryption, credential rotation, and suitable secret-management systems.

22.7 Monitor and patch

Keep Pomerium, Envoy-related dependencies, the container runtime, the operating system, and protected applications updated according to a tested patch-management process.

Monitor security advisories and release notes.

Upgrades should include regression tests for authentication, authorization, session behavior, and upstream routing.

22.8 Security verification checklist

Production security review

0/12Corporate authentication is appropriately securedMFA requirements are establishedSensitive routes use least-privilege policiesNo uncontrolled direct path bypasses PomeriumPublic and internal TLS connections are validatedSecrets are stored securely and rotatedSession expiration and revocation are understoodLogs and metrics have appropriate access controlsPomerium and dependencies are patchedAllow and deny policies have automated testsBackup and recovery procedures are testedApplication-level permissions remain enforced

Completing this checklist supports a review; it is not a substitute for a security assessment or penetration test.

Chapter 23. Production-Ready Pomerium Architecture

The local experiment works on a single computer. Production environments need a more comprehensive design.

23.1 Reference production architecture

#chatgpt-mermaid-_r_2ah_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;fill:rgb(13, 13, 13);}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#chatgpt-mermaid-_r_2ah_ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_2ah_ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_2ah_ .error-icon{fill:rgb(243, 243, 243);}#chatgpt-mermaid-_r_2ah_ .error-text{fill:rgb(13, 13, 13);stroke:rgb(13, 13, 13);}#chatgpt-mermaid-_r_2ah_ .edge-thickness-normal{stroke-width:1px;}#chatgpt-mermaid-_r_2ah_ .edge-thickness-thick{stroke-width:3.5px;}#chatgpt-mermaid-_r_2ah_ .edge-pattern-solid{stroke-dasharray:0;}#chatgpt-mermaid-_r_2ah_ .edge-thickness-invisible{stroke-width:0;fill:none;}#chatgpt-mermaid-_r_2ah_ .edge-pattern-dashed{stroke-dasharray:3;}#chatgpt-mermaid-_r_2ah_ .edge-pattern-dotted{stroke-dasharray:2;}#chatgpt-mermaid-_r_2ah_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_2ah_ .marker.cross{stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_2ah_ svg{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;}#chatgpt-mermaid-_r_2ah_ p{margin:0;}#chatgpt-mermaid-_r_2ah_ .label{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_2ah_ .cluster-label text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_2ah_ .cluster-label span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_2ah_ .cluster-label span p{background-color:transparent;}#chatgpt-mermaid-_r_2ah_ .label text,#chatgpt-mermaid-_r_2ah_ span{fill:rgb(13, 13, 13);color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_2ah_ .node rect,#chatgpt-mermaid-_r_2ah_ .node circle,#chatgpt-mermaid-_r_2ah_ .node ellipse,#chatgpt-mermaid-_r_2ah_ .node polygon,#chatgpt-mermaid-_r_2ah_ .node path{fill:rgb(222, 234, 251);stroke:rgb(83, 154, 248);stroke-width:1px;}#chatgpt-mermaid-_r_2ah_ .rough-node .label text,#chatgpt-mermaid-_r_2ah_ .node .label text,#chatgpt-mermaid-_r_2ah_ .image-shape .label,#chatgpt-mermaid-_r_2ah_ .icon-shape .label{text-anchor:middle;}#chatgpt-mermaid-_r_2ah_ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#chatgpt-mermaid-_r_2ah_ .rough-node .label,#chatgpt-mermaid-_r_2ah_ .node .label,#chatgpt-mermaid-_r_2ah_ .image-shape .label,#chatgpt-mermaid-_r_2ah_ .icon-shape .label{text-align:center;}#chatgpt-mermaid-_r_2ah_ .node.clickable{cursor:pointer;}#chatgpt-mermaid-_r_2ah_ .root .anchor path{fill:rgb(143, 143, 143)!important;stroke-width:0;stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_2ah_ .arrowheadPath{fill:rgb(143, 143, 143);}#chatgpt-mermaid-_r_2ah_ .edgePath .path{stroke:rgb(143, 143, 143);stroke-width:1px;}#chatgpt-mermaid-_r_2ah_ .flowchart-link{stroke:rgb(143, 143, 143);fill:none;}#chatgpt-mermaid-_r_2ah_ .edgeLabel{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_2ah_ .edgeLabel p{background-color:rgb(252, 252, 252);}#chatgpt-mermaid-_r_2ah_ .edgeLabel rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_2ah_ .labelBkg{background-color:rgba(252, 252, 252, 0.5);}#chatgpt-mermaid-_r_2ah_ .cluster rect{fill:rgb(243, 243, 243);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_2ah_ .cluster text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_2ah_ .cluster span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_2ah_ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:12px;background:rgb(243, 243, 243);border:1px solid rgba(0, 0, 0, 0.1);border-radius:2px;pointer-events:none;z-index:100;}#chatgpt-mermaid-_r_2ah_ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_2ah_ rect.text{fill:none;stroke-width:0;}#chatgpt-mermaid-_r_2ah_ .icon-shape,#chatgpt-mermaid-_r_2ah_ .image-shape{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_2ah_ .icon-shape p,#chatgpt-mermaid-_r_2ah_ .image-shape p{background-color:rgb(252, 252, 252);padding:2px;}#chatgpt-mermaid-_r_2ah_ .icon-shape .label rect,#chatgpt-mermaid-_r_2ah_ .image-shape .label rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_2ah_ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#chatgpt-mermaid-_r_2ah_ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#chatgpt-mermaid-_r_2ah_ .node .neo-node{stroke:rgb(83, 154, 248);}#chatgpt-mermaid-_r_2ah_ [data-look=”neo”].node rect,#chatgpt-mermaid-_r_2ah_ [data-look=”neo”].cluster rect,#chatgpt-mermaid-_r_2ah_ [data-look=”neo”].node polygon{stroke:url(#chatgpt-mermaid-_r_2ah_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_2ah_ [data-look=”neo”].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_2ah_ [data-look=”neo”].node path{stroke:url(#chatgpt-mermaid-_r_2ah_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_2ah_ [data-look=”neo”].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_2ah_ [data-look=”neo”].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_2ah_ [data-look=”neo”].node circle{stroke:url(#chatgpt-mermaid-_r_2ah_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_2ah_ [data-look=”neo”].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_2ah_ [data-look=”neo”].icon-shape .icon{fill:url(#chatgpt-mermaid-_r_2ah_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_2ah_ [data-look=”neo”].icon-shape .icon-neo path{stroke:url(#chatgpt-mermaid-_r_2ah_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_2ah_ .node text{font-size:14px;font-weight:600;letter-spacing:normal;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_2ah_ .edgeLabels text{font-size:13px;font-weight:600;letter-spacing:-0.08px;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_2ah_ .node tspan[font-weight=”normal”],#chatgpt-mermaid-_r_2ah_ .edgeLabels tspan[font-weight=”normal”]{font-weight:600;}#chatgpt-mermaid-_r_2ah_ .edgeLabel .label rect{opacity:1;rx:13px;ry:13px;fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-width:1px;}#chatgpt-mermaid-_r_2ah_ .node rect,#chatgpt-mermaid-_r_2ah_ .node circle,#chatgpt-mermaid-_r_2ah_ .node ellipse,#chatgpt-mermaid-_r_2ah_ .node polygon,#chatgpt-mermaid-_r_2ah_ .node path{fill:rgb(229, 243, 255);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_2ah_ .node rect{rx:16px;ry:16px;}#chatgpt-mermaid-_r_2ah_ .mermaid-decision .label-container{fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-dasharray:2,2;}#chatgpt-mermaid-_r_2ah_ .edgePaths .flowchart-link{stroke:rgb(143, 143, 143);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;}#chatgpt-mermaid-_r_2ah_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_2ah_ :root{–mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;}Protected application networkState infrastructurePrivate application access tierMonitoringEngineering toolsAdmin applicationsHighly available PostgreSQLEncrypted backupsPomerium Replica APomerium Replica BEmployees and approvedclientsCorporate DNSHTTPS Load BalancerCorporate IdPCentralized logs and metricsSecrets and certificatemanagement

This is a conceptual deployment reference, not a ready-to-apply production manifest.

It represents an all-in-one Pomerium replica model with shared persistent state and external operational dependencies.

23.2 Production design requirements

AreaEssential concernImplementation direction
IdentitySecure user authenticationCorporate IdP with appropriate MFA
AuthorizationCorrect permissionsTested, least-privilege policies
AvailabilityGateway failuresMultiple replicas where required
Session stateShared persistenceSupported Databroker HA design
TLSEncrypted communicationManaged certificates and trusted upstream TLS
DNSReliable application addressesCorrectly managed corporate domains
SecretsProtection and rotationSecret management platform
LogsOperational and security visibilityCentral collection and retention
MetricsCapacity and error visibilityPrometheus-compatible monitoring
RecoveryRestore after failureTested backup and recovery
UpgradesControlled changesStaging, canary rollout, rollback
Application isolationPrevent bypassPrivate routes and network controls

23.3 Monitoring and alerting

Useful operational signals include:

  • Availability of Pomerium replicas.
  • Readiness and health-check failures.
  • Successful and denied authorization requests.
  • Authentication failures and unusual login patterns.
  • HTTP error-rate changes.
  • Upstream latency and connection failures.
  • Storage connectivity and availability.
  • Resource utilization.
  • Certificate expiration.
  • Configuration deployment failures.

Pomerium exposes Prometheus-compatible metrics. Core deployments require administrators to configure their collection and visualization; Zero and Enterprise provide additional management capabilities. Pomerium

23.4 Backup strategy

A useful backup plan must distinguish between configuration and runtime state.

Configuration backup: Version-control approved policies, route definitions, and deployment manifests.

Persistent state backup: Follow the procedures appropriate to the selected Databroker backend.

Secrets backup: Use protected, organization-approved secret-recovery procedures.

Certificate recovery: Plan certificate renewal and key recovery or replacement as appropriate.

Do not assume that backing up only config.yaml restores every active session or runtime record.

23.5 Upgrading safely

A production upgrade should follow a repeatable process:

  1. Read the new version’s release notes and migration guidance.
  2. Check for breaking changes and security fixes.
  3. Back up applicable configuration and state.
  4. Reproduce the upgrade in staging.
  5. Test authentication, authorization, and upstream routing.
  6. Test both allowed and denied identities.
  7. Deploy with controlled traffic shifting when supported.
  8. Verify health checks, metrics, and logs.
  9. Roll back using the documented procedure if required.

Rollback may be complicated by database or data-format migrations. Verify backward compatibility before relying on a previous image as a recovery strategy.

23.6 Cost considerations

Pomerium Core is open source, but the deployment still consumes resources.

Potential operating costs include compute infrastructure, databases, load balancers, certificates, networking, logging, monitoring, administration, and support.

Pomerium Zero and Enterprise introduce additional product-plan considerations.

Evaluate total operating cost rather than comparing only the software licence price.

23.7 Production-readiness assessment

A deployment is not production-ready simply because the browser login works.

It should demonstrate predictable behavior under normal load, user denial, component failure, expired credentials, configuration changes, and recovery scenarios.

The objective is not zero incidents. It is a system whose behavior, failure modes, and recovery procedures are sufficiently understood and controlled.

Part VIII — Troubleshooting and Mastery

Chapter 24. Common Problems and Solutions

Troubleshooting is one of the most important skills when operating identity-aware access systems.

A good engineer investigates failures systematically rather than repeatedly changing settings without understanding the cause.

24.1 Troubleshooting reference

The error descriptions below represent realistic diagnostic scenarios. Where an exact message has not been independently verified, the wording is illustrative.

Problem or errorLikely causeHow to diagnoseSolutionHow to verify
Docker daemon unavailableDocker engine stoppedCheck Docker statusStart Docker Desktop or Docker EngineRun hello-world
Cannot bind port 443Another process owns the portInspect host listenersFree port or redesign port mappingPomerium starts successfully
Certificate not trustedMissing local CA trustInspect browser certificateReinstall or correct mkcert trustBrowser accepts HTTPS
DNS lookup failsLocal hostname resolution issueResolve hostnameCorrect DNS or local proxy configurationHost resolves to loopback
Pomerium fails to startInvalid configurationInspect logsCorrect YAML or settingsHealth check passes
Authentication redirects repeatedlyCookie, session, IdP, or redirect configuration issueInspect redirect chain and logsCorrect the relevant authentication settingLogin completes
Authorization deniedUser does not satisfy policyCompare identity with route policyCorrect identity or approved policyAllowed user succeeds
502 gateway errorUpstream unreachable or unhealthyCheck upstream status and routeRestore upstream connectivityApplication responds
Shared secret mismatchInconsistent secrets across componentsInspect configuration and secret distributionUse consistent approved secretsHealth and sessions work
Sessions lost after restartEphemeral secrets or stateInspect secrets and Databroker backendConfigure persistent state and stable secretsTest restart
TLS handshake failureCertificate, hostname, protocol, or trust problemInspect TLS configurationFix certificate chain or hostnameSecure connection succeeds
Missing signed identity assertionHeader forwarding or signing configuration incompleteInspect headers and signing-key settingsConfigure required identity assertion settingsUpstream validates JWT
Health check failsInternal component unavailableUse verbose health statusInvestigate the failing componentHealth returns success
Works locally, not remotelyDNS, listener, firewall, or load balancer problemTrace connectivityCorrect deployment networkingApproved remote client connects
Application accessible around PomeriumDirect backend exposureReview all network pathsRestrict backend networkingBypass attempt fails

24.2 Diagnose port conflicts

On Ubuntu or other Linux systems with ss:

sudo ss -ltnp '( sport = :443 )'Code language: JavaScript (javascript)

On macOS:

sudo lsof -nP -iTCP:443 -sTCP:LISTENCode language: CSS (css)

On Windows PowerShell:

Get-NetTCPConnection -LocalPort 443 -State Listen

These commands help identify whether a listener already occupies port 443.

Do not stop an unfamiliar process without understanding what depends on it.

24.3 Diagnose YAML configuration failures

YAML uses indentation to represent structure.

Incorrect indentation can change the meaning of a configuration file.

For example, this is correctly nested:

routes:
  - from: https://portal.localhost.pomerium.io
    to: http://portal:80

    policy:
      - allow:
          or:
            - email:
                is: learner@example.comCode language: JavaScript (javascript)

The policy belongs to the route.

When troubleshooting, check indentation, missing colons, whitespace, and whether the configuration key is valid for the Pomerium release.

Remember that Docker Compose validation alone does not validate the complete Pomerium configuration.

24.4 Diagnose unexpected access denial

A frequent mistake is assuming that successful login means the user should automatically reach the application.

Inspect the route’s policy and the authenticated identity.

For example, a user with email alice@example.org will not satisfy:

policy:
  - allow:
      or:
        - domain:
            is: example.comCode language: CSS (css)

The user authenticated successfully, but the allowed domain is different.

Do not weaken the policy to make the error disappear. Confirm the intended identity and access requirements first.

24.5 Diagnose reverse-proxy errors

If the browser reaches Pomerium but the application does not load, inspect the upstream service.

docker compose ps
docker compose logs --tail=100 portal
docker compose logs --tail=100 pomerium

Verify that the destination in the Pomerium route matches the service name and port.

For example:

to: http://portal:80Code language: JavaScript (javascript)

The name portal must resolve in the container network, and the service must be listening on the expected port.

24.6 Diagnose session persistence

If users are unexpectedly prompted to sign in after restarting Pomerium, inspect the configured secrets and Databroker storage backend.

Stable secrets and persistent state are important, but hosted authentication can still require reauthentication due to its own session lifecycle.

Pomerium documents limitations for its free hosted authentication service, including restricted login options, limited session refresh behavior, and no uptime commitment. Pomerium

24.7 A disciplined incident investigation

Record the following before applying changes:

  1. Exact time of the failure.
  2. Affected hostname and application.
  3. Whether all users or only certain users are affected.
  4. Authentication result.
  5. Authorization result.
  6. Pomerium health status.
  7. Upstream health status.
  8. Relevant configuration changes.
  9. Relevant log and trace information.
  10. The outcome of each corrective action.

This approach makes troubleshooting reproducible and helps prevent repeated incidents.

Chapter 25. Best Practices and Common Mistakes

Good Pomerium operations combine general engineering discipline with practices specific to identity-aware access systems.

25.1 Universal engineering best practices

PracticeWhy it matters
Version-control configurationsSupports review, history, and rollback
Separate development and productionReduces accidental production impact
Test before deploymentDetects configuration and policy errors
Keep dependencies updatedReduces exposure to known vulnerabilities
Monitor systems continuouslyDetects failures and unusual behavior
Protect secretsPrevents credential compromise
Define ownershipEnsures someone maintains every component
Maintain runbooksSupports reliable incident response
Test recoveryConfirms that backups and procedures work

25.2 Pomerium-specific best practices

PracticeWhy it matters
Restrict direct upstream accessPrevents bypassing the identity-aware gateway
Test authorized and denied identitiesConfirms policy behavior
Use trusted identity providersEstablishes reliable authentication
Use independent random secretsProtects sessions and component communication
Verify signed identity assertions when neededPrevents blind trust in identity headers
Choose an appropriate Databroker backendPreserves required state and availability
Keep health endpoints privateProtects operational information
Monitor policy changesDetects unexpected access changes
Understand long-lived connection behaviorSupports realistic revocation planning
Review control-plane responsibilitiesAvoids confusion among Core, Zero, and Enterprise

25.3 Common mistakes beginners should avoid

One mistake is protecting an application with Pomerium while leaving another public address pointing directly to that application.

Another is confusing identity with permission: just because someone has a valid company account does not mean they require access to every engineering tool.

A third is moving directly from a successful Docker demonstration to production without planning certificate management, identity-provider availability, shared state, monitoring, and recovery.

Finally, copying configuration from an older tutorial without checking the current version can introduce deprecated or incompatible behavior.

The correct habit is to use version-matched documentation, test each change, and confirm the observed result.

Chapter 26. Learning Roadmap

The following roadmap organizes your learning into five stages.

The suggested durations are educational estimates, not official Pomerium training requirements.

StageTopicsPractical activityExpected skillSuggested effort
1. FundamentalsZero Trust, proxies, IdP, OAuth, TLSExplain request flow and terminologyConceptual understanding4–6 hours
2. First useDocker, Compose, certificates, routesComplete Verify labIndependent basic deployment4–6 hours
3. Practical proficiencyPPL, multiple routes, sessions, logsComplete Operations Portal projectBasic administration6–10 hours
4. Advanced useOIDC, JWTs, TCP, Kubernetes, HAIntegrate a realistic serviceAdvanced engineering10–16 hours
5. Production readinessSecurity, monitoring, state, upgrades, recoveryDesign and review a production deploymentOperational readiness10–16 hours

Recommended practice schedule

SUGGESTED FIVE-STAGE LEARNING PROGRESSION

  1. Stage 1 — Understand the domainLearn the identity, access, networking, and proxy concepts. Be able to explain why Pomerium is useful without referencing commands.
  2. Stage 2 — Build a working gatewayDeploy Core locally, authenticate, change a policy, and diagnose one deliberate failure.
  3. Stage 3 — Manage multiple applicationsProtect two services with different policies. Introduce persistent state and basic operational checks.
  4. Stage 4 — Integrate with infrastructurePractice corporate identity integration, JWT verification, and at least one additional protocol or deployment environment.
  5. Stage 5 — Design for productionProduce an architecture, security checklist, monitoring strategy, upgrade runbook, and tested recovery plan.

Official learning resources

The following resources are useful for continuing your studies.

ResourceWhat to study
Pomerium documentationProduct overview and capabilities
Official quickstartFirst deployment options
Core fundamentalsStep-by-step beginner lessons
ArchitectureComponents and request flow
AuthorizationPolicies and permissions
Health checksMonitoring runtime health
Security modelThreats and responsibilities
Kubernetes deploymentCluster deployments
Official releasesVersion changes and security fixes
Documentation versionsVersion-matched documentation

Pomerium’s default documentation tracks its rolling main development documentation, with versioned snapshots available. For production work, consult the snapshot appropriate to your deployed release whenever possible. Pomerium

Chapter 27. Exercises and Knowledge Assessment

This chapter tests both conceptual understanding and practical engineering judgment.

Do not look at the answer key until you have attempted the exercises.

27.1 Beginner assessment

Beginner knowledge quiz

0 / 6 answered

1. What does authentication determine?Which application is fastestWho the user isWhich container uses the most memoryWhich IP address should be assigned

2. What is Pomerium primarily?A databaseA compilerAn identity-aware reverse proxyAn operating system

3. What does the ‘from’ field specify in a route?The externally accessed URLThe database usernameThe logging outputThe Docker image

4. If an allow rule and an applicable deny rule both match, what happens?Allow always winsDeny takes precedenceThe request always becomes publicThe user is automatically an administrator

5. What does HTTPS primarily provide?Automatic user authorizationContainer schedulingEncrypted and authenticated transportApplication backups

6. Why must the upstream application be isolated from uncontrolled access?To prevent bypassing PomeriumTo make Docker fasterTo disable DNSTo eliminate configuration files

Check answersReset

27.2 Intermediate exercises

Exercise 7 — Policy implementation

Write a Pomerium policy that allows exactly two authenticated email identities:

alice@example.com
bob@example.comCode language: CSS (css)

Do not allow everyone from the entire domain.

Exercise 8 — Operational troubleshooting

A Pomerium container is running, but the browser cannot reach the protected application.

Identify the first four diagnostic checks you would perform.

Exercise 9 — Session persistence

After restarting Pomerium, a user must authenticate again.

Identify at least two configuration-related factors that may contribute to the problem.

Exercise 10 — Secure the backend

The protected NGINX portal is accessible through Pomerium, but a user can also reach its unprotected public IP address.

Explain why this is a security problem and how you would correct it.

Exercise 11 — Policy verification

A new policy is intended to give production dashboard access to three specific engineers.

Describe a test plan that verifies both successful and denied access.

27.3 Advanced exercises

Exercise 12 — High availability

An engineer deploys three Pomerium replicas, each with independent in-memory Databroker storage.

Explain why this is not a suitable conventional high-availability state architecture and propose an improvement.

Exercise 13 — Identity assertions

A custom application trusts an unsigned X-User-Email header received from the client.

Explain the security issue and describe a safer Pomerium integration.

Exercise 14 — Incident response

An administrator removes a user’s access policy while the user already has a long-lived TCP connection.

Explain what must be considered about the existing connection.

Exercise 15 — Deployment model selection

A company wants to keep application traffic in its own infrastructure but would prefer externally managed configuration.

Which Pomerium deployment model should it evaluate first?

What operational responsibility would remain with the company?

Exercise 16 — Production architecture review

Design a Pomerium deployment for a company with:

  • 1,000 employees.
  • Multiple internal applications.
  • A corporate identity provider.
  • A Kubernetes environment.
  • A high-availability requirement.
  • Centralized logging.

Identify the essential infrastructure components and the top five security controls.

27.4 Answer key and explanations

Intermediate answers

Exercise 7

An appropriate policy is:

policy:
  - allow:
      or:
        - email:
            is: alice@example.com
        - email:
            is: bob@example.comCode language: CSS (css)

This permits either specified identity without permitting the entire email domain.

Exercise 8

Start by checking the running services, gateway logs, local DNS resolution, and HTTPS listener or certificate behavior.

Once those succeed, investigate authentication, authorization, and upstream availability.

Exercise 9

Check whether cryptographic secrets remain stable across restarts and whether the Databroker uses persistent storage.

Also review the authentication provider’s independent session limitations.

Exercise 10

Direct public access bypasses Pomerium’s intended security boundary.

Remove the unprotected public path or enforce appropriate network restrictions, and verify that the backend cannot be reached through an unauthorized route.

Exercise 11

Test all three approved engineers, at least one authenticated but unauthorized identity, and an unauthenticated request.

Also test that access is removed successfully after a policy change.

Advanced answers

Exercise 12

Independent in-memory state does not provide a consistent shared view of sessions and relevant Databroker records.

Use an appropriate supported shared persistent backend, such as PostgreSQL, and design its availability and backup strategy.

Exercise 13

An unsigned client-controlled identity header can be forged.

Use a trusted Pomerium-signed identity assertion, validate its cryptographic signature and claims in the upstream application, and protect the upstream network path.

Exercise 14

Pomerium’s documented behavior for certain long-lived connections evaluates authorization when the connection is established. Existing connections may continue after a policy changes.

Operational controls may be needed to terminate or rotate such connections when access must be revoked promptly.

Exercise 15

Pomerium Zero is a suitable first candidate because it offers a managed control plane while the Core data plane remains in the organization’s environment.

The organization still operates the deployed runtime and remains responsible for applicable networking, application security, and infrastructure controls.

Exercise 16

A suitable conceptual architecture would include a load balancer, multiple Pomerium replicas, corporate identity integration, persistent shared state, protected Kubernetes applications, centralized logs and metrics, certificate management, and secrets management.

Five major controls would include strong authentication, least-privilege authorization, backend isolation, encryption and secret protection, and monitored, tested operational recovery.

This design would still require sizing, threat modeling, and workload-specific validation before production deployment.

Chapter 28. Final Revision and Quick Reference

28.1 Pomerium in one paragraph

Pomerium is an identity-aware reverse proxy that helps control access to protected applications and supported services. It receives application traffic, establishes or validates user identity through an authentication system, evaluates configured access policies, and forwards authorized requests to upstream resources. Pomerium Core provides the open-source execution layer, while Pomerium Zero and Enterprise offer different management approaches and additional capabilities.

28.2 The five most important concepts

ConceptWhat to remember
AuthenticationDetermines who is making the request
AuthorizationDetermines whether the request is permitted
ProxyReceives and forwards protected traffic
RouteDefines the public-facing entry point and backend destination
PolicyDefines the conditions for granting or denying access

28.3 Essential configuration reference

SettingPurpose
routesList of protected routes
fromAddress accessed by the user
toBackend destination
policyAuthorization logic
authenticate_service_urlAuthentication service URL
certificate_fileTLS server certificate
certificate_key_fileTLS private key
shared_secret / SHARED_SECRETInternal shared secret
cookie_secret / COOKIE_SECRETSession cookie protection
databroker_storage_typeDatabroker storage backend
databroker_storage_connection_stringStorage location or connection
log_levelLogging verbosity
pass_identity_headersForward Pomerium identity assertion headers
signing_key_fileSigning key for identity assertions

28.4 Essential command cheat sheet

TaskCommand
Validate Compose syntaxdocker compose config --quiet
Startdocker compose up -d
Show statusdocker compose ps
Show recent logsdocker compose logs --tail=100 pomerium
Follow logsdocker compose logs -f pomerium
Health checkdocker compose exec pomerium pomerium health
Verbose health checkdocker compose exec pomerium pomerium health -v
Restart Pomeriumdocker compose restart pomerium
Show imagesdocker compose images
Stop stackdocker compose down
Start native Pomerium./pomerium -config config.yaml
Pomerium client helppomerium-cli --help

On Linux installations where Docker requires elevated permissions, use the appropriate sudo form for Docker commands.

28.5 Troubleshooting cheat sheet

The diagnostic order to remember

CHECK 1

Container status

Is the process running?

CHECK 2

Gateway reachability

Can HTTPS reach Pomerium?

CHECK 3

Authentication

Can the identity be established?

CHECK 4

Authorization

Does the policy allow access?

CHECK 5

Upstream access

Can Pomerium reach the backend?

CHECK 6

Application health

Can the backend serve the request?

28.6 Security precautions to remember

Always restrict backend access so traffic cannot bypass Pomerium. Use trusted identity sources, maintain narrowly scoped policies, secure secrets, validate transport security and identity assertions, monitor operational behavior, and test access denial as carefully as access success.

A successful login is never sufficient evidence that the full security design is correct.

28.7 Best situations for using Pomerium

Pomerium is particularly useful when an organization wants a central access layer for internal web applications, consistent identity-based route policies, integration with an existing identity provider, or secure access to selected supported services.

It is especially relevant to organizations operating developer and administrative tools across multiple infrastructure environments.

28.8 Situations where another tool may be preferable

A VPN or Tailscale may be preferable when the primary requirement is private device or network connectivity.

Authentik or Keycloak may be more directly relevant when the primary requirement is operating an identity provider.

Teleport may be more appropriate when infrastructure access workflows, SSH governance, and session-oriented controls are the dominant requirement.

Cloudflare Access may be attractive when a cloud-managed application access service better matches the organization’s operational preferences.

28.9 Final mental model

#chatgpt-mermaid-_r_2fk_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;fill:rgb(13, 13, 13);}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#chatgpt-mermaid-_r_2fk_ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_2fk_ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_2fk_ .error-icon{fill:rgb(243, 243, 243);}#chatgpt-mermaid-_r_2fk_ .error-text{fill:rgb(13, 13, 13);stroke:rgb(13, 13, 13);}#chatgpt-mermaid-_r_2fk_ .edge-thickness-normal{stroke-width:1px;}#chatgpt-mermaid-_r_2fk_ .edge-thickness-thick{stroke-width:3.5px;}#chatgpt-mermaid-_r_2fk_ .edge-pattern-solid{stroke-dasharray:0;}#chatgpt-mermaid-_r_2fk_ .edge-thickness-invisible{stroke-width:0;fill:none;}#chatgpt-mermaid-_r_2fk_ .edge-pattern-dashed{stroke-dasharray:3;}#chatgpt-mermaid-_r_2fk_ .edge-pattern-dotted{stroke-dasharray:2;}#chatgpt-mermaid-_r_2fk_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_2fk_ .marker.cross{stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_2fk_ svg{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:16px;}#chatgpt-mermaid-_r_2fk_ p{margin:0;}#chatgpt-mermaid-_r_2fk_ .label{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_2fk_ .cluster-label text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_2fk_ .cluster-label span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_2fk_ .cluster-label span p{background-color:transparent;}#chatgpt-mermaid-_r_2fk_ .label text,#chatgpt-mermaid-_r_2fk_ span{fill:rgb(13, 13, 13);color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_2fk_ .node rect,#chatgpt-mermaid-_r_2fk_ .node circle,#chatgpt-mermaid-_r_2fk_ .node ellipse,#chatgpt-mermaid-_r_2fk_ .node polygon,#chatgpt-mermaid-_r_2fk_ .node path{fill:rgb(222, 234, 251);stroke:rgb(83, 154, 248);stroke-width:1px;}#chatgpt-mermaid-_r_2fk_ .rough-node .label text,#chatgpt-mermaid-_r_2fk_ .node .label text,#chatgpt-mermaid-_r_2fk_ .image-shape .label,#chatgpt-mermaid-_r_2fk_ .icon-shape .label{text-anchor:middle;}#chatgpt-mermaid-_r_2fk_ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#chatgpt-mermaid-_r_2fk_ .rough-node .label,#chatgpt-mermaid-_r_2fk_ .node .label,#chatgpt-mermaid-_r_2fk_ .image-shape .label,#chatgpt-mermaid-_r_2fk_ .icon-shape .label{text-align:center;}#chatgpt-mermaid-_r_2fk_ .node.clickable{cursor:pointer;}#chatgpt-mermaid-_r_2fk_ .root .anchor path{fill:rgb(143, 143, 143)!important;stroke-width:0;stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_2fk_ .arrowheadPath{fill:rgb(143, 143, 143);}#chatgpt-mermaid-_r_2fk_ .edgePath .path{stroke:rgb(143, 143, 143);stroke-width:1px;}#chatgpt-mermaid-_r_2fk_ .flowchart-link{stroke:rgb(143, 143, 143);fill:none;}#chatgpt-mermaid-_r_2fk_ .edgeLabel{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_2fk_ .edgeLabel p{background-color:rgb(252, 252, 252);}#chatgpt-mermaid-_r_2fk_ .edgeLabel rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_2fk_ .labelBkg{background-color:rgba(252, 252, 252, 0.5);}#chatgpt-mermaid-_r_2fk_ .cluster rect{fill:rgb(243, 243, 243);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_2fk_ .cluster text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_2fk_ .cluster span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_2fk_ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;font-size:12px;background:rgb(243, 243, 243);border:1px solid rgba(0, 0, 0, 0.1);border-radius:2px;pointer-events:none;z-index:100;}#chatgpt-mermaid-_r_2fk_ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_2fk_ rect.text{fill:none;stroke-width:0;}#chatgpt-mermaid-_r_2fk_ .icon-shape,#chatgpt-mermaid-_r_2fk_ .image-shape{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_2fk_ .icon-shape p,#chatgpt-mermaid-_r_2fk_ .image-shape p{background-color:rgb(252, 252, 252);padding:2px;}#chatgpt-mermaid-_r_2fk_ .icon-shape .label rect,#chatgpt-mermaid-_r_2fk_ .image-shape .label rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_2fk_ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#chatgpt-mermaid-_r_2fk_ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#chatgpt-mermaid-_r_2fk_ .node .neo-node{stroke:rgb(83, 154, 248);}#chatgpt-mermaid-_r_2fk_ [data-look=”neo”].node rect,#chatgpt-mermaid-_r_2fk_ [data-look=”neo”].cluster rect,#chatgpt-mermaid-_r_2fk_ [data-look=”neo”].node polygon{stroke:url(#chatgpt-mermaid-_r_2fk_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_2fk_ [data-look=”neo”].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_2fk_ [data-look=”neo”].node path{stroke:url(#chatgpt-mermaid-_r_2fk_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_2fk_ [data-look=”neo”].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_2fk_ [data-look=”neo”].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_2fk_ [data-look=”neo”].node circle{stroke:url(#chatgpt-mermaid-_r_2fk_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_2fk_ [data-look=”neo”].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_2fk_ [data-look=”neo”].icon-shape .icon{fill:url(#chatgpt-mermaid-_r_2fk_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_2fk_ [data-look=”neo”].icon-shape .icon-neo path{stroke:url(#chatgpt-mermaid-_r_2fk_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_2fk_ .node text{font-size:14px;font-weight:600;letter-spacing:normal;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_2fk_ .edgeLabels text{font-size:13px;font-weight:600;letter-spacing:-0.08px;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_2fk_ .node tspan[font-weight=”normal”],#chatgpt-mermaid-_r_2fk_ .edgeLabels tspan[font-weight=”normal”]{font-weight:600;}#chatgpt-mermaid-_r_2fk_ .edgeLabel .label rect{opacity:1;rx:13px;ry:13px;fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-width:1px;}#chatgpt-mermaid-_r_2fk_ .node rect,#chatgpt-mermaid-_r_2fk_ .node circle,#chatgpt-mermaid-_r_2fk_ .node ellipse,#chatgpt-mermaid-_r_2fk_ .node polygon,#chatgpt-mermaid-_r_2fk_ .node path{fill:rgb(229, 243, 255);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_2fk_ .node rect{rx:16px;ry:16px;}#chatgpt-mermaid-_r_2fk_ .mermaid-decision .label-container{fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-dasharray:2,2;}#chatgpt-mermaid-_r_2fk_ .edgePaths .flowchart-link{stroke:rgb(143, 143, 143);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;}#chatgpt-mermaid-_r_2fk_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_2fk_ :root{–mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,”Segoe UI”,Helvetica,”Apple Color Emoji”,Arial,sans-serif,”Segoe UI Emoji”,”Segoe UI Symbol”;}Who are you?What may you access?Which application?Authorized connectionApplication responseAuthenticationAuthorizationRouting

When learning Pomerium, return to these questions whenever a configuration or architecture becomes complicated.

If you understand how identity is established, how policy decisions are made, how requests are routed, and how the system behaves during failure, you understand the essential Pomerium operating model.

Course completion

You have now covered all 28 chapters of the learning blueprint, progressing from the foundational security domain through Pomerium architecture, installation, configuration, practical deployment, advanced capabilities, operations, and assessment.

The most valuable next step is to complete the Chapter 15 lab and Chapter 20 project on a real machine, deliberately test both authorized and denied access, and practice recovering from failures. The tutorial provides the procedures and expected behavior; a successful execution in your own environment is what turns that knowledge into practical proficiency.

Find Trusted Cardiac Hospitals

Compare heart hospitals by city and services — all in one place.

Explore Hospitals
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.

Related Posts

Business Excellence and Organizational Maturity: How to Choose the Right Framework

An organization may have a strong strategy and weak execution, disciplined operations and weak workforce development, or reliable project delivery and poor data quality. No single framework…

Read More

An Integrated Organizational Excellence Playbook: From Diagnostic Assessment to Sustainable Improvement

The nine frameworks described in this series address different organizational capabilities. The challenge for leaders is to use them coherently rather than launching nine unrelated maturity programs….

Read More

EFQM Model Explained: A Practical Guide to Organizational Excellence, RADAR Assessment, and Sustainable Performance

A business can meet its quarterly targets and still be heading in the wrong direction. Customer satisfaction might be falling while revenue rises. Employees might deliver exceptional…

Read More

People CMM: A Complete Guide to Workforce Maturity, Competency Development, and Organizational Capability

Organizations often claim that people are their most important asset, yet rely on inconsistent hiring decisions, unclear expectations, informal career development, and managers who have never been…

Read More

P3M3 Explained: Assess Portfolio, Programme, and Project Management Across Five Maturity Levels

Why do some organizations repeatedly deliver successful changes while others depend on last-minute escalation and individual heroics? The answer is rarely just the talent of project managers….

Read More

OPM3 Explained: Assess and Improve Organizational Project Management from Strategy to Results

An organization can deliver individual projects successfully while failing to achieve its strategy. A software launch may finish on schedule even though customers do not adopt it….

Read More
Subscribe
Notify of
guest
0 Comments
Newest
Oldest Most Voted
0
Would love your thoughts, please comment.x
()
x