Pular para o conteúdo principal

Fixando seus IPs

Toda credencial carrega uma lista de endereços dos quais suas requisições podem vir. Uma requisição é aceita só se a assinatura for válida e ela chegar de um desses endereços.

accept = valid_signature(credential) AND source_ip ∈ allowed_ips

A lista é obrigatória: não emitimos credencial sem restrição de origem.

Por que a lista existe, se a requisição já é assinada​

A maioria dos incidentes não envolve assinatura quebrada. Envolve uma chave privada que saiu de onde deveria ficar: um repositório commitado, um arquivo compartilhado, a máquina de um desenvolvedor, uma ferramenta de terceiro. Uma vez fora, a chave produz assinatura válida de qualquer lugar, e o tráfego fica idêntico ao da sua integração real.

A lista tira isso. Uma chave copiada para fora do seu ambiente para de funcionar, porque quem a tem não reproduz junto a sua origem de rede. Ela não substitui a assinatura: a assinatura prova quem produziu a requisição, a lista limita de onde ela pode vir.

É uma segunda camada, não um motivo para afrouxar o cuidado com a chave. Mantenha a privada em HSM ou cofre, use uma credencial por ambiente e por workload, e lembre que tudo que roda dentro do seu perímetro permitido herda essa confiança.

As regras​

RegraValor
Entradas por credencial1 a 50
Formato aceitoEndereços IPv4 públicos individuais (203.0.113.10)
Faixas (CIDR)Não aceitas
IPv6Ainda não suportado
DuplicadosColapsados
OrdemCanônica. A ordem que você envia não muda a credencial
EscopoPor credencial e por ambiente; sandbox e produção são independentes

Faixa é recusada de propósito: com CIDR livre, 0.0.0.0/0 seria uma entrada válida e uma lista obrigatória não restringiria nada. Registre cada endereço de saída explicitamente. O teto de 50 cobre com folga várias regiões, caminhos de failover e workloads separados.

Contra o que a lista é comparada​

O endereço do peer que chega até nós, ou seja, de onde suas requisições saem. Não o seu load balancer, não o seu hostname público, não o navegador de onde você está configurando. Endereço de entrada e de saída são coisas diferentes e quase nunca são o mesmo valor.

Esta seção é sobre o tráfego de você para nós. Os endereços que usamos ao chamar os seus webhooks são a direção oposta e se configuram no seu próprio firewall.

Descubra seu endereço de saída real​

Rode isto de dentro do workload que vai chamar a API, pelo mesmo caminho de rede que ele usa em produção, e não do seu laptop:

curl --fail --silent https://ifconfig.me

Repita em cada instância, task ou função que nos chama. Um endereço que muda entre execuções não é fixo, mesmo que as duas primeiras execuções concordem.

Mudando a lista depois​

Editar os IPs permitidos substitui a credencial por uma nova versão assinada, que mantém a mesma chave e o mesmo client_id, então sua aplicação não muda. A versão anterior deixa de ser aceita naquele momento, inclusive os tokens já emitidos por ela, então uma chamada em curso pode falhar uma vez e se recuperar no token seguinte.

Registre o endereço novo antes de mandar tráfego por ele, e remova o antigo só depois de confirmar o caminho novo. Entradas sobrepostas não custam nada e evitam uma indisponibilidade que você mesmo causou.

Uma requisição recusada​

Uma requisição corretamente assinada, vinda de um endereço fora da lista, é recusada com 403 e IP_NOT_ALLOWED, antes de chegar ao recurso.

A lista só é avaliada depois que a assinatura confere. Uma requisição com assinatura inválida é recusada como falha de autenticação, e nunca revela se o endereço dela seria permitido.

IP de saída fixo por provedor​

O padrão é o mesmo em todo provedor: coloque o workload numa sub-rede privada, sem endereço público próprio, e roteie a saída dele por um componente NAT gerenciado que tenha um endereço público reservado. Esse endereço é o que você registra.

ProvedorComponenteEndereço a reservar
AWSNAT GatewayElastic IP
AzureNAT GatewayIP público estático (SKU Standard)
Google CloudCloud NAT + Cloud RouterIP externo regional reservado
Oracle CloudNAT GatewayIP público reservado

Runtimes serverless e de container gerenciado saem por pools do provedor por padrão, então o endereço de saída deles não é estável. A maioria pode ser anexada à sua VPC ou VNet, e aí passa a seguir o caminho de NAT acima.

