The app server is safe from the internet, and also cut off from it. It cannot install updates, call AWS APIs, or check in with Session Manager:
An error occurred (TargetNotConnected) when calling the StartSession operation: i-0b… is not connected.A NAT gateway fixes the way out without opening a way in. It sits in a public subnet with an Elastic IP; private instances send their outbound traffic to it, it forwards it from its own address, and only the replies come back.
Creating it
An Elastic IP (Chapter 3), allocated for it:
EIP=$(aws ec2 allocate-address --domain vpc --query AllocationId --output text)The gateway, in a public subnet; point SUBNET at public-a first (SUBNET=$(aws ec2 describe-subnets --filters Name=tag:Name,Values=public-a --query "Subnets[0].SubnetId" --output text)):
NAT=$(aws ec2 create-nat-gateway --subnet-id $SUBNET --allocation-id $EIP --query NatGateway.NatGatewayId --output text)It is pending for about a minute. Check until it says available:
aws ec2 describe-nat-gateways --nat-gateway-ids $NAT --query "NatGateways[0].State" --output textThe route
In the private table; point RT at it first (RT=$(aws ec2 describe-route-tables --filters Name=tag:Name,Values=private --query "RouteTables[0].RouteTableId" --output text)):
aws ec2 create-route --route-table-id $RT --destination-cidr-block 0.0.0.0/0 --nat-gateway-id $NATThe cost
A NAT gateway bills by the hour whether or not anything passes through it. One per zone survives a zone failure; one shared by both zones costs half as much. The market uses one.