
Conectarse a recursos privados de AWS, como ejecutar comandos psql contra una base de datos Postgres RDS, suele hacerse mediante un bastion host. Pero los bastion hosts pueden salir caros y ser difíciles de administrar. Aquí te muestro cómo lograrlo de forma económica, práctica y segura con Amazon EC2 Instance Connect.
Las mejores prácticas de seguridad de AWS recomiendan que la base de datos solo sea accesible dentro de un rango de direcciones IP privadas para garantizar el aislamiento de la red. Dicho de otro modo, la práctica recomendada es alojar la base de datos —por ejemplo, RDS— en una subred privada.
Una manera de acceder a recursos privados es a través de un bastion host.
Sin embargo, los bastion hosts también suman costos: suelen ejecutarse 24x7 solo para dar acceso ocasional y obligan a administrar una instancia aislada, con sus parches de seguridad periódicos y reglas de excepción en el firewall de red. Un bastion host mal administrado puede ampliar la superficie de ataque del sistema. Por ejemplo, una amenaza de ciberseguridad derivada de una clave SSH de larga duración —compartida de antemano con un socio comercial— para acceder al bastion host.
La nueva funcionalidad de Amazon EC2 Instance Connect Endpoint, anunciada el 13 de junio de 2023, ofrece un mecanismo adicional para acceder a los workloads en una subred privada sin necesidad de mantener un bastion host.
Tabla de contenidos
· Crear un Security Group para el EC2 Instance Connect Endpoint
· Crear el EC2 Instance Connect Endpoint
· Configurar la política de IAM para la conexión
· Container DevOps conectándose al RDS privado
· Conectarse al RDS mediante el EC2 Instance Connect Endpoint
· InvalidParameter en aws ec2-instance-connect open-tunnel
Visión general

Arquitectura general de EC2 Instance Connect conectándose al RDS en una subred privada
- Los usuarios se conectan desde Internet al servicio EC2 Instance Connect Endpoint mediante AWS CLI con
aws ec2-instance-connect open-tunnel; - Las conexiones de EIC quedan sujetas a los permisos de IAM y, opcionalmente, a logs;
- El Security Group del workload debe permitir el tráfico entrante desde el EC2 Instance Connect Endpoint;
- El EC2 Instance Connect Endpoint se conectará al RDS mediante IPs privadas.
Paso a paso
Requisitos previos
- Para demostrar que la conectividad funciona sin Internet, asegúrate de que la tabla de rutas de la subred del RDS no tenga una ruta hacia un Internet Gateway.
- Anota el Security Group del RDS, por ejemplo,
sg-012345. - Anota la VPC del RDS, por ejemplo,
vpc-012345.
Crearemos el EC2 Instance Connect Endpoint en la misma VPC, tal como se ilustra en el diagrama anterior. 4. Anota las subredes privadas en las que está alojado el RDS, por ejemplo, subnet-0abc101 y subnet-0abc102.
Crearemos el EC2 Instance Connect Endpoint en una de esas subredes. 5. Anota las IPs privadas del RDS, por ejemplo, 10.0.128.61
Nos conectaremos desde Internet a EC2 Instance Connect mediante AWS CLI y, a partir de la versión 2.12.1 de AWS CLI, open-tunnel solo acepta direcciones IP para abrir un túnel.
La IP privada de la instancia RDS se obtiene desde "Network interfaces" en el dashboard de EC2, filtrando por " Description=RDSNetworkInterface".
Si los resultados muestran varias entradas, acota la búsqueda por VPC.
Selecciona la Network Interface correspondiente; la dirección IPv4 privada aparece en el panel "IP addresses".

Buscar la IP privada de RDSNetworkInterface
Con los datos de los recursos privados de AWS a los que queremos conectarnos desde el EC2 Instance Connect Endpoint, primero crearemos un Security Group para el EC2 Instance Connect Endpoint y luego el propio EC2 Instance Connect Endpoint.
Crear un Security Group para el EC2 Instance Connect Endpoint
Crearemos un Security Group independiente para el EC2 Instance Connect Endpoint. No tendrá reglas de entrada, sino una sola regla de salida hacia el RDS, identificado mediante el Security Group del RDS.
- Ve a "Create security group" en la consola de EC2 con este enlace: https://console.aws.amazon.com/ec2/v2/home#CreateSecurityGroup.
- Ingresa un "Security group name" y una "Description" descriptivos.
- Selecciona la VPC del RDS. En este ejemplo, será
vpc-012345. - Deja vacías las "Inbound rules".
- En las "Outbound rules", configura una regla de salida con lo siguiente:
a. Type: Customer TCP
b. Port range: puerto de conectividad del RDS, por ejemplo, 5432 para Postgresql.
c. Destination: selecciona el Security Group del RDS. En este ejemplo, es sg-012345.
d. Description: Outbound connection from EC2 Instance Connect Endpoint to RDS
- Haz clic en "Create Security Group" en la parte inferior derecha de la página.
- Se creará un Security Group independiente, por ejemplo,
sg-0abcde.

