Achieving zero trust with Pomerium JWTs

Just because a user’s session has been authenticated and authorized doesn’t mean a user’s action has been. Upstream services should have confidence the request they’re receiving has been authenticated and authorized before execution.

There are three separate ways to achieve this:

  • Network firewall rules

  • Mutual authentication with client certificates

  • Attaching Pomerium’s JSON Web Token (JWT) to each HTTP request

But first, we’ll talk about why this is important for a zero trust architecture

Zero Trust

A policy enforcement point (PEP) is a key component of a Zero Trust architecture. This is the point at which the system is able to enforce access policies on incoming requests in order to reject unauthorized access attempts. More critically, it is important for there to be no method to circumvent the policy enforcement point.

(see our blog post on Zero Trust Architecture for more about Zero Trust principles)

The Pomerium proxy service serves as the policy enforcement point in a Pomerium deployment. This puts Pomerium’s proxy in a position to evaluate each incoming request against configured policies to determine an overall allow or deny result. Then, the proxy service will either pass on the request to the upstream service or enforce a deny result by serving an error page.

But in order to be effective, a Pomerium deployment must ensure that all requests go through this policy enforcement point.

User 2 should not be able to skip straight to Service B

Verifying request authorization

Any method of accessing the sensitive application or resource without passing through the PEP should be considered a security vulnerability. This leaves two problems for DevSecOps practitioners and network architects:

  • How to ensure the upstream service acts on only verified requests?

  • What mechanism exists to ensure requests are correctly verified?

Let’s look at three different solutions you could use to address this problem.

Network firewall rules

One traditional solution is to use network-level restrictions. You could configure the connections between Pomerium and all upstream services on an internal network segment, protected from external access by a firewall.

However, this runs counter to the Zero Trust principle that network location should not grant any implicit trust. The traditional network-centric model risks lateral movement due to adjacency within the same network segment.

(See our Network-centric vs Application-centric approach for a longer write-up on this problem)

To be fair, this may be a perfectly appropriate solution in certain cases. For example, consider a homelab server. You might run a bunch of docker containers all on the same host using Docker Compose: one container for Pomerium, and one container each for all the individual services you want to secure. Docker Compose makes it easy to set things up so that only Pomerium would be exposed to external traffic from the host’s network interface, while the rest of the containers would be accessible only from within a Docker bridge network common to all the containers.

But even in this scenario there are some subtle risks. One service container could still make direct requests to another service container, resulting in a situation where a vulnerability in one service might present the opportunity for lateral movement to another service.

And as deployments increase in complexity, network-level solutions become even harder to manage. This is the crux of the Perimeter Problem, and is exactly what zero trust architecture exists to solve.

Mutual Authentication with Client certificates (mTLS)

Requiring mTLS between Pomerium and upstream services provides some of the strongest protections against unauthorized direct access. The idea is that each upstream service should require all incoming connections to present a trusted client certificate. No client certificate, no access.

In this scenario, you would use an internal certificate authority to issue a client certificate for Pomerium, then configure Pomerium to use it via the TLS Client Certificate option.

This would prevent both the problem of unauthorized direct access from an end user, as well as the problem from the previous example of unauthorized access from a different service.

However, this solution comes with some drawbacks. The main problem is complexity, a higher deployment cost, and management burdens: organizations deploying mTLS must manage their own certificate authority, issue certificates, and remember to renew and redeploy the certificates regularly.

The Pomerium JWT

The last option for achieving zero trust with Pomerium is through attaching our JSON Web Token (JWT) to each HTTP request, ensuring upstream applications execute only those incoming requests which have validated JWTs.

Using the Pomerium JWT to verify requests is a lighter-weight alternative to mTLS. When this feature is enabled, Pomerium will issue a signed JWT for each authorized request that it proxies to an upstream service. The upstream service can verify this JWT to determine that a request was indeed authorized and is safe to execute. No valid JWT, no access.

This option has the advantage of lowering deployment and management burdens because you don’t need to maintain your own certificate authority. Instead, you would need to:

  • configure Pomerium with a JWT Signing Key and enable the Pass Identity Headers option

  • configure upstream services to verify the Pomerium JWT in each incoming request

For more details on how to do this, see the section on JWT Authentication in the Pomerium documentation. And for upstream services using Go or JavaScript, you can use one of our SDKs.

The Pomerium JWT feature is available to try for free with Pomerium Zero. Whether you’re spinning up a new application or trying to add access control to a legacy service, Pomerium builds zero trust clientless connections to internal web apps and services without the need for a corporate VPN. The result is:

  • Easier with clientless access.

  • Faster by being tunnel-free and deployed where your apps and services are.

  • Safer because every single action is verified before allowed to execute.

  • Tailored to your organization’s needs by integrating all data for context-aware access.

Give Pomerium a try today!

Share:

Stay Connected

Stay up to date with Pomerium news and announcements.

More Blog Posts

See All Blog Posts
Blog
Reference Architecture: Using AWS EKS with Pomerium
Blog
Identity Aware Proxy (IAP): Meaning, Pricing, Solutions
Blog
The Great VPN Myth: What PCI DSS 4.0 Actually Requires for Remote Access

Revolutionize
Your Security

Embrace Seamless Resource Access, Robust Zero Trust Integration, and Streamlined Compliance with Our App.

Pomerium logo
© 2024 Pomerium. All rights reserved