When working with cloud infrastructure, we often need to access private database instances like PostgreSQL RDS that aren't publicly exposed. The standard approach involves using a bastion host as a jump server, but the tunneling mechanics can be tricky to get right.
Let's analyze your current configuration:
- Bastion host:
example.compute-1.amazonaws.com
- Private PostgreSQL:
postgres.example.us-east-1.rds.amazonaws.com:5432
- Authentication: SSH key (
key.pem
)
The issue stems from creating the tunnel after already being inside the bastion. The -L
flag binds to localhost by default, making it only accessible from the bastion itself.
You should establish the tunnel from your local machine to the bastion, which then forwards traffic to RDS:
ssh -i key.pem -N -L 5433:postgres.example.us-east-1.rds.amazonaws.com:5432 ec2-user@example.compute-1.amazonaws.com
Key parameters:
-N
: Don't execute remote commands (just forward ports)-L 5433:...
: Bind local port 5433 to remote PostgreSQL- Different local port avoids conflicts with local PostgreSQL
After establishing the tunnel, test the connection from your local machine:
psql -p 5433 -h localhost -U postgres
For production use, consider these enhancements:
ssh -i key.pem -f -N -L 5433:postgres.example.us-east-1.rds.amazonaws.com:5432 \
-o ServerAliveInterval=60 \
-o ExitOnForwardFailure=yes \
ec2-user@example.compute-1.amazonaws.com
Security group requirements:
- Bastion: Allow SSH (22) from your IP
- RDS: Allow 5432 from bastion's security group
- No need to expose 5432 on bastion
If connections fail:
- Verify SSH connectivity to bastion alone first
- Check RDS security group allows the bastion
- Test network connectivity from bastion to RDS
- Confirm PostgreSQL is configured to accept connections
For frequent access, add to ~/.ssh/config
:
Host aws-bastion
HostName example.compute-1.amazonaws.com
User ec2-user
IdentityFile ~/path/to/key.pem
LocalForward 5433 postgres.example.us-east-1.rds.amazonaws.com:5432
Then simply run:
ssh -fN aws-bastion
When working with cloud infrastructure, you often need to access private database instances (like AWS RDS) that aren't publicly accessible. A common pattern is to use a bastion host (jump server) as an entry point to your VPC. Here's the scenario:
- Bastion host: example.compute-1.amazonaws.com (publicly accessible)
- Private PostgreSQL RDS: postgres.example.us-east-1.rds.amazonaws.com:5432
While you can SSH into the bastion and then connect to the database, you might want direct access from your local machine for development tools.
The correct approach is to establish the SSH tunnel from your local machine, not from within the bastion. Here's the proper command structure:
ssh -i key.pem -N -L [local_port]:[rds_endpoint]:[rds_port] ec2-user@[bastion_host]
Key flags:
-N
: Don't execute remote commands (just forward ports)-L
: Local port forwarding
For your specific case, run this on your local machine:
ssh -i key.pem -N -L 5433:postgres.example.us-east-1.rds.amazonaws.com:5432 ec2-user@example.compute-1.amazonaws.com
Notice we're using port 5433 locally to avoid conflicts if you have a local PostgreSQL server running. You can then connect using:
psql -h localhost -p 5433 -U postgres
While you mentioned opening port 5432 on the bastion, this isn't actually necessary for SSH tunneling. The connection happens over SSH (port 22). The security groups should be configured as:
- Bastion: Allow inbound SSH (port 22) from your IP
- RDS: Allow inbound PostgreSQL (port 5432) from the bastion's security group
For development, you might want a more persistent solution. Consider using autossh
:
autossh -M 0 -f -i key.pem -N -L 5433:postgres.example.us-east-1.rds.amazonaws.com:5432 ec2-user@example.compute-1.amazonaws.com
Key additions:
-M 0
: Disable monitoring (or use a monitoring port)-f
: Run in background
If connections fail:
- Verify the bastion can connect to RDS (test from within the bastion)
- Check security group rules for both bastion and RDS
- Confirm your local firewall isn't blocking the local port
- Add
-v
flag to SSH for verbose debugging
For frequent use, add this to your ~/.ssh/config:
Host db-tunnel
HostName example.compute-1.amazonaws.com
User ec2-user
IdentityFile ~/path/to/key.pem
LocalForward 5433 postgres.example.us-east-1.rds.amazonaws.com:5432
ServerAliveInterval 60
ServerAliveCountMax 2
Then simply run:
ssh -N db-tunnel