Crear un nuevo Security Group para el EC2 Instance Connect Endpoint
Crear el EC2 Instance Connect Endpoint
- Ve a la página Create endpoint dentro de la VPC con este enlace: https://console.aws.amazon.com/vpc/home#CreateVpcEndpoint
- Ingresa un nombre descriptivo para el endpoint.
- En Service Category, selecciona "EC2 Instance Connect Endpoint".
- En la lista de VPC, selecciona la VPC del RDS. En este ejemplo, selecciona
vpc-012345. - En "Security groups", selecciona el Security Group creado para el EC2 Instance Connect Endpoint. En este ejemplo, es
sg-0abcde. - Selecciona una de las subredes en las que se aloja el RDS. En este ejemplo, será
subnet-0abc101osubnet-0abc102. - Haz clic en "Create endpoint".

Crear el EC2 Instance Connect Endpoint y usar el Security Group del EC2 Instance Connect Endpoint
Configurar la política de IAM para la conexión
Con el EC2 Instance Connect Endpoint creado y la conectividad lista mediante el Security Group asociado, pasaremos a crear el usuario de IAM con privilegios mínimos que podrá usar la conexión.
- Ve a Create Policy en la consola de IAM con este enlace: https://console.aws.amazon.com/iamv2/home#/policies/create?step=addPermissions
- Cambia al editor de políticas JSON e ingresa la política de abajo. Reemplaza el Resource del EC2 Instance Connect Endpoint por el ARN correspondiente y sustituye las variables entre corchetes angulares por los valores de tu entorno:
{ "Version": "2012-10-17", "Statement": [\ {\ "Effect": "Allow",\ "Action": "ec2-instance-connect:OpenTunnel",\ "Resource": "arn:aws:ec2:<AWS Region>:<AWS Account>:instance-connect-endpoint/eice-<EICE ID>",\ "Condition": {\ "NumericEquals": {\ "ec2-instance-connect:remotePort": "5432"\ },\ "IpAddress": {\ "ec2-instance-connect:privateIpAddress": [\ "<CIDR of subnet-0abc101>",\ "<CIDR of subnet-0abc102>"\ ]\ }\ }\ },\ {\ "Sid": "Describe",\ "Action": [\ "ec2:DescribeInstances",\ "ec2:DescribeInstanceConnectEndpoints"\ ],\ "Effect": "Allow",\ "Resource": "*"\ }\ ]}Container DevOps conectándose al RDS privado
Ahora que tenemos EC2 Instance Connect y la política de privilegios mínimos asociada al usuario de IAM, podemos probar la conexión.
Nos conectaremos con un cliente Postgres a partir de una imagen de contenedor de Postgres, siguiendo el enfoque Container DevOps.
Container DevOps ayuda a alcanzar confiabilidad, repetibilidad y seguridad:
- Confiabilidad gracias a una imagen de contenedor empaquetada con la versión de las herramientas, las dependencias y la configuración para asegurar consistencia.
- Repetibilidad al usar la misma imagen de contenedor en el pipeline de CICD, lo que permite reproducir el mismo error en el entorno de depuración de DevOps.
- Seguridad mediante el escaneo de seguridad de las imágenes de contenedor y el escaneo con SCAT de cualquier script de automatización antes de usarlos en el equipo de DevOps y en la automatización de CICD.
Conectarse al RDS mediante el EC2 Instance Connect Endpoint
- Usa el perfil de AWS del usuario de IAM al que se le asoció la política creada arriba.
- Ejecuta un cliente Postgres desde Docker para conectarte al RDS privado con el comando
docker run -it — rm — network=bridge postgres psql -h host.docker.internal -U <db user> - Ingresa la contraseña del
db user. - Si todo va bien, deberías ver el prompt de
postgres.
% docker run -it --rm --network=bridge postgres psql -h host.docker.internal -U postgresPassword for user postgres:psql (15.3 (Debian 15.3-1.pgdg120+1), server 14.7)SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, compression: off)Type "help" for help.
postgres=>Solución de problemas
InvalidParameter en awsec2-instance-connect open-tunnel
Me encontré con el siguiente error al ejecutar aws ec2-instance-connect open-tunnel:
% aws ec2-instance-connect open-tunnel --instance-connect-endpoint-id <EIC ID> --private-ip-address <RDS Endpoint DNS> --local-port 5432 --remote-port 5432Listening for connections on port 5432.
[1] Accepted new tcp connection, opening websocket tunnel.2023-06-20 23:32:09,666 - awscli.customizations.ec2instanceconnect.websocket - ERROR - {"ErrorCode":"InvalidParameter","Message":"The specified PrivateIpAddress is not valid. Specify a valid IPv4 PrivateIpAddress and retry your request."}
AWS_ERROR_HTTP_WEBSOCKET_UPGRADE_FAILURE: Failed to upgrade HTTP connection to Websocket.Este error se debe a que la implementación de WebSocket que usa AWS CLI requiere una IP privada. Resuelve el endpoint del RDS a su IP interna y pásala como parámetro de --private-ip-address en aws ec2-instance-connect open-tunnel.
EC2 Instance Connect es una forma muy mejorada de conectarse a recursos privados como RDS. Al ser un servicio administrado, aporta seguridad, ahorra dinero y reduce la carga de gestión.
Y lo más importante: ¡es fácil de usar!