Começar pela matriz de fluxos
Num projeto fictício de fundos, os ambientes Prod e Dev precisam de enviar ficheiros para Serviços, mas não de comunicar entre si. Antes de escolher o hub, escreve origem, destino, protocolo, porta, direção inicial, resposta e responsável. Acrescenta os fluxos que devem falhar. A matriz torna a palavra isolamento verificável e ajuda o negócio a identificar dependências omitidas. Um diagrama que só mostra três VPCs ligadas não revela quem pode iniciar ligações nem o efeito da próxima propagação automática de um prefixo.
Procurar exceções ao agregado
Uma migração altera o destino de 172.28.0.0/16 e mantém uma rota 172.28.40.0/24 para o caminho antigo. O batch em 172.28.40.8 continua dependente desse caminho. Seleciona primeiro o prefixo correspondente mais específico; compara prioridade estática e propagada apenas quando o destino é idêntico. Mantém IPv4 e IPv6 separados. No inventário, regista a associação real da tabela à subnet de origem, porque ler outra tabela pode produzir uma explicação convincente para uma configuração que o pacote nunca utiliza.
Separar associação de propagação
No TGW, a associação de um attachment determina a tabela consultada para tráfego que entra por ele. Propagar o CIDR de Prod para a tabela de Serviços permite que essa tabela conheça o destino Prod. Não significa que Prod passe a consultar a tabela de Serviços. Desenha duas setas de cores diferentes para estas relações. Um attachment pode propagar para várias tabelas, mas associa-se a uma. Rever ambas as relações evita abrir comunicação lateral quando a intenção era apenas permitir retorno de um serviço comum.
Percorrer pedido e resposta
Segue um pedido desde a subnet até ao attachment de destino e depois faz o percurso inverso. Uma rota para Serviços na tabela de Prod não cria automaticamente uma rota para Prod na tabela usada por Serviços. Confirma ainda se a zona de origem está habilitada no attachment VPC. Uma aplicação que funciona numa zona pode falhar noutra com tabelas aparentemente iguais. Regista estes pré-requisitos antes de aumentar permissões. Uma rota válida também não prova que o security group, a aplicação ou a autenticação permitam a utilização pretendida.
Exercício local com limites explícitos
Executa o modelo apresentado nesta aula com Python 3.13. O código usa apenas dados em memória e não configura AWS. Prevê o destino de três endereços antes de executar: um dentro da exceção /24, outro apenas no /16 e outro sem rota. Depois observa uma matriz sintética Prod, Dev e Serviços. Remove o retorno de Prod, volta a executar e explica a diferença. O modelo rejeita empates que não sabe resolver; não implementa rotas locais, prefix lists, BGP, filtros, appliances, DNS real ou testes de conectividade.
Decidir a aceitação e a retirada
Entrega ao RUN a matriz aprovada, as associações, a evidência dos caminhos permitidos e proibidos, o plano de reversão e as dependências ainda ativas. Num ensaio autorizado, testa os destinos reais do batch e cada zona prevista, com janela e critérios de paragem. Um resultado positivo isolado não autoriza retirar um caminho com exceções por validar. Se o tempo terminar, a decisão pode ser aceitação parcial com âmbito e risco explícitos. O exemplo é fictício: os controlos e responsáveis concretos devem seguir a governação da organização.
"""Selected in-memory reasoning fixtures. No AWS, DNS packets or network tests.
Run with Python 3.13: python3 run.py
Excludes VPC local routes, prefix lists, BGP, appliances, filters and DNS caches.
"""
import ipaddress
import json
def route(address, entries):
"""Entries are (canonical CIDR, target, static|propagated)."""
address = ipaddress.ip_address(address)
matches = []
for cidr, target, origin in entries:
network = ipaddress.ip_network(cidr, strict=True)
if origin not in ('static', 'propagated'):
raise ValueError('unsupported origin')
if address.version == network.version and address in network:
matches.append((network.prefixlen, origin == 'static', target))
if not matches:
return None
priority = max((n, static) for n, static, _ in matches)
winners = [target for n, static, target in matches if (n, static) == priority]
if len(winners) != 1:
raise ValueError('unsupported equal-priority tie')
return winners[0]
def dns_view(name, zones, rules):
"""Select only a suffix and authority; absence is a fixture label, not a DNS RCODE engine.
zones maps suffix -> exact names. rules is a list of forwarding suffixes.
Excludes wildcards, delegation, DNS record types, aliases and caching.
"""
name = name.lower().rstrip('.')
candidates = []
for kind, suffixes in [('zone', zones), ('forward', rules)]:
for suffix in suffixes:
suffix = suffix.lower().rstrip('.')
if name == suffix or name.endswith('.' + suffix):
candidates.append((len(suffix.split('.')), kind == 'forward', suffix, kind))
if not candidates:
return {'kind': 'public-lookup-not-executed'}
_, _, suffix, kind = max(candidates)
if kind == 'forward':
return {'kind': 'forward', 'suffix': suffix}
present = name in [n.lower().rstrip('.') for n in zones[suffix]]
return {'kind': 'zone', 'suffix': suffix, 'namePresent': present}
def run():
checks = []
def check(name, actual, expected):
if actual != expected:
raise AssertionError((name, actual, expected))
checks.append({'name': name, 'actual': actual, 'expected': expected, 'passed': True})
entries = [('172.28.0.0/16', 'new', 'static'), ('172.28.40.0/24', 'old', 'static')]
check('specific exception', route('172.28.40.8', entries), 'old')
check('aggregate destination', route('172.28.10.8', entries), 'new')
check('no route', route('192.0.2.1', entries), None)
check('identical CIDR priority', route('172.22.1.4', [('172.22.0.0/16','vpn','propagated'),('172.22.0.0/16','peer','static')]), 'peer')
check('specific propagated beats broad static', route('172.22.1.4', [('172.22.0.0/16','peer','static'),('172.22.1.0/24','vpn','propagated')]), 'vpn')
check('family separation', route('2001:db8::1', [('0.0.0.0/0','ipv4','static')]), None)
check('IPv6 specific match', route('2001:db8:1::8', [('::/0','default','static'),('2001:db8:1::/48','private','static')]), 'private')
check('specific blackhole', route('10.90.7.20', [('10.90.0.0/16','services','static'),('10.90.7.0/24','DROP','static')]), 'DROP')
tables = {'prod': {'services'}, 'dev': {'services'}, 'services': {'prod','dev'}}
check('forward and return', 'services' in tables['prod'] and 'prod' in tables['services'], True)
check('lateral path absent', 'dev' in tables['prod'] or 'prod' in tables['dev'], False)
tables['services'].remove('prod')
check('broken return', 'services' in tables['prod'] and 'prod' in tables['services'], False)
zones = {'example.com': ['api.apps.example.com'], 'apps.example.com': []}
check('more specific private view', dns_view('api.apps.example.com', zones, []), {'kind':'zone','suffix':'apps.example.com','namePresent':False})
check('missing name stays private', dns_view('portal.example.com', zones, []), {'kind':'zone','suffix':'example.com','namePresent':False})
check('same suffix forwarding', dns_view('api.apps.example.com', zones, ['apps.example.com']), {'kind':'forward','suffix':'apps.example.com'})
check('most specific forwarding', dns_view('api.payroll.example.com', {}, ['example.com','payroll.example.com']), {'kind':'forward','suffix':'payroll.example.com'})
check('label boundary', dns_view('notexample.com', zones, []), {'kind':'public-lookup-not-executed'})
check('case and final dot', dns_view('API.APPS.EXAMPLE.COM.', zones, []), {'kind':'zone','suffix':'apps.example.com','namePresent':False})
try:
route('10.1.0.1', [('10.1.0.0/16','a','static'),('10.1.0.0/16','b','static')])
except ValueError:
check('ambiguous tie rejected', True, True)
else:
raise AssertionError('ambiguous tie accepted')
return {'scope':'In-memory fixtures only; no AWS resources or network traffic.', 'checks':checks, 'passed':len(checks)}
if __name__ == '__main__':
print(json.dumps(run(), indent=2))
Prod alcança Serviços, mas Serviços não conhece Prod. O timeout não se resolve repetindo a rota de ida.
Armadilhas comuns
Confundir propagação com associação; esquecer o retorno; testar só um endereço do agregado; contar attachments como prova de isolamento.
Tópicos relacionados: Redes, endpoints e conectividade híbrida · Resiliência, capacidade e recuperação · Acesso privado e arranque sem dependências escondidas
Uma ligação só está aceite quando a evidência cobre o fluxo aprovado, as exceções e as fronteiras que devem permanecer fechadas.
Referência: How Transit Gateway works · SAA-C03