To communicate outside of the VPC, each non-default subnet needs a routing table and an internet gateway associated to it (the default subnets get an external gateway and a routing table by default).
Depending on the way you have created public subnet in the VPC, you might need to explicitly add them additionally. Your VPC setup sounds like it matches Scenario 1 - a private cloud (VPC) with a single public subnet, and an Internet gateway to enable communication over the Internet from the AWS VPC documentation.
You will need to add an internet gateway to your VPC and inside the Public subnet's routing table assign 0.0.0.0/0
(default route) to go to the assigned internet gateway. There is a nice illustration of the exact network topology inside the documentation.
Also, for more information, you can check the VPC Internet Gateway AWS documentation. Unfortunately it's a little messy and a non-obvious gotcha.
For more details about connection issues, see also: Troubleshooting Connecting to Your Instance.
For posterity, this is a 5 step process. Bastion host refers to the public facing server, which you'll want to harden against potential attacks and through which your connections will travel to servers within your private subnet.
Step 1: Enable IP Forwarding (Bastion Host)
SSH to the bastion host and at the prompt, execute the following command:
echo 1 > /proc/sys/net/ipv4/ip_forward
Step 2: Modify IP Tables (Bastion Host)
SSH to the bastion host and at the prompt, execute the following commands:
sudo iptables -t nat -A PREROUTING -p tcp -m tcp --dport {PUBLIC_SSH_PORT} -j DNAT --to-destination {PRIVATE_IP_ADDRESS}:22
sudo iptables -t nat -A POSTROUTING -p tcp -m tcp --dport {PUBLIC_SSH_PORT} -j MASQUERADE
where:
- {PUBLIC_SSH_PORT} is the port on the bastion host you plan to connect through
- {PRIVATE_IP_ADDRESS} is the address of the server in the private subnet you plan to connect to
For more detailed information on what these configurations mean, you can run the following commands at the command prompt to view the man pages:
man iptables
man iptables-extensions
Step 3: Configure Security Groups (Amazon AWS Console)
Login to your Amazon AWS console and navigate to the Security Groups dashboard. Edit the security group assigned to your bastion host and add:
- Custom TCP Rule to allow inbound and outbound connections on {PUBLIC_SSH_PORT} from whatever IP address you will be connecting from
- Custom TCP Rule to allow inbound and outbound connections for All Traffic to/from the security group of the private server (type in the security group ID in the Custom IP field) - you could restrict this to just SSH traffic but if you have other services and servers running that you need to access, this is the simplest configuration
Edit the security group assigned to your private server and add:
- Custom TCP Rule to allow inbound and outbound connections for All Traffic to/from the security group of the bastion host (type in the security group ID in the Custom IP field) - you could restrict this to just SSH traffic but if you have other services and servers running that you need to access, this is the simplest configuration
Step 4: Disable Source/Destination check (Amazon AWS Console)
Login to your Amazon AWS console and navigate to the Instances dashboard. Click on the bastion host that you just configured to forward connections. Disable source/destination checks from the action menu. This is the only device for which source/destination checks need to be disabled.
Step 5: Make Configurations Persistent (Across Server Restarts)
Modify the /etc/sysctl.conf
file, and update the following line (change 0 to 1):
# Controls IP packet forwarding
net.ipv4.ip_forward = 1
Save the iptables
configuration (to /etc/sysconfig/iptables
) so it will be reloaded on boot:
sudo service iptables save
And finally, make sure that iptables
itself starts up on boot:
sudo chkconfig iptables on
NOTE: You don't need to setup and configure a separate Amazon NAT instance to gain SSH access to private servers. The NAT instance is ideal if you plan to manage Internet access for various devices you may have within your private subnet.
Best Answer
Connect to db in private subnet instance via NAT with MySQL Workbench
Create a mysql user who can connect remotely:
root
user cannot connect remotelycreate a user who is allowed to connect from your IP address (or use % which means any address)
-- connect to the db instance in the private subnet via SSH
-- log into mysql as root and type password when prompted:
mysql -h localhost -u root -p
-- run the following query to create a user
CREATE USER 'username'@'XX.XX.XX.XX' IDENTIFIED BY 'mypassword';
-- ensure that the user you've added has all privileges required:
GRANT ALL PRIVILEGES ON *.* TO 'username'@'IP' IDENTIFIED BY 'password';
ensure that the users you are adding are not duplicates in either username or password
-- view the user table in terminal with the following mysql query:
select * from mysql.user\G;
-- it's a good idea to delete the anonymous user for both security and potential user collisions: https://stackoverflow.com/questions/10299148
when complete run query:
FLUSH PRIVILEGES;
Set up your security groups to allow remote MySQL connection via the NAT instance:
with WorkBench you're SSH tunnelling up to the NAT then connecting via port 3306 to the db instance
ensure that the IP you're connecting from is allowed to connect to port 3306 in AWS security group
-- the NAT instance should have SSH(22) inbound from your IP address
-- the NAT instance should have MySQL(3306) outbound towards the VPC address range (eg 10.0.0.0/16)
-- the db instance in the VPC private subnet should allow inbound MySQL(3306) from the VPC private IP range (eg 10.0.0.0/16)
Set up Workbench to connect to your db instance via the NAT instance:
-- choose 'Standard TCP/IP over SSH' as connection method
-- SSH host is the public IP of the NAT intance e.g. XX.XX.XX.XX
-- SSH Username = ec2-user
-- SSH Password is blank (clear this if necessary)
-- SSH Key File = browse to location of the key_pair.pem file
-- MySQL Hostname = private IP address of the db instance in the VPC
-- MySQL Server Port = 3306
-- username = the name you just added in CREATE USER
-- password = just added in CREATE USER