
Per connettersi a risorse AWS private, ad esempio per lanciare comandi psql su un database Postgres RDS, di solito si ricorre a un bastion host. Ma i bastion host possono essere costosi e difficili da gestire. Le mostro come farlo in modo economico, pratico e sicuro con Amazon EC2 Instance Connect.
Le best practice di sicurezza AWS raccomandano di rendere il database accessibile solo su un intervallo di indirizzi IP privati, così da garantire l'isolamento di rete. In altre parole, è buona prassi ospitare il database, ad esempio un'istanza RDS, in una subnet privata.
Un modo per accedere alle risorse private è proprio tramite bastion host.
I bastion host, però, hanno un costo: spesso restano attivi 24x7 solo per consentire accessi sporadici e portano con sé l'onere di gestire un'istanza dedicata, tra patch di sicurezza periodiche e regole di eccezione nel firewall di rete. Un bastion host gestito male può addirittura ampliare la superficie di attacco del sistema: si pensi al rischio di cybersecurity legato a una chiave SSH a lunga scadenza condivisa in anticipo con un partner per accedere al bastion stesso.
La nuova funzionalità Amazon EC2 Instance Connect Endpoint, annunciata il 13 giugno 2023, offre un meccanismo aggiuntivo per accedere ai workloads in una subnet privata senza dover mantenere un bastion host.
Indice dei contenuti
· Creare un Security Group per l'EC2 Instance Connect Endpoint
· Creare l'EC2 Instance Connect Endpoint
· Configurare la policy IAM per la connessione
· Container DevOps per connettersi all'RDS privato
· Connettersi all'RDS tramite EC2 Instance Connect Endpoint
· InvalidParameter da aws ec2-instance-connect open-tunnel
Panoramica

Architettura complessiva di EC2 Instance Connect che si collega a un RDS in una subnet privata
- Gli utenti si connettono da Internet al servizio EC2 Instance Connect Endpoint usando AWS CLI con
aws ec2-instance-connect open-tunnel; - Le connessioni EIC sono soggette ai permessi IAM e, in opzione, al logging;
- Le connessioni provenienti dall'EC2 Instance Connect Endpoint devono essere ammesse in ingresso dal Security Group del workload;
- L'EC2 Instance Connect Endpoint si collega all'RDS tramite IP privati.
Procedura passo passo
Prerequisiti
- Per dimostrare che la connettività funziona senza passare da Internet, verificare che la route table della subnet dell'RDS non contenga una route verso un Internet Gateway.
- Annotare il Security Group dell'RDS, ad esempio
sg-012345. - Annotare la VPC dell'RDS, ad esempio
vpc-012345.
Creeremo l'EC2 Instance Connect Endpoint nella stessa VPC, come illustrato nel diagramma in alto. 4. Annotare le subnet private in cui è ospitato l'RDS, ad esempio subnet-0abc101 e subnet-0abc102.
Creeremo l'EC2 Instance Connect Endpoint in una di queste subnet. 5. Annotare gli IP privati dell'RDS, ad esempio 10.0.128.61
Ci collegheremo da Internet all'EC2 Instance Connect tramite AWS CLI; nella versione 2.12.1 di AWS CLI, open-tunnel accetta solo indirizzi IP per aprire un tunnel.
L'IP privato dell'istanza RDS si trova in "Network interfaces" nel Dashboard EC2, filtrando per "Description=RDSNetworkInterface".
Se i risultati restituiscono più voci, restringere la ricerca filtrando per VPC.
Selezionare la Network Interface di interesse: l'indirizzo IPv4 privato è riportato nel pannello "IP addresses".

