Why VPNs Are Fading Away
If you’ve ever spent ten minutes wrestling with a finicky VPN client just to check a Grafana dashboard, you know the frustration. Beyond the user experience, VPNs rely on a ‘castle-and-moat’ security model. Once a user clears the perimeter, they often gain lateral access to the entire network. This creates a massive security hole. Modern infrastructure is moving toward Zero Trust, a model where identity is verified for every single request, regardless of where the user is sitting.
Identity-Aware Proxies (IAP) like Pomerium solve this by moving security to the application layer. Instead of launching a client, users simply visit a URL like internal-tool.company.com. Pomerium intercepts the traffic, validates the user’s session against an Identity Provider (IdP) like GitHub or Okta, and checks specific access policies. It’s faster, safer, and significantly easier to manage.
Why Pomerium Wins in Production
Pomerium acts as a unified gatekeeper for your services. It’s lightweight enough to run as a single binary but robust enough to handle high-traffic enterprise environments. After replacing a legacy OpenVPN setup with Pomerium for a team of 150+ engineers, we saw a 40% drop in access-related support tickets.
Key advantages include:
- Zero Client Software: If you have a web browser, you have access. No more troubleshooting broken VPN drivers on macOS or Linux.
- Granular Control: You can write policies that allow access only if a user is in the ‘DevOps’ GitHub team and connecting from a specific country.
- Deep Audit Trails: Every single click and request is logged with an associated identity. This provides a level of visibility that network-level VPNs simply can’t match.
Setting Up Your Environment
We’ll use Docker Compose to build a proof-of-concept. This setup simulates a real-world environment by protecting a dummy internal application behind the Pomerium proxy. You will need a domain name (or a modified /etc/hosts file) and a GitHub account to act as your IdP.
1. Generate Your Encryption Keys
Pomerium requires two unique 32-byte base64 encoded strings to secure cookies and encrypt internal communication. Generate them quickly with this command:
head -c32 /dev/urandom | base64
Run this twice. Save the first string as your COOKIE_SECRET and the second as your SHARED_SECRET. Keep these safe; they are the keys to your kingdom.
2. The Docker Compose Configuration
Create a directory named pomerium-lab and drop the following into a docker-compose.yaml file. This defines the proxy and a simple ‘Hello World’ app to protect.
version: '3'
services:
pomerium:
image: cache.pomerium.io/pomerium/pomerium:latest
container_name: pomerium
volumes:
- ./config.yaml:/pomerium/config.yaml
ports:
- "443:443"
environment:
- COOKIE_SECRET=YOUR_FIRST_SECRET
- SHARED_SECRET=YOUR_SECOND_SECRET
internal-app:
image: nginxdemos/hello
container_name: internal-app
expose:
- "80"
Defining Your Access Policies
The config.yaml file is where you define your logic. To use GitHub, you must first create an OAuth App in your GitHub Developer Settings. Set the ‘Authorization callback URL’ to https://authenticate.yourdomain.com/oauth2/callback.
Configuring the Proxy
Create a config.yaml in the same folder with this structure:
address: ":443"
authenticate_service_url: https://authenticate.yourdomain.com
idp_provider: github
idp_client_id: "your-github-id"
idp_client_secret: "your-github-secret"
routes:
- from: https://internal-tool.yourdomain.com
to: http://internal-app:80
policy:
allow:
and:
- domain:
is: yourcompany.com
- github:
groups:
- "engineering-team"
This policy is strict. It ensures that only users with a yourcompany.com email who are also members of your ‘engineering-team’ on GitHub can see the app. Everyone else gets a 403 Forbidden page before they even touch your application server.
Verification and Performance
Launch the stack with docker-compose up -d. When you navigate to your tool’s URL, Pomerium will redirect you to GitHub for a standard OAuth login. Once you approve, you are passed back to the internal app seamlessly.
Monitoring Access
Visibility is a core tenet of Zero Trust. You can watch access decisions in real-time by tailing the logs:
docker logs -f pomerium
A successful entry will show a check_result: allow along with the user’s GitHub ID. This makes auditing for compliance (like SOC2 or ISO27001) significantly easier than digging through firewall logs.
Latency and Scaling
In production tests, Pomerium typically adds less than 5ms to 10ms of overhead per request. For standard web tools, this is imperceptible to users. If you are handling thousands of concurrent users, you can scale horizontally by running multiple proxy instances behind a load balancer. For Kubernetes users, the Pomerium Ingress Controller can automate this entire configuration via standard Ingress resources.
Offboarding Made Simple
The biggest operational win is how this handles employee departures. When an engineer leaves and you remove them from your GitHub organization, their access to every internal tool vanishes instantly. You no longer have to hunt down stale VPN credentials or rotate shared SSH keys. By centralizing access around your primary identity provider, you reduce the attack surface and the administrative burden simultaneously.

