At some point, every AWS team thinking about Zero Trust runs into the same moment: you discover AWS Verified Access, you like the idea of VPN‑less secure access, then you open the pricing page and quietly close the tab. A quick search later and you find comments like: “You can set up OIDC with an ALB for almost free. We were originally going to use Verified Access but then realized ALBs had that obscure setting and would work fine.” I actually found that comment on Reddit while preparing this article. It made the article a tad bit longer, but it also perfectly captures the tension I want to dig into.
On paper, the comparison looks obvious. AWS Verified Access charges per application hour and per gigabyte of data processed, and if you have dozens of internal tools, that line item can grow fast. An ALB with OIDC authentication feels practically free by comparison when you add one more listener rule, reuse your identity provider, and you’re done. Client VPN is a known quantity too: relatively cheap, battle‑tested, and many engineers already know how to run it. Honestly, it’s not surprising that many teams decide that Verified Access is not it for them.
But the uncomfortable truth is that while ALB + OIDC and Client VPN can contribute to a Zero Trust architecture, neither natively provides the same managed, device-aware, application-level access model as Verified Access. It is cloud-native application-layer authentication offload, but by itself it is not a complete ZTNA solution. In other words, ALB + OIDC is great at answering “who is this user and can they log in?” but it does not natively incorporate managed device-posture signals or centrally evaluate AVA-style trust policies. ZTNA makes access decisions using identity and contextual signals at the application-access layer, rather than granting broad network reachability after a single VPN connection.
Verified Access is designed as a Zero Trust Network Access (ZTNA) service that evaluates each request against identity and device posture, enforcing fine‑grained policies rather than granting broad network access once you’re “on the VPN” or “past the ALB.” To achieve this Zero Trust Network Access on a normal day, you’d have to manually assemble a full Zero Trust stack: identity, device posture, policy engine, enforcement points, and telemetry/monitoring, all wired together per application. If you don’t use Verified Access, here’s roughly what you’d need to assemble yourself:
- At least one IdP + MFA/SSO.
- One or more device posture systems (MDM/UEM + EDR) with an API.
- A central PDP (authorization service) and policy language.
- Multiple PEPs (reverse proxies/gateways) in front of each app.
- A resource catalog and sensitivity classification.
- Logging/SIEM + monitoring and feedback loops.
- Segmentation + controlled VPN for edge cases.
Verified Access packages much of that access-control integration into a managed AWS service. When a team chooses “almost free” alternatives instead of Verified Access, they’re not just trading price but also trading away the ability to treat every request as potentially risky rather than trusting the tunnel or the subnet.
This article assumes you care about Zero Trust more than routine checkboxes and looks closely at what Verified Access actually gives you, where your existing solutions are genuinely good enough, and how to deploy Verified Access only where it earns its keep so that you’re paying for security posture, not just another shiny AWS service on your bill.
What AWS Verified Access actually does
💡 Disclaimer: Zero Trust Network Access is one component of a broader Zero Trust architecture, not the whole architecture. There are still other parts to consider but now we focus on the network access.
This article isn't comparing AWS Verified Access to third-party ZTNA platforms like Cloudflare Access, Zscaler, or Tailscale. The question here is “if you're already building on AWS, when is Verified Access worth paying for over the AWS-native alternatives people most commonly compare it against (case in point ALB + OIDC and Client VPN)?”
The following diagram shows the core components and how this actually works for one request:
Starting with the user icon on the left:
- A user opens an internal app URL in their browser, say, the internal wiki we host on EC2 behind an ALB in a private subnet.
- The request is evaluated using claims from the configured identity and device trust providers (in our case IAM Identity Center for identity, Jamf for device posture) against the group and endpoint policies.
- Verified Access evaluates the group policy first, then the endpoint policy; access is allowed only when both policies permit the request.
- Verified Access evaluates access to the endpoint; if the applicable policies allow it, the endpoint forwards traffic to its configured target, such as an ALB or EC2 instance.
In other words, every user request is mediated by Verified Access. It is enriched with identity and device posture from trust providers, evaluated against your Zero Trust policy in real time, and only then allowed to hit the endpoint and the application in your VPC. That’s the core difference you should keep in mind when we start comparing this lower-cost alternatives teams often choose instead.
Now that we’ve seen how Verified Access treats every request as a Zero Trust decision, it’s worth looking closely at what is actually happening in that “almost free ALB + OIDC” pattern we reach for instead.
On the other hand, let’s look at the ALB + OIDC flow:
- A user hits the ALB URL for an internal app.
- If they’re not authenticated, ALB redirects them to the configured OIDC provider (Cognito, Okta, Azure AD/M365, etc.).
- The IdP runs the OAuth/OIDC flow, the user logs in, and ALB validates the returned ID token or auth code.
- Once the token is valid, ALB forwards the request to the target group (your EC2 app) with user claims in HTTP headers; the application can use the identity headers injected by the ALB, provided targets cannot be reached by paths that bypass the ALB. If the application uses x-amzn-oidc-data to identify a user, it should validate that header’s signature and confirm that its signer is the expected ALB.
If you already have an Application Load Balancer in front of your internal apps, enabling OIDC authentication feels like the way forward. You flip on an authenticate-oidc action in a listener rule, point it at your identity provider, and your app never has to implement redirects, token verification, or cookie handling itself. You offload the entire login dance to the infrastructure layer and your backend just reads x-amzn-oidc-* headers or similar to know who the user is.
Cost-wise, it also is a good move. An ALB has a relatively low baseline hourly charge in many regions, and you’re already paying for it to front your applications. Adding OIDC auth is just one more listener rule, not a new service with its own per‑app, per‑hour line item like Verified Access.
However, if you put ALB + OIDC next to the Verified Access diagram you just saw, you start noticing gaps.
First, there’s no device posture in the picture. The ALB only talks to your identity provider and validates tokens; it doesn’t natively query Jamf, CrowdStrike, JumpCloud, or any other device trust provider on each request. You get strong user authentication, but no built‑in notion of whether the laptop itself is healthy, managed, or compromised. In the Verified Access flow, that device context is part of every decision.
Second, policies live on the ALB, not in a Zero Trust engine. Each load balancer and listener rule carries its own configuration and conditions, so your access rules are scattered across infrastructure objects rather than expressed centrally as Zero Trust policies evaluated per request. Verified Access, in contrast, evaluates each application access request inside the AVA instance and group using identity and device context, and then decides whether to forward traffic to the endpoint. You can even deny access because someone's laptop is running an unsupported OS.
ALB + OIDC mainly protects the “front door.” Once traffic has passed the ALB and reached the target group, there’s no AVA‑style per‑request re‑evaluation based on broader risk or device state unless you build that yourself in the application. In other words, ALB + OIDC gives you robust login, but it doesn’t behave like a Zero Trust access layer that treats every request as potentially risky, aggregates device posture, and enforces fine‑grained policies across multiple applications.
Practically speaking, ALB + OIDC is usually enough when:
- The application is low‑risk internal tooling that never leaves your trusted user population.
- You don’t need device posture in the decision, only “is this a known user in the right group?”.
- You’re comfortable managing per‑ALB authentication rules instead of having a central Zero Trust policy engine.
- The main goal is to offload login from the app code, not to build a full Zero Trust access layer.
So the point isn’t that ALB + OIDC is bad. It’s a great way to do some things and relatively improve security with very little cost and configuration. It’s just not the same thing as what Verified Access is doing, and if your goal is Zero Trust, that distinction in how your network is accessed matters.
Why VPNs don’t qualify as Zero Trust Network Access
The other common alternative is AWS Client VPN. If you’ve been around AWS networking for a while, AWS Client VPN feels like the sensible default for remote access without a site restriction. You create a Client VPN endpoint, associate one or more VPC subnets as target networks, add an authorization rule for a CIDR range, and your users connect with an OpenVPN-based client to reach “the internal network.” Once the tunnel is up and the right routes and security groups are in place, developers can hit EC2 instances, RDS databases, internal ALBs, or even on‑prem resources almost as if they were on the office LAN.
From a comfort point of view, this makes sense. VPNs match how we have thought about network security for years: you join a “trusted” network, and after that, access is mostly managed with IP ranges and security groups. With Client VPN, one subnet association and a few authorization rules can give users access to an entire VPC, and it’s straightforward to add more destinations by expanding those rules. For smaller environments, this can be perfectly adequate.
But compared to the Verified Access flow you saw earlier, a conventional Client VPN deployment is not, by itself, ZTNA: it grants network-level connectivity, while Verified Access makes application-access decisions using identity and device-trust context. When a user connects to Client VPN, you’re effectively granting them a broad network foothold; policy is applied at the level of subnets and CIDR ranges, not at the level of individual application requests vetted on identity and device posture. Zero Trust Network Access, and specifically AWS Verified Access, flips that model: it assumes the network is untrusted (Never Trust, Always verify!), validates each request before it reaches the application, and bases decisions on who the user is and what state their device is in rather than on the fact that they happen to be “on the VPN.”
So VPNs are still useful, especially when you have many legacy protocols and management flows that Verified Access doesn’t yet cover.
💡 Side note: Since February 2025, AWS Verified Access has supported selected non-HTTP workloads, including TCP-based resources such as SSH and RDP. That certainly narrows the gap, but VPNs still remain the better fit for many legacy protocols, administrative access patterns, and environments that don't map well to the Verified Access model.
But if your goal is Zero Trust for human access to internal apps, Client VPN is fundamentally a “joined the network, now you’re mostly in” model, which is very different from AVA’s “every request is verified before it gets anywhere near the private subnet” approach.
What Verified Access really costs and when it’s worth paying for
AWS Verified Access pricing for HTTP(S) applications has two moving parts: app hours and data processed per app. You’re billed hourly for each associated application, and separately for the volume of data AVA processes for that application. Let’s take a closer look at the official sample pricing published by AWS on the service information page.
In the small case, the numbers look harmless. If you run 10 applications for one hour in US East (Ohio), that’s 10 app‑hours at $0.27/hr and a small amount of data. With 0.5 GB processed per app, AWS’s own example breaks down as:
- App hours: 10 × $0.27 = $2.70
- Data processing: 0.5 GB × 10 apps × $0.02 = $0.10
- Total: $2.80 for that hour.
No one is going to argue with $2.80 for a short test or a small pilot.
Where people get nervous is when they unconsciously scale that pattern out to “every internal app.” The same pricing page shows a month‑long example for 300 applications in US East (Ohio): 223,200 app‑hours across the month, with tiered rates (first 148,800 hours at $0.27/hr, the remaining 74,400 at $0.20/hr), and 1 GB of data processed per app. The breakdown is:
- First 148,800 app‑hours: 148,800 × $0.27 = $40,176.00
- Next 74,400 app‑hours: 74,400 × $0.20 = $14,880.00
- Data processing: 1 GB × 300 apps × $0.02 = $6.00
- Total: $55,062.00 for the month.
Even I paused at that number. I had to take a breath before I tried to unpack how we got $55,062.00. That number is why a lot of engineers look at Verified Access, look at ALB + OIDC or Client VPN, and decide AVA is “too expensive.” It’s not that the pricing is wrong; it’s that using AVA as the front door (actually make it hundreds of front doors) for hundreds of low‑risk internal tools is the wrong deployment model if you care about your bill.
A large app estate does not necessarily require one endpoint per logical application: where architecture and policy boundaries permit, an ALB-based endpoint can front multiple routed applications. Validate the isolation and authorization implications before consolidating.
From a Zero Trust point of view, the way to make Verified Access worth paying for is to treat it as a premium security layer for the handful of applications where identity + device posture + per‑request policy enforcement actually matter, not as a generic load balancer replacement for everything your company is running including developer sandboxes and abandoned projects. That usually means:
- High‑risk internal apps that are reachable from the public internet or from untrusted networks.
- Admin panels, dashboards, or control planes used by contractors, partners, or mixed‑trust user populations.
- Regulated workloads where you explicitly need to demonstrate device‑aware, identity‑centric access controls, not just “we have VPN and a login form.”
One important optimization people often overlook is scheduling Verified Access resources so they only run during business hours. For genuinely business-hours-only services, automation can remove the application association or endpoint outside operating hours but make sure to weigh availability, deployment complexity, and the fact that partial app-hours are billed as full hours.
The same goes for what sits behind Verified Access: avoid routing high-volume assets through Verified Access solely by default; separate public assets when appropriate, but you can keep assets behind it when access to them is sensitive.
| Choose | Best fit | Key limitation |
|---|---|---|
| Verified Access | High-value private apps, contractors or partners, device-posture requirements, identity- and device-aware application access | Per-application-hour and data-processing costs |
| ALB + OIDC | HTTP(S) apps where you need authentication offload and identity propagation at low incremental cost | No native device-trust evaluation or centralized AVA-style policy engine |
| AWS Client VPN | Broad access to private networks, legacy protocols, administration, or resources that do not fit a web-access model | Network-level access model; requires careful routing, authorization, and segmentation |
When to use Verified Access, ALB + OIDC, and VPN
We started this article with a Reddit comment saying ALB + OIDC is almost free. I don’t disagree with that statement. I just don’t think it’s answering the same question.
If authentication is all you need, ALB + OIDC or Client VPN can be perfectly rational choices. For deep‑internal tools, low‑risk applications, and legacy protocols, they may even be the better choice.
But if you’re trying to implement Zero Trust Network Access with identity‑aware, device‑aware, per‑request policy enforcement, then you’re solving a different problem entirely. In that world, the comparison shouldn’t be “Can I authenticate users more cheaply?” Of course you can.
If you sketch a list of five to ten applications in your environment that would genuinely worry you if they were protected by “just VPN” or “just ALB + OIDC”, that’s probably your starting point. And that’s probably where AWS Verified Access starts earning its cost.


Top comments (0)