Client VPN assegna un indirizzo al client, l'handshake si completa e la connessione continua a non andare da nessuna parte. Prima di toccare certificati o versioni del client, guarda la tabella delle rotte del punto di terminazione stesso. Un punto di terminazione AWS Client VPN inoltra un pacchetto solo quando una delle sue rotte copre il prefisso di destinazione; se nulla corrisponde, il pacchetto viene scartato al punto di terminazione e l'host di destinazione non vede mai un SYN.

È una decisione di inoltro, non di autenticazione. Avviene dopo che il tunnel è attivo e dopo che le regole di autorizzazione sono state valutate, ed è per questo che un certificato valido e un gruppo valido possono comunque produrre una connessione morta.

Il punto di terminazione inoltra solo ciò che copre la sua tabella delle rotte

Ogni rotta è un CIDR di destinazione più la sottorete che deve ricevere il traffico. Il punto di terminazione confronta la destinazione del client con quell'elenco, sceglie la voce corrispondente e invia il pacchetto nella sottorete associata. Nessuna voce significa nessun salto successivo.

Nota cosa non è la rotta. Non è una voce della tabella delle rotte della VPC e non autorizza nulla. Le regole di autorizzazione decidono se un gruppo può raggiungere una destinazione; le rotte decidono se il punto di terminazione ha un posto dove inviare il pacchetto. Entrambe devono concordare, e falliscono con sintomi diversi, quindi indovinare quale sia rotta fa perdere un pomeriggio.

Il disallineamento classico è una VPC con peering. Qualcuno aggiunge una rotta per 10.20.0.0/24 mentre l'host vive in 10.20.4.0/24, così l'indirizzo cade fuori da ogni voce. Una cattura lato client mostra SYN ripetuti senza risposta, e i log della destinazione non mostrano assolutamente nulla.

Leggi l'elenco delle rotte prima del certificato

Le rotte del punto di terminazione sono un oggetto a sé, quindi interrogale direttamente invece di leggere la tabella della VPC:

aws ec2 describe-client-vpn-routes --client-vpn-endpoint-id cvpn-endpoint-0123456789abcdef0 --query 'Routes[].{Dest:DestinationCidr,Target:TargetSubnet,Origin:Origin}'

Prendi l'indirizzo esatto e la lunghezza del prefisso dal client che fallisce, poi controlla la copertura carattere per carattere. Vale la corrispondenza del prefisso più lungo, quindi una rotta più ampia non ti salva quando una più stretta punta altrove.

Una risorsa per destinazione con for_each

I blocchi di rotte scritti a mano derivano nel momento in cui qualcuno aggiunge un prefisso nella console. Tieni le destinazioni in una mappa e crea una risorsa per chiave, così ogni aggiunta o rimozione resta isolata.

variable "client_vpn_routes" {
  type = map(string)
  default = {
    "10.20.0.0/16"  = "subnet-0aa11bb22cc33dd44"
    "172.31.0.0/20" = "subnet-0aa11bb22cc33dd44"
  }
}

resource "aws_ec2_client_vpn_route" "this" {
  for_each               = var.client_vpn_routes
  client_vpn_endpoint_id = var.client_vpn_endpoint_id
  destination_cidr_block = each.key
  target_vpc_subnet_id   = each.value
  depends_on             = [aws_ec2_client_vpn_network_association.this]
}

Mantieni la dipendenza dall'associazione di rete. Una rotta ha bisogno di una sottorete associata, quindi un apply che crea entrambe deve ordinare prima l'associazione, e senza quel riferimento Terraform è libero di provare prima la rotta. Poi leggi il piano: il numero di aggiunte di rotte deve corrispondere ai prefissi aggiunti. Se il piano sostituisce anche il punto di terminazione, la risorsa del punto di terminazione è scritta male, e applicarla disconnette ogni client connesso.

Adottare un punto di terminazione che non hai creato

La maggior parte dei team eredita un punto di terminazione costruito nella console, ed è per questo che non esiste codice delle rotte. Non alzare un secondo punto di terminazione solo per portare le rotte in Terraform.

Importa invece, oppure passa gli id come variabili e lascia gli oggetti ereditati non gestiti. L'import richiede il formato di identificatore che il provider documenta per ogni tipo di risorsa, che codifica il punto di terminazione, il prefisso di destinazione e la sottorete di destinazione. Copia quella stringa dalla documentazione della risorsa invece di comporla a memoria, esegui un piano e aspettati nessuna modifica prima di aggiungere qualcosa di nuovo.

Segui il pacchetto nell'ordine in cui viaggia

Quando la rotta esiste e la connessione fallisce ancora, percorri il cammino in ordine invece di indovinare al livello superiore.

  1. Rotta: un prefisso copre la destinazione e punta a una sottorete associata al punto di terminazione.
  2. Autorizzazione: una regola di autorizzazione consente quella destinazione per il gruppo dell'utente. Una rotta da sola non concede mai accesso.
  3. Percorso di ritorno: la tabella delle rotte della sottorete di destinazione rimanda le risposte verso il punto di terminazione, e il gruppo di sicurezza consente la porta dal pool di indirizzi del client.
  4. Applicazione: apri una vera connessione TCP dal client, poi conferma che i log della destinazione mostrano l'indirizzo di origine atteso dal pool.

Cambia un prefisso per apply, rileggi l'elenco delle rotte dopo, e annota insieme la destinazione, la regola che autorizza e il percorso di ritorno. La prossima persona che esegue il debug di una connessione rifiutata dovrebbe partire da quell'inventario, non da una teoria sui certificati.

Articoli correlati