Securing Internal Infrastructure: Deploying Pomerium as a Zero Trust Ingress Proxy for Docker Containers
The Paradigm Shift: Moving Beyond the Traditional Perimeter
For decades, securing internal business applications relied on a simple premise: build a strong perimeter defense. Organizations trusted everything inside the corporate network and distrusted everything outside it. Typically, this took the form of a Virtual Private Network (VPN). However, in modern containerized environments, this model is no longer sufficient. Once an attacker breaches the VPN, they gain lateral access to the entire internal network, exposing sensitive Docker containers and microservices.
To mitigate this risk, modern enterprises are shifting toward a Zero Trust Architecture (ZTA). The core philosophy of Zero Trust is simple: never trust, always verify. Access requests must be continuously authenticated, authorized, and encrypted, regardless of whether they originate from inside or outside the network perimeter. This is where Pomerium excels as an open-source, identity-aware access proxy.
What is Pomerium?
Pomerium is an enterprise-grade, Zero Trust ingress proxy that validates every request based on identity and context. Instead of granting network-level access, Pomerium acts as a gatekeeper for individual applications. It integrates seamlessly with existing Identity Providers (IdPs) like Google Workspace, Okta, Microsoft Entra ID, and GitHub to enforce centralized authorization policies.
Key Benefits of Using Pomerium for Docker Ingress
- Identity-Aware Authorization: Access control is tied directly to user identity and group memberships rather than IP addresses.
- Seamless User Experience: Eliminates the need for cumbersome VPN clients, allowing users to access internal apps securely via a standard web browser.
- Contextual Security Policies: Define granular rules based on device posture, geographic location, time of day, and domain.
- Centralized Logging and Auditing: Every single request and access decision is logged, providing complete visibility for compliance and security auditing.
Architecture Overview: How Pomerium Protects Docker Containers
When deploying Pomerium as an ingress proxy for Docker containers, it intercepts all incoming HTTP/HTTPS traffic before it reaches your upstream services. The workflow follows a strict sequence to ensure maximum security:
- The Request: A user attempts to access an internal service (e.g.,
grafana.internal.company.com). - Authentication Check: Pomerium checks for a valid session cookie. If none exists, the user is redirected to the configured Identity Provider (IdP) for authentication.
- Authorization Evaluation: Once authenticated, Pomerium evaluates the user's identity against the defined policy for that specific route.
- Upstream Forwarding: If authorized, Pomerium proxies the request to the target Docker container over a secure internal network. If unauthorized, access is denied instantly.
Pomerium operates at Layer 7 (the application layer), which means it can inspect application headers and safely strip sensitive authorization tokens before passing requests to upstream containers.---
Step-by-Step Guide: Deploying Pomerium with Docker Compose
Let's walk through a practical implementation of Pomerium protecting an internal business application—in this case, a standard Nginx container representing a private dashboard—using Docker Compose.
Step 1: Prerequisites and Identity Provider Setup
Before writing configuration files, you need to set up an OAuth application within your chosen IdP (e.g., Google Cloud Console or Okta). You will need to obtain the following credentials:
- Client ID
- Client Secret
- Redirect URL: This must match your Pomerium authenticate URL, typically
[https://authenticate.yourdomain.com/oauth2/callback](https://authenticate.yourdomain.com/oauth2/callback)
Step 2: Generate Encryption Keys
Pomerium requires a cryptographically secure key to sign session cookies and encrypt configuration state. You can generate a 32-byte base64-encoded string using the following command in your terminal:
head -c32 /dev/urandom | base64Keep this value secure; you will need to input it as the SHARED_SECRET and COOKIE_SECRET in your configuration.
Step 3: Creating the Pomerium Configuration File
Create a file named config.yaml. This file tells Pomerium how to authenticate users and where to route traffic. Replace the placeholder values with your actual domain and credential details.
# config.yaml
authenticate_service_url: [https://authenticate.example.com](https://authenticate.example.com)
idp_provider: google
idp_client_id: "YOUR_CLIENT_ID.apps.googleusercontent.com"
idp_client_secret: "YOUR_CLIENT_SECRET"
cookie_secret: "YOUR_GENERATED_COOKIE_SECRET"
shared_secret: "YOUR_GENERATED_SHARED_SECRET"
routes:
- from: [https://dashboard.example.com](https://dashboard.example.com)
to: http://internal-dashboard:80
policy:
- allow:
and:
- domain:
is: company.com
- groups:
has: engineeringIn this policy configuration, only users with an email address ending in company.com who belong to the engineering group are permitted to access the internal dashboard container.
Step 4: Defining the Docker Compose Infrastructure
Next, create a docker-compose.yml file to orchestrate the Pomerium proxy alongside your internal containerized applications. We will use a shared internal bridge network to ensure the upstream application is isolated from the public internet.
version: '3.8'
services:
pomerium:
image: pomerium/pomerium:latest
container_name: pomerium_proxy
volumes:
- ./config.yaml:/pomerium/config.yaml:ro
ports:
- "443:443"
- "80:80"
volumes:
- ./certs:/certs
environment:
- CERTIFICATE_FILE=/certs/example.com.crt
- CERTIFICATE_KEY_FILE=/certs/example.com.key
networks:
- internal_network
restart: always
internal-dashboard:
image: nginx:alpine
container_name: internal_dashboard_app
networks:
- internal_network
# Note: No ports are exposed to the host machine.
# Traffic can only reach this container through Pomerium.
restart: always
networks:
internal_network:
driver: bridgeCrucial Security Note: Notice that the internal-dashboard service does not expose any public ports to the host machine. It does not have a ports directive. This configuration ensures that the container is entirely unreachable from outside the Docker internal bridge network, completely eliminating direct exposure to unauthorized network scanners.
Production Best Practices for Pomerium Deployments
Moving a Zero Trust Ingress from a proof-of-concept to an enterprise production environment requires careful attention to scalability, resilience, and hardened security measures. Consider implementing the following practices:
1. Automated TLS Certificate Management
Pomerium relies heavily on TLS to encrypt communication channels. For production workloads, manually managing certificates is inefficient and error-prone. It is highly recommended to integrate Pomerium with Let's Encrypt or an enterprise PKI infrastructure via Certbot or a cloud-native ingress controller like Traefik or Nginx Ingress to automate certificate renewal pipelines.
2. Hardening Contextual Policies
Do not rely solely on email domain verification. Threat actors can occasionally spoof domains or compromise standard corporate accounts. Enhance your Pomerium policies by adding multi-factor authentication (MFA) requirements, validating device certificates, or utilizing IP threat intelligence feeds to block traffic originating from high-risk geographic locations.
3. High Availability (HA) Topology
For mission-critical enterprise services, Pomerium should be deployed in a stateless, high-availability mode across multiple Docker hosts or within a container orchestration platform like Kubernetes. Utilize an external distributed datastore (such as Redis) to manage centralized session states uniformly across all running proxy instances.
Conclusion: The Future of Internal Infrastructure Security
Implementing Pomerium as a Zero Trust Ingress Proxy offers a modern, secure, and user-friendly alternative to legacy corporate VPNs. By decoupling network access from application authorization, you drastically minimize your attack surface and protect internal Docker containers from unauthorized discovery and lateral movement attacks. Embracing a Zero Trust architecture today ensures that your organizational infrastructure remains secure, auditable, and resilient against evolving cybersecurity threats.
