DevOps Peach

AWS Basics · Networking with Amazon VPC · Lesson 3 of 5

NAT Gateway, NAT Instance and Bastion Host

Give private instances one-way Internet access with NAT, and SSH into them safely through a bastion host.

Practice interactively →

The problem

An instance in a private subnet has no route to the IGW and no public IP. That's great for security, but it still needs to run yum update, download packages... and you still need to SSH in to manage it.

NAT: out yes, in no

NAT translates private IPs → one public IP that many machines share. NAT only allows outbound connections started from the inside; the Internet can't open a connection to a private instance on its own.

After you create the NAT Gateway, add 0.0.0.0/0 → nat-xxxx to the private subnet's route table.

flowchart LR
  Admin[You] -- SSH --> Bastion
  subgraph VPC["VPC 10.0.0.0/16"]
    subgraph Pub["Public subnet"]
      Bastion[Bastion host]
      NAT[NAT Gateway + EIP]
    end
    subgraph Priv["Private subnet"]
      App[EC2 private 10.0.2.15]
    end
  end
  Bastion -- SSH --> App
  App -- outbound --> NAT --> IGW[Internet Gateway] --> Internet((Internet))
  %% step Admin: You SSH to the bastion host, the only instance exposed for admin access.
  %% step Bastion: From the bastion you jump to private instances, using ssh -J so the key stays on your machine.
  %% step App: The private instance has no public IP and no route from the Internet.
  %% step NAT: Its outbound traffic goes to the NAT Gateway in the public subnet, which uses an Elastic IP.
  %% step IGW: The NAT Gateway sends traffic out through the Internet Gateway; replies come back the same way.

Bastion host

A bastion is a small EC2 instance in a public subnet that acts as your SSH "gateway". You SSH into the bastion, then SSH from there into the private instance.

Don't copy your .pem file onto the bastion — if the bastion is compromised, so is your key. Use ProxyJump (ssh -J) or agent forwarding (ssh -A) instead: the key stays only on your machine.

Handy commands

Task Command
Create a NAT GW in the public subnet aws ec2 create-nat-gateway --subnet-id subnet-pub --allocation-id eipalloc-xxxx
Route private traffic to the NAT aws ec2 create-route --route-table-id rtb-priv --destination-cidr-block 0.0.0.0/0 --nat-gateway-id nat-xxxx
Jump through the bastion ssh -J ec2-user@<bastion-ip> ec2-user@<private-ip>
SSH with agent forwarding ssh -A -i key.pem ec2-user@<bastion-ip>
Check Internet access ping -c 3 8.8.8.8

Common mistakes

Practice interactively →