O Client VPN entrega um endereço ao cliente, o handshake termina, e a conexão continua sem ir a lugar algum. Antes de mexer em certificados ou versões de cliente, olhe para a tabela de rotas do próprio endpoint. Um endpoint do AWS Client VPN só encaminha um pacote quando uma das suas rotas cobre o prefixo de destino; se nada corresponder, o pacote é descartado no endpoint e o host de destino nunca vê um SYN.

Essa é uma decisão de encaminhamento, não de autenticação. Ela acontece depois que o túnel está de pé e depois que as regras de autorização são avaliadas, por isso um certificado válido e um grupo válido ainda podem produzir uma conexão morta.

O endpoint só encaminha o que a sua tabela de rotas cobre

Cada rota é um CIDR de destino mais a sub-rede que deve receber o tráfego. O endpoint compara o destino do cliente com essa lista, escolhe a entrada correspondente e envia o pacote para a sub-rede associada. Sem entrada não há próximo salto.

Repare no que a rota não é. Ela não é uma entrada da tabela de rotas da VPC e não autoriza nada. As regras de autorização decidem se um grupo pode alcançar um destino; as rotas decidem se o endpoint tem onde enviar o pacote. As duas precisam concordar, e elas falham com sintomas diferentes, então adivinhar qual está quebrada desperdiça uma tarde.

A incompatibilidade clássica é uma VPC com peering. Alguém adiciona uma rota para 10.20.0.0/24 enquanto o host vive em 10.20.4.0/24, então o endereço fica fora de todas as entradas. Uma captura no lado do cliente mostra SYN repetidos sem resposta, e os logs do destino não mostram absolutamente nada.

Leia a lista de rotas antes do certificado

As rotas do endpoint são um objeto próprio, então consulte-as diretamente em vez de ler a tabela da VPC:

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

Pegue o endereço exato e o comprimento do prefixo do cliente que falha, e depois confira a cobertura caractere por caractere. Vale a correspondência do prefixo mais longo, então uma rota mais ampla não salva você quando uma mais estreita aponta para outro lugar.

Um recurso por destino com for_each

Blocos de rotas escritos à mão saem do lugar no momento em que alguém adiciona um prefixo no console. Mantenha os destinos em um mapa e crie um recurso por chave, para que cada adição ou remoção fique isolada.

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]
}

Mantenha a dependência da associação de rede. Uma rota precisa de uma sub-rede associada, então um apply que cria as duas coisas deve ordenar a associação primeiro, e sem essa referência o Terraform fica livre para tentar a rota primeiro. Depois leia o plano: o número de adições de rotas deve corresponder aos prefixos que você adicionou. Se o plano também substitui o endpoint, o recurso do endpoint está escrito errado, e aplicá-lo desconecta todos os clientes conectados.

Adotar um endpoint que você não criou

A maioria das equipes herda um endpoint construído no console, e por isso não existe código de rotas. Não levante um segundo endpoint só para trazer rotas para o Terraform.

Importe em vez disso, ou passe os ids como variáveis e deixe os objetos herdados sem gestão. A importação exige o formato de identificador que o provedor documenta para cada tipo de recurso, que codifica o endpoint, o prefixo de destino e a sub-rede de destino. Copie essa string da documentação do recurso em vez de compô-la de memória, execute um plano e espere que não haja mudanças antes de adicionar algo novo.

Siga o pacote na ordem em que ele viaja

Quando a rota existe e a conexão ainda falha, percorra o caminho em ordem em vez de adivinhar na camada superior.

  1. Rota: um prefixo cobre o destino e aponta para uma sub-rede associada ao endpoint.
  2. Autorização: uma regra de autorização permite esse destino para o grupo do usuário. Uma rota sozinha nunca concede acesso.
  3. Caminho de volta: a tabela de rotas da sub-rede de destino envia as respostas de volta para o endpoint, e o grupo de segurança permite a porta a partir do pool de endereços do cliente.
  4. Aplicação: abra uma conexão TCP real a partir do cliente, e depois confirme que os logs do destino mostram o endereço de origem esperado do pool.

Mude um prefixo por apply, releia a lista de rotas depois, e registre o destino, a regra que autoriza e o caminho de volta juntos. A próxima pessoa a depurar uma conexão recusada deve começar por esse inventário, não por uma teoria sobre certificados.

Artigos relacionados