
Conectar-se a recursos privados da AWS, como rodar comandos psql em um banco Postgres RDS, normalmente é feito via bastion host. Mas bastion hosts podem sair caro e dar trabalho para gerenciar. Vou mostrar como fazer isso de forma econômica, prática e segura com o Amazon EC2 Instance Connect.
As boas práticas de segurança da AWS recomendam que o banco de dados fique acessível apenas em uma faixa de IPs privados, garantindo o isolamento de rede. Em outras palavras, a recomendação é hospedar bancos como o RDS em uma sub-rede privada.
Uma das formas de acessar recursos privados é por um bastion host.
Só que bastion hosts também geram custo: costumam ficar no ar 24x7 só para fornecer acesso esporádico e ainda exigem o trabalho de gerenciar uma instância dedicada — patches de segurança periódicos, regras de exceção no firewall de rede e por aí vai. Bastion hosts mal gerenciados podem aumentar a superfície de ataque do seu sistema. Um exemplo é a ameaça de uma chave SSH de longa duração, compartilhada previamente com um parceiro de negócios para acessar o bastion host.
O novo recurso do Amazon EC2 Instance Connect Endpoint, anunciado em 13/06/2023, oferece um mecanismo adicional para acessar workloads em uma sub-rede privada sem precisar manter um bastion host.
Sumário
· Criar um Security Group para o EC2 Instance Connect Endpoint
· Criar o EC2 Instance Connect Endpoint
· Configurar a policy do IAM para a conexão
· Container DevOps conectando ao RDS privado
· Conectar ao RDS via EC2 Instance Connect Endpoint
· InvalidParameter no aws ec2-instance-connect open-tunnel
Visão geral

Arquitetura geral do EC2 Instance Connect conectando-se ao RDS em uma sub-rede privada
- Os usuários se conectam pela internet ao serviço EC2 Instance Connect Endpoint via AWS CLI com
aws ec2-instance-connect open-tunnel; - As conexões EIC ficam sujeitas às permissões do IAM e, opcionalmente, a logs;
- As conexões originadas no EC2 Instance Connect Endpoint precisam ser liberadas como inbound pelo Security Group da workload;
- O EC2 Instance Connect Endpoint se conecta ao RDS por IPs privados.
Passo a passo
Pré-requisitos
- Para demonstrar a conectividade sem internet, confirme que a route table da sub-rede do RDS não tem rota para um Internet Gateway.
- Anote o Security Group do RDS, por exemplo,
sg-012345. - Anote a VPC do RDS, por exemplo,
vpc-012345.
Vamos criar o EC2 Instance Connect Endpoint na mesma VPC, conforme o diagrama acima. 4. Anote as sub-redes privadas em que o RDS está hospedado, por exemplo, subnet-0abc101 e subnet-0abc102.
Vamos criar o EC2 Instance Connect Endpoint em uma dessas sub-redes. 5. Anote os IPs privados do RDS, por exemplo, 10.0.128.61
Vamos nos conectar pela internet ao EC2 Instance Connect via AWS CLI e, até a versão 2.12.1 do AWS CLI, o open-tunnel aceita apenas endereços IP para abrir o túnel.
O IP privado da instância do RDS pode ser encontrado em "Network interfaces" no EC2 Dashboard, filtrando por "Description=RDSNetworkInterface".
Se aparecerem várias entradas, refine o filtro pela VPC.
Selecione a Network Interface correspondente; o endereço IPv4 privado fica no painel "IP addresses".

