You add one inbound rule for the VPN client pool, remove nothing, and the service is still reachable from the internet. Nothing is broken. A security group does not have an override, a priority or a final deny that the narrow rule could win against. Every group attached to the instance contributes its own allowances to one combined set, and the broad rule you forgot about is still in that set. Making the instance VPN-only means auditing all of them, not adding a better-sounding rule to one.

Write down the service before you write the rule

Start with the exact destination, protocol and port, and the network interface the service actually listens on. An instance with several interfaces or several services on one port needs the audit run per interface, because the attached groups can differ. Then determine which source address that interface really receives for a VPN user, rather than the address the client shows in its own connection window.

Those two addresses diverge more often than people expect once translation and routing are involved.

Three source models, three different rules

With private routed access, the instance receives the client pool or the corporate range, subject to however the path is routed and translated. With a public endpoint reached through corporate egress, the instance sees the corporate NAT address instead, and only if that destination actually uses the VPN path, since split tunnelling can leave it on a home connection. With a managed Client VPN endpoint, the documented association and target-network model applies, and the client address comes from the configured client CIDR.

What does not work is referencing a VPN gateway as a security-group source. Group references match elastic network interfaces inside the VPC or a peered network, and a gateway forwarding packets is not one of them.

Read the union across every attached group

Open the instance, find its network interface, and list every security group attached to it. For each one, check every rule that covers your protocol and port, including wide port ranges and both address families. An IPv4 rule from 0.0.0.0/0 does not excuse you from checking ::/0, and a rule allowing all traffic hides the port question entirely. Only after that inventory can you say what the effective permission for the service is.

The AWS rule reference describes security groups as allow-only and states that the rules from all attached groups are aggregated, which is the whole mechanism behind this failure.

Network ACLs are a separate, stateless policy with ordered allow and deny entries, and they evaluate on the subnet rather than on the instance.

Do not answer with a deny wall

Adding a subnet-wide NACL deny to imitate a firewall you are used to is the wrong tool and a risky one. NACL entries are ordered and stateless, so a deny placed above an existing allow silently breaks unrelated traffic, including the return path for the sessions you were trying to keep. Fix the broad security-group allowance in the group that owns it, then leave the ACL alone unless it is genuinely part of the design.

Removing a public address from the instance is a stronger guarantee, and it is also an architectural change with administration and application consequences rather than a checkbox on an allowlist.

Test with a new session and keep a way in

Before you retire any existing allowance, confirm an approved independent administration path, because the rule you are about to delete may be the one your session recovery depends on. Then test a fresh permitted connection from the VPN and a fresh denied connection from an authorised non-VPN test path. Existing tracked sessions survive rule changes in ways that make old open shells useless as acceptance evidence.

Last, keep the application's own authorization in place. A translated corporate exit can represent hundreds of people, and network admission never identified an individual user or their device.

Artitgels cun il medem tema