Ricerca dell'IP privato di RDSNetworkInterface
Raccolte le informazioni sulle risorse AWS private a cui vogliamo connetterci tramite l'EC2 Instance Connect Endpoint, creeremo prima un Security Group dedicato e poi l'EC2 Instance Connect Endpoint vero e proprio.
Creare un Security Group per l'EC2 Instance Connect Endpoint
Creeremo un Security Group dedicato per l'EC2 Instance Connect Endpoint, senza regole in ingresso e con un'unica regola in uscita per raggiungere l'RDS, identificato tramite il proprio Security Group.
- Aprire "Create security group" nella console EC2 a questo link https://console.aws.amazon.com/ec2/v2/home#CreateSecurityGroup.
- Inserire un "Security group name" e una "Description" significativi.
- Selezionare la VPC dell'RDS. In questo esempio è
vpc-012345. - Lasciare vuote le "Inbound rules".
- In "Outbound rules", configurare una regola in uscita con i seguenti parametri:
a. Type: Custom TCP
b. Port range: porta di connettività dell'RDS, ad esempio 5432 per Postgresql
c. Destination: selezionare il Security Group dell'RDS. In questo esempio è sg-012345.
d. Description: Outbound connection from EC2 Instance Connect Endpoint to RDS
- Selezionare "Create Security Group" in basso a destra.
- Verrà creato un Security Group dedicato, ad esempio
sg-0abcde.

Creazione di un nuovo Security Group per l'EC2 Instance Connect Endpoint
Creare l'EC2 Instance Connect Endpoint
- Aprire la pagina Create endpoint nella VPC a questo link https://console.aws.amazon.com/vpc/home#CreateVpcEndpoint
- Inserire un nome significativo per l'Endpoint
- In Service Category selezionare "EC2 Instance Connect Endpoint"
- Nella lista VPC selezionare la VPC dell'RDS. In questo esempio:
vpc-012345 - In "Security groups" selezionare il Security Group creato per l'EC2 Instance Connect Endpoint. In questo esempio:
sg-0abcde - Selezionare una delle subnet che ospitano l'RDS. In questo esempio:
subnet-0abc101osubnet-0abc102 - Selezionare "Create endpoint"

Creare l'EC2 Instance Connect Endpoint utilizzando il relativo Security Group
Configurare la policy IAM per la connessione
Creato l'EC2 Instance Connect Endpoint e impostata la connettività tramite Security Group, passiamo a creare l'utente IAM con il minimo privilegio necessario per utilizzare la connessione.
- Aprire Create Policy nella console IAM a questo link https://console.aws.amazon.com/iamv2/home#/policies/create?step=addPermissions
- Passare al JSON Policy Editor e incollare la policy seguente. Sostituire la Resource dell'EC2 Instance Connect Endpoint con l'ARN corrispondente e le variabili tra parentesi angolari con i valori del proprio 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 per connettersi all'RDS privato
Ora che abbiamo l'EC2 Instance Connect e una policy a privilegi minimi associata all'utente IAM, possiamo testare la connessione.
Ci collegheremo con un client Postgres a partire da una container image Postgres, seguendo l'approccio Container DevOps.
Un approccio Container DevOps consente di ottenere affidabilità, ripetibilità e sicurezza:
- Affidabilità: la container image racchiude versione degli strumenti, dipendenze e configurazioni, garantendo coerenza.
- Ripetibilità: la stessa container image viene utilizzata nella pipeline CICD e l'eventuale errore può essere riprodotto fedelmente nell'ambiente di debug DevOps.
- Sicurezza: la container image viene sottoposta a security scanning e gli script di automazione vengono analizzati con SCAT prima di essere distribuiti al team DevOps e usati nell'automazione CICD.
Connettersi all'RDS tramite EC2 Instance Connect Endpoint
- Utilizzare il profilo AWS dell'utente IAM associato alla policy creata in precedenza
- Avviare un client Postgres da Docker per collegarsi all'RDS privato con il comando
docker run -it — rm — network=bridge postgres psql -h host.docker.internal -U <db user> - Inserire la password del
db user - Se tutto funziona correttamente, comparirà il prompt
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 da aws ec2-instance-connect open-tunnel
Eseguendo aws ec2-instance-connect open-tunnel ho riscontrato il seguente errore:
% 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.L'errore dipende dall'implementazione del WebSocket di AWS CLI, che richiede un IP privato. Risolvere l'Endpoint dell'RDS al suo IP interno e passarlo come parametro --private-ip-address di aws ec2-instance-connect open-tunnel.
EC2 Instance Connect è un modo decisamente più efficace per collegarsi a risorse private come RDS. Trattandosi di un servizio gestito, alza il livello di sicurezza, riduce i costi e abbatte gli oneri di gestione.
E, soprattutto, è davvero semplice da usare!