RDS Access through SSH Tunnel
Using SSH tunnels, it is possible to access remote resources that are not exposed to the Internet through intermediate hosts, or to expose your local services to the Internet.
Setup
To make SSH commands shorter and easier to use, edit the ~/.ssh/config
and add the configuration for the hosts you are going to connect to.
The configuration defines default SSH options, so instead of a command
like this
ssh ec2-user@ec2-55-222-55-55.compute-1.amazonaws.com -i ~/.ssh/my_key.pem,
we can just use ssh my-remote-host.
An example config:
Host my-remote-host
HostName ec2-55-222-55-55.compute-1.amazonaws.com
StrictHostKeyChecking no
User ec2-user
IdentityFile ~/.ssh/my_key.pem
Expose Local Resource To the Internet
The SSH command to expose the local resource through the intermediate
host is ssh -R:
remote_port=8181
local_port=8888
ssh my-remote-host -R *:${remote_port}:localhost:${local_port}
With the command above, we connect to my-remote-host and instruct
it to accept connections to port 8181 and forward them to
localhost:8888.
The *:8181 means that the remote host will accept connections on any
network interface (by default, it will use only 127.0.0.1).
localhost:8888 <===== my-remote-host <===== my-remote-host:8181
You also need to make sure that the firewall on my-remote-host allows
connections to port 8181.
Example: Access RDS Database Through the EC2 Instance
It is a good idea to make RDS databases not available from the Internet, so they can only be accessed from the EC2 instances where applications are running.
On the other hand, during development, it is convenient to have the database accessible from your local machine. It is easy to do by running the following command:
ssh my-aws-host -L 5532:my-rds-host-name.cdiofumqrcpr.us-east-1.rds.amazonaws.com:5432
Here my-aws-host is the EC2 instance that has DB access and
my-rds-host-name.cdiofumqrcpr...:5532 is the RDS host name and port.
After that, you can use localhost:5532 on your local machine to
connect to the remote database, for example, with psql:
psql postgresql://my_db_user@localhost:5532/my_db_name
Or dump the database with pg_dump:
pg_dump -Fc -v --dbname=postgresql://my_db_user@localhost:5532/my_db_name -f my_db_name$(date --iso-8601).pq
Note: neither command above specifies the database password. To make
them work, the password can be specified in the ~/.pgpass file (so it will
not be present in the shell history or visible on the screen when the
command is executed).
The ~/.pgpass file looks like this:
localhost:5532:*:my_db_user_one:XXXYYY localhost:5532:*:my_db_user_two:XXXYYY
Example: Connect to Redis on AWS
Similarly to the PostgreSQL example above, we can create an SSH tunnel to the EC2 instance that has Redis access and expose Redis locally:
ssh my-ec2-instance -L 6379:id.wssxxx.0001.appp1.cache.amazonaws.com:6379
After that, we can use redis-cli or any other tool on the local
machine to connect to Redis on port 6379.
Example: Expose Local Server Through the EC2 Instance
Sometimes it can be necessary to make a locally running app available through the Internet. There are several ways to do that:
- If you have the "real" IP address (you may need to ask your Internet provider to set up a real IP for you), you only need to make sure that your firewall allows connections to the port your app is running on
- Use a service like ngrok, which will do the forwarding from the Internet to your local machine
- Use an SSH tunnel to the EC2 instance (or any other machine that's accessible from the Internet)
Let's say there is an app running locally on port 8888 (localhost:8888)
and we want to make it available via the EC2 instance
ec2-55-222-55-55.compute-1.amazonaws.com:8181.
To use the SSH tunnel, first, make sure there is a GatewayPorts yes
option in the sshd config on the server. SSH to the instance and open
/etc/sshd_config:
sudo vim /etc/sshd_config
Find and change, or add, the GatewayPorts yes option and save the config.
Restart sshd:
sudo service sshd restart
Second, check and change, if necessary, the security group configuration for the EC2 instance and allow access to port 8181.
Now, from your local machine, run:
ssh my-aws-host -R *:8181:localhost:8888
Now you should be able to access your local app via
ec2-55-222-55-55.compute-1.amazonaws.com:8181.
Troubleshooting
If the connection fails, check the following:
- the SSH connection and tunnel are established successfully - check the SSH output
- sometimes, the connection is working, but the tunnel isn't; in the SSH output, you can see something like "Port forwarding is disabled to avoid man-in-the-middle attacks." and the instructions on what to do
- you don't have anything running locally on the specified port
- check with
nc -v 127.0.0.1 5532to see if there is a connection - additionally check with
netstat -l | grep 5532andlsof -i :5532
- check with
Useful searches for other issues are "ssh tunnel aws rds problem" and "ssh tunnel aws rds connection error".