Procure o IP privado do RDSNetworkInterface
De posse das informações dos recursos privados da AWS aos quais queremos nos conectar pelo EC2 Instance Connect Endpoint, vamos criar primeiro um Security Group para o EC2 Instance Connect Endpoint e, em seguida, o próprio EC2 Instance Connect Endpoint.
Criar um Security Group para o EC2 Instance Connect Endpoint
Vamos criar um Security Group dedicado para o EC2 Instance Connect Endpoint. Esse Security Group não terá regras de inbound, apenas uma regra de outbound para conectar ao RDS marcado com o Security Group do RDS.
- Acesse "Create security group" no console do EC2 por este link https://console.aws.amazon.com/ec2/v2/home#CreateSecurityGroup.
- Informe um "Security group name" e uma "Description" descritivos.
- Selecione a VPC do RDS. Neste exemplo, será
vpc-012345. - Deixe as "Inbound rules" vazias.
- Em "Outbound rules", configure uma regra de outbound assim:
a. Type: Custom TCP
b. Port range: porta de conectividade do RDS, como 5432 para PostgreSQL
c. Destination: selecione o Security Group do RDS. Neste exemplo, é sg-012345
d. Description: conexão de saída do EC2 Instance Connect Endpoint para o RDS
- Clique em "Create Security Group" no canto inferior direito da página.
- Um Security Group dedicado será criado, por exemplo,
sg-0abcde.

Crie um novo Security Group para o EC2 Instance Connect Endpoint
Criar o EC2 Instance Connect Endpoint
- Acesse a página "Create endpoint" da VPC por este link https://console.aws.amazon.com/vpc/home#CreateVpcEndpoint
- Informe um Endpoint name descritivo.
- Em Service Category, selecione "EC2 Instance Connect Endpoint".
- Na lista de VPCs, selecione a VPC do RDS. Neste exemplo, selecione
vpc-012345. - Em "Security groups", selecione o Security Group criado para o EC2 Instance Connect Endpoint. Neste exemplo, é
sg-0abcde. - Selecione uma das sub-redes em que o RDS está hospedado. Neste exemplo, será
subnet-0abc101ousubnet-0abc102. - Clique em "Create endpoint".

Crie o EC2 Instance Connect Endpoint usando o Security Group do EC2 Instance Connect Endpoint
Configurar a policy do IAM para a conexão
Com o EC2 Instance Connect Endpoint criado e a conectividade estabelecida pelos Security Groups, vamos criar o usuário IAM com o mínimo de privilégios para usar a conexão.
- Acesse "Create Policy" no console do IAM por este link https://console.aws.amazon.com/iamv2/home#/policies/create?step=addPermissions
- Mude para o JSON Policy Editor e cole a policy abaixo. Substitua o Resource do EC2 Instance Connect Endpoint pelo ARN correspondente e troque as variáveis entre colchetes angulares pelos valores do seu ambiente:
{ "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 conectando ao RDS privado
Agora que temos o EC2 Instance Connect e a policy de menor privilégio associada ao usuário IAM, podemos testar a conexão.
Vamos nos conectar usando um cliente Postgres a partir de uma imagem de container Postgres, seguindo a abordagem de Container DevOps.
O Container DevOps ajuda a alcançar confiabilidade, repetibilidade e segurança:
- Confiabilidade com a imagem de container empacotada com a versão das ferramentas, dependências e configurações para garantir consistência.
- Repetibilidade ao usar a mesma imagem de container no pipeline de CICD, podendo reproduzir o mesmo erro no ambiente de debug do DevOps.
- Segurança ao realizar varredura de segurança da imagem de container e analisar todos os scripts de automação com SCAT antes de utilizá-los pelo time de DevOps e nas automações de CICD.
Conectar ao RDS via EC2 Instance Connect Endpoint
- Use o profile da AWS do usuário IAM associado à policy criada acima.
- Execute um cliente Postgres a partir do Docker para conectar ao RDS privado com o comando
docker run -it — rm — network=bridge postgres psql -h host.docker.internal -U <db user> - Informe a senha do
db user. - Se tudo der certo, você verá o prompt do
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=>Troubleshooting
InvalidParameter no aws ec2-instance-connect open-tunnel
Me deparei com o erro abaixo ao executar 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.Esse erro ocorre porque a implementação de WebSocket usada pelo AWS CLI exige um IP privado. Resolva o endpoint do RDS para o IP interno e use-o como parâmetro do --private-ip-address no aws ec2-instance-connect open-tunnel.
O EC2 Instance Connect é uma forma muito mais eficiente de se conectar a recursos privados como o RDS. Por ser um serviço gerenciado, ele aumenta a segurança, reduz custos e diminui o trabalho de gerenciamento.
E o melhor: é fácil de usar!