You are connected to the AWS Client VPN endpoint, the private subnet answers, and every public page still times out. That combination narrows the problem to one of three objects on the managed side: the route the client installs, the endpoint's route together with its authorization rule, or the associated subnet's onward hop. I check them in that order because each failure looks different from the client. This runbook covers the VPC-associated managed endpoint, not an OpenVPN server on an EC2 instance and not a Cloud WAN or Transit Gateway attachment.

Start with what the client actually routes

A connected state proves the TLS session and the client CIDR assignment, nothing more. Ask the operating system where a public address would go while the tunnel is up. On Linux, ip route get 1.1.1.1 should name the tunnel interface; on macOS, netstat -rn -f inet | head -5 shows the default entry; on Windows, Find-NetRoute -RemoteIPAddress 1.1.1.1 prints the chosen interface and next hop.

Then read the split-tunnel flag, because it decides whether the endpoint's published routes are the only destinations the client sends into the tunnel:

aws ec2 describe-client-vpn-endpoints \
  --client-vpn-endpoint-ids cvpn-endpoint-0123456789abcdef0 \
  --query 'ClientVpnEndpoints[0].SplitTunnel'

With SplitTunnel true, a public destination uses the tunnel only when the endpoint publishes a route that covers it, so a missing 0.0.0.0/0 leaves that traffic on the local interface. With it false, the client captures the traffic, but the endpoint still has to route and authorize it; otherwise packets enter the tunnel and stop there. Reconnect the client after changing either setting, since routes and DNS servers are delivered at connect time and a running client can keep its old set.

Read the endpoint route and the authorization rule separately

These are two objects, and creating one does not create the other. List the endpoint routes and look for a default whose target is an associated subnet:

aws ec2 describe-client-vpn-routes \
  --client-vpn-endpoint-id cvpn-endpoint-0123456789abcdef0

Each route has exactly one target subnet, so three associations need a matching default route each. AWS documents this coverage requirement, and the practical symptom of a gap is a user who works from one subnet and stalls from another, which reads as an intermittent fault instead of a missing route. The official Client VPN scenario documentation describes the public-subnet arrangement these routes belong to.

Authorization is the second object. When no rule covers the public destination, the tunnel carries the packet and the service discards it, so private resources keep working while the internet does not:

aws ec2 describe-client-vpn-authorization-rules \
  --client-vpn-endpoint-id cvpn-endpoint-0123456789abcdef0

A rule for the VPC CIDR says nothing about 0.0.0.0/0. Adding the missing pieces for a full tunnel means one route per associated subnet plus an authorization rule you can audit later:

aws ec2 create-client-vpn-route \
  --client-vpn-endpoint-id cvpn-endpoint-0123456789abcdef0 \
  --destination-cidr-block 0.0.0.0/0 \
  --target-vpc-subnet-id subnet-0a1b2c3d4e5f67890
aws ec2 create-client-vpn-authorization-rule \
  --client-vpn-endpoint-id cvpn-endpoint-0123456789abcdef0 \
  --destination-cidr-block 0.0.0.0/0 \
  --access-all \
  --description "internet egress for full tunnel"

--access-all grants the destination to every client of the endpoint, so keep it only while the tunnel is meant to be full; a rule bound to a directory group is preferable when you have groups to bind.

Follow the packet out of the associated subnet

The endpoint route decides that AWS hands the packet to that subnet. It does not decide the next hop beyond it, which lives in the subnet's own VPC route table:

aws ec2 describe-route-tables \
  --filters Name=association.subnet-id,Values=subnet-0a1b2c3d4e5f67890 \
  --query 'RouteTables[].Routes[?DestinationCidrBlock==`0.0.0.0/0`]'

A usable default points at an internet gateway for a public subnet, or at a NAT gateway for a private one, and a state of blackhole means the target was deleted and the path now dies quietly. These are different tables from the endpoint's route list, and repairing one does not repair the other.

Two filters sit on this hop. The security group applied to the target network association must allow outbound traffic toward the public destination, and any applicable network ACL must allow the request and the return traffic on ephemeral ports. A restrictive association security group is a common reason private access works while public access does not.

Pick the first layer from the symptom rather than changing all three at once:

What you observeLayer to check first
No tunnel interface for a public IPClient route or split-tunnel flag
Tunnel interface chosen, request times outEndpoint route and authorization rule
Endpoint route present, still times outSubnet route table, association security group
Named host fails, numeric address worksDNS servers and their own authorization

Separate DNS failure from a dead route

Name resolution fails differently from forwarding, and full tunnel makes the difference matter because the pushed resolver is now reached through the tunnel. If the endpoint specifies VPC DNS servers, their addresses need route coverage and authorization like any other destination. Query the resolver directly to see which failure you have: dig +short example.com @10.0.0.2, or nslookup example.com 10.0.0.2 on Windows.

When a numeric URL answers and a named one does not, stop editing the default route and work on DNS. A request to an IP address proves nothing about a named virtual host and its certificate either, so keep one named test in the final check.

Timing helps. A TCP connection that gets no response within a few seconds points at routing or a filter, while a request that hangs inside name lookup points at the resolver. Changing the default route while the resolver is unreachable tends to turn one failure into two.

Roll back cleanly, then verify the egress path

Both objects were additive, so rollback is deletion rather than repair:

aws ec2 delete-client-vpn-route \
  --client-vpn-endpoint-id cvpn-endpoint-0123456789abcdef0 \
  --destination-cidr-block 0.0.0.0/0 \
  --target-vpc-subnet-id subnet-0a1b2c3d4e5f67890
aws ec2 delete-client-vpn-authorization-rule \
  --client-vpn-endpoint-id cvpn-endpoint-0123456789abcdef0 \
  --destination-cidr-block 0.0.0.0/0 \
  --access-all

Reconnect, then confirm which path the traffic leaves by. Compare the observed public address with the NAT gateway's elastic IP address, or with the internet gateway you intended to use, and check that a private resource still answers in the same session.

Finish with a short list, and treat the last item as part of the change rather than as documentation:

  • One 0.0.0.0/0 endpoint route for every associated subnet.
  • An authorization rule that covers 0.0.0.0/0 for the clients you mean to serve.
  • A non-blackhole VPC default route on each associated subnet.
  • Association security group egress, plus ACL return traffic.
  • Resolver addresses routed and authorized, verified with a named request.
  • A recorded rollback for the route and the rule.

One scope note: this is an IPv4 path. A dual-stack client keeps whatever IPv6 connectivity it already has, so an IPv6 default route is a separate decision with its own authorization rather than a side effect of this one.

متعلقہ مضامین