Connect to RDS using EC2 Instance Connect Endpoint

Keerti Sri Surapaneni
4 min readJun 27, 2023

Since EC2 Instance Connect Endpoint released this month, the hype has been real. Most guides show how to connect to EC2 instances, but EC2 Instance Connect Endpoint (EICE) can do more. You can use it to connect to RDS or ElastiCache Redis in a private subnet without the need for bastions.

Update: As of June 28, AWS seems to have restricted access to remote ports 22 and 3389, so we can only ssh and RDP to EC2 instances. We will have to see if they allow access to other remote ports again. 😞

When trying to connect to other remote ports such as RDS, getting the below error now:

2023–06–28 14:08:02,226 - awscli.customizations.ec2instanceconnect.websocket - ERROR - {"ErrorCode":"InvalidParameter","Message":"The specified RemotePort is not valid. Specify either 22 or 3389 as the RemotePort and retry your request."}
AWS_ERROR_HTTP_WEBSOCKET_UPGRADE_FAILURE: Failed to upgrade HTTP connection to Websocket.

Why EICE instead of bastions?

  • Simpler architecture and cost savings: EIC Endpoints eliminate the need for Internet Gateway, NAT Gateway, and bastions, simplifying the architecture of your AWS environment. This results in a streamlined infrastructure, reducing complexity. And don’t forget, cost savings!!
  • No maintenance overhead: EIC Endpoints eliminate the maintenance overhead associated with bastions, such as patching and updating.
  • Enhanced security: Bastions require a public IP address to connect to the internet, making them vulnerable to security breaches. Additionally, SSH keys are sent to the bastion, posing a risk. EIC Endpoints create ephemeral keys to connect to the end resource over the private network, enhancing security and reducing the risk of unauthorized access.
EC2 Instance Connect Endpoint

Pre-requistes:

  • aws-cli should be at version >= 2.12

In this tutorial, you will learn how to connect to an RDS instance and Elasticache Redis Cluster via EICE.

  • To get started, make sure that the user has the necessary permissions to create the EC2 instance connect endpoint.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "InstanceConnectEndPointPermissions",
"Effect": "Allow",
"Action": [
"ec2:CreateInstanceConnectEndpoint",
"ec2:CreateNetworkInterface",
"ec2:CreateTags",
"iam:CreateServiceLinkedRole"
],
"Resource": "*"
}
}
  • The below IAM permissions are needed to allow users to use EC2 Instance Connect Endpoint to connect to end resources. The below code allows all permissions for ec2-instance-connect. However, it is recommended restrict the permissions further as applicable.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "InstanceConnectEndPointPermissions",
"Effect": "Allow",
"Action": [
"ec2:DescribeInstances",
"ec2:DescribeInstanceConnectEndpoints",
"ec2-instance-connect:*"
],
"Resource": "*"
}
}
  • Next, create a security group for EICE. The security group doesn’t require inbound rules, but you should open outbound ports to the VPC CIDR or specific resource security group (RDS/ElastiCache Cluster).
    In the below screenshot, I have used the resource security group as the destination. 3306 is the MySQL DB port and 6379 is the ElastiCache Redis port.
  • Create an Instance Connect endpoint.
    In the console, go to VPC -> Endpoints -> select EC2 Instance Connect Endpoint and choose the VPC where your end resources reside, the Security group you created in the previous step and a private subnet.

Note: We can only have one EIC endpoint per VPC.

  • Allow end resources to receive connections from EICE . Here I have created a new security group and allowed inbound connections on MySQL and Redis ports from EICE security group and attached it to both MySQL and Redis resources.
  • Open a Websocket tunnel to remote DB/Redis using this command:
aws ec2-instance-connect open-tunnel - instance-connect-endpoint-id <eice-id> - private-ip-address <private IP of DB/Redis endpoint> - local-port <any port> - remote-port <DB/Redis port>

The command requires four parameters:

  • instance-connect-endpoint-id: the EC2 Instance Connect endpoint ID
  • private-ip-address: The target private IP you want to open a tunnel for (In our case, it will be the private IP of the RDS/Redis endpoint)
  • local-port: Specify the local port to listen on. Each new
    connection will have a separate websocket tunnel read and write to it.
  • remote-port: Specify the remote port to connect to on the
    end resource (RDS/Redis port).
  • Now that the tunnel is open and listening, you can communicate with the end resource via a client. Ensure that you mention the hostname as localhost or 127.0.0.1, and the port should be the local port you specified.

DB client example:

You will be prompted to enter your DB credentials, so make sure to have them handy.

mysql -h 127.0.0.1 -P 8080 -u admin -p

Redis client example:

redis-cli -h localhost -p 7070 --tls

That’s it! With EICE, we have securely connected to both RDS and ElastiCache Redis in private subnet without the need for bastions.

--

--