# Pré-requisitos: uma VPC com sub-rede pública roteada para um Internet Gateway,
# e o workload numa sub-rede privada, sem IP público próprio.

export AWS_REGION=<region>

# 1. reserve the address — note AllocationId and PublicIp
aws ec2 allocate-address --domain vpc

# 2. create the NAT Gateway in the PUBLIC subnet, using that address
aws ec2 create-nat-gateway \
--subnet-id <public-subnet-id> \
--allocation-id <allocation-id>

aws ec2 wait nat-gateway-available --nat-gateway-ids <nat-gateway-id>

# 3. send the private subnet's outbound traffic through it
# (use replace-route if a 0.0.0.0/0 route already exists)
aws ec2 create-route \
--route-table-id <private-route-table-id> \
--destination-cidr-block 0.0.0.0/0 \
--nat-gateway-id <nat-gateway-id>

# 4. confirm the reserved address...
aws ec2 describe-addresses --allocation-ids <allocation-id> \
--query 'Addresses[0].PublicIp' --output text

# 5. ...and that the workload actually egresses through it
curl --fail --silent https://ifconfig.me
Duas conferências, não uma

Ler o endereço no provedor só prova que ele está reservado. Só o curl de dentro do workload prova que o seu tráfego realmente sai por ele. Os dois têm que devolver o mesmo IPv4.

Quando você não tem endereço fixo​

Plataformas sem anexação a VPC, runtimes de terceiros cuja rede você não controla, ou links com endereçamento dinâmico: canalize só o tráfego destinado à nossa API por um único ponto fixo que seja seu: uma instância pequena com endereço público reservado, numa rede que você controla.

your workload (rotating address)
│
▼
egress proxy (fixed address — the one you register)
│
▼
LB Pay API

Quatro requisitos:

  1. Continue assinando na sua aplicação. O proxy encaminha tráfego; ele nunca deve guardar sua chave privada nem reassinar nada.
  2. Não termine TLS sem um motivo específico. Encaminhar a conexão cifrada mantém o proxy fora do escopo do conteúdo das requisições, e um proxy que altera a requisição quebra a assinatura.
  3. Restrinja quem pode usá-lo. Do nosso lado o proxy é uma origem confiável, então ele deve aceitar conexões só dos seus workloads e encaminhar só para a nossa API.
  4. Faça-o redundante. Um proxy só é ponto único de falha para toda integração atrás dele. Duas instâncias, cada uma com seu endereço reservado, ambas registradas.
# TCP passthrough — forwards the encrypted stream untouched.
stream {
resolver 1.1.1.1;

server {
listen 443;
ssl_preread on;
proxy_pass api.sdb.lbpay.com.br:443;
}
}

Nem todo runtime respeita HTTPS_PROXY automaticamente. Alguns exigem o proxy configurado explicitamente no cliente HTTP. Confirme com a conferência de saída, rodada pelo mesmo cliente que a sua integração usa.

Diagnóstico​

Quase toda falha tem a mesma causa raiz: o endereço de onde você acha que sai não é o endereço que nós vemos.

SintomaCausa provávelO que fazer
IP_NOT_ALLOWED logo após registrarVocê registrou um endereço de entrada: load balancer, CDN, hostname ou o seu próprio navegadorRode a conferência de saída de dentro do workload e compare
IP_NOT_ALLOWED só em algumas requisiçõesO workload sai por um pool rotativo do provedorRoteie a saída por um NAT gateway na sua VPC, ou por um proxy dedicado
A aplicação funciona, o job em lote falhaO segundo workload roda em outra sub-rede ou conta, com saída própriaRegistre o endereço de saída de cada chamador na mesma credencial
Falhas só durante failover regionalA região de failover sai por um endereço que nunca foi registradoRegistre os endereços de failover antes, não durante o incidente
Erros de assinatura depois de introduzir um proxyO proxy termina TLS e altera a requisiçãoEncaminhe a conexão intacta; nunca reassine no proxy
O endereço mudou sozinhoEle era efêmero, não reservadoReserve o endereço explicitamente e prenda o componente NAT a ele

Antes de ir para produção​

  1. Mapeie todo sistema que nos chama, inclusive jobs em lote, ferramentas internas e terceiros agindo em seu nome.
  2. Descubra o endereço de saída real de cada um, de dentro do workload.
  3. Dê um caminho de saída fixo a tudo que não tiver um.
  4. Registre todos os endereços resultantes, failover incluído.
  5. Faça no sandbox primeiro, confirme que a integração continua funcionando, depois repita em produção.