{"id":79542,"date":"2026-10-28T06:22:37","date_gmt":"2026-10-28T06:22:37","guid":{"rendered":"https:\/\/www.devopsschool.com\/blog\/?p=79542"},"modified":"2026-10-28T06:22:39","modified_gmt":"2026-10-28T06:22:39","slug":"the-complete-pomerium-tutorial-from-absolute-beginner-to-advanced-zero-trust-access-engineering","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/the-complete-pomerium-tutorial-from-absolute-beginner-to-advanced-zero-trust-access-engineering\/","title":{"rendered":"The Complete Pomerium Tutorial: From Absolute Beginner to Advanced Zero Trust Access Engineering"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Course overview<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This tutorial teaches the underlying technology first, then Pomerium, then hands-on implementation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Beginner \u2192 Advanced<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">28 Chapters<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Practical labs<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Primary technology<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Zero Trust Network Access (ZTNA), Identity-Aware Proxy (IAP), Access Management<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Learning environment<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Windows, Ubuntu, macOS, Docker, and applicable Linux distributions<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Learning approach<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Concepts, diagrams, experiments, configurations, labs, troubleshooting, and assessments<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Final outcome<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Design, deploy, secure, operate, and troubleshoot Pomerium independently<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Research and version baseline<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Official documentation and release information checked: October 28, 2026.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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 (<code>darwin\/amd64<\/code>) binary support. GitHub+1<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The course primarily uses:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Pomerium Core for self-managed, open-source experiments.<\/li>\n\n\n\n<li>Docker Compose for a consistent local environment.<\/li>\n\n\n\n<li>Pomerium&#8217;s hosted authentication service for the first experiments, avoiding the need to configure your own identity provider immediately.<\/li>\n\n\n\n<li>Realistic access policies and private demo applications.<\/li>\n\n\n\n<li>Enterprise and cloud-managed deployment models when discussing larger environments.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The local examples are educational rather than production-ready defaults. Production changes are introduced separately and explicitly.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Part I \u2014 Understand the World Before the Tool<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 1. The Big Picture<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">1.1 Imagine a company with many internal applications<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Suppose a company has 500 employees using several internal systems:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Application<\/th><th>Purpose<\/th><th>Who should access it?<\/th><\/tr><tr><td>Grafana<\/td><td>Monitoring dashboards<\/td><td>DevOps and SRE teams<\/td><\/tr><tr><td>Jenkins<\/td><td>Continuous Integration\/Continuous Delivery<\/td><td>Authorized developers<\/td><\/tr><tr><td>Internal Admin Portal<\/td><td>Company administration<\/td><td>Administrators<\/td><\/tr><tr><td>Kubernetes Dashboard<\/td><td>Cluster management<\/td><td>Platform engineers<\/td><\/tr><tr><td>Internal Wiki<\/td><td>Documentation<\/td><td>Employees<\/td><\/tr><tr><td>Database Management UI<\/td><td>Database administration<\/td><td>Database administrators<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">These applications might run on company servers, Amazon Web Services (AWS), Microsoft Azure, Google Cloud, or Kubernetes clusters.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The company must answer some important questions:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>How can employees access these applications securely from home, an office, or while traveling?<\/li>\n\n\n\n<li>How does the company know who is connecting?<\/li>\n\n\n\n<li>How can it allow developers to access Jenkins but not the finance administration portal?<\/li>\n\n\n\n<li>How can it remove access when an employee leaves?<\/li>\n\n\n\n<li>How can it establish a central record of application access?<\/li>\n\n\n\n<li>Can it avoid giving employees access to an entire private network?<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">These are identity, access management, and application security problems.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">1.2 The traditional approach: Virtual Private Networks<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Historically, many companies used a Virtual Private Network (VPN).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A VPN creates an encrypted connection between a user&#8217;s device and a private network.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Imagine the company&#8217;s private network as an office building.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Traditional remote-access concept<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">EmployeeRemote laptop<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">VPNNetwork tunnel<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Private networkInternal resources<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A VPN provides network connectivity. Additional controls are still necessary to restrict which resources the user can reach.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">VPNs are useful, but several operational challenges can arise:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Users typically need VPN client software.<\/li>\n\n\n\n<li>Administrators must manage VPN connectivity and client configurations.<\/li>\n\n\n\n<li>Network access may be broader than necessary.<\/li>\n\n\n\n<li>Applications may each have separate login systems.<\/li>\n\n\n\n<li>Security teams need additional mechanisms to manage fine-grained application permissions.<\/li>\n\n\n\n<li>A compromised device may gain access to network services that were not intended for that user.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">1.3 The modern approach: Zero Trust<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instead, access decisions consider identity, permissions, and other relevant conditions.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, a user wants to open an internal dashboard.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The system can ask:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Who is the user?<\/li>\n\n\n\n<li>Has the user authenticated?<\/li>\n\n\n\n<li>Is the user allowed to access this application?<\/li>\n\n\n\n<li>Is the session still valid?<\/li>\n\n\n\n<li>Do any additional access restrictions apply?<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The National Institute of Standards and Technology (NIST) describes these principles in Special Publication 800-207, Zero Trust Architecture. CSRC<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">1.4 The office security analogy<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Compare two ways of securing an office building.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Traditional perimeter security: A guard checks someone at the front entrance. Inside, additional permissions depend on locks and other controls.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium acts like a central access checkpoint for the applications it protects.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The actual technology is more precise than the analogy: Pomerium validates user sessions, evaluates configured policies, and forwards authorized requests to the correct service.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">1.5 Where Pomerium fits<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">#chatgpt-mermaid-_r_1e3_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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=&#8221;neo&#8221;].node rect,#chatgpt-mermaid-_r_1e3_ [data-look=&#8221;neo&#8221;].cluster rect,#chatgpt-mermaid-_r_1e3_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_1e3_ [data-look=&#8221;neo&#8221;].node path{stroke:url(#chatgpt-mermaid-_r_1e3_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_1e3_ [data-look=&#8221;neo&#8221;].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1e3_ [data-look=&#8221;neo&#8221;].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_1e3_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_1e3_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].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=&#8221;normal&#8221;],#chatgpt-mermaid-_r_1e3_ .edgeLabels tspan[font-weight=&#8221;normal&#8221;]{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{&#8211;mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;}Employee opens an internalweb applicationPomerium receives therequestIdentity is verifiedIs access permitted?Application receives therequestAccess deniedYesNo<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">What happens here?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The employee requests an application through a Pomerium-protected address. Pomerium establishes or validates the user&#8217;s identity and evaluates an authorization policy.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Only an authorized request is forwarded to the protected application.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This allows access decisions to focus on the individual application rather than granting general network connectivity.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">1.6 Who uses Pomerium?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium is particularly relevant to platform engineering, DevOps, Site Reliability Engineering (SRE), cybersecurity, identity and access management, and internal application development teams.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It is useful for protecting web-based tools, internal administrative interfaces, developer services, monitoring tools, and other supported services.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What You Should Understand Before Moving On<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium addresses application access rather than simply providing network connectivity.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The central idea is:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Verify identity, evaluate permission, and grant access only to the requested resource.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 2. Prerequisite Concepts<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Before learning Pomerium itself, understand the concepts that make its behavior possible.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2.1 Authentication versus authorization<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">These two concepts are fundamental.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Authentication answers:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Who are you?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Examples include signing in with a password, using a security key, or completing multifactor authentication.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Authorization answers:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">What are you allowed to access or do?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">An authenticated employee might be allowed to read internal documentation but forbidden from accessing production administration tools.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Concept<\/th><th>Simple definition<\/th><th>Analogy<\/th><th>Practical example<\/th><th>Importance<\/th><\/tr><tr><td>Authentication<\/td><td>Proving identity<\/td><td>Showing an ID card<\/td><td>Signing in with Google<\/td><td>Essential<\/td><\/tr><tr><td>Authorization<\/td><td>Checking permission<\/td><td>Checking room access<\/td><td>Allowing only administrators into Grafana<\/td><td>Essential<\/td><\/tr><tr><td>Identity Provider<\/td><td>System that authenticates users<\/td><td>ID issuing office<\/td><td>Microsoft Entra ID, Okta<\/td><td>Essential<\/td><\/tr><tr><td>Single Sign-On<\/td><td>Reusing one login across applications<\/td><td>One identity badge<\/td><td>Corporate login for several tools<\/td><td>Essential<\/td><\/tr><tr><td>Reverse Proxy<\/td><td>Server that receives requests and forwards them to other servers<\/td><td>Reception desk<\/td><td>Pomerium forwarding traffic to Grafana<\/td><td>Essential<\/td><\/tr><tr><td>Zero Trust<\/td><td>Avoiding implicit trust based only on network position<\/td><td>Check each protected doorway<\/td><td>Verify access to every protected application<\/td><td>Essential<\/td><\/tr><tr><td>Access policy<\/td><td>Rules determining access<\/td><td>Entry requirements<\/td><td>Allow selected email addresses<\/td><td>Essential<\/td><\/tr><tr><td>TLS<\/td><td>Encryption and server authentication for network connections<\/td><td>Protected communication channel<\/td><td>HTTPS<\/td><td>Essential<\/td><\/tr><tr><td>DNS<\/td><td>Resolves names to network addresses<\/td><td>Address directory<\/td><td>Finding an application&#8217;s server IP<\/td><td>Essential<\/td><\/tr><tr><td>Container<\/td><td>Packaged application running in an isolated environment<\/td><td>Separate application workspace<\/td><td>Docker container<\/td><td>Helpful<\/td><\/tr><tr><td>Kubernetes<\/td><td>Platform for running and managing containerized applications<\/td><td>Automated operations coordinator<\/td><td>Managing Pomerium replicas<\/td><td>Advanced<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">2.2 How a website request works<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">When someone types an address such as <code>https:\/\/dashboard.example.com<\/code>, several things happen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">First, the browser resolves the hostname to an Internet Protocol (IP) address, normally through the Domain Name System (DNS).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Next, the browser establishes a network connection.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Finally, the server processes the request and returns an HTTP response.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium can sit between the browser and the actual application server.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2.3 Forward proxy versus reverse proxy<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A forward proxy usually acts on behalf of clients that want to connect to other systems.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A reverse proxy acts as the entry point to one or more backend services.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium is primarily a reverse proxy, with additional identity and policy enforcement functionality.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">Browser\n   |\n   | HTTPS request\n   v\nPomerium\n   |\n   | Authorized upstream request\n   v\nGrafana<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The word upstream refers to the service behind Pomerium. Downstream refers to the client side of the connection.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2.4 Identity providers and Single Sign-On<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">An Identity Provider (IdP) is a trusted system that authenticates users.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Examples include:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Microsoft Entra ID<\/li>\n\n\n\n<li>Okta<\/li>\n\n\n\n<li>Google identity services<\/li>\n\n\n\n<li>Authentik<\/li>\n\n\n\n<li>Keycloak<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">A user can authenticate through the identity provider rather than managing an independent password inside every protected application.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium then uses identity information to evaluate access policies.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2.5 OAuth 2.0 and OpenID Connect<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Two standards frequently appear in Pomerium documentation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">OAuth 2.0 is an authorization framework for delegated access. It enables applications to obtain access tokens with defined permissions.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>The browser attempts to access a protected service.<\/li>\n\n\n\n<li>The user is redirected to an identity provider.<\/li>\n\n\n\n<li>The user signs in.<\/li>\n\n\n\n<li>The identity provider returns the appropriate authentication result through the protocol.<\/li>\n\n\n\n<li>Pomerium establishes a session and evaluates access policy.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">The learner does not need to implement OAuth 2.0 manually to complete the first Pomerium laboratory.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2.6 Cookies, sessions, and tokens<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">These concepts are related but different.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A cookie is a small piece of information stored by a browser and sent to a website according to cookie rules.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A session represents the ongoing authenticated relationship between a user and a system.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A token is information used to represent identity, authorization, or other claims.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">One common token format is a JavaScript Object Notation Web Token, normally abbreviated as JSON Web Token (JWT).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">JWTs can contain digitally signed claims, such as the issuer, intended audience, identity, or expiration.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A signed JWT is not automatically encrypted. Systems must validate its signature and important claims before trusting it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium uses sessions and identity information as part of its access decision workflow.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2.7 Docker and Docker Compose<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A Docker image is a packaged definition of application software and its environment.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A container is a running instance of an image.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Docker Compose lets you describe multiple cooperating containers in one configuration file.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, our laboratory will use separate containers for Pomerium and a demo application.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Docker Compose allows us to start both without manually installing a web server into the host operating system.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2.8 Essential versus optional prerequisites<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For the first laboratory, you only need basic computer skills, a browser, a terminal, and the ability to install Docker.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Understanding DNS, HTTPS, authentication, and YAML configuration is essential conceptually, but the examples below will teach them as they are used.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Kubernetes, PostgreSQL, custom identity-provider administration, public certificates, and distributed deployment are advanced topics. They are not prerequisites for first success.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 3. Essential Terminology and Glossary<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">3.1 Beginner terminology<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Term<\/th><th>Full form<\/th><th>Simple meaning<\/th><th>Example<\/th><th>Why it matters<\/th><\/tr><tr><td>IAP<\/td><td>Identity-Aware Proxy<\/td><td>Proxy that uses identity to control access<\/td><td>Pomerium<\/td><td>Main tool category<\/td><\/tr><tr><td>ZTNA<\/td><td>Zero Trust Network Access<\/td><td>Identity- and policy-based access to resources<\/td><td>Restricted internal apps<\/td><td>Security design<\/td><\/tr><tr><td>IdP<\/td><td>Identity Provider<\/td><td>Service responsible for authenticating users<\/td><td>Okta<\/td><td>Establishes identity<\/td><\/tr><tr><td>SSO<\/td><td>Single Sign-On<\/td><td>Login reused across services<\/td><td>Corporate login<\/td><td>Simplifies access<\/td><\/tr><tr><td>MFA<\/td><td>Multifactor Authentication<\/td><td>Multiple ways of proving identity<\/td><td>Password plus passkey<\/td><td>Stronger authentication<\/td><\/tr><tr><td>HTTP<\/td><td>Hypertext Transfer Protocol<\/td><td>Web request protocol<\/td><td>GET request<\/td><td>Application communication<\/td><\/tr><tr><td>HTTPS<\/td><td>HTTP Secure<\/td><td>HTTP over TLS<\/td><td>Secure web application<\/td><td>Encrypted communication<\/td><\/tr><tr><td>TLS<\/td><td>Transport Layer Security<\/td><td>Secure network communication protocol<\/td><td>HTTPS connection<\/td><td>Protects data in transit<\/td><\/tr><tr><td>DNS<\/td><td>Domain Name System<\/td><td>Maps hostnames to addresses<\/td><td><code>app.example.com<\/code><\/td><td>Routing<\/td><\/tr><tr><td>URL<\/td><td>Uniform Resource Locator<\/td><td>Address identifying a resource<\/td><td><code>https:\/\/app.example.com<\/code><\/td><td>Route identification<\/td><\/tr><tr><td>Proxy<\/td><td>Intermediary server<\/td><td>Receives and forwards requests<\/td><td>Pomerium<\/td><td>Main traffic component<\/td><\/tr><tr><td>Upstream<\/td><td>Backend receiving proxied traffic<\/td><td>Protected application<\/td><td>Grafana<\/td><td>Routing destination<\/td><\/tr><tr><td>Route<\/td><td>Mapping from an external address to a backend<\/td><td>Application mapping<\/td><td>App URL \u2192 service<\/td><td>Essential configuration<\/td><\/tr><tr><td>Policy<\/td><td>Rule controlling permitted access<\/td><td>Allow selected users<\/td><td>Email restriction<\/td><td>Core security function<\/td><\/tr><tr><td>Session<\/td><td>Authenticated interaction state<\/td><td>Logged-in browser session<\/td><td>Login session<\/td><td>Tracks authentication<\/td><\/tr><tr><td>YAML<\/td><td>YAML Ain&#8217;t Markup Language<\/td><td>Human-readable configuration format<\/td><td><code>config.yaml<\/code><\/td><td>Configuration<\/td><\/tr><tr><td>CLI<\/td><td>Command-Line Interface<\/td><td>Text-based interaction with software<\/td><td><code>docker compose<\/code><\/td><td>Operations<\/td><\/tr><tr><td>Container<\/td><td>Isolated application environment<\/td><td>Running Docker image<\/td><td>Pomerium container<\/td><td>Local deployment<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">3.2 Intermediate and advanced terminology<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">| Term | Full form | Simple meaning | Example | Why it matters |<br>|&#8212;|&#8212;|&#8212;|&#8212;|&#8212;|<br>| OIDC | OpenID Connect | Standard identity protocol | Corporate SSO | Authentication |<br>| OAuth 2.0 | OAuth authorization framework | Delegated authorization protocol | Token-based integration | Identity integrations |<br>| JWT | JSON Web Token | Structured claims in a token | Signed identity assertion | Identity validation |<br>| JWKS | JSON Web Key Set | Published cryptographic verification keys | JWT signature verification | Application trust |<br>| PPL | Pomerium Policy Language | Language for access policies | Email or group rule | Authorization |<br>| RBAC | Role-Based Access Control | Permissions based on roles | Admin versus viewer | Governance |<br>| ABAC | Attribute-Based Access Control | Permissions based on attributes | Team and device conditions | Fine-grained policies |<br>| gRPC | Google-originated Remote Procedure Call framework | Protocol for service communication | Proxy to Authorize | Internal architecture |<br>| Databroker | Pomerium state-management component | Stores sessions and related data | User session records | State management |<br>| Envoy | High-performance proxy software | Handles network proxy traffic | Pomerium&#8217;s proxy engine | Underlying architecture |<br>| mTLS | Mutual Transport Layer Security | Both peers authenticate with certificates | Secure service connections | Stronger transport trust |<br>| CA | Certificate Authority | Entity that issues trusted certificates | Internal CA | TLS certificate trust |<br>| HA | High Availability | Design that tolerates component failure | Multiple replicas | Production reliability |<br>| Observability | Understanding system behavior through telemetry | Logs and metrics | Debugging failed logins | Operations |<br>| Data plane | Components processing application traffic | Pomerium Core proxy services | Request processing |<br>| Control plane | System managing configuration and policy | Pomerium Zero | Configuration management |<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">3.3 Commonly confused terms<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>These are different<\/th><th>Main distinction<\/th><\/tr><tr><td>Authentication vs authorization<\/td><td>Identity verification vs permission checking<\/td><\/tr><tr><td>VPN vs IAP<\/td><td>Network connectivity vs application-aware access gateway<\/td><\/tr><tr><td>Identity Provider vs Pomerium<\/td><td>Authenticates identities vs enforces application access<\/td><\/tr><tr><td>HTTP vs HTTPS<\/td><td>Web protocol vs its TLS-protected form<\/td><\/tr><tr><td>Session vs JWT<\/td><td>Authenticated state vs a token format<\/td><\/tr><tr><td>Proxy vs load balancer<\/td><td>Request interception and processing vs traffic distribution; functions can overlap<\/td><\/tr><tr><td>Pomerium Core vs Pomerium Zero<\/td><td>Self-managed data plane and configuration vs managed control plane<\/td><\/tr><tr><td>Container vs virtual machine<\/td><td>Application-level isolation vs virtualized operating-system environments<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">A useful habit is to distinguish identity, permission, network connectivity, and application behavior when diagnosing an access problem. They are different layers.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 4. How the Technology Domain Works Without Pomerium<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">4.1 A company builds its own access architecture<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Imagine a small engineering team running an internal dashboard.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Without Pomerium, the team might implement access control using the dashboard&#8217;s own authentication system, a VPN, an application gateway, or several individually managed security components.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A basic system could look like this:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">#chatgpt-mermaid-_r_1ef_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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=&#8221;neo&#8221;].node rect,#chatgpt-mermaid-_r_1ef_ [data-look=&#8221;neo&#8221;].cluster rect,#chatgpt-mermaid-_r_1ef_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_1ef_ [data-look=&#8221;neo&#8221;].node path{stroke:url(#chatgpt-mermaid-_r_1ef_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_1ef_ [data-look=&#8221;neo&#8221;].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1ef_ [data-look=&#8221;neo&#8221;].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_1ef_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_1ef_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].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=&#8221;normal&#8221;],#chatgpt-mermaid-_r_1ef_ .edgeLabels tspan[font-weight=&#8221;normal&#8221;]{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{&#8211;mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;}EmployeeVPN or network gatewayInternal applicationIdentity providerApplication permissionsApplication data<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The diagram represents a possible architecture, not a claim that every VPN deployment works exactly this way.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The employee first obtains connectivity to the internal network. The application then authenticates the employee and decides whether to allow the requested operation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If the organization has ten applications, each may need its own identity integration, session handling, and authorization model.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This can become operationally complicated, especially when some applications lack modern authentication features.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">4.2 How an application determines access<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Suppose an employee wants to view a monitoring dashboard.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The process may involve:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Resolving the dashboard hostname.<\/li>\n\n\n\n<li>Establishing network connectivity.<\/li>\n\n\n\n<li>Connecting to the application&#8217;s HTTPS endpoint.<\/li>\n\n\n\n<li>Providing login credentials or using SSO.<\/li>\n\n\n\n<li>Establishing an authenticated session.<\/li>\n\n\n\n<li>Evaluating application-specific permissions.<\/li>\n\n\n\n<li>Returning the requested dashboard data.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">If any stage fails, the application cannot complete the request successfully.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">4.3 What a centralized application access gateway changes<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Now introduce the idea of a centralized gateway without focusing on a particular product.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">#chatgpt-mermaid-_r_1em_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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=&#8221;neo&#8221;].node rect,#chatgpt-mermaid-_r_1em_ [data-look=&#8221;neo&#8221;].cluster rect,#chatgpt-mermaid-_r_1em_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_1em_ [data-look=&#8221;neo&#8221;].node path{stroke:url(#chatgpt-mermaid-_r_1em_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_1em_ [data-look=&#8221;neo&#8221;].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1em_ [data-look=&#8221;neo&#8221;].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_1em_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_1em_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].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=&#8221;normal&#8221;],#chatgpt-mermaid-_r_1em_ .edgeLabels tspan[font-weight=&#8221;normal&#8221;]{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{&#8211;mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;}Employee browserIdentity-aware accessgatewayCorporate identity providerCentral access policyPrivate applicationRequests applicationAuthenticate identityIdentity resultEvaluate permissionAllow or denyOnly authorized requests<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This architecture moves an important part of the access decision out of each application and into a shared gateway.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The application can remain on a private network, provided users cannot bypass the gateway to reach it directly.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">4.4 Universal concepts versus product-specific implementation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The following ideas are not unique to Pomerium:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Identity-based authentication<\/li>\n\n\n\n<li>Access policies<\/li>\n\n\n\n<li>HTTPS and TLS<\/li>\n\n\n\n<li>Reverse proxies<\/li>\n\n\n\n<li>User sessions<\/li>\n\n\n\n<li>Zero Trust principles<\/li>\n\n\n\n<li>Application-level access enforcement<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium implements these ideas through its own architecture, configuration model, policy language, and integrations.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That distinction matters because understanding the domain lets you evaluate Pomerium intelligently rather than learning a collection of commands without knowing why they exist.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Part II \u2014 Understand Pomerium<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 5. What Is Pomerium?<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">5.1 One-sentence definition<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium is an identity-aware reverse proxy that authenticates users, evaluates access policies, and securely connects authorized clients to protected applications and services.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">5.2 Beginner-friendly definition<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium is a security gateway you place in front of applications.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instead of letting everyone connect directly to your internal Grafana, Jenkins, or administration portal, you make Pomerium the controlled entry point.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium determines whether a user has a valid identity and permission to access the requested application.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When access is allowed, Pomerium forwards the request to the application.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">5.3 Technical definition<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium is an identity- and context-aware reverse proxy built around Zero Trust principles.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium can be run as one integrated instance or as multiple cooperating service components.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">5.4 What category does Pomerium belong to?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium belongs to several overlapping technology categories.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Category<\/th><th>Relationship to Pomerium<\/th><\/tr><tr><td>Identity-Aware Proxy<\/td><td>Primary product category<\/td><\/tr><tr><td>Zero Trust Network Access<\/td><td>Provides resource-specific access capabilities<\/td><\/tr><tr><td>Reverse Proxy<\/td><td>Forwards authorized traffic to backend services<\/td><\/tr><tr><td>Identity and Access Management<\/td><td>Integrates with IAM systems to make access decisions<\/td><\/tr><tr><td>Application Access Gateway<\/td><td>Centralizes access to protected applications<\/td><\/tr><tr><td>Security Policy Enforcement<\/td><td>Evaluates permissions before forwarding traffic<\/td><\/tr><tr><td>Cloud-native infrastructure<\/td><td>Deployable with containers and Kubernetes<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium is not itself a complete identity provider or a general replacement for all network security controls.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">5.5 Pomerium editions and deployment models<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">One important distinction is that Pomerium Core, Pomerium Zero, and Pomerium Enterprise are not identical products with identical management capabilities.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Offering<\/th><th>What it is<\/th><th>Management model<\/th><th>Main audience<\/th><\/tr><tr><td>Pomerium Core<\/td><td>Open-source proxy and services<\/td><td>Self-managed<\/td><td>Developers, DevOps, platform teams<\/td><\/tr><tr><td>Pomerium Zero<\/td><td>Hosted control plane managing Core clusters<\/td><td>Cloud-managed configuration; self-hosted proxy<\/td><td>Individuals and teams wanting easier management<\/td><\/tr><tr><td>Pomerium Enterprise<\/td><td>Self-hosted control plane with additional governance features<\/td><td>Organization-managed<\/td><td>Larger organizations with advanced operational requirements<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">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<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">5.6 Where does it run?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium Core supports several deployment methods.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/images.openai.com\/static-rsc-4\/f5AuWZQ38vfu1VQ-2U9NiRBGDpPtOCyYSZvLNlSbB22jGFMvGiqjMqaI-zi8hHPmFhIBU3CDilGjnm-lkDVZ6SDGcvydl9oxZ_8r55-zu6mPWqVeKe5e7SMIEA6W-4lsROy7e9j2bawzDvgU1WK23OMPo1urcPNJVidyuRnGO3o?purpose=inline\">[macOS] \uac1c\ubc1c\ud658\uacbd \uad6c\ucd95 &#8211; Docker, Colima \uc124\uce58<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Docker containers<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The easiest starting environment for beginners. Pomerium and the applications it protects run in separate containers.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/images.openai.com\/static-rsc-4\/6kFL8DMsSxof_V_zqOgg7Lj9-lG5J8IVJ6H7q_v6MtNRi7hfuobvhfAZBGAjetWMwcecNqXfpI7NnIoRmDlGB8_Mnh5Ztyj5PPrPiRApgsDNDIP_QxQ5LtywTlRqnzxhJzyvmabObDe9aMnbvsBtwCLV0bvTyH-l0cQya9xiAGI?purpose=inline\">Se simplifier Kubernetes avec Helm et les Charts<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Kubernetes<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Suitable for orchestrated environments, ingress management, automated deployments, and scaling.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/images.openai.com\/static-rsc-4\/Mx33ePpDQHTLNCIx6yM2G2r7epZI8MSfs24YhuRaZLdRGPhOS63CIjkUDVIRV69Q1EGaPfxIgpnGSLdCjdEnYS5Gc1-N_3ZWZoQtxvUtFVTZUHm-8BQlcHhp7WekPcLH_T6BLTXm0xl5tYrfW89zJ70aTTIo03ZEjjXN5pc6QuE?purpose=inline\">Linux Logo, Tux, Linux Kernel, Ubuntu, Free Software, Linux Mint, MX Linux, Bird transparent background PNG clipart | HiClipart<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Linux servers and virtual machines<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium can also run using official packages or prebuilt binaries.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The installation chapters explain operating-system differences in detail.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">5.7 What Pomerium does not do<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Understanding limitations prevents architecture mistakes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium does not automatically provide:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>A complete corporate user directory.<\/li>\n\n\n\n<li>A replacement for application-specific business permissions.<\/li>\n\n\n\n<li>An antivirus or endpoint detection system.<\/li>\n\n\n\n<li>A Web Application Firewall (WAF) covering every attack category.<\/li>\n\n\n\n<li>Database backup, disaster recovery, or application data protection.<\/li>\n\n\n\n<li>General-purpose network connectivity equivalent to every VPN use case.<\/li>\n\n\n\n<li>Protection against an application being accessed through a separate, unprotected network path.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Its job is to enforce an access boundary for the resources routed through it.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 6. Why Does Pomerium Exist?<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">6.1 The problem of inconsistent access controls<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Consider an organization with 30 internal applications.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Some applications use local passwords. Others support corporate SSO. Some are accessible only through VPN. Others have been exposed through reverse proxies.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Administrators may need to update several systems whenever someone joins, changes teams, or leaves.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium provides a way to standardize an important layer of application access.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">6.2 Three real-world scenarios<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Scenario<\/th><th>Without Pomerium<\/th><th>With Pomerium<\/th><th>Main benefit<\/th><\/tr><tr><td>Internal Grafana<\/td><td>Configure a VPN or separate authentication for dashboard access<\/td><td>Protect Grafana with an identity-based route and policy<\/td><td>Centralized application access<\/td><\/tr><tr><td>Developer tools<\/td><td>Manage different access approaches for Jenkins, documentation, and utilities<\/td><td>Configure protected routes with distinct permissions<\/td><td>Consistent enforcement<\/td><\/tr><tr><td>Contractor access<\/td><td>Provision broader connectivity or application-specific credentials<\/td><td>Grant access to specifically approved protected applications<\/td><td>Reduced unnecessary access<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">These benefits are conditional on correct deployment, identity integration, and network isolation.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">6.3 Why not use only a VPN?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">VPNs are useful for private networking, especially where applications require general IP connectivity.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">However, a VPN does not inherently provide the same application-level authorization model as Pomerium.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Conversely, Pomerium is not always the right tool for access to arbitrary network protocols or complete private networks.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Organizations can use both technologies together.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">6.4 What trade-offs does Pomerium introduce?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium adds a security enforcement component to the request path.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That introduces responsibilities:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Deploying and maintaining a reliable gateway.<\/li>\n\n\n\n<li>Managing TLS certificates and access policies.<\/li>\n\n\n\n<li>Ensuring identity-provider availability.<\/li>\n\n\n\n<li>Controlling session and state storage.<\/li>\n\n\n\n<li>Preventing direct access that bypasses the proxy.<\/li>\n\n\n\n<li>Monitoring gateway health and response latency.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">An access gateway becomes part of the application&#8217;s availability architecture. If it is unavailable, legitimate users may also be unable to access the protected application.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">6.5 When is Pomerium unnecessary?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">You may not need Pomerium when an application already has strong corporate SSO, appropriate authorization, reliable audit capabilities, and an acceptable network security architecture.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It may also be excessive for a small local-only tool used by one person.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The decision should depend on actual security and operational requirements, not on the desire to add another infrastructure component.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 7. How Pomerium Works<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">7.1 The four logical components<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium contains four main logical services.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Component<\/th><th>Responsibility<\/th><th>Everyday analogy<\/th><\/tr><tr><td>Proxy<\/td><td>Accepts and forwards traffic<\/td><td>Reception desk<\/td><\/tr><tr><td>Authenticate<\/td><td>Establishes user identity and login session<\/td><td>Identity verification counter<\/td><\/tr><tr><td>Authorize<\/td><td>Checks whether the request is permitted<\/td><td>Access-control officer<\/td><\/tr><tr><td>Databroker<\/td><td>Manages state, sessions, and identity-related records<\/td><td>Secure records office<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">These are logical services. They do not necessarily require four separately deployed servers.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In the beginner deployment, the Core components run together, while the first login experience uses Pomerium&#8217;s external hosted authentication service.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">7.2 End-to-end request architecture<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">#chatgpt-mermaid-_r_1fm_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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=&#8221;neo&#8221;].node rect,#chatgpt-mermaid-_r_1fm_ [data-look=&#8221;neo&#8221;].cluster rect,#chatgpt-mermaid-_r_1fm_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_1fm_ [data-look=&#8221;neo&#8221;].node path{stroke:url(#chatgpt-mermaid-_r_1fm_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_1fm_ [data-look=&#8221;neo&#8221;].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1fm_ [data-look=&#8221;neo&#8221;].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_1fm_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_1fm_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].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=&#8221;normal&#8221;],#chatgpt-mermaid-_r_1fm_ .edgeLabels tspan[font-weight=&#8221;normal&#8221;]{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{&#8211;mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;}User browserPomerium ProxyAuthorization serviceAuthentication serviceIdentity providerDatabrokerProtected applicationHTTPS requestCheck accessIf login requiredOIDC authenticationSession establishedSession informationAccess decisionAuthorized trafficResponseHTTPS response<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This diagram summarizes the logical interactions; the browser also participates in authentication redirects.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">7.3 Step-by-step execution<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Step 1 \u2014 The browser requests an application.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">An employee opens a Pomerium-protected URL.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Step 2 \u2014 The proxy receives the request.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium identifies the matching route and initiates an authorization check.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Step 3 \u2014 Authentication is checked.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If the request lacks a valid session, the user is directed into the authentication process.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Step 4 \u2014 The identity provider authenticates the user.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This may involve a password, passkey, or another factor according to the identity-provider configuration.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Step 5 \u2014 Session information is established.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium manages the session using its authentication and Databroker components.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Step 6 \u2014 Authorization evaluates the request.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The service evaluates the policy using relevant authenticated identity and request context.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Step 7 \u2014 Pomerium either allows or denies access.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If the request is permitted, Pomerium forwards it to the upstream application.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Step 8 \u2014 The application responds.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The response returns through Pomerium to the browser.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium&#8217;s documented architecture uses gRPC communication among relevant internal components and evaluates HTTP authorization on a per-request basis. Pomerium+1<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">7.4 Authentication does not equal authorization<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Suppose two employees successfully authenticate.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The first employee is a platform engineer. The second is a marketing analyst.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Both may have valid corporate identities.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">However, a production administration route might permit only the first employee.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Authentication succeeds for both, but authorization produces different decisions.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That is the central distinction behind Pomerium&#8217;s access-control model.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">7.5 Understanding state<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium maintains data about users and sessions.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Its Databroker supports different storage approaches, including memory, local file storage, and PostgreSQL.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The choice affects session persistence and high availability.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We will explore those differences when designing production architecture.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 8. Core Features Explained Simply<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">8.1 Essential features<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Feature<\/th><th>What it does<\/th><th>Problem solved<\/th><th>Example<\/th><th>Level<\/th><\/tr><tr><td>Identity-aware reverse proxy<\/td><td>Accepts and controls application requests<\/td><td>Uncontrolled application entry<\/td><td>Protect Grafana<\/td><td>Beginner<\/td><\/tr><tr><td>Authentication integration<\/td><td>Connects user login to an identity provider<\/td><td>Repeated login systems<\/td><td>Corporate SSO<\/td><td>Beginner<\/td><\/tr><tr><td>Access policies<\/td><td>Controls who can access a route<\/td><td>Excessive access<\/td><td>Allow specific users<\/td><td>Beginner<\/td><\/tr><tr><td>Application routing<\/td><td>Maps external URLs to backend services<\/td><td>Complex access paths<\/td><td>Dashboard hostname to Grafana<\/td><td>Beginner<\/td><\/tr><tr><td>Session handling<\/td><td>Maintains authenticated interactions<\/td><td>Repeated authentication<\/td><td>Browser login session<\/td><td>Beginner<\/td><\/tr><tr><td>TLS support<\/td><td>Secures transport connections<\/td><td>Unencrypted communication<\/td><td>HTTPS<\/td><td>Beginner<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">8.2 Everyday operational features<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Feature<\/th><th>Simple explanation<\/th><th>Practical example<\/th><th>Level<\/th><\/tr><tr><td>Configuration files<\/td><td>Define how Pomerium behaves<\/td><td>YAML configuration<\/td><td>Beginner<\/td><\/tr><tr><td>Environment variables<\/td><td>Supply configuration outside the file<\/td><td>Secrets injected at runtime<\/td><td>Intermediate<\/td><\/tr><tr><td>Logs<\/td><td>Show significant operational events<\/td><td>Diagnose login errors<\/td><td>Beginner<\/td><\/tr><tr><td>Health checks<\/td><td>Report whether services are ready and healthy<\/td><td>Container health probe<\/td><td>Intermediate<\/td><\/tr><tr><td>Metrics<\/td><td>Expose operational measurements<\/td><td>Prometheus monitoring<\/td><td>Intermediate<\/td><\/tr><tr><td>Hot configuration reload<\/td><td>Apply supported configuration changes without restarting the process<\/td><td>Update a route policy<\/td><td>Intermediate<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">8.3 Integration features<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Feature<\/th><th>Practical purpose<\/th><th>Typical environment<\/th><th>Level<\/th><\/tr><tr><td>OIDC integration<\/td><td>Authenticate through existing identity providers<\/td><td>Corporate IAM<\/td><td>Intermediate<\/td><\/tr><tr><td>Signed identity assertions<\/td><td>Allow applications to verify identity information sent by Pomerium<\/td><td>Custom applications<\/td><td>Intermediate<\/td><\/tr><tr><td>Kubernetes integration<\/td><td>Protect services in Kubernetes environments<\/td><td>EKS or other Kubernetes clusters<\/td><td>Advanced<\/td><\/tr><tr><td>TCP connectivity clients<\/td><td>Access supported non-HTTP services through Pomerium<\/td><td>Developer services<\/td><td>Advanced<\/td><\/tr><tr><td>Terraform integrations<\/td><td>Manage supported configuration declaratively<\/td><td>Infrastructure as Code<\/td><td>Advanced<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">8.4 Security features<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Feature<\/th><th>Problem addressed<\/th><th>Example<\/th><\/tr><tr><td>Per-route authorization<\/td><td>Users getting access to applications outside their role<\/td><td>Only SREs can access monitoring<\/td><\/tr><tr><td>Deny policies<\/td><td>Explicitly blocked identities or conditions<\/td><td>Deny a named user<\/td><\/tr><tr><td>Identity assertions<\/td><td>Applications need trustworthy identity information<\/td><td>Verify signed JWT<\/td><\/tr><tr><td>Session restrictions<\/td><td>Long-lived or inappropriate sessions<\/td><td>Configure session expiration<\/td><\/tr><tr><td>Certificate validation<\/td><td>Untrusted network connections<\/td><td>Validate upstream TLS<\/td><\/tr><tr><td>Mutual TLS<\/td><td>Need for certificate-based authentication<\/td><td>Client-to-gateway certificate authentication<\/td><\/tr><tr><td>Contextual policies<\/td><td>Decisions require additional conditions<\/td><td>Policy using available device or request attributes<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">8.5 Advanced and production features<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Feature<\/th><th>Availability or dependency<\/th><th>Main value<\/th><\/tr><tr><td>Multiple Pomerium replicas<\/td><td>Core with appropriate shared state<\/td><td>Availability and capacity<\/td><\/tr><tr><td>Split-service deployment<\/td><td>Core<\/td><td>Independent component placement<\/td><\/tr><tr><td>PostgreSQL-backed Databroker<\/td><td>Core<\/td><td>Persistent shared state<\/td><\/tr><tr><td>Pomerium Policy Language<\/td><td>Core<\/td><td>Declarative authorization<\/td><\/tr><tr><td>Kubernetes Ingress Controller<\/td><td>Separate Pomerium Kubernetes integration<\/td><td>Kubernetes-native routes<\/td><\/tr><tr><td>Service accounts<\/td><td>Zero and Enterprise feature<\/td><td>Machine authentication<\/td><\/tr><tr><td>Centralized management console<\/td><td>Zero or Enterprise<\/td><td>Easier multi-application management<\/td><\/tr><tr><td>Directory synchronization<\/td><td>Enterprise feature<\/td><td>Organization-scale identity management<\/td><\/tr><tr><td>Namespace-based governance<\/td><td>Enterprise feature<\/td><td>Delegated administration<\/td><\/tr><tr><td>Enterprise API<\/td><td>Enterprise<\/td><td>Programmatic administration<\/td><\/tr><tr><td>Advanced Rego policies<\/td><td>Enterprise<\/td><td>More expressive policy logic<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The official Pomerium product documentation distinguishes these capabilities across Core, Zero, and Enterprise. Pomerium+2<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 9. Similar Tools and Alternatives<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium is one of several technologies that address application access.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The correct alternative depends on whether you primarily need application authentication, cloud-managed access, general private networking, or infrastructure access.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">9.1 Comparison<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Tool<\/th><th>Primary purpose<\/th><th>Main strength<\/th><th>Main limitation or trade-off<\/th><th>Best use case<\/th><th>Relationship to Pomerium<\/th><\/tr><tr><td>Pomerium<\/td><td>Identity-aware application access<\/td><td>Open-source proxy with route-level policies<\/td><td>Requires gateway operations and configuration<\/td><td>Self-hosted protected web apps<\/td><td>Reference tool<\/td><\/tr><tr><td>OAuth2 Proxy<\/td><td>OAuth\/OIDC authentication proxy<\/td><td>Focused authentication integration<\/td><td>Advanced authorization designs may require additional components<\/td><td>Add SSO to existing web apps<\/td><td>Direct alternative for some use cases<\/td><\/tr><tr><td>Cloudflare Access<\/td><td>Managed identity-aware application access<\/td><td>Managed service with device and identity policies<\/td><td>Dependence on Cloudflare service and architecture<\/td><td>Cloud-managed application access<\/td><td>Direct alternative<\/td><\/tr><tr><td>Authentik<\/td><td>Identity provider and proxy authentication<\/td><td>Integrated identity and application access features<\/td><td>Managing the broader identity platform adds responsibility<\/td><td>Self-hosted identity and app access<\/td><td>Alternative or complementary<\/td><\/tr><tr><td>Authelia<\/td><td>Authentication and authorization portal<\/td><td>Self-hosted authentication alongside reverse proxies<\/td><td>Requires compatible integration and operations<\/td><td>Protect self-hosted services<\/td><td>Alternative architecture<\/td><\/tr><tr><td>Teleport<\/td><td>Infrastructure and application access<\/td><td>Strong SSH, Kubernetes, database, and session-oriented capabilities<\/td><td>Broader infrastructure platform with different operational model<\/td><td>Infrastructure access governance<\/td><td>Overlapping alternative<\/td><\/tr><tr><td>Tailscale<\/td><td>Identity-based private networking<\/td><td>Simple private device and network connectivity<\/td><td>Different focus from per-request HTTP proxy enforcement<\/td><td>Devices, private networks, remote connectivity<\/td><td>Often complementary<\/td><\/tr><tr><td>NGINX with external authentication<\/td><td>Reverse proxy with external access checks<\/td><td>Flexible integration into existing proxy stacks<\/td><td>Requires separate identity and authorization design<\/td><td>Organizations already using NGINX<\/td><td>Component alternative<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Cloudflare Access, Authentik, Teleport, and Tailscale provide substantially different technical models despite their overlapping access-security goals. Cloudflare One docs+3<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">9.2 Pomerium versus OAuth2 Proxy<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium is attractive when you also want a unified identity-aware routing gateway with a dedicated authorization architecture.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is a design distinction, not an absolute statement that one product is always more secure.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">9.3 Pomerium versus Cloudflare Access<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Cloudflare Access offers a managed, identity-aware access layer.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium Core allows organizations to operate the proxy and configuration within their own environment.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium Zero provides a middle ground by retaining the self-hosted data plane while using a hosted management service.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Choose based on control-plane location, trust boundaries, networking requirements, cost, operational skills, and the features needed.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">9.4 Pomerium versus Authentik<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Authentik can function as an identity provider and can also protect applications through proxy or forward-authentication integrations.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium focuses on the identity-aware access gateway.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">These tools can sometimes work together, with Authentik supplying identity and Pomerium enforcing access to protected applications.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">9.5 Pomerium versus Tailscale<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Tailscale is more naturally suited to secure device and network connectivity.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium is more naturally suited to application access through an identity-aware proxy.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A team might use Tailscale for private connectivity between environments while Pomerium enforces access to specific web applications.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Which Tool Should You Choose and Why?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">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<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Start by evaluating Pomerium Core.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Its identity-aware routing and policy model directly match this requirement.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Part III \u2014 Architecture and Workflows<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 10. Architecture Explained from Simple to Advanced<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">10.1 Architecture level 1: The smallest working setup<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The first architecture uses one Pomerium instance and one web application.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">#chatgpt-mermaid-_r_1gs_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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=&#8221;neo&#8221;].node rect,#chatgpt-mermaid-_r_1gs_ [data-look=&#8221;neo&#8221;].cluster rect,#chatgpt-mermaid-_r_1gs_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_1gs_ [data-look=&#8221;neo&#8221;].node path{stroke:url(#chatgpt-mermaid-_r_1gs_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_1gs_ [data-look=&#8221;neo&#8221;].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1gs_ [data-look=&#8221;neo&#8221;].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_1gs_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_1gs_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].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=&#8221;normal&#8221;],#chatgpt-mermaid-_r_1gs_ .edgeLabels tspan[font-weight=&#8221;normal&#8221;]{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{&#8211;mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;}BrowserPomerium CorePrivate web applicationHosted authenticationHTTPSAuthorized HTTPAuthentication<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium receives browser requests, handles the required authorization process, and forwards permitted traffic to the private application.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is the setup we will build locally.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">10.2 Architecture level 2: Inside Pomerium Core<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">#chatgpt-mermaid-_r_1h3_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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=&#8221;neo&#8221;].node rect,#chatgpt-mermaid-_r_1h3_ [data-look=&#8221;neo&#8221;].cluster rect,#chatgpt-mermaid-_r_1h3_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_1h3_ [data-look=&#8221;neo&#8221;].node path{stroke:url(#chatgpt-mermaid-_r_1h3_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_1h3_ [data-look=&#8221;neo&#8221;].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1h3_ [data-look=&#8221;neo&#8221;].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_1h3_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_1h3_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].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=&#8221;normal&#8221;],#chatgpt-mermaid-_r_1h3_ .edgeLabels tspan[font-weight=&#8221;normal&#8221;]{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{&#8211;mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;}Pomerium Core \u2014 all-in-oneProxyAuthorizeAuthenticateDatabrokerBrowserIdentity providerUpstream applicationLogin redirects<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">An all-in-one deployment contains the logical Pomerium services in one running process.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Why this is useful: It reduces configuration and deployment complexity while preserving the main Pomerium architecture.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium officially recommends all-in-one mode for its simplicity, and notes that it can also be used in large production environments. Pomerium<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">10.3 Architecture level 3: Split-service deployment<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In a split-service deployment, components are separated so that they can be deployed and operated independently.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">#chatgpt-mermaid-_r_1he_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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=&#8221;neo&#8221;].node rect,#chatgpt-mermaid-_r_1he_ [data-look=&#8221;neo&#8221;].cluster rect,#chatgpt-mermaid-_r_1he_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_1he_ [data-look=&#8221;neo&#8221;].node path{stroke:url(#chatgpt-mermaid-_r_1he_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_1he_ [data-look=&#8221;neo&#8221;].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1he_ [data-look=&#8221;neo&#8221;].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_1he_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_1he_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].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=&#8221;normal&#8221;],#chatgpt-mermaid-_r_1he_ .edgeLabels tspan[font-weight=&#8221;normal&#8221;]{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{&#8211;mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;}BrowserLoad balancerPomerium Proxy servicePomerium Authorize servicePomerium AuthenticateservicePomerium DatabrokerserviceIdentity providerPersistent storagePrivate applications<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Separating services can provide more deployment control, but it also introduces operational complexity.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Administrators must explicitly configure inter-service communication, addresses, credentials, and appropriate transport security.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">More components do not automatically mean higher availability. Reliability depends on replica counts, state storage, dependencies, and failure handling.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">10.4 Understanding the Databroker storage options<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Storage type<\/th><th>Persistence<\/th><th>Multi-replica suitability<\/th><th>Best use<\/th><\/tr><tr><td>Memory<\/td><td>No persistence across process restarts<\/td><td>Not suitable for independent memory-backed Databroker replicas<\/td><td>Initial experiments<\/td><\/tr><tr><td>File<\/td><td>Persistent local storage<\/td><td>Normally single-instance; clustered Databroker is a separate advanced capability<\/td><td>Small self-managed installations<\/td><\/tr><tr><td>PostgreSQL<\/td><td>Persistent database<\/td><td>Suitable for shared-state multi-replica deployments<\/td><td>Conventional production HA architecture<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">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<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">10.5 Architecture level 4: Production deployment<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A production deployment might use multiple Pomerium instances, a load balancer, private upstream services, centralized monitoring, and persistent database storage.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">#chatgpt-mermaid-_r_1hp_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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=&#8221;neo&#8221;].node rect,#chatgpt-mermaid-_r_1hp_ [data-look=&#8221;neo&#8221;].cluster rect,#chatgpt-mermaid-_r_1hp_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_1hp_ [data-look=&#8221;neo&#8221;].node path{stroke:url(#chatgpt-mermaid-_r_1hp_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_1hp_ [data-look=&#8221;neo&#8221;].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1hp_ [data-look=&#8221;neo&#8221;].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_1hp_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_1hp_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].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=&#8221;normal&#8221;],#chatgpt-mermaid-_r_1hp_ .edgeLabels tspan[font-weight=&#8221;normal&#8221;]{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{&#8211;mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;}Application access layerPomerium Replica 1Pomerium Replica 2Employees and approvedclientsHTTPS load balancerCorporate Identity ProviderPostgreSQLPrivate applicationsLogging and monitoring<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The diagram deliberately simplifies internal Pomerium communications to focus on deployment topology.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">10.6 Control plane versus data plane<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">This distinction is important when considering Pomerium Zero and Enterprise.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Data plane: Components processing the actual application requests.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Control plane: Components managing configuration, routes, policies, and operational settings.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">With Pomerium Core, the organization manages both configuration and runtime infrastructure.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">With Pomerium Zero, the management control plane is hosted, while the Pomerium proxy data plane runs in the organization&#8217;s environment.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">With Pomerium Enterprise, the organization can operate the additional management control plane itself.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 11. The Complete Workflow<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">11.1 Authentication, authorization, and application access<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A more detailed workflow includes both success and failure paths.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">#chatgpt-mermaid-_r_1i0_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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=&#8221;neo&#8221;].node rect,#chatgpt-mermaid-_r_1i0_ [data-look=&#8221;neo&#8221;].cluster rect,#chatgpt-mermaid-_r_1i0_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_1i0_ [data-look=&#8221;neo&#8221;].node path{stroke:url(#chatgpt-mermaid-_r_1i0_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_1i0_ [data-look=&#8221;neo&#8221;].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1i0_ [data-look=&#8221;neo&#8221;].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_1i0_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_1i0_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].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=&#8221;normal&#8221;],#chatgpt-mermaid-_r_1i0_ .edgeLabels tspan[font-weight=&#8221;normal&#8221;]{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{&#8211;mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;}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<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">11.2 Example: Accessing an engineering dashboard<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">An employee opens the dashboard URL.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium determines whether the employee has an authenticated session. If not, the browser follows the login process.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After authentication, Pomerium evaluates the policy associated with the dashboard route.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If the employee satisfies the policy, Pomerium forwards the request to the dashboard.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If the employee does not satisfy the policy, the request is denied before reaching the dashboard.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">11.3 How to recognize the results<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Outcome<\/th><th>What it means<\/th><th>Expected observation<\/th><\/tr><tr><td>Successful authorization<\/td><td>User satisfies the route policy<\/td><td>Application content loads<\/td><\/tr><tr><td>Authentication required<\/td><td>No valid session is available<\/td><td>Browser enters login process<\/td><\/tr><tr><td>Authentication failure<\/td><td>Login is not completed successfully<\/td><td>Authentication error or failed login<\/td><\/tr><tr><td>Authorization failure<\/td><td>Authenticated user lacks permission<\/td><td>Access denied<\/td><\/tr><tr><td>Upstream failure<\/td><td>Backend is unavailable or incorrectly configured<\/td><td>Proxy or upstream error<\/td><\/tr><tr><td>TLS failure<\/td><td>Secure connection cannot be validated or established<\/td><td>Browser or TLS diagnostic error<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">An HTTP status code alone may not tell you exactly which condition occurred. Redirects, application responses, and gateway-generated errors must be interpreted together.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 12. Where Pomerium Fits into a Larger System<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">12.1 A realistic enterprise technology stack<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Consider a software engineering organization using:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>An identity provider for employee identities.<\/li>\n\n\n\n<li>Kubernetes for application deployment.<\/li>\n\n\n\n<li>Grafana for monitoring.<\/li>\n\n\n\n<li>Jenkins for continuous integration.<\/li>\n\n\n\n<li>Terraform for infrastructure configuration.<\/li>\n\n\n\n<li>Prometheus for monitoring metrics.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium can be the access layer protecting the relevant internal applications.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">#chatgpt-mermaid-_r_1i7_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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=&#8221;neo&#8221;].node rect,#chatgpt-mermaid-_r_1i7_ [data-look=&#8221;neo&#8221;].cluster rect,#chatgpt-mermaid-_r_1i7_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_1i7_ [data-look=&#8221;neo&#8221;].node path{stroke:url(#chatgpt-mermaid-_r_1i7_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_1i7_ [data-look=&#8221;neo&#8221;].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1i7_ [data-look=&#8221;neo&#8221;].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_1i7_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_1i7_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].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=&#8221;normal&#8221;],#chatgpt-mermaid-_r_1i7_ .edgeLabels tspan[font-weight=&#8221;normal&#8221;]{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{&#8211;mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;}Private infrastructureGrafanaJenkinsInternal Admin PortalEmployeesCorporate Identity ProviderPomerium Access GatewayObservability platformInfrastructure configurationDeployment and configuration<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">12.2 Who owns each component?<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Component<\/th><th>Typical responsible team<\/th><th>Responsibility<\/th><\/tr><tr><td>Identity provider<\/td><td>IAM or IT security<\/td><td>User identities, authentication, MFA<\/td><\/tr><tr><td>Pomerium<\/td><td>Platform engineering or security engineering<\/td><td>Gateway deployment and access enforcement<\/td><\/tr><tr><td>Application<\/td><td>Application development team<\/td><td>Application correctness and internal permissions<\/td><\/tr><tr><td>DNS and certificates<\/td><td>Infrastructure or platform team<\/td><td>Domain routing and TLS lifecycle<\/td><\/tr><tr><td>Databroker storage<\/td><td>Infrastructure or database operations<\/td><td>Availability and recovery<\/td><\/tr><tr><td>Monitoring<\/td><td>SRE or observability team<\/td><td>Metrics, alerts, incident diagnosis<\/td><\/tr><tr><td>Access policies<\/td><td>Application owners and security teams<\/td><td>Approval and lifecycle of permissions<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">12.3 The most important architectural security rule<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The protected application must not be independently accessible through an uncontrolled path that bypasses Pomerium.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, if Grafana is protected at one hostname but remains publicly available through an unprotected IP address, the access boundary is incomplete.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is why production network isolation matters just as much as writing the right access policy.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Part IV \u2014 Installation and First Success<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 13. Prerequisites and Environment Preparation<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Our first working environment will run entirely on your local computer, except for the external hosted authentication service used to sign in.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You do not need to purchase a domain, create a cloud server, or operate an identity provider for this experiment.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">13.1 What you need<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Requirement<\/th><th>Needed for first lab?<\/th><th>Notes<\/th><\/tr><tr><td>Windows, macOS, or Linux<\/td><td>Yes<\/td><td>Must support the selected Docker installation<\/td><\/tr><tr><td>Docker Engine or Docker Desktop<\/td><td>Yes<\/td><td>Runs the containers<\/td><\/tr><tr><td>Docker Compose<\/td><td>Yes<\/td><td>Starts Pomerium and the demo service together<\/td><\/tr><tr><td>Internet connection<\/td><td>Yes<\/td><td>Downloads images and supports hosted authentication<\/td><\/tr><tr><td>Web browser<\/td><td>Yes<\/td><td>Completes authentication<\/td><\/tr><tr><td>A usable email identity<\/td><td>Yes<\/td><td>Used in the access policy and login<\/td><\/tr><tr><td>Text editor<\/td><td>Yes<\/td><td>Creates YAML files<\/td><\/tr><tr><td><code>mkcert<\/code><\/td><td>Recommended for this lab<\/td><td>Creates locally trusted TLS certificates<\/td><\/tr><tr><td>Domain registration<\/td><td>No<\/td><td>We use a special localhost domain<\/td><\/tr><tr><td>Kubernetes<\/td><td>No<\/td><td>Introduced later<\/td><\/tr><tr><td>PostgreSQL<\/td><td>No<\/td><td>Introduced for persistent and replicated deployments<\/td><\/tr><tr><td>Pomerium commercial licence<\/td><td>No<\/td><td>We use Pomerium Core<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">13.2 Hardware recommendations<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For a basic two-container demonstration, a modern laptop with several gigabytes of available memory is usually sufficient.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">These are practical classroom recommendations, not officially published minimum Pomerium server requirements.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Actual production capacity must be measured against requests per second, connection counts, authentication load, policy complexity, and dependencies.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">13.3 Network requirements<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Our first lab uses these connections:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Connection<\/th><th>Port<\/th><th>Purpose<\/th><\/tr><tr><td>Browser \u2192 local Pomerium<\/td><td>TCP 443<\/td><td>HTTPS access<\/td><\/tr><tr><td>Pomerium \u2192 demo Verify container<\/td><td>TCP 8000<\/td><td>Private Docker-network traffic<\/td><\/tr><tr><td>Browser \u2192 hosted authentication<\/td><td>HTTPS\/TCP 443<\/td><td>User sign-in<\/td><\/tr><tr><td>Container environment \u2192 external dependencies<\/td><td>As required<\/td><td>Image download and authentication-related services<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Only Pomerium&#8217;s HTTPS endpoint needs to be published on the host.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The demo application should not expose a separate host port.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">13.4 What is <code>localhost.pomerium.io<\/code>?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium documentation uses hostnames such as:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">verify<\/span><span class=\"hljs-selector-class\">.localhost<\/span><span class=\"hljs-selector-class\">.pomerium<\/span><span class=\"hljs-selector-class\">.io<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This special local development domain resolves to the loopback address <code>127.0.0.1<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That means the browser reaches a service on your own computer.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It avoids the need to manually register a production domain for the local example.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Corporate DNS restrictions, proxy settings, or DNS-rebinding protection may interfere with this special domain. We will account for that during troubleshooting. Pomerium<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">13.5 Pre-installation checklist<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Environment readiness<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 14. Install Pomerium on Supported Operating Systems<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The recommended beginner approach is to install Docker on the host and run the official Pomerium Linux container image.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This keeps the actual Pomerium deployment nearly identical across Windows, Ubuntu, and macOS.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">14.1 Operating-system compatibility<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Operating system<\/th><th>Recommended beginner method<\/th><th>Native Pomerium Core server<\/th><\/tr><tr><td>Windows 10\/11, subject to Docker prerequisites<\/td><td>Docker Desktop with a Linux-container backend<\/td><td>No official native Windows server binary documented<\/td><\/tr><tr><td>Ubuntu<\/td><td>Docker Engine and Compose<\/td><td>Linux binary or <code>.deb<\/code> package available<\/td><\/tr><tr><td>macOS Apple Silicon<\/td><td>Docker Desktop<\/td><td>Native ARM64 binary available<\/td><\/tr><tr><td>macOS Intel<\/td><td>Compatible Docker Linux-container environment<\/td><td>Native <code>darwin\/amd64<\/code> removed in Pomerium v0.33<\/td><\/tr><tr><td>Debian<\/td><td>Docker Engine<\/td><td>Linux binary or <code>.deb<\/code> package<\/td><\/tr><tr><td>Fedora<\/td><td>Docker Engine<\/td><td>Linux binary or compatible <code>.rpm<\/code> package<\/td><\/tr><tr><td>RHEL and compatible distributions<\/td><td>Supported container runtime<\/td><td>Linux binary or applicable <code>.rpm<\/code> package<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Native binary support, package support, and container support are distinct. Do not infer one from another. Pomerium+1<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">A. Windows Installation<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">Step 1 \u2014 Prepare Windows<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Use a supported Windows installation that meets Docker Desktop&#8217;s current system requirements.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For a typical Windows 11 setup, Docker Desktop can use Windows Subsystem for Linux 2 (WSL 2).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If WSL is not installed, open PowerShell as Administrator and run:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">wsl --install<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This installs or enables the necessary WSL components on supported systems. Restart the computer if prompted.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Verify:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">wsl --status<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">If WSL installation fails because virtualization is unavailable, check firmware virtualization settings and the official Microsoft documentation.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Step 2 \u2014 Install Docker Desktop<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Download Docker Desktop from the official installation page:<a href=\"https:\/\/docs.docker.com\/desktop\/setup\/install\/windows-install\/?utm_source=chatgpt.com\">Docker Desktop for Windows \u2014 Official installation instructions<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Run the installer and select the WSL 2-based backend where appropriate.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Start Docker Desktop, complete its setup, and wait until the Docker engine is running.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Docker&#8217;s official instructions provide the current Windows requirements and supported backends. Docker Docs<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Step 3 \u2014 Verify Docker<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Open a new PowerShell window:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker --version\ndocker compose version\ndocker run --rm hello-world<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The <code>hello-world<\/code> image should print a message indicating that Docker successfully ran a container.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If the Docker engine is unavailable, start Docker Desktop and confirm that Linux containers are enabled.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Step 4 \u2014 Install mkcert<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">If Windows Package Manager is available:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">winget<\/span> <span class=\"hljs-selector-tag\">install<\/span> <span class=\"hljs-selector-tag\">-e<\/span> <span class=\"hljs-selector-tag\">--id<\/span> <span class=\"hljs-selector-tag\">FiloSottile<\/span><span class=\"hljs-selector-class\">.mkcert<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Alternatively, use the installation methods documented by the official mkcert project, including Chocolatey or Scoop.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Open a new PowerShell terminal and verify:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">mkcert -version<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The installation guidance and binaries are available in the official <a href=\"https:\/\/github.com\/FiloSottile\/mkcert?utm_source=chatgpt.com\">mkcert project<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">B. Ubuntu Installation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The following procedure uses Docker&#8217;s official APT repository rather than an arbitrary installation script.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Step 1 \u2014 Check the Ubuntu version<\/h4>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">cat \/etc\/os-release\nuname -m<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Verify your operating-system release and CPU architecture are supported by Docker.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For an existing installation, first review whether older Docker packages conflict with the official repository packages.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Step 2 \u2014 Install repository prerequisites<\/h4>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">sudo apt update\nsudo apt install -y ca-certificates curl<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><code>ca-certificates<\/code> provides trusted certificate authorities. <code>curl<\/code> downloads resources over HTTP or HTTPS.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Step 3 \u2014 Add Docker&#8217;s official package signing key<\/h4>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">sudo install -m <span class=\"hljs-number\">0755<\/span> -d \/etc\/apt\/keyrings\n\nsudo curl -fsSL \\\n  <span class=\"hljs-attr\">https<\/span>:<span class=\"hljs-comment\">\/\/download.docker.com\/linux\/ubuntu\/gpg \\<\/span>\n  -o \/etc\/apt\/keyrings\/docker.asc\n\nsudo chmod a+r \/etc\/apt\/keyrings\/docker.asc<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The signing key enables APT to verify packages from the configured repository.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Step 4 \u2014 Add the Docker package repository<\/h4>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">sudo tee \/etc\/apt\/sources.list.d\/docker.sources &gt; <span class=\"hljs-regexp\">\/dev\/<\/span><span class=\"hljs-literal\">null<\/span> &lt;&lt;EOF\n<span class=\"hljs-attr\">Types<\/span>: deb\n<span class=\"hljs-attr\">URIs<\/span>: https:<span class=\"hljs-comment\">\/\/download.docker.com\/linux\/ubuntu<\/span>\nSuites: $(. \/etc\/os-release &amp;&amp; echo <span class=\"hljs-string\">\"${UBUNTU_CODENAME:-$VERSION_CODENAME}\"<\/span>)\n<span class=\"hljs-attr\">Components<\/span>: stable\n<span class=\"hljs-attr\">Architectures<\/span>: $(dpkg --print-architecture)\nSigned-By: <span class=\"hljs-regexp\">\/etc\/<\/span>apt\/keyrings\/docker.asc\nEOF<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This creates the repository configuration corresponding to your Ubuntu release.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Step 5 \u2014 Install Docker and Compose<\/h4>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">sudo<\/span> <span class=\"hljs-selector-tag\">apt<\/span> <span class=\"hljs-selector-tag\">update<\/span>\n\n<span class=\"hljs-selector-tag\">sudo<\/span> <span class=\"hljs-selector-tag\">apt<\/span> <span class=\"hljs-selector-tag\">install<\/span> <span class=\"hljs-selector-tag\">-y<\/span> \\\n  <span class=\"hljs-selector-tag\">docker-ce<\/span> \\\n  <span class=\"hljs-selector-tag\">docker-ce-cli<\/span> \\\n  <span class=\"hljs-selector-tag\">containerd<\/span><span class=\"hljs-selector-class\">.io<\/span> \\\n  <span class=\"hljs-selector-tag\">docker-buildx-plugin<\/span> \\\n  <span class=\"hljs-selector-tag\">docker-compose-plugin<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">These are the packages specified by Docker&#8217;s Ubuntu installation guide. Docker Docs<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Step 6 \u2014 Start Docker<\/h4>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">sudo systemctl enable --now docker\nsudo systemctl status docker<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The service should report an active state.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Verify container execution:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">sudo docker run --rm hello-world\nsudo docker compose version<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">On a standard Docker Engine installation, you may need to prefix Docker commands with <code>sudo<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Adding users to the <code>docker<\/code> group grants powerful Docker daemon permissions, effectively root-equivalent access in a typical rootful Docker installation. Do not make this change casually.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Step 7 \u2014 Install mkcert<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">First install its certificate-store dependency:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">sudo apt install -y libnss3-tools<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">For an <code>x86_64<\/code> Ubuntu computer, the mkcert project&#8217;s documented prebuilt-binary method is:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">curl -JLO \\\n  <span class=\"hljs-string\">\"https:\/\/dl.filippo.io\/mkcert\/latest?for=linux\/amd64\"<\/span>\n\nchmod +x mkcert-v*-linux-amd64\n\nsudo install -m <span class=\"hljs-number\">0755<\/span> \\\n  mkcert-v*-linux-amd64 \\\n  \/usr\/local\/bin\/mkcert<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Verify:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">mkcert -version<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">For ARM64 or other architectures, select the matching binary from the project&#8217;s official releases rather than using an AMD64 binary.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">C. macOS Installation<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">Step 1 \u2014 Check the architecture<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Open Terminal:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">uname -m\nsw_vers<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Common architecture values include:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>arm64<\/code>: Apple Silicon<\/li>\n\n\n\n<li><code>x86_64<\/code>: Intel Mac<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Choose Docker Desktop for the correct architecture.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Step 2 \u2014 Install Docker Desktop<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Download Docker Desktop from:<a href=\"https:\/\/docs.docker.com\/desktop\/setup\/install\/mac-install\/?utm_source=chatgpt.com\">Docker Desktop for macOS \u2014 Official instructions<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Open the <code>.dmg<\/code> installer, move Docker into Applications, and start it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Complete the initial configuration.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Docker Desktop may require specific macOS versions, system resources, privileges, and licensing depending on the environment and commercial use. Docker Docs<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Step 3 \u2014 Verify Docker<\/h4>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker --version\ndocker compose version\ndocker run --rm hello-world<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">If Docker commands cannot communicate with the engine, make sure Docker Desktop has started.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Step 4 \u2014 Install mkcert<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">If Homebrew is installed:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">brew install mkcert<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">For Firefox integration, the official mkcert instructions also recommend:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">brew install nss<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Verify:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">mkcert -version<\/code><\/span><\/pre>\n\n\n<h4 class=\"wp-block-heading\">Optional \u2014 Native macOS installation<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">For a supported Apple Silicon environment, Pomerium&#8217;s release documentation provides standalone macOS ARM64 binaries.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For the course&#8217;s pinned release, the documented release-artifact naming convention gives:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">curl -fL -o pomerium.tar.gz \\\n  <span class=\"hljs-attr\">https<\/span>:<span class=\"hljs-comment\">\/\/github.com\/pomerium\/pomerium\/releases\/download\/v0.33.4\/pomerium-darwin-arm64.tar.gz<\/span>\n\ntar -xzf pomerium.tar.gz<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">After supplying a valid <code>config.yaml<\/code>, the native binary can be started with:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">.\/pomerium -config config.yaml<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Verify the archive&#8217;s release assets and integrity before relying on them. This is an alternative deployment method, not a requirement for the Docker lab.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">D. Debian, Fedora, RHEL, Rocky Linux, and AlmaLinux<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For these systems, first identify the distribution and architecture.<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">cat \/etc\/os-release\nuname -m<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Debian uses APT repositories, while Fedora, RHEL, and related distributions commonly use RPM packages with DNF.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, on a Docker-supported Fedora release, the official repository installation is:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">sudo dnf config-manager addrepo \\\n  --<span class=\"hljs-keyword\">from<\/span>-repofile \\\n  <span class=\"hljs-attr\">https<\/span>:<span class=\"hljs-comment\">\/\/download.docker.com\/linux\/fedora\/docker-ce.repo<\/span>\n\nsudo dnf install -y \\\n  docker-ce \\\n  docker-ce-cli \\\n  containerd.io \\\n  docker-buildx-plugin \\\n  docker-compose-plugin\n\nsudo systemctl enable --now docker\nsudo docker run --rm hello-world<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This assumes the prerequisite repository-management command is available.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Use the distribution-specific official guides for other systems. In particular, do not blindly use Fedora repository instructions on Rocky Linux, AlmaLinux, or RHEL.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Relevant resources:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/docs.docker.com\/engine\/install\/debian\/?utm_source=chatgpt.com\">Docker on Debian<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/docs.docker.com\/engine\/install\/fedora\/?utm_source=chatgpt.com\">Docker on Fedora<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/docs.docker.com\/engine\/install\/rhel\/?utm_source=chatgpt.com\">Docker on RHEL<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/docs.docker.com\/engine\/install\/centos\/?utm_source=chatgpt.com\">Docker on CentOS-compatible environments<\/a><\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium&#8217;s native Linux binaries and package repositories are documented separately in <a href=\"https:\/\/www.pomerium.com\/docs\/deploy\/core?utm_source=chatgpt.com\">Pomerium Core deployment documentation<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Installation verification summary<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Environment<\/th><th>Key verification<\/th><th>Successful result<\/th><\/tr><tr><td>Windows<\/td><td>Docker Desktop running; Docker and Compose commands succeed<\/td><td>Docker engine responds<\/td><\/tr><tr><td>Ubuntu<\/td><td>Docker systemd service running; hello-world succeeds<\/td><td>Containers can run<\/td><\/tr><tr><td>macOS<\/td><td>Docker Desktop running; hello-world succeeds<\/td><td>Containers can run<\/td><\/tr><tr><td>Other Linux<\/td><td>Appropriate container runtime and Compose installed<\/td><td>Container execution works<\/td><\/tr><tr><td>All systems<\/td><td>mkcert version command works<\/td><td>Certificate utility available<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">At this point, you have installed the tools needed to run Pomerium, but Pomerium itself has not yet been deployed.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 15. Your First Working Pomerium Example<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">We will now protect an application using Pomerium Core.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">15.1 What we are going to build<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">We will use Pomerium&#8217;s demo Verify application.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The application is designed to help confirm identity information and test whether the gateway is working.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Our local deployment will contain:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>One Pomerium container.<\/li>\n\n\n\n<li>One Verify application container.<\/li>\n\n\n\n<li>An explicit email-based access policy.<\/li>\n\n\n\n<li>A locally trusted TLS certificate.<\/li>\n\n\n\n<li>A private Docker network.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">This follows Pomerium&#8217;s official Core fundamentals approach while adding local TLS certificate management. Pomerium+1<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">15.2 Target architecture<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">#chatgpt-mermaid-_r_1ol_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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=&#8221;neo&#8221;].node rect,#chatgpt-mermaid-_r_1ol_ [data-look=&#8221;neo&#8221;].cluster rect,#chatgpt-mermaid-_r_1ol_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_1ol_ [data-look=&#8221;neo&#8221;].node path{stroke:url(#chatgpt-mermaid-_r_1ol_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_1ol_ [data-look=&#8221;neo&#8221;].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_1ol_ [data-look=&#8221;neo&#8221;].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_1ol_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_1ol_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].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=&#8221;normal&#8221;],#chatgpt-mermaid-_r_1ol_ .edgeLabels tspan[font-weight=&#8221;normal&#8221;]{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{&#8211;mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;}Browser on your computerPomerium Core containerPomerium hostedauthenticationVerify demo containerhttps:\/\/verify.localhost.pomerium.ioSign-in flowAuthorized request<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">15.3 Create the project directory<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Choose the commands matching your operating system.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">macOS or Linux Terminal:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">mkdir -p ~<span class=\"hljs-regexp\">\/pomerium-lab\/<\/span>certs\ncd ~<span class=\"hljs-regexp\">\/pomerium-lab<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Windows PowerShell:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-keyword\">New<\/span>-Item -ItemType Directory -Force `\n  -Path <span class=\"hljs-string\">\"$HOME\\pomerium-lab\\certs\"<\/span>\n\nSet-Location <span class=\"hljs-string\">\"$HOME\\pomerium-lab\"<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Our initial project structure will be:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">pomerium-lab\/\n\u251c\u2500\u2500 compose.yaml\n\u251c\u2500\u2500 config.yaml\n\u2514\u2500\u2500 certs\/<\/code><\/span><\/pre>\n\n\n<h3 class=\"wp-block-heading\">15.4 Generate locally trusted TLS certificates<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">We need HTTPS because authentication sessions and browser security depend on secure connections.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>mkcert<\/code> makes local development certificates that your computer can trust.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">macOS or Linux Terminal:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">cd ~<span class=\"hljs-regexp\">\/pomerium-lab\/<\/span>certs\n\nmkcert -install\n\nmkcert <span class=\"hljs-string\">\"*.localhost.pomerium.io\"<\/span>\n\ncd ..<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Windows PowerShell:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-built_in\">Set<\/span>-Location <span class=\"hljs-string\">\"$HOME\\pomerium-lab\\certs\"<\/span>\n\nmkcert -install\n\nmkcert <span class=\"hljs-string\">\"*.localhost.pomerium.io\"<\/span>\n\n<span class=\"hljs-built_in\">Set<\/span>-Location ..<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">You should now have files resembling:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">certs\/\n\u251c\u2500\u2500 _wildcard.localhost.pomerium.io.pem\n\u2514\u2500\u2500 _wildcard.localhost.pomerium.io-key.pem<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The first file contains the local server certificate. The second contains its private key.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The certificate is for local development only. Do not publish the private key, and do not share mkcert&#8217;s local root certificate authority private key.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">15.5 Create the Pomerium configuration<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Create <code>config.yaml<\/code> in the project root using your text editor.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\"># config.yaml<\/span>\n\n<span class=\"hljs-comment\"># Development authentication service.<\/span>\nauthenticate_service_url: https:<span class=\"hljs-comment\">\/\/authenticate.pomerium.app<\/span>\n\n<span class=\"hljs-comment\"># Locally trusted TLS certificate.<\/span>\ncertificate_file: \/pomerium\/certs\/_wildcard.localhost.pomerium.io.pem\ncertificate_key_file: \/pomerium\/certs\/_wildcard.localhost.pomerium.io-key.pem\n\n<span class=\"hljs-comment\"># Protected application routes.<\/span>\nroutes:\n  - from: https:<span class=\"hljs-comment\">\/\/verify.localhost.pomerium.io<\/span>\n    to: http:<span class=\"hljs-comment\">\/\/verify:8000<\/span>\n\n    pass_identity_headers: <span class=\"hljs-keyword\">true<\/span>\n\n    policy:\n      - allow:\n          <span class=\"hljs-keyword\">or<\/span>:\n            - email:\n                is: learner@example.com<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Important: Replace <code>learner@example.com<\/code> with the email address you will actually use to authenticate.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Understanding the configuration<\/h4>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Setting<\/th><th>Explanation<\/th><\/tr><tr><td><code>authenticate_service_url<\/code><\/td><td>Specifies the hosted authentication service used in this demonstration<\/td><\/tr><tr><td><code>certificate_file<\/code><\/td><td>Path to the server certificate inside the Pomerium container<\/td><\/tr><tr><td><code>certificate_key_file<\/code><\/td><td>Path to the corresponding private key<\/td><\/tr><tr><td><code>routes<\/code><\/td><td>Collection of protected application routes<\/td><\/tr><tr><td><code>from<\/code><\/td><td>Address users open in their browsers<\/td><\/tr><tr><td><code>to<\/code><\/td><td>Destination to which Pomerium forwards authorized requests<\/td><\/tr><tr><td><code>pass_identity_headers<\/code><\/td><td>Enables forwarding of Pomerium identity assertion headers<\/td><\/tr><tr><td><code>policy<\/code><\/td><td>Defines authorization rules<\/td><\/tr><tr><td><code>allow<\/code><\/td><td>Specifies conditions that grant access<\/td><\/tr><tr><td><code>email<\/code><\/td><td>Checks the authenticated user&#8217;s email identity<\/td><\/tr><tr><td><code>is<\/code><\/td><td>Requires an exact value match<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The Verify app will be reachable through Pomerium, not through a separately published application port.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">15.6 Create Docker Compose configuration<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Create <code>compose.yaml<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">services:\n  pomerium:\n    image: pomerium\/pomerium:v0<span class=\"hljs-number\">.33<\/span><span class=\"hljs-number\">.4<\/span>\n\n    ports:\n      - <span class=\"hljs-string\">\"127.0.0.1:443:443\"<\/span>\n\n    volumes:\n      - .\/config.yaml:\/pomerium\/config.yaml:ro\n      - .\/certs:\/pomerium\/certs:ro\n\n    networks:\n      - <span class=\"hljs-keyword\">private<\/span>\n\n  verify:\n    image: pomerium\/verify:latest\n\n    expose:\n      - <span class=\"hljs-string\">\"8000\"<\/span>\n\n    networks:\n      - <span class=\"hljs-keyword\">private<\/span>\n\nnetworks:\n  <span class=\"hljs-keyword\">private<\/span>: {}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h4 class=\"wp-block-heading\">What the file does<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\"><code>pomerium<\/code> service: Runs the official Pomerium Core image.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>verify<\/code> service: Runs the official demo application.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Port mapping: Binds Pomerium&#8217;s HTTPS listener to the local machine&#8217;s loopback interface on port 443.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Volumes: Mounts configuration and certificates from the host computer into the container.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Read-only mounts: The <code>:ro<\/code> suffix prevents the container from writing to those mounted host paths.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Private network: Allows the two containers to communicate.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>expose<\/code>: Documents the Verify service&#8217;s internal port without publishing that port to the host.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This uses a pinned Pomerium Core version to make the tutorial reproducible. The demo image follows the official example&#8217;s <code>latest<\/code> pattern; pin that dependency to a tested version or image digest for a reproducible production build.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">15.7 Validate the Compose file<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Open Terminal or PowerShell inside <code>pomerium-lab<\/code>.<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose config --quiet<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This checks the Compose configuration.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If the command succeeds, it normally produces no output.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It does not fully validate Pomerium&#8217;s own configuration, certificates, or access policies.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">15.8 Start the application stack<\/h3>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose up -d<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The command downloads images when necessary, creates the Docker network, and starts the services.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>-d<\/code> option means detached mode: the containers run without occupying the current terminal.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">15.9 Check container status<\/h3>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose ps<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Both services should show a running state.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To inspect Pomerium&#8217;s output:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose logs --tail=100 pomerium<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Look for successful startup and configuration messages.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Do not assume that a container being listed as running means the full authentication process works. We must test it.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">15.10 Run Pomerium&#8217;s health check<\/h3>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose exec pomerium pomerium health<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Pomerium&#8217;s official container includes a health subcommand. It returns success when its applicable health checks pass.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For more detail:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose exec pomerium pomerium health -v<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Pomerium supports health reporting for components such as its proxy, authorization service, configuration, and storage. Pomerium<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">15.11 Open the application<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Your local protected application<\/p>\n\n\n\n<figure class=\"wp-block-embed\"><div class=\"wp-block-embed__wrapper\">\nhttps:\/\/verify.localhost.pomerium.io\n<\/div><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Open local Verify applicationThis URL only works after you have deployed the local lab successfully.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Your browser should reach Pomerium and enter the authentication flow.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Sign in using the email identity configured in <code>config.yaml<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Once your identity is verified and the route policy is satisfied, you should reach the Pomerium Verify application.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Depending on the Verify image and assertion configuration, the application may display available identity and session details.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If your route is denied, confirm the configured email exactly matches the authenticated identity.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">15.12 Test authorization<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">To understand why Pomerium is valuable, perform a small access-control experiment.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Open <code>config.yaml<\/code> and temporarily replace the permitted email address with a different address that you do not own.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">policy<\/span>:\n  <span class=\"hljs-selector-tag\">-<\/span> <span class=\"hljs-selector-tag\">allow<\/span>:\n      <span class=\"hljs-selector-tag\">or<\/span>:\n        <span class=\"hljs-selector-tag\">-<\/span> <span class=\"hljs-selector-tag\">email<\/span>:\n            <span class=\"hljs-selector-tag\">is<\/span>: <span class=\"hljs-selector-tag\">another-user<\/span><span class=\"hljs-keyword\">@example<\/span>.com<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Save the file.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium supports hot reloading of several configuration settings, but for a simple reproducible lab, explicitly restart its container:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose restart pomerium<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Return to the Verify application in your browser and refresh.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Your authenticated identity should no longer satisfy the route policy, so access should be denied.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Restore your actual email address in the configuration and restart Pomerium again.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This experiment demonstrates the difference between being authenticated and being authorized.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">15.13 Test application isolation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Observe that the Verify container has no host-published application port.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, opening <code>http:\/\/localhost:8000<\/code> should not reach this Verify service through the normal host network, assuming no unrelated application is listening there.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The Verify service is reached by Pomerium through the Docker network.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is only a local demonstration of network isolation, not a complete container-hardening or production network-security design.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">15.14 Shut down safely<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">When finished:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose down<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This stops and removes the containers and the Compose network.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Your configuration files and certificates remain in your project directory.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Do not add <code>--volumes<\/code> to a cleanup command casually in later projects, because named volumes may hold persistent data.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">15.15 First-lab troubleshooting<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Symptom<\/th><th>Likely cause<\/th><th>First action<\/th><\/tr><tr><td>Docker command fails<\/td><td>Docker engine unavailable<\/td><td>Start Docker Desktop or Docker service<\/td><\/tr><tr><td>Port binding error<\/td><td>Port 443 already used<\/td><td>Identify the competing listener<\/td><\/tr><tr><td>Browser certificate warning<\/td><td>mkcert certificate not trusted<\/td><td>Check mkcert installation and trust<\/td><\/tr><tr><td>Login repeatedly fails<\/td><td>Authentication or browser session problem<\/td><td>Inspect logs and browser redirects<\/td><\/tr><tr><td>Access denied<\/td><td>Email does not match policy<\/td><td>Verify authenticated email<\/td><\/tr><tr><td>Proxy error<\/td><td>Verify container not reachable<\/td><td>Check Compose network and service status<\/td><\/tr><tr><td>Nothing loads<\/td><td>Container not running, port problem, or DNS issue<\/td><td>Check <code>docker compose ps<\/code> and logs<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">15.16 Success criteria<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">You have completed your first Pomerium deployment when you can demonstrate all of the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Pomerium starts in Docker.<\/li>\n\n\n\n<li>The Verify application is reachable through the Pomerium HTTPS route.<\/li>\n\n\n\n<li>Authentication completes successfully.<\/li>\n\n\n\n<li>The authorized identity can access the application.<\/li>\n\n\n\n<li>An identity that does not meet the policy is denied.<\/li>\n\n\n\n<li>The application is not independently published on the host&#8217;s port 8000.<\/li>\n\n\n\n<li>Pomerium logs and health checks can be inspected.<\/li>\n\n\n\n<li>You can stop the environment safely.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">You have now built a working identity-aware application access gateway.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Part V \u2014 Commands, Configuration, and Daily Usage<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 16. Essential Commands and Operations<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium Core is primarily a service rather than an interactive command-line application.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In our Docker deployment, most daily operations use Docker Compose. The Pomerium server binary also supports operational commands such as health checks.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Do not confuse the Pomerium server binary with the separate <code>pomerium-cli<\/code> client used for certain non-HTTP connections.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">16.1 Docker Compose command reference<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Command<\/th><th>Purpose<\/th><th>When to use it<\/th><th>Warning<\/th><\/tr><tr><td><code>docker compose up -d<\/code><\/td><td>Start the stack<\/td><td>Initial startup<\/td><td>Starts configured services<\/td><\/tr><tr><td><code>docker compose ps<\/code><\/td><td>Show service status<\/td><td>Routine inspection<\/td><td>Running does not prove application health<\/td><\/tr><tr><td><code>docker compose logs<\/code><\/td><td>Show logs<\/td><td>Troubleshooting<\/td><td>Logs can contain sensitive data<\/td><\/tr><tr><td><code>docker compose logs -f<\/code><\/td><td>Follow logs<\/td><td>Live diagnosis<\/td><td>Runs until interrupted<\/td><\/tr><tr><td><code>docker compose restart pomerium<\/code><\/td><td>Restart Pomerium<\/td><td>Apply restart-requiring changes<\/td><td>Interrupts active connections<\/td><\/tr><tr><td><code>docker compose pull<\/code><\/td><td>Download configured images<\/td><td>Preparing upgrades<\/td><td>May download newer images for floating tags<\/td><\/tr><tr><td><code>docker compose config --quiet<\/code><\/td><td>Validate Compose configuration<\/td><td>Before deployment<\/td><td>Does not validate Pomerium policies<\/td><\/tr><tr><td><code>docker compose exec pomerium pomerium health<\/code><\/td><td>Check Pomerium health<\/td><td>Routine verification<\/td><td>Requires running container<\/td><\/tr><tr><td><code>docker compose down<\/code><\/td><td>Stop and remove Compose services<\/td><td>Lab cleanup<\/td><td>Interrupts access<\/td><\/tr><tr><td><code>docker compose down --volumes<\/code><\/td><td>Remove containers and named volumes<\/td><td>Destructive lab reset<\/td><td>Deletes persisted volume data<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">16.2 Basic daily operations<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Start the environment:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose up -d<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Inspect it:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose ps<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Read recent logs:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose logs --tail=100 pomerium<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Follow new log messages:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose logs -f pomerium<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Stop following logs with <code>Ctrl+C<\/code>. This does not stop the container.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">16.3 Inspect container health<\/h3>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose exec pomerium pomerium health<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Verbose diagnostic output:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose exec pomerium pomerium health -v<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Pomerium&#8217;s health command uses process exit status to indicate success or failure. A successful check exits with code zero.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">16.4 Check the running image<\/h3>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose images<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This helps identify which container images are associated with the current Compose project.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To inspect the pinned Pomerium image:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker image inspect pomerium\/pomerium:v0.33.4<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Image inspection provides container-image metadata. It is not a substitute for checking Pomerium&#8217;s release notes and security advisories.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">16.5 Native Pomerium commands<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For users running a native server binary, the documented startup form is:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">.\/pomerium -config config.yaml<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The configuration path identifies the file to load.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium&#8217;s operational health command is:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">pomerium health<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">For command-specific assistance:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">pomerium health --help<\/code><\/span><\/pre>\n\n\n<h3 class=\"wp-block-heading\">16.6 The separate Pomerium client<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>pomerium-cli<\/code> tool is used for supported client-side connections such as TCP routes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After installing the appropriate client from the official Pomerium client documentation, inspect its available commands:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">pomerium-cli --help<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">For example, the client supports TCP access to correctly configured Pomerium TCP routes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is an advanced topic because it requires more than a browser-accessible HTTP route. Pomerium<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 17. Configuration Explained<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">17.1 Pomerium&#8217;s configuration model<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium Core supports configuration files and environment variables.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Common configuration formats include YAML, JSON, and TOML, although this tutorial uses YAML because it is widely used in infrastructure management.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When the same configuration key is specified in both the configuration file and the environment, the environment variable takes precedence. Pomerium<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">17.2 Global settings versus route settings<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Global configuration affects the Pomerium deployment more broadly.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Route-specific configuration affects a particular protected application.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\"># Global setting<\/span>\nlog_level: info\n\nroutes:\n  <span class=\"hljs-comment\"># Route-specific settings<\/span>\n  - from: https:<span class=\"hljs-comment\">\/\/portal.localhost.pomerium.io<\/span>\n    to: http:<span class=\"hljs-comment\">\/\/portal:80<\/span>\n\n    policy:\n      - allow:\n          <span class=\"hljs-keyword\">or<\/span>:\n            - email:\n                is: learner@example.com<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The logging setting is global.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The URL mapping and policy are specific to the portal route.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">17.3 Understanding Pomerium Policy Language<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium Policy Language (PPL) lets administrators describe authorization logic.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The major building blocks are:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Component<\/th><th>Meaning<\/th><\/tr><tr><td><code>allow<\/code><\/td><td>Define circumstances granting access<\/td><\/tr><tr><td><code>deny<\/code><\/td><td>Define circumstances denying access<\/td><\/tr><tr><td><code>and<\/code><\/td><td>Require multiple conditions<\/td><\/tr><tr><td><code>or<\/code><\/td><td>Permit matching any of several conditions<\/td><\/tr><tr><td><code>email<\/code><\/td><td>Compare an authenticated email<\/td><\/tr><tr><td><code>domain<\/code><\/td><td>Compare the email&#8217;s domain<\/td><\/tr><tr><td><code>user<\/code><\/td><td>Compare a user identifier<\/td><\/tr><tr><td><code>groups<\/code><\/td><td>Evaluate group-related identity data when available<\/td><\/tr><tr><td><code>claim\/...<\/code><\/td><td>Evaluate a particular identity claim<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">For example, to permit either of two users:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-17\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">policy<\/span>:\n  <span class=\"hljs-selector-tag\">-<\/span> <span class=\"hljs-selector-tag\">allow<\/span>:\n      <span class=\"hljs-selector-tag\">or<\/span>:\n        <span class=\"hljs-selector-tag\">-<\/span> <span class=\"hljs-selector-tag\">email<\/span>:\n            <span class=\"hljs-selector-tag\">is<\/span>: <span class=\"hljs-selector-tag\">alice<\/span><span class=\"hljs-keyword\">@example<\/span>.com\n        - <span class=\"hljs-attribute\">email:<\/span>\n            <span class=\"hljs-attribute\">is:<\/span> bob@example.com<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">17.4 Combining allow and deny logic<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Suppose everyone in <code>example.com<\/code> may access a portal except a specifically blocked user.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-18\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">policy<\/span>:\n  <span class=\"hljs-selector-tag\">allow<\/span>:\n    <span class=\"hljs-selector-tag\">and<\/span>:\n      <span class=\"hljs-selector-tag\">-<\/span> <span class=\"hljs-selector-tag\">domain<\/span>:\n          <span class=\"hljs-selector-tag\">is<\/span>: <span class=\"hljs-selector-tag\">example<\/span><span class=\"hljs-selector-class\">.com<\/span>\n\n  <span class=\"hljs-selector-tag\">deny<\/span>:\n    <span class=\"hljs-selector-tag\">and<\/span>:\n      <span class=\"hljs-selector-tag\">-<\/span> <span class=\"hljs-selector-tag\">email<\/span>:\n          <span class=\"hljs-selector-tag\">is<\/span>: <span class=\"hljs-selector-tag\">blocked<\/span><span class=\"hljs-keyword\">@example<\/span>.com<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-18\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Pomerium&#8217;s policy evaluation requires an applicable allow decision and no matching deny condition. Explicit deny takes precedence over allow. Pomerium<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">17.5 Handling secrets correctly<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Our first lab intentionally used minimal configuration.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For a more persistent setup, we should explicitly configure cryptographic secrets and state storage.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium uses important secrets such as:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Shared secret: Used for secure communication among Pomerium services.<\/li>\n\n\n\n<li>Cookie secret: Used to protect session cookies.<\/li>\n\n\n\n<li>Identity-provider credentials: Required when using a custom identity provider.<\/li>\n\n\n\n<li>Signing key: Used when providing signed identity assertions to applications.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">These have different purposes. Do not reuse the same secret for unrelated settings.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">17.6 Generate cryptographically random secrets<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A simple cross-platform approach is to use a temporary Alpine Linux container.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Run this command twice:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-19\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">docker run --rm alpine:<span class=\"hljs-number\">3.20<\/span> \\\n  sh -c <span class=\"hljs-string\">\"head -c 32 \/dev\/urandom | base64\"<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-19\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">On Windows PowerShell, use the same command on one line:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-20\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">docker run --rm alpine:<span class=\"hljs-number\">3.20<\/span> sh -c <span class=\"hljs-string\">\"head -c 32 \/dev\/urandom | base64\"<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-20\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Each execution should produce a different Base64-encoded random value.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Use one value for <code>SHARED_SECRET<\/code> and another for <code>COOKIE_SECRET<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">17.7 Create a local environment file<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In your project directory, create <code>.env<\/code>.<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">POMERIUM_SHARED_SECRET=REPLACE_WITH_FIRST_GENERATED_VALUE\nPOMERIUM_COOKIE_SECRET=REPLACE_WITH_SECOND_GENERATED_VALUE<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Replace both placeholders.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Do not commit this file to a Git repository.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create <code>.gitignore<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-21\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-class\">.env<\/span>\n\n<span class=\"hljs-selector-tag\">certs<\/span><span class=\"hljs-comment\">\/*-key.pem\n*.key\nec_private.pem<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-21\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This file helps prevent accidental source-control commits, but it does not provide encryption or a production secrets-management system.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">17.8 Enable persistent Databroker storage<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Update <code>config.yaml<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-22\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">authenticate_service_url: https:<span class=\"hljs-comment\">\/\/authenticate.pomerium.app<\/span>\n\ncertificate_file: \/pomerium\/certs\/_wildcard.localhost.pomerium.io.pem\ncertificate_key_file: \/pomerium\/certs\/_wildcard.localhost.pomerium.io-key.pem\n\n<span class=\"hljs-comment\"># Persist session-related data locally.<\/span>\ndatabroker_storage_type: file\ndatabroker_storage_connection_string: file:<span class=\"hljs-comment\">\/\/\/data\/pomerium<\/span>\n\nlog_level: info\n\nroutes:\n  - from: https:<span class=\"hljs-comment\">\/\/verify.localhost.pomerium.io<\/span>\n    to: http:<span class=\"hljs-comment\">\/\/verify:8000<\/span>\n\n    pass_identity_headers: <span class=\"hljs-keyword\">true<\/span>\n\n    policy:\n      - allow:\n          <span class=\"hljs-keyword\">or<\/span>:\n            - email:\n                is: learner@example.com<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-22\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Remember to replace the email.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now replace <code>compose.yaml<\/code> with:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-23\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">services:\n  pomerium:\n    image: pomerium\/pomerium:v0<span class=\"hljs-number\">.33<\/span><span class=\"hljs-number\">.4<\/span>\n\n    ports:\n      - <span class=\"hljs-string\">\"127.0.0.1:443:443\"<\/span>\n\n    environment:\n      SHARED_SECRET: ${POMERIUM_SHARED_SECRET}\n      COOKIE_SECRET: ${POMERIUM_COOKIE_SECRET}\n\n    volumes:\n      - .\/config.yaml:\/pomerium\/config.yaml:ro\n      - .\/certs:\/pomerium\/certs:ro\n      - pomerium-data:\/data\n\n    networks:\n      - <span class=\"hljs-keyword\">private<\/span>\n\n  verify:\n    image: pomerium\/verify:latest\n\n    expose:\n      - <span class=\"hljs-string\">\"8000\"<\/span>\n\n    networks:\n      - <span class=\"hljs-keyword\">private<\/span>\n\nnetworks:\n  <span class=\"hljs-keyword\">private<\/span>: {}\n\nvolumes:\n  pomerium-data:<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-23\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The named volume stores the local Databroker files across ordinary container recreation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is a persistent, single-instance configuration\u2014not a high-availability architecture.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">17.9 Apply the changes<\/h3>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose config --quiet\ndocker compose up -d<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Recreating Pomerium after introducing new secrets may invalidate previously established sessions. Sign in again if necessary.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Verify health:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose exec pomerium pomerium health -v<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The file-backed Databroker should now be configured, provided the volume is mounted and writable.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The hosted authentication service still has its own session limitations. Persistent local storage does not remove those limitations.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">17.10 Configuration precedence<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Source<\/th><th>Behavior<\/th><th>Typical usage<\/th><\/tr><tr><td>YAML configuration file<\/td><td>Defines Core configuration<\/td><td>Routes, policies, runtime settings<\/td><\/tr><tr><td>Environment variables<\/td><td>Override duplicate file keys<\/td><td>Runtime secrets and deployment settings<\/td><\/tr><tr><td>Product-specific control plane<\/td><td>Manages supported configuration in Zero or Enterprise<\/td><td>Centralized administration<\/td><\/tr><tr><td>Bootstrap configuration<\/td><td>Initializes important runtime settings<\/td><td>Internal service secrets and addresses<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium can hot-reload several configuration categories, including routes and policies. Other changes may require service recreation or restart.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Always verify the effective behavior after a configuration update.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 18. Logs, Status, and Verification<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">18.1 Installation success is not operational success<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A running container proves only that a process is running.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A fully working Pomerium deployment must also authenticate users, evaluate policies, connect to upstream applications, and return the correct responses.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">18.2 Routine diagnostic commands<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Inspect the deployment:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose ps<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Check Pomerium health:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose exec pomerium pomerium health -v<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Inspect recent logs:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose logs --tail=200 pomerium<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Inspect all service logs:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose logs --tail=100<\/code><\/span><\/pre>\n\n\n<h3 class=\"wp-block-heading\">18.3 Understanding health endpoints<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium exposes internal health checks, normally on <code>127.0.0.1:28080<\/code> within its runtime environment.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Endpoint<\/th><th>Purpose<\/th><\/tr><tr><td><code>\/startupz<\/code><\/td><td>Startup readiness<\/td><\/tr><tr><td><code>\/readyz<\/code><\/td><td>Readiness to receive traffic<\/td><\/tr><tr><td><code>\/healthz<\/code><\/td><td>Liveness<\/td><\/tr><tr><td><code>\/status<\/code><\/td><td>Human-readable component status<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">These are distinct from Pomerium&#8217;s public listener and routing endpoints.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The internal health port should not be exposed directly to the public Internet. Pomerium<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">18.4 HTTP connectivity check<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">On macOS or Linux:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-24\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">curl -I https:<span class=\"hljs-comment\">\/\/verify.localhost.pomerium.io\/ping<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-24\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">On Windows PowerShell:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-25\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">curl.exe -I https:<span class=\"hljs-comment\">\/\/verify.localhost.pomerium.io\/ping<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-25\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Pomerium documents <code>\/ping<\/code> as a special endpoint for basic connectivity and health checks.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A normal result is an HTTP success response such as <code>200 OK<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This proves basic HTTPS reachability to Pomerium, not that authentication or an upstream application is functioning.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">18.5 Understanding HTTP status codes<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Status<\/th><th>Meaning<\/th><th>What to inspect<\/th><\/tr><tr><td>200<\/td><td>Successful response<\/td><td>Confirm it is from the expected endpoint<\/td><\/tr><tr><td>301 \/ 302<\/td><td>Redirect<\/td><td>Check login and destination URLs<\/td><\/tr><tr><td>401<\/td><td>Authentication-related failure<\/td><td>Credentials, tokens, session<\/td><\/tr><tr><td>403<\/td><td>Access forbidden<\/td><td>Policy and user identity<\/td><\/tr><tr><td>404<\/td><td>Resource not found<\/td><td>Hostname, route, application path<\/td><\/tr><tr><td>502<\/td><td>Bad gateway<\/td><td>Upstream availability and connectivity<\/td><\/tr><tr><td>503<\/td><td>Service unavailable<\/td><td>Gateway or backend health<\/td><\/tr><tr><td>504<\/td><td>Gateway timeout<\/td><td>Connectivity, slow backend, timeout configuration<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">These are general HTTP meanings. The exact cause depends on the responding component.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">18.6 Log levels<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium supports logging levels such as <code>info<\/code>, <code>warn<\/code>, <code>error<\/code>, <code>debug<\/code>, and <code>trace<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For routine operation:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-26\" data-shcb-language-name=\"HTTP\" data-shcb-language-slug=\"http\"><span><code class=\"hljs language-http\"><span class=\"hljs-attribute\">log_level<\/span>: info<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-26\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTTP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">http<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">For targeted troubleshooting:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-27\" data-shcb-language-name=\"HTTP\" data-shcb-language-slug=\"http\"><span><code class=\"hljs language-http\"><span class=\"hljs-attribute\">log_level<\/span>: debug<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-27\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTTP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">http<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Use more verbose levels temporarily when needed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Verbose logs can increase data volume and expose sensitive operational context. Restrict access and return to the normal logging level after diagnosis.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">18.7 A systematic troubleshooting method<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">#chatgpt-mermaid-_r_22g_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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=&#8221;neo&#8221;].node rect,#chatgpt-mermaid-_r_22g_ [data-look=&#8221;neo&#8221;].cluster rect,#chatgpt-mermaid-_r_22g_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_22g_ [data-look=&#8221;neo&#8221;].node path{stroke:url(#chatgpt-mermaid-_r_22g_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_22g_ [data-look=&#8221;neo&#8221;].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_22g_ [data-look=&#8221;neo&#8221;].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_22g_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_22g_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].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=&#8221;normal&#8221;],#chatgpt-mermaid-_r_22g_ .edgeLabels tspan[font-weight=&#8221;normal&#8221;]{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{&#8211;mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;}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<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Always find which layer is failing before changing configuration.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Part VI \u2014 Real-World Applications<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 19. Practical Use Cases<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium becomes particularly useful when access to multiple protected resources must be controlled consistently.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Use case 1 \u2014 Protect a personal development dashboard<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Problem: A developer has a private dashboard and does not want arbitrary visitors reaching it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Environment: A small self-hosted server or container environment.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Implementation: Deploy Pomerium in front of the dashboard and allow only the developer&#8217;s authenticated identity.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Expected outcome: The dashboard is accessed through the approved route, while direct access is restricted.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Success measurements: Successful authorized access, expected denial for unauthorized identities, and absence of unprotected public backend routes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Risk: The developer must still maintain the server, certificates, identity provider, and security updates.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Use case 2 \u2014 Centralize access for a development team<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Problem: A team maintains Jenkins, Grafana, internal documentation, and several engineering tools.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Environment: Applications hosted in Docker or virtual machines.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Implementation: Configure separate Pomerium routes and policies for different tools.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Protected service<\/th><th>Example access rule<\/th><\/tr><tr><td>Developer wiki<\/td><td>Approved employee identities<\/td><\/tr><tr><td>Jenkins<\/td><td>Authorized engineering team<\/td><\/tr><tr><td>Grafana<\/td><td>Engineering and operations<\/td><\/tr><tr><td>Administration portal<\/td><td>Explicit administrator identities<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Expected outcome: Consistent, reviewable access policies across multiple applications.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Success measurements: Authorized versus denied requests, access-provisioning effort, and number of independently exposed services.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Risk: Incorrect policy scope could grant broader access than intended.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Use case 3 \u2014 Secure production administration tools<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Problem: Production administration applications should not be freely reachable.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Environment: Private cloud networks or data centers.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Implementation: Deploy Pomerium as an enforced access boundary, integrate corporate authentication, require suitable MFA, and restrict routes to approved identities.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Expected outcome: Access to administration interfaces is controlled centrally.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Success measurements: Policy-test results, authentication success and failure trends, audit coverage, and gateway uptime.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Risk: A misconfigured network route could allow access around Pomerium. The administration application must also enforce its internal privileges.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Use case 4 \u2014 Protect applications running in Kubernetes<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Problem: Teams need access to internal services running inside Kubernetes clusters.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Environment: Kubernetes with an ingress controller, internal services, and a corporate IdP.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Implementation: Deploy the supported Pomerium Kubernetes integration, configure routes, and enforce authorization policies.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Expected outcome: Developers reach approved applications through the protected ingress layer.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Success measurements: Valid ingress routing, successful allow\/deny tests, deployment availability, and changes managed through version control.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Risk: Kubernetes networking, ingress configuration, TLS certificate issuance, and Pomerium access policies must be coordinated.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Use case 5 \u2014 Control contractor access<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Problem: A contractor needs access to one project tool but should not receive unnecessary network or application permissions.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Environment: Corporate identity provider and internal project application.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Implementation: Establish a contractor identity, define a narrow route policy, and remove permission when work finishes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Expected outcome: Access is limited to the approved service and duration.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Success measurements: Only approved identities succeed; access removal takes effect as expected.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Risk: Time-based access lifecycle and session revocation must be designed carefully. A route policy alone does not automatically implement every contract-expiration rule.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Use case 6 \u2014 Secure machine-to-machine access<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Problem: An automated process needs to call a protected service without an interactive browser login.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Environment: Automated pipelines, scheduled jobs, or service integrations.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Implementation: Evaluate Pomerium Zero or Enterprise service accounts, or another supported token-based integration appropriate to the authentication model.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Expected outcome: An authorized machine identity can access the intended endpoint without sharing a human user&#8217;s password.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Success measurements: Successful token validation, least-privilege policy behavior, and safe credential rotation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Risk: Exposed service-account tokens can be abused. Tokens require protection, expiration, and rotation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium documents service-account creation for Zero and Enterprise, along with token-based access methods. Pomerium<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 20. A Complete Hands-On Project<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Project: Secure an Internal Operations Portal with Pomerium<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">We will now extend the first lab into a more realistic multi-application setup.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The project includes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>A private NGINX web portal.<\/li>\n\n\n\n<li>The Pomerium Verify application.<\/li>\n\n\n\n<li>Two protected routes.<\/li>\n\n\n\n<li>Email-based authorization.<\/li>\n\n\n\n<li>Local HTTPS certificates.<\/li>\n\n\n\n<li>Persistent Pomerium state.<\/li>\n\n\n\n<li>Runtime secrets separated from configuration.<\/li>\n\n\n\n<li>A basic Pomerium health check.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">20.1 Project objective<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Build a private web portal that a permitted user can access through Pomerium, while unauthorized users are denied.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">20.2 Architecture<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">#chatgpt-mermaid-_r_22r_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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=&#8221;neo&#8221;].node rect,#chatgpt-mermaid-_r_22r_ [data-look=&#8221;neo&#8221;].cluster rect,#chatgpt-mermaid-_r_22r_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_22r_ [data-look=&#8221;neo&#8221;].node path{stroke:url(#chatgpt-mermaid-_r_22r_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_22r_ [data-look=&#8221;neo&#8221;].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_22r_ [data-look=&#8221;neo&#8221;].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_22r_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_22r_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].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=&#8221;normal&#8221;],#chatgpt-mermaid-_r_22r_ .edgeLabels tspan[font-weight=&#8221;normal&#8221;]{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{&#8211;mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;}Private Docker networkVerify applicationNGINX operations portalBrowserPomerium CoreHosted authenticationPersistent Databroker filesHTTPSLoginRoute 1Route 2<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">20.3 Directory structure<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Our completed project will look like this:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">pomerium-lab\/\n\u251c\u2500\u2500 .env\n\u251c\u2500\u2500 .gitignore\n\u251c\u2500\u2500 compose.yaml\n\u251c\u2500\u2500 config.yaml\n\u251c\u2500\u2500 certs\/\n\u2502   \u251c\u2500\u2500 _wildcard.localhost.pomerium.io.pem\n\u2502   \u2514\u2500\u2500 _wildcard.localhost.pomerium.io-key.pem\n\u2514\u2500\u2500 site\/\n    \u2514\u2500\u2500 index.html<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Use the secrets and certificates generated in the previous chapters.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">20.4 Create the application directory<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">macOS\/Linux:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">cd ~\/pomerium-lab\nmkdir -p site<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Windows PowerShell:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-28\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-built_in\">Set<\/span>-Location <span class=\"hljs-string\">\"$HOME\\pomerium-lab\"<\/span>\nNew-Item -ItemType Directory -Force site<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-28\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">20.5 Build the private web application<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Create <code>site\/index.html<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-29\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-meta\">&lt;!DOCTYPE <span class=\"hljs-meta-keyword\">html<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">html<\/span> <span class=\"hljs-attr\">lang<\/span>=<span class=\"hljs-string\">\"en\"<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">head<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">meta<\/span> <span class=\"hljs-attr\">charset<\/span>=<span class=\"hljs-string\">\"UTF-8\"<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">meta<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"viewport\"<\/span>\n        <span class=\"hljs-attr\">content<\/span>=<span class=\"hljs-string\">\"width=device-width, initial-scale=1\"<\/span>&gt;<\/span>\n\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">title<\/span>&gt;<\/span>Internal Operations Portal<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">title<\/span>&gt;<\/span>\n\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">style<\/span>&gt;<\/span><span class=\"css\">\n    <span class=\"hljs-selector-tag\">body<\/span> {\n      <span class=\"hljs-attribute\">font-family<\/span>: Arial, sans-serif;\n      <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-number\">#f5f7fa<\/span>;\n      <span class=\"hljs-attribute\">margin<\/span>: <span class=\"hljs-number\">0<\/span>;\n      <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">40px<\/span> <span class=\"hljs-number\">20px<\/span>;\n    }\n\n    <span class=\"hljs-selector-tag\">main<\/span> {\n      <span class=\"hljs-attribute\">max-width<\/span>: <span class=\"hljs-number\">700px<\/span>;\n      <span class=\"hljs-attribute\">margin<\/span>: <span class=\"hljs-number\">0<\/span> auto;\n      <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">32px<\/span>;\n      <span class=\"hljs-attribute\">background<\/span>: white;\n      <span class=\"hljs-attribute\">border-radius<\/span>: <span class=\"hljs-number\">12px<\/span>;\n      <span class=\"hljs-attribute\">box-shadow<\/span>: <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">4px<\/span> <span class=\"hljs-number\">20px<\/span> <span class=\"hljs-number\">#00000010<\/span>;\n    }\n\n    <span class=\"hljs-selector-tag\">h1<\/span> {\n      <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#1e293b<\/span>;\n    }\n\n    <span class=\"hljs-selector-tag\">p<\/span> {\n      <span class=\"hljs-attribute\">line-height<\/span>: <span class=\"hljs-number\">1.7<\/span>;\n    }\n\n    <span class=\"hljs-selector-class\">.status<\/span> {\n      <span class=\"hljs-attribute\">display<\/span>: inline-block;\n      <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">8px<\/span> <span class=\"hljs-number\">14px<\/span>;\n      <span class=\"hljs-attribute\">border-radius<\/span>: <span class=\"hljs-number\">8px<\/span>;\n      <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-number\">#dcfce7<\/span>;\n      <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#166534<\/span>;\n    }\n  <\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">style<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">head<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">body<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">main<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h1<\/span>&gt;<\/span>Internal Operations Portal<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h1<\/span>&gt;<\/span>\n\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n      This application is protected by Pomerium.\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"status\"<\/span>&gt;<\/span>\n      Application is reachable.\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h2<\/span>&gt;<\/span>About this demonstration<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h2<\/span>&gt;<\/span>\n\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n      Pomerium authenticates and authorizes requests\n      before forwarding traffic to this private\n      NGINX application.\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n      The NGINX container has no published host port.\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">main<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">body<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">html<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-29\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This is intentionally a simple static application.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It does not implement its own login functionality. The access enforcement happens before traffic reaches it.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">20.6 Create the final Pomerium configuration<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Replace <code>config.yaml<\/code> with:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-30\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">authenticate_service_url: https:<span class=\"hljs-comment\">\/\/authenticate.pomerium.app<\/span>\n\ncertificate_file: \/pomerium\/certs\/_wildcard.localhost.pomerium.io.pem\ncertificate_key_file: \/pomerium\/certs\/_wildcard.localhost.pomerium.io-key.pem\n\ndatabroker_storage_type: file\ndatabroker_storage_connection_string: file:<span class=\"hljs-comment\">\/\/\/data\/pomerium<\/span>\n\nlog_level: info\n\nroutes:\n  <span class=\"hljs-comment\"># Route 1: Identity verification demonstration<\/span>\n  - from: https:<span class=\"hljs-comment\">\/\/verify.localhost.pomerium.io<\/span>\n    to: http:<span class=\"hljs-comment\">\/\/verify:8000<\/span>\n\n    pass_identity_headers: <span class=\"hljs-keyword\">true<\/span>\n\n    policy:\n      - allow:\n          <span class=\"hljs-keyword\">or<\/span>:\n            - email:\n                is: learner@example.com\n\n  <span class=\"hljs-comment\"># Route 2: Internal operations portal<\/span>\n  - from: https:<span class=\"hljs-comment\">\/\/portal.localhost.pomerium.io<\/span>\n    to: http:<span class=\"hljs-comment\">\/\/portal:80<\/span>\n\n    policy:\n      - allow:\n          <span class=\"hljs-keyword\">or<\/span>:\n            - email:\n                is: learner@example.com<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-30\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Replace both occurrences of <code>learner@example.com<\/code> with your authenticated email.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The two routes have different <code>from<\/code> addresses and different upstream destinations.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Their policies are currently identical, but each can be changed independently.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">20.7 Create the final Compose configuration<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Replace <code>compose.yaml<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-31\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">services:\n  pomerium:\n    image: pomerium\/pomerium:v0<span class=\"hljs-number\">.33<\/span><span class=\"hljs-number\">.4<\/span>\n\n    ports:\n      - <span class=\"hljs-string\">\"127.0.0.1:443:443\"<\/span>\n\n    environment:\n      SHARED_SECRET: ${POMERIUM_SHARED_SECRET}\n      COOKIE_SECRET: ${POMERIUM_COOKIE_SECRET}\n\n    volumes:\n      - .\/config.yaml:\/pomerium\/config.yaml:ro\n      - .\/certs:\/pomerium\/certs:ro\n      - pomerium-data:\/data\n\n    healthcheck:\n      test: &#91;<span class=\"hljs-string\">\"CMD\"<\/span>, <span class=\"hljs-string\">\"pomerium\"<\/span>, <span class=\"hljs-string\">\"health\"<\/span>]\n      interval: <span class=\"hljs-number\">30<\/span>s\n      timeout: <span class=\"hljs-number\">5<\/span>s\n      retries: <span class=\"hljs-number\">5<\/span>\n\n    networks:\n      - <span class=\"hljs-keyword\">private<\/span>\n\n  verify:\n    image: pomerium\/verify:latest\n\n    expose:\n      - <span class=\"hljs-string\">\"8000\"<\/span>\n\n    networks:\n      - <span class=\"hljs-keyword\">private<\/span>\n\n  portal:\n    image: nginx:stable-alpine\n\n    volumes:\n      - .\/site:\/usr\/share\/nginx\/html:ro\n\n    expose:\n      - <span class=\"hljs-string\">\"80\"<\/span>\n\n    networks:\n      - <span class=\"hljs-keyword\">private<\/span>\n\nnetworks:\n  <span class=\"hljs-keyword\">private<\/span>: {}\n\nvolumes:\n  pomerium-data:<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-31\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This Compose file defines three services.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Only Pomerium publishes a host port.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The Verify and NGINX applications are private within the Compose network.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">20.8 Ensure secrets exist<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Your <code>.env<\/code> file must contain real, randomly generated values for:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">POMERIUM_SHARED_SECRET=REPLACE_WITH_GENERATED_VALUE\nPOMERIUM_COOKIE_SECRET=REPLACE_WITH_ANOTHER_GENERATED_VALUE<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Do not leave the placeholders unchanged.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The file should remain local and excluded from version control.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">20.9 Validate and start the project<\/h3>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose config --quiet\ndocker compose up -d\ndocker compose ps<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The services should start.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium should eventually report healthy.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Check:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose exec pomerium pomerium health -v<\/code><\/span><\/pre>\n\n\n<h3 class=\"wp-block-heading\">20.10 Test both applications<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Verify application<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Identity and authorization test<a href=\"https:\/\/verify.localhost.pomerium.io\/?utm_source=chatgpt.com\">Open Verify<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Operations portal<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Private NGINX application<a href=\"https:\/\/portal.localhost.pomerium.io\/?utm_source=chatgpt.com\">Open Operations Portal<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">These are local lab addresses and will only work on a computer where the corresponding Pomerium stack is running.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After successful authentication, the Operations Portal should display the HTML page we created.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">20.11 Experiment: Different application permissions<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Change the portal route to permit a different email while leaving the Verify route unchanged:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> <code> - from: https:\/\/portal.localhost.pomerium.io\n    to: http:\/\/portal:80\n\n    policy:\n      - allow:\n          or:\n            - email:\n                is: other-user@example.com<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Restart Pomerium:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose restart pomerium<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Now test both routes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Your original identity should still satisfy the Verify policy but should no longer satisfy the portal policy.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This demonstrates independent access rules for different applications.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Restore your original portal policy afterward.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">20.12 Verify network exposure<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Inspect published ports:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose ps<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Only the Pomerium service should show a published host port.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The NGINX container&#8217;s internal port 80 should not appear as a separately published host port.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">20.13 Failure experiment<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Stop only the portal service:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose stop portal<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Try to access:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-32\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">https:<span class=\"hljs-comment\">\/\/portal.localhost.pomerium.io<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-32\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Pomerium should remain available, but its portal upstream is now unavailable.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You may receive a gateway error such as a 502 or 503 response, depending on the failure state.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Restore the portal:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose start portal<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Verify that the application becomes reachable again.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This teaches the distinction between gateway availability and upstream application availability.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">20.14 Cleanup<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Stop the complete project:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose down<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This preserves the named volume and project files.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For an intentional complete lab reset, after confirming that no useful data remains in the named volumes:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose down --volumes<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The second command deletes Compose-managed named volumes associated with the project. Do not use it on production systems without reviewing the consequences.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">20.15 Project completion criteria<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Your project is complete when:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Both applications are reachable through separate Pomerium routes.<\/li>\n\n\n\n<li>Unauthorized identities fail route authorization.<\/li>\n\n\n\n<li>The upstream containers are not exposed through host-published ports.<\/li>\n\n\n\n<li>Pomerium provides a successful health check.<\/li>\n\n\n\n<li>You can inspect logs and change policies.<\/li>\n\n\n\n<li>You understand how an upstream failure differs from a Pomerium failure.<\/li>\n\n\n\n<li>You can stop and restore the environment safely.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">20.16 Suggested improvements<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">These improvements form the bridge to the advanced chapters.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Part VII \u2014 Advanced Capabilities<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 21. Advanced Pomerium Features<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The following capabilities are not required for the first local laboratory. Learn them after becoming comfortable with routing, authentication, policies, and operations.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">21.1 Advanced authorization policies<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A basic policy might allow one authenticated email address.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Advanced policies can combine multiple conditions, such as identity attributes, group membership, request context, and other supported criteria.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-33\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">policy<\/span>:\n  <span class=\"hljs-selector-tag\">allow<\/span>:\n    <span class=\"hljs-selector-tag\">or<\/span>:\n      <span class=\"hljs-selector-tag\">-<\/span> <span class=\"hljs-selector-tag\">email<\/span>:\n          <span class=\"hljs-selector-tag\">is<\/span>: <span class=\"hljs-selector-tag\">lead<\/span><span class=\"hljs-keyword\">@example<\/span>.com\n\n      - <span class=\"hljs-attribute\">domain:<\/span>\n          <span class=\"hljs-attribute\">is:<\/span> engineering.example.com\n\n  <span class=\"hljs-attribute\">deny:<\/span>\n    <span class=\"hljs-attribute\">and:<\/span>\n      - <span class=\"hljs-attribute\">email:<\/span>\n          <span class=\"hljs-attribute\">is:<\/span> suspended@example.com<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-33\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This illustrative policy allows a named user or users with the specified email domain, except the explicitly denied identity.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Prerequisite: Understanding how <code>allow<\/code>, <code>deny<\/code>, <code>and<\/code>, and <code>or<\/code> interact.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Trade-off: More complex policies can create surprising access decisions if they are not tested.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For sensitive services, create a test matrix before deploying a policy:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Identity<\/th><th>Should access?<\/th><th>Why?<\/th><\/tr><tr><td>Approved engineer<\/td><td>Yes<\/td><td>Meets allow condition<\/td><\/tr><tr><td>Approved team lead<\/td><td>Yes<\/td><td>Meets allow condition<\/td><\/tr><tr><td>Suspended employee<\/td><td>No<\/td><td>Explicit deny<\/td><\/tr><tr><td>External visitor<\/td><td>No<\/td><td>No matching allow<\/td><\/tr><tr><td>Missing identity data<\/td><td>No<\/td><td>Required policy condition cannot be established<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium Enterprise also supports Rego policies for advanced logic using Open Policy Agent&#8217;s policy language. Rego is not required for ordinary Core policies. Pomerium<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">21.2 Integrating a custom identity provider<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Our beginner lab uses Pomerium&#8217;s hosted authentication service.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A production deployment will often use a corporate identity provider.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The architecture changes to:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">ApplicationCorporate IdPPomeriumBrowserApplicationCorporate IdPPomeriumBrowser#chatgpt-mermaid-_r_26s_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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=&#8221;neo&#8221;]{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_26s_ rect.note[data-look=&#8221;neo&#8221;]{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&gt;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$=&#8221;-arrowhead&#8221;] path{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_26s_ .sequenceNumber{fill:#707070;}#chatgpt-mermaid-_r_26s_ [id$=&#8221;-sequencenumber&#8221;]{fill:rgb(143, 143, 143);}#chatgpt-mermaid-_r_26s_ [id$=&#8221;-crosshead&#8221;] 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&gt;tspan{fill:rgb(13, 13, 13);stroke:none;}#chatgpt-mermaid-_r_26s_ .loopText,#chatgpt-mermaid-_r_26s_ .loopText&gt;tspan{fill:rgb(13, 13, 13);stroke:none;}#chatgpt-mermaid-_r_26s_ .sectionTitle,#chatgpt-mermaid-_r_26s_ .sectionTitle&gt;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&gt;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=&#8221;neo&#8221;].node rect,#chatgpt-mermaid-_r_26s_ [data-look=&#8221;neo&#8221;].cluster rect,#chatgpt-mermaid-_r_26s_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_26s_ [data-look=&#8221;neo&#8221;].node path{stroke:url(#chatgpt-mermaid-_r_26s_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_26s_ [data-look=&#8221;neo&#8221;].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_26s_ [data-look=&#8221;neo&#8221;].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_26s_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_26s_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].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{&#8211;mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;}Request protected applicationInitiate authenticationAuthenticate through OIDCAuthentication redirectComplete authentication flowEstablish session and evaluate policyAuthorized requestApplication responseReturn response<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For a custom OpenID Connect integration, typical setup involves registering an application with the identity provider.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The integration requires values such as the provider or issuer information, a client identifier, a client secret, and approved redirect addresses.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium exposes corresponding settings such as:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-34\" data-shcb-language-name=\"HTTP\" data-shcb-language-slug=\"http\"><span><code class=\"hljs language-http\"><span class=\"hljs-attribute\">idp_provider<\/span>: oidc\n<span class=\"hljs-attribute\">idp_client_id<\/span>: REPLACE_WITH_CLIENT_ID\n<span class=\"hljs-attribute\">idp_client_secret<\/span>: REPLACE_WITH_CLIENT_SECRET<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-34\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTTP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">http<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Use the official instructions for the selected identity provider:<a href=\"https:\/\/www.pomerium.com\/docs\/capabilities\/authentication?utm_source=chatgpt.com\">Pomerium Authentication and SSO documentation<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Do not commit identity-provider client secrets to version control.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">21.3 Signed identity assertions and JWT verification<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">An internal application may need to know which user Pomerium authenticated.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium supports a signed identity assertion, commonly supplied through:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-35\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\">X-Pomerium-Jwt-Assertion: <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">SIGNED_JWT<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-35\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The application can verify the signature using Pomerium&#8217;s public key and validate important claims.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Generate a signing key<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">On a machine with OpenSSL installed:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-36\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">openssl<\/span> <span class=\"hljs-selector-tag\">ecparam<\/span> \\\n  <span class=\"hljs-selector-tag\">-genkey<\/span> \\\n  <span class=\"hljs-selector-tag\">-name<\/span> <span class=\"hljs-selector-tag\">prime256v1<\/span> \\\n  <span class=\"hljs-selector-tag\">-noout<\/span> \\\n  <span class=\"hljs-selector-tag\">-out<\/span> <span class=\"hljs-selector-tag\">ec_private<\/span><span class=\"hljs-selector-class\">.pem<\/span>\n\n<span class=\"hljs-selector-tag\">openssl<\/span> <span class=\"hljs-selector-tag\">ec<\/span> \\\n  <span class=\"hljs-selector-tag\">-in<\/span> <span class=\"hljs-selector-tag\">ec_private<\/span><span class=\"hljs-selector-class\">.pem<\/span> \\\n  <span class=\"hljs-selector-tag\">-pubout<\/span> \\\n  <span class=\"hljs-selector-tag\">-out<\/span> <span class=\"hljs-selector-tag\">ec_public<\/span><span class=\"hljs-selector-class\">.pem<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-36\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The private key must remain protected.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After securely mounting the private key in the Pomerium container, configure:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-37\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">signing_key_file: <span class=\"hljs-regexp\">\/pomerium\/<\/span>ec_private.pem<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-37\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">On a protected route:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-38\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">pass_identity_headers: <span class=\"hljs-literal\">true<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-38\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">An upstream application can retrieve the corresponding verification information from Pomerium&#8217;s JSON Web Key Set endpoint.<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">\/.well-known\/pomerium\/jwks.json<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Do not paste production identity tokens into public debugging websites. Pomerium<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">21.4 TCP and UDP access<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium also supports certain non-HTTP protocols through its client tools.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is a different workflow from accessing a normal website.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, a TCP route may look like:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-39\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">routes:\n  - <span class=\"hljs-keyword\">from<\/span>: tcp+https:<span class=\"hljs-comment\">\/\/ssh.example.com:22<\/span>\n    to: tcp:<span class=\"hljs-comment\">\/\/ssh.internal.example.com:22<\/span>\n\n    policy:\n      - allow:\n          or:\n            - email:\n                is: engineer@example.com<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-39\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This example assumes the named infrastructure exists and the upstream server is reachable.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A correctly configured client connection might use:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-40\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">pomerium-cli<\/span> <span class=\"hljs-selector-tag\">tcp<\/span> <span class=\"hljs-selector-tag\">ssh<\/span><span class=\"hljs-selector-class\">.example<\/span><span class=\"hljs-selector-class\">.com<\/span><span class=\"hljs-selector-pseudo\">:22<\/span> \\\n  <span class=\"hljs-selector-tag\">--listen<\/span> 127<span class=\"hljs-selector-class\">.0<\/span><span class=\"hljs-selector-class\">.0<\/span><span class=\"hljs-selector-class\">.1<\/span><span class=\"hljs-selector-pseudo\">:2222<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-40\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">In another terminal, a user can connect through the local forwarded port:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-41\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">ssh<\/span> 127<span class=\"hljs-selector-class\">.0<\/span><span class=\"hljs-selector-class\">.0<\/span><span class=\"hljs-selector-class\">.1<\/span> <span class=\"hljs-selector-tag\">-p<\/span> 2222<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-41\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">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 <code>pomerium-cli<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium also supports UDP tunneling using the appropriate client and route configuration.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">There is a significant security distinction: Pomerium&#8217;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<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">21.5 Kubernetes integration<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In Kubernetes, Pomerium can be deployed using its supported Kubernetes integration and Ingress Controller.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">An Ingress resource describes how incoming traffic is routed to a service.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The Pomerium controller integrates protected routing with Kubernetes configuration workflows.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">#chatgpt-mermaid-_r_291_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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=&#8221;neo&#8221;].node rect,#chatgpt-mermaid-_r_291_ [data-look=&#8221;neo&#8221;].cluster rect,#chatgpt-mermaid-_r_291_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_291_ [data-look=&#8221;neo&#8221;].node path{stroke:url(#chatgpt-mermaid-_r_291_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_291_ [data-look=&#8221;neo&#8221;].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_291_ [data-look=&#8221;neo&#8221;].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_291_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_291_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].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=&#8221;normal&#8221;],#chatgpt-mermaid-_r_291_ .edgeLabels tspan[font-weight=&#8221;normal&#8221;]{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{&#8211;mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;}UserKubernetes external entrypointPomeriumIdentity providerKubernetes ServiceApplication Pods<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A realistic Kubernetes deployment must account for service discovery, cluster networking, ingress configuration, persistent state, TLS certificates, and operational monitoring.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The Pomerium Ingress Controller documentation lists Kubernetes, supported CPU architectures, PostgreSQL, and a certificate-management solution among its prerequisites.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Official guide:<a href=\"https:\/\/www.pomerium.com\/docs\/deploy\/k8s\/install?utm_source=chatgpt.com\">Pomerium Kubernetes installation<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">21.6 High availability<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">High availability means designing the system so that an individual component failure does not necessarily interrupt the entire service.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A typical high-availability design includes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Multiple Pomerium replicas.<\/li>\n\n\n\n<li>Shared and persistent state where required.<\/li>\n\n\n\n<li>A load balancer.<\/li>\n\n\n\n<li>Correctly configured health checks.<\/li>\n\n\n\n<li>Consistent secrets across replicas.<\/li>\n\n\n\n<li>Redundant networking and certificate management.<\/li>\n\n\n\n<li>Monitoring and tested recovery procedures.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">For a conventional multi-replica Core design, PostgreSQL-backed Databroker storage is an important option.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Simply starting multiple containers with independent in-memory Databrokers is not a correct substitute for shared session state.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">21.7 Automatic certificate management<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Public deployments can use automated certificate management.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium Core supports automatic certificates in suitable environments, including configurations using Let&#8217;s Encrypt.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A documented configuration key is:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-42\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">autocert: <span class=\"hljs-literal\">true<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-42\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">However, enabling that setting alone is not sufficient.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You also need a compatible deployment environment, correctly configured public DNS, certificate issuance connectivity, and the necessary network ports and storage behavior.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The first laboratory intentionally uses <code>mkcert<\/code> instead because it is local and does not require a publicly reachable server.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">21.8 Managing machine access with service accounts<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Human users commonly authenticate through interactive browser-based flows.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Automated jobs need a different authentication strategy.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium Zero and Enterprise provide service-account capabilities for supported machine-to-machine access.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A service account represents a non-human identity that can be authorized by policy.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Service-account credentials must be scoped carefully, stored securely, rotated, and revoked when no longer required.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">21.9 Reverse tunneling<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium also documents reverse-tunneling capabilities for situations where Pomerium cannot directly reach an upstream service.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In a reverse-tunnel architecture, an authenticated SSH client establishes an outbound connection to Pomerium and acts as an upstream endpoint.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This can help expose authorized access to services located behind restrictive network boundaries.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It introduces additional trust, key-management, and tunnel-availability responsibilities and should not be treated as a substitute for proper policy enforcement.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The official feature also has runtime configuration requirements and protocol limitations. Pomerium<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">21.10 Enterprise-scale management<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">When applications, teams, and policies multiply, management can become a larger challenge than proxying itself.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium Zero and Enterprise address different aspects of this complexity.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Important capabilities include centralized configuration, managed cluster settings, service accounts, operational visibility, and\u2014depending on the offering\u2014namespace governance, directory synchronization, and administration APIs.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Choose the management model based on organizational requirements rather than assuming that the largest edition is automatically necessary.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 22. Security Best Practices<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Installing Pomerium does not automatically make all protected applications secure.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The complete security design depends on identity management, network architecture, configuration, application security, and operations.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">22.1 The security model<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium can enforce an important application access boundary, but the full security chain is broader.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">#chatgpt-mermaid-_r_29o_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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=&#8221;neo&#8221;].node rect,#chatgpt-mermaid-_r_29o_ [data-look=&#8221;neo&#8221;].cluster rect,#chatgpt-mermaid-_r_29o_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_29o_ [data-look=&#8221;neo&#8221;].node path{stroke:url(#chatgpt-mermaid-_r_29o_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_29o_ [data-look=&#8221;neo&#8221;].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_29o_ [data-look=&#8221;neo&#8221;].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_29o_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_29o_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].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=&#8221;normal&#8221;],#chatgpt-mermaid-_r_29o_ .edgeLabels tspan[font-weight=&#8221;normal&#8221;]{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{&#8211;mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;}Trusted identity providerSecure user authenticationCorrect PomeriumauthorizationProtected applicationnetworkApplication-level permissionsMonitoring and incidentresponse<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium&#8217;s published threat model explicitly identifies several responsibilities outside its protection scope, including the security of trusted third-party identity providers and upstream applications&#8217; own access-control systems. Pomerium<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">22.2 Insecure practices versus safer alternatives<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Insecure practice<\/th><th>Risk<\/th><th>Safer alternative<\/th><\/tr><tr><td>Allow every authenticated user to reach sensitive routes<\/td><td>Excessive permissions<\/td><td>Explicit least-privilege route policies<\/td><\/tr><tr><td>Publish the backend application directly<\/td><td>Bypass of Pomerium<\/td><td>Restrict backend network reachability<\/td><\/tr><tr><td>Use the hosted demo authentication service as an assumed production SLA<\/td><td>Authentication dependency risk<\/td><td>Evaluate a production IdP and authentication architecture<\/td><\/tr><tr><td>Store secrets in public Git repositories<\/td><td>Credential exposure<\/td><td>Secret manager or protected runtime injection<\/td><\/tr><tr><td>Use weak or reused secrets<\/td><td>Compromised sessions or services<\/td><td>Independent cryptographically random secrets<\/td><\/tr><tr><td>Disable TLS verification<\/td><td>Susceptibility to interception<\/td><td>Trusted certificates and correct hostname validation<\/td><\/tr><tr><td>Use local development certificates in production<\/td><td>Inappropriate certificate trust<\/td><td>Managed production certificates<\/td><\/tr><tr><td>Run unreviewed floating container versions<\/td><td>Unexpected changes<\/td><td>Tested version or digest pinning<\/td><\/tr><tr><td>Expose metrics or administration endpoints publicly<\/td><td>Information disclosure or attack surface<\/td><td>Private monitoring endpoints<\/td><\/tr><tr><td>Ignore authentication failures<\/td><td>Missed incidents<\/td><td>Logging, alerts, and investigation<\/td><\/tr><tr><td>Depend on one instance without recovery planning<\/td><td>Availability risk<\/td><td>Tested HA or recovery architecture<\/td><\/tr><tr><td>Rely only on Pomerium for all application permissions<\/td><td>Internal privilege errors<\/td><td>Enforce application-level authorization too<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">22.3 Protect authentication<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Use the identity provider&#8217;s appropriate security controls.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Depending on the organization&#8217;s requirements, these may include phishing-resistant MFA, managed-device policies, credential lifecycle management, and timely account deprovisioning.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium&#8217;s policies should use identity attributes that are trustworthy and consistently populated.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">22.4 Follow least privilege<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A good policy grants access only to the people and services that need it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, a production administration portal should not automatically become available to every person with a company email address.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Use specific groups, identities, or contextual conditions when appropriate.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">22.5 Protect upstream applications<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The gateway cannot protect traffic that bypasses it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Use private networks, host firewalls, cloud security groups, Kubernetes NetworkPolicies where appropriate, and application-side validation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If the application trusts Pomerium-supplied identity information, verify the signed assertion rather than blindly trusting arbitrary client-controlled headers.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">22.6 Secure secrets and state<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Protect:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Identity-provider credentials.<\/li>\n\n\n\n<li>Shared and cookie secrets.<\/li>\n\n\n\n<li>TLS private keys.<\/li>\n\n\n\n<li>JWT signing keys.<\/li>\n\n\n\n<li>Service-account tokens.<\/li>\n\n\n\n<li>Databroker database credentials.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Use access restrictions, backup encryption, credential rotation, and suitable secret-management systems.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">22.7 Monitor and patch<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Keep Pomerium, Envoy-related dependencies, the container runtime, the operating system, and protected applications updated according to a tested patch-management process.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Monitor security advisories and release notes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Upgrades should include regression tests for authentication, authorization, session behavior, and upstream routing.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">22.8 Security verification checklist<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Production security review<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Completing this checklist supports a review; it is not a substitute for a security assessment or penetration test.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 23. Production-Ready Pomerium Architecture<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The local experiment works on a single computer. Production environments need a more comprehensive design.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">23.1 Reference production architecture<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">#chatgpt-mermaid-_r_2ah_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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=&#8221;neo&#8221;].node rect,#chatgpt-mermaid-_r_2ah_ [data-look=&#8221;neo&#8221;].cluster rect,#chatgpt-mermaid-_r_2ah_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_2ah_ [data-look=&#8221;neo&#8221;].node path{stroke:url(#chatgpt-mermaid-_r_2ah_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_2ah_ [data-look=&#8221;neo&#8221;].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_2ah_ [data-look=&#8221;neo&#8221;].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_2ah_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_2ah_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].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=&#8221;normal&#8221;],#chatgpt-mermaid-_r_2ah_ .edgeLabels tspan[font-weight=&#8221;normal&#8221;]{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{&#8211;mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;}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<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is a conceptual deployment reference, not a ready-to-apply production manifest.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It represents an all-in-one Pomerium replica model with shared persistent state and external operational dependencies.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">23.2 Production design requirements<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Area<\/th><th>Essential concern<\/th><th>Implementation direction<\/th><\/tr><tr><td>Identity<\/td><td>Secure user authentication<\/td><td>Corporate IdP with appropriate MFA<\/td><\/tr><tr><td>Authorization<\/td><td>Correct permissions<\/td><td>Tested, least-privilege policies<\/td><\/tr><tr><td>Availability<\/td><td>Gateway failures<\/td><td>Multiple replicas where required<\/td><\/tr><tr><td>Session state<\/td><td>Shared persistence<\/td><td>Supported Databroker HA design<\/td><\/tr><tr><td>TLS<\/td><td>Encrypted communication<\/td><td>Managed certificates and trusted upstream TLS<\/td><\/tr><tr><td>DNS<\/td><td>Reliable application addresses<\/td><td>Correctly managed corporate domains<\/td><\/tr><tr><td>Secrets<\/td><td>Protection and rotation<\/td><td>Secret management platform<\/td><\/tr><tr><td>Logs<\/td><td>Operational and security visibility<\/td><td>Central collection and retention<\/td><\/tr><tr><td>Metrics<\/td><td>Capacity and error visibility<\/td><td>Prometheus-compatible monitoring<\/td><\/tr><tr><td>Recovery<\/td><td>Restore after failure<\/td><td>Tested backup and recovery<\/td><\/tr><tr><td>Upgrades<\/td><td>Controlled changes<\/td><td>Staging, canary rollout, rollback<\/td><\/tr><tr><td>Application isolation<\/td><td>Prevent bypass<\/td><td>Private routes and network controls<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">23.3 Monitoring and alerting<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Useful operational signals include:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Availability of Pomerium replicas.<\/li>\n\n\n\n<li>Readiness and health-check failures.<\/li>\n\n\n\n<li>Successful and denied authorization requests.<\/li>\n\n\n\n<li>Authentication failures and unusual login patterns.<\/li>\n\n\n\n<li>HTTP error-rate changes.<\/li>\n\n\n\n<li>Upstream latency and connection failures.<\/li>\n\n\n\n<li>Storage connectivity and availability.<\/li>\n\n\n\n<li>Resource utilization.<\/li>\n\n\n\n<li>Certificate expiration.<\/li>\n\n\n\n<li>Configuration deployment failures.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium exposes Prometheus-compatible metrics. Core deployments require administrators to configure their collection and visualization; Zero and Enterprise provide additional management capabilities. Pomerium<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">23.4 Backup strategy<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A useful backup plan must distinguish between configuration and runtime state.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Configuration backup: Version-control approved policies, route definitions, and deployment manifests.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Persistent state backup: Follow the procedures appropriate to the selected Databroker backend.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Secrets backup: Use protected, organization-approved secret-recovery procedures.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Certificate recovery: Plan certificate renewal and key recovery or replacement as appropriate.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Do not assume that backing up only <code>config.yaml<\/code> restores every active session or runtime record.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">23.5 Upgrading safely<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A production upgrade should follow a repeatable process:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Read the new version&#8217;s release notes and migration guidance.<\/li>\n\n\n\n<li>Check for breaking changes and security fixes.<\/li>\n\n\n\n<li>Back up applicable configuration and state.<\/li>\n\n\n\n<li>Reproduce the upgrade in staging.<\/li>\n\n\n\n<li>Test authentication, authorization, and upstream routing.<\/li>\n\n\n\n<li>Test both allowed and denied identities.<\/li>\n\n\n\n<li>Deploy with controlled traffic shifting when supported.<\/li>\n\n\n\n<li>Verify health checks, metrics, and logs.<\/li>\n\n\n\n<li>Roll back using the documented procedure if required.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Rollback may be complicated by database or data-format migrations. Verify backward compatibility before relying on a previous image as a recovery strategy.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">23.6 Cost considerations<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium Core is open source, but the deployment still consumes resources.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Potential operating costs include compute infrastructure, databases, load balancers, certificates, networking, logging, monitoring, administration, and support.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium Zero and Enterprise introduce additional product-plan considerations.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Evaluate total operating cost rather than comparing only the software licence price.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">23.7 Production-readiness assessment<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A deployment is not production-ready simply because the browser login works.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It should demonstrate predictable behavior under normal load, user denial, component failure, expired credentials, configuration changes, and recovery scenarios.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The objective is not zero incidents. It is a system whose behavior, failure modes, and recovery procedures are sufficiently understood and controlled.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Part VIII \u2014 Troubleshooting and Mastery<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 24. Common Problems and Solutions<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Troubleshooting is one of the most important skills when operating identity-aware access systems.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A good engineer investigates failures systematically rather than repeatedly changing settings without understanding the cause.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">24.1 Troubleshooting reference<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The error descriptions below represent realistic diagnostic scenarios. Where an exact message has not been independently verified, the wording is illustrative.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Problem or error<\/th><th>Likely cause<\/th><th>How to diagnose<\/th><th>Solution<\/th><th>How to verify<\/th><\/tr><tr><td>Docker daemon unavailable<\/td><td>Docker engine stopped<\/td><td>Check Docker status<\/td><td>Start Docker Desktop or Docker Engine<\/td><td>Run hello-world<\/td><\/tr><tr><td>Cannot bind port 443<\/td><td>Another process owns the port<\/td><td>Inspect host listeners<\/td><td>Free port or redesign port mapping<\/td><td>Pomerium starts successfully<\/td><\/tr><tr><td>Certificate not trusted<\/td><td>Missing local CA trust<\/td><td>Inspect browser certificate<\/td><td>Reinstall or correct mkcert trust<\/td><td>Browser accepts HTTPS<\/td><\/tr><tr><td>DNS lookup fails<\/td><td>Local hostname resolution issue<\/td><td>Resolve hostname<\/td><td>Correct DNS or local proxy configuration<\/td><td>Host resolves to loopback<\/td><\/tr><tr><td>Pomerium fails to start<\/td><td>Invalid configuration<\/td><td>Inspect logs<\/td><td>Correct YAML or settings<\/td><td>Health check passes<\/td><\/tr><tr><td>Authentication redirects repeatedly<\/td><td>Cookie, session, IdP, or redirect configuration issue<\/td><td>Inspect redirect chain and logs<\/td><td>Correct the relevant authentication setting<\/td><td>Login completes<\/td><\/tr><tr><td>Authorization denied<\/td><td>User does not satisfy policy<\/td><td>Compare identity with route policy<\/td><td>Correct identity or approved policy<\/td><td>Allowed user succeeds<\/td><\/tr><tr><td>502 gateway error<\/td><td>Upstream unreachable or unhealthy<\/td><td>Check upstream status and route<\/td><td>Restore upstream connectivity<\/td><td>Application responds<\/td><\/tr><tr><td>Shared secret mismatch<\/td><td>Inconsistent secrets across components<\/td><td>Inspect configuration and secret distribution<\/td><td>Use consistent approved secrets<\/td><td>Health and sessions work<\/td><\/tr><tr><td>Sessions lost after restart<\/td><td>Ephemeral secrets or state<\/td><td>Inspect secrets and Databroker backend<\/td><td>Configure persistent state and stable secrets<\/td><td>Test restart<\/td><\/tr><tr><td>TLS handshake failure<\/td><td>Certificate, hostname, protocol, or trust problem<\/td><td>Inspect TLS configuration<\/td><td>Fix certificate chain or hostname<\/td><td>Secure connection succeeds<\/td><\/tr><tr><td>Missing signed identity assertion<\/td><td>Header forwarding or signing configuration incomplete<\/td><td>Inspect headers and signing-key settings<\/td><td>Configure required identity assertion settings<\/td><td>Upstream validates JWT<\/td><\/tr><tr><td>Health check fails<\/td><td>Internal component unavailable<\/td><td>Use verbose health status<\/td><td>Investigate the failing component<\/td><td>Health returns success<\/td><\/tr><tr><td>Works locally, not remotely<\/td><td>DNS, listener, firewall, or load balancer problem<\/td><td>Trace connectivity<\/td><td>Correct deployment networking<\/td><td>Approved remote client connects<\/td><\/tr><tr><td>Application accessible around Pomerium<\/td><td>Direct backend exposure<\/td><td>Review all network paths<\/td><td>Restrict backend networking<\/td><td>Bypass attempt fails<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">24.2 Diagnose port conflicts<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">On Ubuntu or other Linux systems with <code>ss<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-43\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">sudo ss -ltnp <span class=\"hljs-string\">'( sport = :443 )'<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-43\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">On macOS:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-44\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">sudo<\/span> <span class=\"hljs-selector-tag\">lsof<\/span> <span class=\"hljs-selector-tag\">-nP<\/span> <span class=\"hljs-selector-tag\">-iTCP<\/span><span class=\"hljs-selector-pseudo\">:443<\/span> <span class=\"hljs-selector-tag\">-sTCP<\/span><span class=\"hljs-selector-pseudo\">:LISTEN<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-44\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">On Windows PowerShell:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">Get-NetTCPConnection -LocalPort 443 -State Listen<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">These commands help identify whether a listener already occupies port 443.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Do not stop an unfamiliar process without understanding what depends on it.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">24.3 Diagnose YAML configuration failures<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">YAML uses indentation to represent structure.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Incorrect indentation can change the meaning of a configuration file.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, this is correctly nested:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-45\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">routes:\n  - <span class=\"hljs-keyword\">from<\/span>: https:<span class=\"hljs-comment\">\/\/portal.localhost.pomerium.io<\/span>\n    to: http:<span class=\"hljs-comment\">\/\/portal:80<\/span>\n\n    policy:\n      - allow:\n          or:\n            - email:\n                is: learner@example.com<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-45\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The <code>policy<\/code> belongs to the route.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When troubleshooting, check indentation, missing colons, whitespace, and whether the configuration key is valid for the Pomerium release.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Remember that Docker Compose validation alone does not validate the complete Pomerium configuration.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">24.4 Diagnose unexpected access denial<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A frequent mistake is assuming that successful login means the user should automatically reach the application.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Inspect the route&#8217;s policy and the authenticated identity.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, a user with email <code>alice@example.org<\/code> will not satisfy:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-46\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">policy<\/span>:\n  <span class=\"hljs-selector-tag\">-<\/span> <span class=\"hljs-selector-tag\">allow<\/span>:\n      <span class=\"hljs-selector-tag\">or<\/span>:\n        <span class=\"hljs-selector-tag\">-<\/span> <span class=\"hljs-selector-tag\">domain<\/span>:\n            <span class=\"hljs-selector-tag\">is<\/span>: <span class=\"hljs-selector-tag\">example<\/span><span class=\"hljs-selector-class\">.com<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-46\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The user authenticated successfully, but the allowed domain is different.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Do not weaken the policy to make the error disappear. Confirm the intended identity and access requirements first.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">24.5 Diagnose reverse-proxy errors<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If the browser reaches Pomerium but the application does not load, inspect the upstream service.<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker compose ps\ndocker compose logs --tail=100 portal\ndocker compose logs --tail=100 pomerium<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Verify that the destination in the Pomerium route matches the service name and port.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-47\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">to: http:<span class=\"hljs-comment\">\/\/portal:80<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-47\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The name <code>portal<\/code> must resolve in the container network, and the service must be listening on the expected port.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">24.6 Diagnose session persistence<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If users are unexpectedly prompted to sign in after restarting Pomerium, inspect the configured secrets and Databroker storage backend.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Stable secrets and persistent state are important, but hosted authentication can still require reauthentication due to its own session lifecycle.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium documents limitations for its free hosted authentication service, including restricted login options, limited session refresh behavior, and no uptime commitment. Pomerium<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">24.7 A disciplined incident investigation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Record the following before applying changes:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Exact time of the failure.<\/li>\n\n\n\n<li>Affected hostname and application.<\/li>\n\n\n\n<li>Whether all users or only certain users are affected.<\/li>\n\n\n\n<li>Authentication result.<\/li>\n\n\n\n<li>Authorization result.<\/li>\n\n\n\n<li>Pomerium health status.<\/li>\n\n\n\n<li>Upstream health status.<\/li>\n\n\n\n<li>Relevant configuration changes.<\/li>\n\n\n\n<li>Relevant log and trace information.<\/li>\n\n\n\n<li>The outcome of each corrective action.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">This approach makes troubleshooting reproducible and helps prevent repeated incidents.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 25. Best Practices and Common Mistakes<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Good Pomerium operations combine general engineering discipline with practices specific to identity-aware access systems.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">25.1 Universal engineering best practices<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Practice<\/th><th>Why it matters<\/th><\/tr><tr><td>Version-control configurations<\/td><td>Supports review, history, and rollback<\/td><\/tr><tr><td>Separate development and production<\/td><td>Reduces accidental production impact<\/td><\/tr><tr><td>Test before deployment<\/td><td>Detects configuration and policy errors<\/td><\/tr><tr><td>Keep dependencies updated<\/td><td>Reduces exposure to known vulnerabilities<\/td><\/tr><tr><td>Monitor systems continuously<\/td><td>Detects failures and unusual behavior<\/td><\/tr><tr><td>Protect secrets<\/td><td>Prevents credential compromise<\/td><\/tr><tr><td>Define ownership<\/td><td>Ensures someone maintains every component<\/td><\/tr><tr><td>Maintain runbooks<\/td><td>Supports reliable incident response<\/td><\/tr><tr><td>Test recovery<\/td><td>Confirms that backups and procedures work<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">25.2 Pomerium-specific best practices<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Practice<\/th><th>Why it matters<\/th><\/tr><tr><td>Restrict direct upstream access<\/td><td>Prevents bypassing the identity-aware gateway<\/td><\/tr><tr><td>Test authorized and denied identities<\/td><td>Confirms policy behavior<\/td><\/tr><tr><td>Use trusted identity providers<\/td><td>Establishes reliable authentication<\/td><\/tr><tr><td>Use independent random secrets<\/td><td>Protects sessions and component communication<\/td><\/tr><tr><td>Verify signed identity assertions when needed<\/td><td>Prevents blind trust in identity headers<\/td><\/tr><tr><td>Choose an appropriate Databroker backend<\/td><td>Preserves required state and availability<\/td><\/tr><tr><td>Keep health endpoints private<\/td><td>Protects operational information<\/td><\/tr><tr><td>Monitor policy changes<\/td><td>Detects unexpected access changes<\/td><\/tr><tr><td>Understand long-lived connection behavior<\/td><td>Supports realistic revocation planning<\/td><\/tr><tr><td>Review control-plane responsibilities<\/td><td>Avoids confusion among Core, Zero, and Enterprise<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">25.3 Common mistakes beginners should avoid<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">One mistake is protecting an application with Pomerium while leaving another public address pointing directly to that application.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Another is confusing identity with permission: just because someone has a valid company account does not mean they require access to every engineering tool.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A third is moving directly from a successful Docker demonstration to production without planning certificate management, identity-provider availability, shared state, monitoring, and recovery.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Finally, copying configuration from an older tutorial without checking the current version can introduce deprecated or incompatible behavior.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The correct habit is to use version-matched documentation, test each change, and confirm the observed result.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 26. Learning Roadmap<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The following roadmap organizes your learning into five stages.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The suggested durations are educational estimates, not official Pomerium training requirements.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Stage<\/th><th>Topics<\/th><th>Practical activity<\/th><th>Expected skill<\/th><th>Suggested effort<\/th><\/tr><tr><td>1. Fundamentals<\/td><td>Zero Trust, proxies, IdP, OAuth, TLS<\/td><td>Explain request flow and terminology<\/td><td>Conceptual understanding<\/td><td>4\u20136 hours<\/td><\/tr><tr><td>2. First use<\/td><td>Docker, Compose, certificates, routes<\/td><td>Complete Verify lab<\/td><td>Independent basic deployment<\/td><td>4\u20136 hours<\/td><\/tr><tr><td>3. Practical proficiency<\/td><td>PPL, multiple routes, sessions, logs<\/td><td>Complete Operations Portal project<\/td><td>Basic administration<\/td><td>6\u201310 hours<\/td><\/tr><tr><td>4. Advanced use<\/td><td>OIDC, JWTs, TCP, Kubernetes, HA<\/td><td>Integrate a realistic service<\/td><td>Advanced engineering<\/td><td>10\u201316 hours<\/td><\/tr><tr><td>5. Production readiness<\/td><td>Security, monitoring, state, upgrades, recovery<\/td><td>Design and review a production deployment<\/td><td>Operational readiness<\/td><td>10\u201316 hours<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Recommended practice schedule<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">SUGGESTED FIVE-STAGE LEARNING PROGRESSION<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Stage 1 \u2014 Understand the domainLearn the identity, access, networking, and proxy concepts. Be able to explain why Pomerium is useful without referencing commands.<\/li>\n\n\n\n<li>Stage 2 \u2014 Build a working gatewayDeploy Core locally, authenticate, change a policy, and diagnose one deliberate failure.<\/li>\n\n\n\n<li>Stage 3 \u2014 Manage multiple applicationsProtect two services with different policies. Introduce persistent state and basic operational checks.<\/li>\n\n\n\n<li>Stage 4 \u2014 Integrate with infrastructurePractice corporate identity integration, JWT verification, and at least one additional protocol or deployment environment.<\/li>\n\n\n\n<li>Stage 5 \u2014 Design for productionProduce an architecture, security checklist, monitoring strategy, upgrade runbook, and tested recovery plan.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Official learning resources<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The following resources are useful for continuing your studies.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Resource<\/th><th>What to study<\/th><\/tr><tr><td><a href=\"https:\/\/www.pomerium.com\/docs?utm_source=chatgpt.com\">Pomerium documentation<\/a><\/td><td>Product overview and capabilities<\/td><\/tr><tr><td><a href=\"https:\/\/www.pomerium.com\/docs\/get-started\/quickstart?utm_source=chatgpt.com\">Official quickstart<\/a><\/td><td>First deployment options<\/td><\/tr><tr><td><a href=\"https:\/\/www.pomerium.com\/docs\/get-started\/fundamentals\/core\/get-started?utm_source=chatgpt.com\">Core fundamentals<\/a><\/td><td>Step-by-step beginner lessons<\/td><\/tr><tr><td><a href=\"https:\/\/www.pomerium.com\/docs\/internals\/architecture?utm_source=chatgpt.com\">Architecture<\/a><\/td><td>Components and request flow<\/td><\/tr><tr><td><a href=\"https:\/\/www.pomerium.com\/docs\/capabilities\/authorization?utm_source=chatgpt.com\">Authorization<\/a><\/td><td>Policies and permissions<\/td><\/tr><tr><td><a href=\"https:\/\/www.pomerium.com\/docs\/internals\/health-checks?utm_source=chatgpt.com\">Health checks<\/a><\/td><td>Monitoring runtime health<\/td><\/tr><tr><td><a href=\"https:\/\/www.pomerium.com\/docs\/internals\/security?utm_source=chatgpt.com\">Security model<\/a><\/td><td>Threats and responsibilities<\/td><\/tr><tr><td><a href=\"https:\/\/www.pomerium.com\/docs\/deploy\/k8s\/install?utm_source=chatgpt.com\">Kubernetes deployment<\/a><\/td><td>Cluster deployments<\/td><\/tr><tr><td><a href=\"https:\/\/github.com\/pomerium\/pomerium\/releases?utm_source=chatgpt.com\">Official releases<\/a><\/td><td>Version changes and security fixes<\/td><\/tr><tr><td><a href=\"https:\/\/www.pomerium.com\/docs\/versions?utm_source=chatgpt.com\">Documentation versions<\/a><\/td><td>Version-matched documentation<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium&#8217;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<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 27. Exercises and Knowledge Assessment<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This chapter tests both conceptual understanding and practical engineering judgment.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Do not look at the answer key until you have attempted the exercises.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">27.1 Beginner assessment<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Beginner knowledge quiz<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">0 \/ 6 answered<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">1. What does authentication determine?Which application is fastestWho the user isWhich container uses the most memoryWhich IP address should be assigned<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">2. What is Pomerium primarily?A databaseA compilerAn identity-aware reverse proxyAn operating system<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">3. What does the &#8216;from&#8217; field specify in a route?The externally accessed URLThe database usernameThe logging outputThe Docker image<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">5. What does HTTPS primarily provide?Automatic user authorizationContainer schedulingEncrypted and authenticated transportApplication backups<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">6. Why must the upstream application be isolated from uncontrolled access?To prevent bypassing PomeriumTo make Docker fasterTo disable DNSTo eliminate configuration files<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Check answersReset<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">27.2 Intermediate exercises<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Exercise 7 \u2014 Policy implementation<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Write a Pomerium policy that allows exactly two authenticated email identities:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-48\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">alice<\/span><span class=\"hljs-keyword\">@example<\/span>.com\nbob@example.com<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-48\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Do not allow everyone from the entire domain.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Exercise 8 \u2014 Operational troubleshooting<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A Pomerium container is running, but the browser cannot reach the protected application.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Identify the first four diagnostic checks you would perform.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Exercise 9 \u2014 Session persistence<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After restarting Pomerium, a user must authenticate again.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Identify at least two configuration-related factors that may contribute to the problem.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Exercise 10 \u2014 Secure the backend<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The protected NGINX portal is accessible through Pomerium, but a user can also reach its unprotected public IP address.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Explain why this is a security problem and how you would correct it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Exercise 11 \u2014 Policy verification<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A new policy is intended to give production dashboard access to three specific engineers.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Describe a test plan that verifies both successful and denied access.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">27.3 Advanced exercises<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Exercise 12 \u2014 High availability<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">An engineer deploys three Pomerium replicas, each with independent in-memory Databroker storage.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Explain why this is not a suitable conventional high-availability state architecture and propose an improvement.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Exercise 13 \u2014 Identity assertions<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A custom application trusts an unsigned <code>X-User-Email<\/code> header received from the client.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Explain the security issue and describe a safer Pomerium integration.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Exercise 14 \u2014 Incident response<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">An administrator removes a user&#8217;s access policy while the user already has a long-lived TCP connection.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Explain what must be considered about the existing connection.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Exercise 15 \u2014 Deployment model selection<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A company wants to keep application traffic in its own infrastructure but would prefer externally managed configuration.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Which Pomerium deployment model should it evaluate first?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">What operational responsibility would remain with the company?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Exercise 16 \u2014 Production architecture review<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Design a Pomerium deployment for a company with:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>1,000 employees.<\/li>\n\n\n\n<li>Multiple internal applications.<\/li>\n\n\n\n<li>A corporate identity provider.<\/li>\n\n\n\n<li>A Kubernetes environment.<\/li>\n\n\n\n<li>A high-availability requirement.<\/li>\n\n\n\n<li>Centralized logging.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Identify the essential infrastructure components and the top five security controls.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">27.4 Answer key and explanations<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">Intermediate answers<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Exercise 7<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">An appropriate policy is:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-49\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">policy<\/span>:\n  <span class=\"hljs-selector-tag\">-<\/span> <span class=\"hljs-selector-tag\">allow<\/span>:\n      <span class=\"hljs-selector-tag\">or<\/span>:\n        <span class=\"hljs-selector-tag\">-<\/span> <span class=\"hljs-selector-tag\">email<\/span>:\n            <span class=\"hljs-selector-tag\">is<\/span>: <span class=\"hljs-selector-tag\">alice<\/span><span class=\"hljs-keyword\">@example<\/span>.com\n        - <span class=\"hljs-attribute\">email:<\/span>\n            <span class=\"hljs-attribute\">is:<\/span> bob@example.com<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-49\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This permits either specified identity without permitting the entire email domain.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Exercise 8<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Start by checking the running services, gateway logs, local DNS resolution, and HTTPS listener or certificate behavior.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Once those succeed, investigate authentication, authorization, and upstream availability.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Exercise 9<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Check whether cryptographic secrets remain stable across restarts and whether the Databroker uses persistent storage.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Also review the authentication provider&#8217;s independent session limitations.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Exercise 10<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Direct public access bypasses Pomerium&#8217;s intended security boundary.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Remove the unprotected public path or enforce appropriate network restrictions, and verify that the backend cannot be reached through an unauthorized route.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Exercise 11<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Test all three approved engineers, at least one authenticated but unauthorized identity, and an unauthenticated request.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Also test that access is removed successfully after a policy change.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Advanced answers<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Exercise 12<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Independent in-memory state does not provide a consistent shared view of sessions and relevant Databroker records.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Use an appropriate supported shared persistent backend, such as PostgreSQL, and design its availability and backup strategy.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Exercise 13<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">An unsigned client-controlled identity header can be forged.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Use a trusted Pomerium-signed identity assertion, validate its cryptographic signature and claims in the upstream application, and protect the upstream network path.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Exercise 14<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium&#8217;s documented behavior for certain long-lived connections evaluates authorization when the connection is established. Existing connections may continue after a policy changes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Operational controls may be needed to terminate or rotate such connections when access must be revoked promptly.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Exercise 15<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pomerium Zero is a suitable first candidate because it offers a managed control plane while the Core data plane remains in the organization&#8217;s environment.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The organization still operates the deployed runtime and remains responsible for applicable networking, application security, and infrastructure controls.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Exercise 16<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Five major controls would include strong authentication, least-privilege authorization, backend isolation, encryption and secret protection, and monitored, tested operational recovery.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This design would still require sizing, threat modeling, and workload-specific validation before production deployment.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 28. Final Revision and Quick Reference<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">28.1 Pomerium in one paragraph<\/h3>\n\n\n\n<p class=\"wp-block-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.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">28.2 The five most important concepts<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Concept<\/th><th>What to remember<\/th><\/tr><tr><td>Authentication<\/td><td>Determines who is making the request<\/td><\/tr><tr><td>Authorization<\/td><td>Determines whether the request is permitted<\/td><\/tr><tr><td>Proxy<\/td><td>Receives and forwards protected traffic<\/td><\/tr><tr><td>Route<\/td><td>Defines the public-facing entry point and backend destination<\/td><\/tr><tr><td>Policy<\/td><td>Defines the conditions for granting or denying access<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">28.3 Essential configuration reference<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Setting<\/th><th>Purpose<\/th><\/tr><tr><td><code>routes<\/code><\/td><td>List of protected routes<\/td><\/tr><tr><td><code>from<\/code><\/td><td>Address accessed by the user<\/td><\/tr><tr><td><code>to<\/code><\/td><td>Backend destination<\/td><\/tr><tr><td><code>policy<\/code><\/td><td>Authorization logic<\/td><\/tr><tr><td><code>authenticate_service_url<\/code><\/td><td>Authentication service URL<\/td><\/tr><tr><td><code>certificate_file<\/code><\/td><td>TLS server certificate<\/td><\/tr><tr><td><code>certificate_key_file<\/code><\/td><td>TLS private key<\/td><\/tr><tr><td><code>shared_secret<\/code> \/ <code>SHARED_SECRET<\/code><\/td><td>Internal shared secret<\/td><\/tr><tr><td><code>cookie_secret<\/code> \/ <code>COOKIE_SECRET<\/code><\/td><td>Session cookie protection<\/td><\/tr><tr><td><code>databroker_storage_type<\/code><\/td><td>Databroker storage backend<\/td><\/tr><tr><td><code>databroker_storage_connection_string<\/code><\/td><td>Storage location or connection<\/td><\/tr><tr><td><code>log_level<\/code><\/td><td>Logging verbosity<\/td><\/tr><tr><td><code>pass_identity_headers<\/code><\/td><td>Forward Pomerium identity assertion headers<\/td><\/tr><tr><td><code>signing_key_file<\/code><\/td><td>Signing key for identity assertions<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">28.4 Essential command cheat sheet<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Task<\/th><th>Command<\/th><\/tr><tr><td>Validate Compose syntax<\/td><td><code>docker compose config --quiet<\/code><\/td><\/tr><tr><td>Start<\/td><td><code>docker compose up -d<\/code><\/td><\/tr><tr><td>Show status<\/td><td><code>docker compose ps<\/code><\/td><\/tr><tr><td>Show recent logs<\/td><td><code>docker compose logs --tail=100 pomerium<\/code><\/td><\/tr><tr><td>Follow logs<\/td><td><code>docker compose logs -f pomerium<\/code><\/td><\/tr><tr><td>Health check<\/td><td><code>docker compose exec pomerium pomerium health<\/code><\/td><\/tr><tr><td>Verbose health check<\/td><td><code>docker compose exec pomerium pomerium health -v<\/code><\/td><\/tr><tr><td>Restart Pomerium<\/td><td><code>docker compose restart pomerium<\/code><\/td><\/tr><tr><td>Show images<\/td><td><code>docker compose images<\/code><\/td><\/tr><tr><td>Stop stack<\/td><td><code>docker compose down<\/code><\/td><\/tr><tr><td>Start native Pomerium<\/td><td><code>.\/pomerium -config config.yaml<\/code><\/td><\/tr><tr><td>Pomerium client help<\/td><td><code>pomerium-cli --help<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">On Linux installations where Docker requires elevated permissions, use the appropriate <code>sudo<\/code> form for Docker commands.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">28.5 Troubleshooting cheat sheet<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The diagnostic order to remember<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">CHECK 1<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Container status<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Is the process running?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">CHECK 2<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Gateway reachability<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Can HTTPS reach Pomerium?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">CHECK 3<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Authentication<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Can the identity be established?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">CHECK 4<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Authorization<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Does the policy allow access?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">CHECK 5<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Upstream access<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Can Pomerium reach the backend?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">CHECK 6<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Application health<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Can the backend serve the request?<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">28.6 Security precautions to remember<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A successful login is never sufficient evidence that the full security design is correct.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">28.7 Best situations for using Pomerium<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It is especially relevant to organizations operating developer and administrative tools across multiple infrastructure environments.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">28.8 Situations where another tool may be preferable<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A VPN or Tailscale may be preferable when the primary requirement is private device or network connectivity.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Authentik or Keycloak may be more directly relevant when the primary requirement is operating an identity provider.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Teleport may be more appropriate when infrastructure access workflows, SSH governance, and session-oriented controls are the dominant requirement.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Cloudflare Access may be attractive when a cloud-managed application access service better matches the organization&#8217;s operational preferences.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">28.9 Final mental model<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">#chatgpt-mermaid-_r_2fk_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;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=&#8221;neo&#8221;].node rect,#chatgpt-mermaid-_r_2fk_ [data-look=&#8221;neo&#8221;].cluster rect,#chatgpt-mermaid-_r_2fk_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_2fk_ [data-look=&#8221;neo&#8221;].node path{stroke:url(#chatgpt-mermaid-_r_2fk_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_2fk_ [data-look=&#8221;neo&#8221;].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_2fk_ [data-look=&#8221;neo&#8221;].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_2fk_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_2fk_ [data-look=&#8221;neo&#8221;].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=&#8221;neo&#8221;].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=&#8221;normal&#8221;],#chatgpt-mermaid-_r_2fk_ .edgeLabels tspan[font-weight=&#8221;normal&#8221;]{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{&#8211;mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,&#8221;Segoe UI&#8221;,Helvetica,&#8221;Apple Color Emoji&#8221;,Arial,sans-serif,&#8221;Segoe UI Emoji&#8221;,&#8221;Segoe UI Symbol&#8221;;}Who are you?What may you access?Which application?Authorized connectionApplication responseAuthenticationAuthorizationRouting<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When learning Pomerium, return to these questions whenever a configuration or architecture becomes complicated.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Course completion<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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&#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[11138],"tags":[],"class_list":["post-79542","post","type-post","status-publish","format-standard","hentry","category-best-tools"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/79542","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=79542"}],"version-history":[{"count":1,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/79542\/revisions"}],"predecessor-version":[{"id":79543,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/79542\/revisions\/79543"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=79542"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=79542"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=79542"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}