Cloud Intelligence™Cloud Intelligence™

Cloud Intelligence™

Acesso seguro ao RDS privado com Amazon EC2 Instance Connect Endpoint

By Richard KangJun 29, 20237 min read

Esta página também está disponível em English, Deutsch, Español, Français, Italiano e 日本語.

aws security best practices

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

· Sumário

· Visão geral

· Passo a passo

· Pré-requisitos

· 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

· Troubleshooting

· InvalidParameter no aws ec2-instance-connect open-tunnel

· Conclusão

Visão geral

aws security best practices

Arquitetura geral do EC2 Instance Connect conectando-se ao RDS em uma sub-rede privada

  1. Os usuários se conectam pela internet ao serviço EC2 Instance Connect Endpoint via AWS CLI com aws ec2-instance-connect open-tunnel;
  2. As conexões EIC ficam sujeitas às permissões do IAM e, opcionalmente, a logs;
  3. As conexões originadas no EC2 Instance Connect Endpoint precisam ser liberadas como inbound pelo Security Group da workload;
  4. O EC2 Instance Connect Endpoint se conecta ao RDS por IPs privados.

Passo a passo

Pré-requisitos

  1. Para demonstrar a conectividade sem internet, confirme que a route table da sub-rede do RDS não tem rota para um Internet Gateway.
  2. Anote o Security Group do RDS, por exemplo, sg-012345.
  3. 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".

ec2 security group

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.

"ec2-instance-connect"

Crie um novo Security Group para o EC2 Instance Connect Endpoint

Criar o EC2 Instance Connect Endpoint

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

"aws

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.

  1. Acesse "Create Policy" no console do IAM por este link https://console.aws.amazon.com/iamv2/home#/policies/create?step=addPermissions
  2. 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

  1. Use o profile da AWS do usuário IAM associado à policy criada acima.
  2. 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>
  3. Informe a senha do db user.
  4. Se tudo der certo, você verá o prompt do postgres.
% docker run -it --rm --network=bridge postgres psql -h host.docker.internal -U postgres
Password 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 5432
Listening 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!