An AWS Verified Access architecture gives a person access to one private application after the identity provider says who they are. The application load balancer stays on private subnets. Verified Access is the ingress. There is no standing client VPN that drops the laptop onto the VPC and hopes security groups do the rest. The security lead gets a log line with the user and the endpoint. The engineer stops maintaining a bastion fleet for browser-based tools.
Rutagon builds the instance, the trust provider, the endpoint, and the Cedar policy that actually matches your groups. We file sample logs in the GRC you already run when application access is an in-scope control. SSH and other thick clients stay on Session Manager. Verified Access is the browser path.
The pieces and how traffic moves
A Verified Access trust provider connects IAM Identity Center or an OIDC identity provider. A Verified Access instance holds that trust. A group gathers endpoints that share a policy. An endpoint targets an internal load balancer or a network interface. The user hits the Verified Access endpoint. Cedar evaluates the identity claims. On permit, Verified Access proxies to the private load balancer. The load balancer's security group allows the Verified Access endpoint, not the internet.
That last sentence is the architecture. If the load balancer remains public "during migration," you have two front doors and the log only covers one of them. We remove the public listener when the endpoint is healthy. Data perimeter work is the broader account story. This design is the human path to a specific app.
AWS describes the service in What is AWS Verified Access. The policy language is Cedar. The context keys depend on the trust provider name you configured. A sample copied from a guide that uses context.oidc fails closed if you named the provider something else. We decode one successful identity assertion in a non-production instance and write the policy against those claim names.
permit(principal, action, resource)
when {
context.idc.groups.contains("app-finance")
};
idc in that example is the trust provider name, not a universal key. If your provider is named differently, the clause changes. Fail closed is the behavior we want from a mismatch. We test a user in the group and a user outside it before anyone calls the migration done.
AWS Verified Access architecture we put in production
The policy is per application group, not one permit for the whole company. Finance tools require the finance group. Admin tools require a smaller group and, where you already have a device trust provider, a posture check. We do not pretend a user-only policy is device trust. If device posture is out of scope, the evidence says so. Overclaiming posture is how an auditor's question goes badly.
Access logs go to CloudWatch Logs or S3 with the user identity, the endpoint, and the decision. That log is the evidence that access was identity-tied. A VPN connection log that says an IP joined the network is a weaker artifact for the same control. We set a retention that matches your audit window and we block public read on the log bucket. A private app with a public log bucket is a new finding.
DNS is the cutover. Users receive a name that lands on Verified Access. The old public name is removed after the internal health check passes through the proxy. We keep the old name only for a measured rollback window, and it still points at Verified Access or it is off. Pointing it at the public load balancer "just in case" recreates the standing path.
Identity Center is the usual trust provider when the workforce is already there. An OIDC provider works when the workforce IdP is elsewhere and you do not want a second directory. The application should not also prompt for a local password if the Verified Access session is the gate. Double login means one of the gates is decorative. Cognito versus custom auth is about your own product's users. Verified Access is about your employees reaching an internal app. We do not mix those populations in one policy.
What we refuse to migrate onto it
SSH, database clients, and other non-HTTP tools do not belong on a Verified Access endpoint. Forcing them through a browser hop creates a shadow VPN. Session Manager or a narrowly scoped bastion replacement stays for shells. The architecture decision is written down so the next incident does not add a client VPN "temporarily."
Mutual TLS between services is unchanged. Verified Access is a human ingress. Service-to-service calls inside the VPC do not hairpin through it. Teams that route health checks through the public identity path make outages during IdP downtime. Health checks hit the private load balancer from inside the VPC.
Cost is an endpoint and the traffic through it, and it replaces VPN connection hours and bastion instances you can retire. We put both on the scorecard so the migration is not only a security story. If you cannot retire the VPN because of the thick clients, say that, and still move the browser apps. Partial migration with an honest remainder beats a stalled "all or nothing" plan.
IMDSv2 enforcement still applies to any instances behind the private load balancer. Verified Access does not fix metadata credentials. We mention it so the hardening pass stays coherent.
Evidence and operations
The packet is the trust provider configuration, the Cedar policy, a successful and a denied log line with identities redacted as your policy requires, and the security group showing the load balancer is private. We file it in the GRC you already run. Operations own the IdP groups. A policy that checks app-finance fails when someone renames the group in the IdP and forgets Cedar. We document the group id where the provider supplies a stable identifier, because display names change.
Rutagon implements this on AWS. We do not sell a separate gateway product and we do not claim your SOC 2 attestation. The outcome is a private application with an identity on each request and a log you can sample.
Frequently Asked Questions
How is this different from a client VPN?
A client VPN places the device on the network. Verified Access proxies an authenticated user to one application endpoint and can deny everyone else without exposing the subnet. The private load balancer does not stay open to the internet beside it. SSH remains a separate path.
Why do Cedar samples fail in a new account?
Context keys follow the trust provider name you set. A policy written for context.oidc does not match a provider named idc. We read a real assertion and bind the policy to those claims. A mismatch fails closed, which is what the test is for.
Can Verified Access replace Session Manager?
It covers browser applications. Shells and database clients stay on Session Manager or an equivalent that does not require a standing network tunnel. Putting non-HTTP tools through the identity proxy creates a second, worse VPN.
What do you log for an access review or an audit sample?
The user, the endpoint, and the allow or deny decision, shipped to CloudWatch Logs or a locked S3 bucket. Retention matches your window. We file a sample in the GRC you already run. The log is identity-tied, which a bare VPN session list is not.
Does the application keep its own login?
If Verified Access is the gate, a second local password is usually leftover. We remove it when the app can trust the proxied identity, and we leave it only when the app's own session is a real control you still test. One of the two has to be the control you describe.
Talk to us about a private application path on AWS. Contact Rutagon at rutagon.com/contact, 907-841-8407, or contact@rutagon.com.