I am new to AWS and trying to set up and initialize an RDS instance. Since I have a newly created account, it does not support EC2-Classic, which (from what I understand) means that my RDS instance must be deployed into a private subnet in a VPC. However, once the RDS instance created, how can I connect to it from the outside world? I understand that I can connect to it from the public subnets in my VPC, so my application servers will be able to use the DB with no problem. However, I want to be able to say, fire up Squirrel or some other GUI client in order to initialize the schema, or add columns and tables as my application grows. How can I do this if it is required to live in a private subnet?
How to connect to an AWS RDS database (deployed in VPC) with an SQL client
amazon-web-servicesrds
Related Solutions
Security groups won't be visible, because VPC security groups have no meaning outide their VPC... and your Classic instance is (of course) outside the VPC.
Private VPC IP addresses of the instances won't work in the security config, either, since they also have no meaning outside the VPC.
The solution is that you have to open up access (in the RDS security group) for the public IP addresses that will be visible to RDS --
If the VPC machines are in a public subnet, you would use each machine's public IP address. (If the VPC machines are in a public subnet and don't have public IPs, that's an incorrect configuration).
If the VPC machines are in a private subnet, you need the public IP address(es) associated with the VPC's NAT instance(s) to be open in the RDS security group, because those VPC machines will be using that source address to contact the Classic RDS, and the address of the NAT instance is what will be visible to RDS.
For an RDS instance in VPC to "publicly" (Internet) accessible, all of the subnets it is attached to must be "public" -- as opposed to "private" -- subnets of the VPC.
A public subnet is essentially defined as a subnet that has the Internet Gateway object (igw-xxxxxxxx) as its route to "the Internet," or at least to any Internet destinations you need to access. Typically, this is a destination address of 0.0.0.0/0
. Public subnets must be used for instances (including RDS) that will have an associated public IP address, and should not be used for instances that will not have public IP addresses, since private addresses do not work across the Internet without translation.
A private subnet, by contrast, has its routing table configured to reach Internet destinations via another EC2 instance, typically a NAT instance. This shows in the VPC route table associated with that subnet as i-xxxxxxxx, rather than "igw." That machine (which, itself, will actually be on a different subnet than the ones for which it acts as a route destination) serves as a translator, allowing the private-IP-only instances to transparently make outbound Internet requests using the NAT machine's public IP for their Internet needs. Instances with a public IP address cannot interact properly with the Internet if attached to a private subnet.
In the specific case, here, the subnets associated with the RDS instance were not really configured as something that could be simply classified as either a private or public subnet, because the subnet had no default route at all. Adding a default route through the "igw" object, or, as OP did, adding a static route to the Internet IP address where connectivity was needed, into the VPC route table for the subnets fixes the connectivity issue.
However... If you experience a similar issue, you can't simply change the route table or build new route tables and associate the subnets with them, unless you have nothing else already working correctly on the subnets, because the change could reasonably be expected to break existing connectivity. The correct course, in that case, would be to provision the instances on different subnets with the correct route table entries in place.
When setting up a VPC, it's ideal to clearly define the subnet roles and fully provision then with the necessary routes when the VPC is first commissioned. It's also important to remember that the entire VPC "LAN" is a software-defined network. Unlike in a physical network, where the router can become a bottleneck and it's often sensible to place machines with heavy traffic among them on the same subnet... traffic crossing subnets has no performance disadvantage on VPC. Machines should be placed on subnets that are appropriate for the machine's IP addressing needs -- public address, public subnet; no public address, private subnet.
More discussion of the logistics of private/public subnets in VPC can be found in Why Do We Need Private Subnet in VPC (at Stack Overflow).
Best Answer
One solution (but not the only solution!) is to use what's called a Bastion Host. A Bastion Host is an ultra-low-powered server that sits in your public subnet and is the only server that allows inbound SSH connections.
This server should be thoroughly hardened, and depending on your level of paranoia, there are a few techniques you can use to hide the fact that this server is listening for SSH connections at all. See, for example, http://www.portknocking.org/view/details. Of course, you don't need to harden it just to connect to your RDS instance.
Anyway, you can setup your EC2 Security Group rules as follows:
By the way, you can achieve "only from the Bastion Host" either by specifying the private IP address of your Bastion Host, or listing the security group name the Bastion Host uses.
Now you have two options from here:
OPTION #1: Set up local port forwarding as part of your SSH connection
For example, if you're on OS X or Linux, SSH into the bastion host and setup local port forwarding with:
And let's say you're connecting to Postgres from an Ubuntu-based Bastion Host. It might look like this:
Your local machine is now listening on port
5432
and will forward any of those connections to<bastion-host-public-ip>
which in turn will forward it to port5432
on<rds-private-ip>
OPTION #2: Look for this feature in your Database Client
I know DBVisualizer supports this. I'm not sure about Squirrel. Basically, instead of setting up the local port forwarding manually using SSH, your SQL client handles this for you.