# Blocos Match da configuração SSH e aprovação do agente

Uma aprovação SSH só tem significado quando a conexão aprovada é a mesma que o SSH fará. Isso parece óbvio até que um agente execute `ssh prod`, um alias selecione outro `HostName`, um bloco `Match` altere o usuário remoto e o `ProxyJump` envie a sessão por um bastion que ninguém mencionou na solicitação.

A maioria dos erros de configuração SSH é contornável quando alguém acompanha o terminal. A pessoa vê um aviso inesperado sobre a chave do host, percebe `root@...` ou se lembra de que `prod` significa outra coisa na rede do escritório. Um agente autônomo não tem esse tipo de desconfiança. Ele usa o alias recebido e segue a configuração exatamente.

Por isso, os blocos `Match` da configuração SSH merecem uma revisão de segurança antes que um agente receba acesso SSH. A ideia não é proibir aliases, bastions ou configurações condicionais. O objetivo é fazer com que a ação solicitada, a configuração SSH efetiva e a conexão aprovada por uma pessoa descrevam a mesma coisa.

## Um alias de host é uma entrada, não uma identidade

`ssh app-prod` não informa onde o SSH vai se conectar, qual conta usará, qual chave oferecerá ou se o tráfego passará primeiro por outra máquina. Ele informa ao OpenSSH com qual argumento de configuração começar.

Essa diferença se perde porque os aliases tornam o trabalho normal na linha de comando mais prático. Um nome curto como `app-prod` é mais fácil de digitar do que um hostname totalmente qualificado com um usuário específico e uma porta fora do padrão. Também é mais fácil entregá-lo a um agente. Mas o alias é apenas um identificador. Seu significado vem de todas as configurações correspondentes nos arquivos que o SSH lê.

O OpenSSH lê primeiro as opções da linha de comando, depois `~/.ssh/config` do usuário e, por fim, a configuração global do sistema. Para a maioria das opções de valor único, o primeiro valor obtido pelo SSH é o que será usado. O manual `ssh_config(5)` do OpenSSH deixa clara a consequência prática: coloque as declarações específicas primeiro e os padrões gerais depois. Um bloco amplo `Host *` no início pode neutralizar silenciosamente uma regra condicional mais cuidadosa definida depois.

Comece com um inventário que registre cada alias que um agente pode usar em termos que um revisor consiga verificar:

| Alias | Destino resolvido | Usuário remoto | Rota | Intenção da identidade |
|---|---|---|---|---|
| `staging-api` | `api-01.staging.example.net` | `deploy` | direta | identidade de deploy de staging |
| `prod-api` | `api-01.prod.example.net` | `deploy` | `prod-bastion` | identidade de deploy de produção |
| `prod-breakfix` | `api-01.prod.example.net` | `ops` | `prod-bastion` | identidade exclusiva para incidentes |

Não escreva `production` na coluna de destino. Escreva o alvo real usado pelo SSH. Não escreva `usuário padrão`. Escreva `deploy`, `ubuntu`, `ec2-user` ou qualquer conta recebida pelo servidor. Se houver um jump host na rota, dê o nome dele. Se o alias se comportar de forma diferente em redes distintas, ele precisa de sua própria linha, porque representa uma conexão efetiva diferente.

A distinção útil é esta: **um alias identifica uma entrada de configuração; um destino identifica o endpoint remoto**. Confundir os dois leva a aprovações erradas. Um revisor pode concordar com a abertura de uma sessão para `staging-api` e ainda assim estar enganado sobre o endpoint real, porque o alias contém um comportamento antigo ou condicional.

Por isso, os aliases devem descrever uma finalidade operacional, não escondê-la. `prod-readonly`, `prod-deploy` e `prod-breakfix` fazem o revisor parar no ponto certo. Um único alias chamado `prod`, que escolhe usuários, chaves e rotas por meio de blocos condicionais, economiza alguns toques no teclado e cria um problema permanente de revisão.

## Blocos Match são lógica executável de conexão

Um bloco `Match` não é um rótulo para um grupo de hosts. É uma seção condicional de `ssh_config` que altera quais diretivas se aplicam. As condições podem incluir o host solicitado, o host original, o usuário remoto, o usuário local, o estado da canonicalização, a rede local, um comando solicitado e um comando `exec` que o SSH executa pelo shell local.

Esse poder é útil. Também significa que uma configuração pode conter comportamentos invisíveis quando você inspeciona apenas o alias `Host` próximo.

Considere esta configuração:

```sshconfig
Host prod-api
    HostName api-01.prod.example.net
    User deploy
    ProxyJump prod-bastion

Match originalhost prod-api user root
    IdentityFile ~/.ssh/breakfix_ed25519
    IdentitiesOnly yes
```

Um revisor que lê apenas o bloco `Host prod-api` vê uma conexão de deploy como `deploy`. Se alguém executar `ssh -l root prod-api`, a condição `Match originalhost prod-api user root` poderá ser aplicada. A configuração da identidade também depende de onde as configurações anteriores de identidade foram obtidas e de a opção aceitar vários valores. O ponto principal é mais simples: a conexão mudou por causa de um argumento de usuário na linha de comando, não porque o alias mudou.

Para uso por agentes, evite regras `Match user` que concedam uma identidade ou rota mais privilegiada. A regra parece organizada porque agrupa o comportamento pelo nome da conta. Também é fácil para uma ferramenta chamadora alterá-la com `-l`, `user@host` ou um comando gerado. Coloque o `User` pretendido diretamente em um alias com finalidade específica.

Uma versão mais segura torna cada intenção explícita:

```sshconfig
Host prod-deploy
    HostName api-01.prod.example.net
    User deploy
    ProxyJump prod-bastion
    IdentityFile ~/.ssh/prod_deploy_ed25519
    IdentitiesOnly yes

Host prod-breakfix
    HostName api-01.prod.example.net
    User ops
    ProxyJump prod-bastion
    IdentityFile ~/.ssh/prod_breakfix_ed25519
    IdentitiesOnly yes
```

Isso não torna o acesso privilegiado inofensivo. Torna a conexão solicitada legível. Um agente precisa de autorização separada para chamar `prod-breakfix`; ele não pode chegar a esse comportamento apenas variando o nome do usuário.

`Match exec` merece ainda menos confiança em configurações voltadas a agentes. Ele executa um comando do shell local enquanto o SSH avalia a configuração. Equipes usam esse recurso para detectar a rede, consultar inventários ou selecionar credenciais. Isso transforma uma tentativa de conexão SSH em um caminho de código local com dependências do ambiente. Se você precisa dessa flexibilidade no trabalho humano, mantenha esses aliases fora do conjunto que um agente pode chamar. Uma revisão de conexão não deveria exigir a engenharia reversa de um comando shell arbitrário.

## O primeiro valor correspondente pode neutralizar sua exceção

O erro mais persistente na configuração SSH não é uma seção inválida. É uma seção válida colocada depois de uma regra mais ampla que já definiu a opção.

Suponha que um desenvolvedor escreva isto ao tentar exigir um bastion para produção:

```sshconfig
Host *
    User deploy
    ProxyJump dev-bastion

Host prod-*
    ProxyJump prod-bastion
```

A expectativa é compreensível: `prod-*` parece mais específico, portanto deveria vencer. O OpenSSH não ordena os blocos por especificidade. Ele os processa na ordem do arquivo e, para muitas diretivas, o primeiro valor obtido vence. `prod-api` manterá `dev-bastion`, porque o `Host *` anterior já forneceu `ProxyJump`.

Coloque os blocos específicos primeiro:

```sshconfig
Host prod-*
    ProxyJump prod-bastion

Host *
    User deploy
    ServerAliveInterval 30
```

Isso não é apenas uma questão de estilo. Uma rota pelo bastion errado pode colocar a sessão no caminho de rede errado. Um padrão amplo `User deploy` pode fazer um alias de produção autenticar como uma conta que não deveria estar naquele host. Um `IdentityFile` amplo pode oferecer uma credencial inesperada antes da pretendida.

Não transforme a regra do primeiro valor em uma regra universal. Algumas diretivas aceitam deliberadamente vários valores, e `IdentityFile` é um exemplo comum. Várias identidades configuradas podem ser adicionadas ao conjunto considerado pelo SSH. Isso cria outro problema: um alias específico pode indicar a identidade correta, mas ainda deixar outras identidades disponíveis por causa da configuração anterior ou do agente SSH local.

Para conexões automatizadas, torne a seleção da identidade explícita e previsível:

```sshconfig
Host prod-deploy
    HostName api-01.prod.example.net
    User deploy
    IdentityFile ~/.ssh/prod_deploy_ed25519
    IdentitiesOnly yes
    ProxyJump prod-bastion
```

`IdentitiesOnly yes` informa ao OpenSSH que deve usar apenas as identidades configuradas no SSH ou fornecidas na linha de comando, em vez de tentar livremente todas as identidades disponíveis em um agente. Isso não corrige uma configuração desorganizada. Ele impede que uma chave não relacionada, carregada em um agente local, se torne uma candidata por acidente.

Uma recomendação comum diz para colocar todos os padrões em `Host *` e substituir apenas quando necessário. Isso é razoável para configurações inofensivas, como intervalos de keepalive. É uma prática ruim para seleção de usuários, rotas, arquivos de identidade, portas, `ProxyCommand` e reescrita de hosts. Padrões que afetam autoridade devem ser poucos. Um pouco de repetição custa menos do que explicar por que um agente chegou à máquina certa pelo caminho errado.

## ProxyJump cria outra conexão que precisa ser revisada

`ProxyJump` não é apenas um complemento da conexão com o destino. O SSH primeiro se conecta ao jump host e depois estabelece, a partir dele, um caminho de encaminhamento TCP até o destino. Vários proxies podem ser listados e percorridos em sequência. O manual do OpenSSH também alerta que a configuração do host de destino geralmente não se aplica aos jump hosts.

É nesse detalhe que muitas revisões falham. Uma configuração pode ser precisa sobre `prod-api` e completamente vaga sobre `prod-bastion`.

```sshconfig
Host prod-api
    HostName 10.40.8.17
    User deploy
    ProxyJump prod-bastion

Host prod-bastion
    HostName bastion.prod.example.net
    User jump
    IdentityFile ~/.ssh/bastion_ed25519
    IdentitiesOnly yes
```

Aqui existem duas decisões de autenticação e duas identidades de host:

1. O SSH autentica o cliente local em `bastion.prod.example.net` como `jump`.
2. O bastion encaminha um fluxo TCP para `10.40.8.17`.
3. O SSH autentica, por esse fluxo, no destino como `deploy`.

O jump host pode ter outra chave, usuário, porta e registro de chave de host. Ele também pode ser selecionado por um alias curinga ou bloco condicional que ninguém verifica porque o agente solicitou apenas `prod-api`.

Revise cada salto com `ssh -G`, não apenas o alias final:

```sh
ssh -G prod-api | egrep '^(hostname|user|port|proxyjump|identityfile|identitiesonly) '
ssh -G prod-bastion | egrep '^(hostname|user|port|identityfile|identitiesonly) '
```

A saída tem uma opção por linha. Uma revisão correta pode produzir este formato:

```text
hostname api-01.prod.example.net
user deploy
port 22
proxyjump prod-bastion
identityfile ~/.ssh/prod_deploy_ed25519
identitiesonly yes
```

Depois, verifique o bastion separadamente. Se `prod-api` usar uma cadeia separada por vírgulas, como `edge-bastion,prod-bastion`, execute o comando para os dois aliases. Uma cadeia não é uma rota opaca. São várias configurações independentes do cliente SSH.

Evite definir uma rota genérica de salto em `Host *` ou em um padrão amplo como `Host *.internal`. Ela tende a capturar hosts temporários, ambientes de staging e aliases adicionados meses depois. Defina a rota no local certo, nos aliases que precisam dela. Se muitos aliases de produção precisarem da mesma rota, use um padrão restrito, reservado a aliases de produção, e não o reutilize sem cuidado.

Verifique também `ProxyCommand`. O OpenSSH trata `ProxyJump` e `ProxyCommand` como opções concorrentes: a primeira especificada impede que instâncias posteriores da outra tenham efeito. Uma configuração que parece usar um bastion pode estar executando um comando de proxy definido antes. O revisor deve sinalizar qualquer uma das duas configurações, pois ambas alteram o ponto de origem da conexão de rede e a forma como ela chega ao destino.

## A seleção do usuário muda a autoridade aprovada

A conta remota faz parte da ação solicitada. `deploy@api-01.prod.example.net` e `ops@api-01.prod.example.net` podem chegar ao mesmo servidor, mas não têm a mesma autoridade, perfil de shell, comandos forçados, permissões de sudo ou trilha de auditoria.

O SSH pode obter o usuário remoto de vários lugares: `user@host` no comando, `ssh -l user host`, uma diretiva `User` ou o usuário local, se nenhum outro valor for fornecido. Uma revisão que pergunta apenas «Qual host?» está incompleta.

Use aliases que fixem o usuário sempre que um agente tiver uma tarefa definida:

```sshconfig
Host inventory-read
    HostName inventory.prod.example.net
    User inventory_ro
    IdentityFile ~/.ssh/inventory_ro_ed25519
    IdentitiesOnly yes

Host inventory-deploy
    HostName inventory.prod.example.net
    User deploy
    IdentityFile ~/.ssh/inventory_deploy_ed25519
    IdentitiesOnly yes
```

Não entregue a um agente um hostname genérico presumindo que um prompt ou wrapper o manterá na conta correta. Um gerador de comandos pode emitir `ops@inventory.prod.example.net` com a mesma facilidade que `deploy@inventory.prod.example.net`. A configuração deve tornar o caminho autorizado o mais fácil e deixar os caminhos privilegiados claramente distintos.

Teste as formas alternativas que uma ferramenta pode gerar:

```sh
ssh -G inventory-read | grep '^user '
ssh -G -l ops inventory-read | grep '^user '
ssh -G ops@inventory-read | grep '^user '
```

Se o segundo ou terceiro comando produzir uma conta que você não pretendia permitir a um agente, não considere a configuração revisada. Corrija a interface chamadora ou isole esse alias. Um bloco `Match user` também pode ser ativado por uma dessas variantes, por isso ele precisa de testes explícitos, não apenas de inspeção visual.

Para as equipes, reserve o acesso `root` para um alias de emergência com nome próprio e mantenha-o fora das permissões comuns dos agentes. Esconder `User root` atrás de uma condição `Match` é pior do que escrevê-lo claramente. A condição vira uma caça ao tesouro durante um incidente, e às vezes um chamador consegue satisfazê-la alterando um parâmetro da linha de comando.

## IdentityFile controla mais do que o caminho da chave

`IdentityFile` parece uma configuração de seleção de arquivo. Na prática, ele decide qual credencial o SSH pode apresentar, e isso determina quais regras de autorização remota o servidor avaliará.

Um erro comum se parece com isto:

```sshconfig
Host *
    IdentityFile ~/.ssh/id_ed25519

Host prod-*
    IdentityFile ~/.ssh/prod_ed25519
```

O operador pensa que a produção usará `prod_ed25519`. O SSH pode ter os dois arquivos de identidade na lista de candidatos, porque `IdentityFile` aceita várias entradas. Se um agente SSH tiver chaves adicionais e `IdentitiesOnly` estiver ausente, ele também poderá oferecê-las. Alguns servidores rejeitam várias tentativas cedo, e outros aceitam uma identidade não pretendida que por acaso concede acesso. Nenhum dos dois resultados expressa claramente a intenção.

Um alias voltado a agentes deve declarar uma única finalidade de credencial e limitar as ofertas:

```sshconfig
Host reports-export
    HostName reports.prod.example.net
    User exporter
    IdentityFile ~/.ssh/reports_export_ed25519
    IdentitiesOnly yes
```

Depois, examine a configuração efetiva em vez de confiar na seção:

```sh
ssh -G reports-export | grep '^identityfile '
ssh -G reports-export | grep '^identitiesonly '
```

Mais de uma linha `identityfile` não está automaticamente errada. Configurações baseadas em certificados e uma rotação planejada de chaves podem justificar isso. Mas todas as identidades listadas devem pertencer ao mesmo limite de autoridade. Se um alias puder oferecer uma chave pessoal de administrador, uma chave antiga de deploy e uma chave de automação de produção, ele não tem uma história clara de autorização.

Não resolva isso armazenando chaves privadas nos arquivos, no ambiente, no prompt ou em um script gerado pelo agente. Isso apenas transforma uma ambiguidade de configuração em exposição de credencial. O Sallyport mantém as chaves SSH em seu cofre criptografado e executa ações SSH por meio de seu helper, mas não consegue tornar honesta uma configuração SSH ambígua. O alias, a rota, o usuário e a intenção da identidade ainda precisam estar claros antes que um operador aprove o processo do agente.

A mesma regra vale para os nomes das chaves. Um caminho como `~/.ssh/id_ed25519` não informa nada sobre o uso pretendido. `prod_deploy_ed25519` é melhor, mas a configuração precisa trazer a explicação completa: qual grupo de hosts, qual usuário e qual rota usam a chave. Os nomes dos arquivos ajudam na revisão, mas não a substituem.

## A canonicalização pode fazer um alias corresponder duas vezes

A canonicalização de host é uma das formas menos visíveis de alterar a configuração SSH. Quando `CanonicalizeHostname yes` está habilitado, o OpenSSH pode receber um nome não qualificado, acrescentar sufixos de domínio configurados, resolvê-lo e depois processar novamente a configuração usando o novo nome do destino. `Match canonical` se aplica nessa segunda passagem. `Match final` solicita uma análise final e faz a correspondência durante essa passagem; quando a canonicalização está habilitada, as condições canonical e final correspondem juntas.

Esse comportamento pode ser útil em redes internas grandes. Também pode transformar um alias curto em uma armadilha de configuração condicional.

```sshconfig
CanonicalizeHostname yes
CanonicalDomains corp.example.net

Host build
    User ci

Match canonical host *.prod.example.net
    ProxyJump prod-bastion
```

O chamador executa `ssh build`. A primeira passagem vê `build`. Se a canonicalização resolver esse nome como `build.prod.example.net`, o SSH analisa a configuração novamente e o bloco `Match canonical host *.prod.example.net` pode definir uma rota de produção. A conexão não mudou porque o chamador pediu outro alias. Ela mudou porque o DNS e uma segunda passagem alteraram o host visto pelas regras posteriores.

O manual do OpenSSH distingue duas condições que muitas pessoas tratam como equivalentes:

- `Match originalhost` testa o token de host fornecido pelo chamador.
- `Match host` testa o destino depois da substituição de `HostName` ou da canonicalização.

Use `originalhost` quando precisar vincular o comportamento a um alias nomeado deliberadamente. Use `host` quando o comportamento depender do destino realmente resolvido. Não use nenhuma das duas condições de forma casual para alterar privilégios.

A canonicalização tem outra particularidade importante com bastions. `CanonicalizeHostname yes` normalmente não se aplica a conexões que usam `ProxyCommand` ou `ProxyJump`; `CanonicalizeHostname always` estende o recurso às conexões por proxy. Assim, dois aliases estruturalmente parecidos podem seguir regras de reescrita diferentes apenas porque um deles usa um jump host.

Para permissões de agentes, a política mais simples costuma ser a melhor: desabilite a canonicalização para os aliases entregues a um agente e use valores `HostName` completos e explícitos. Se o ambiente precisar de canonicalização, teste cada alias permitido no contexto de rede exato em que o agente será executado. Não presuma que um hostname curto será resolvido da mesma forma na rede doméstica, na rede corporativa, em uma VPN e no Wi-Fi do escritório.

`Match localnetwork` traz a mesma preocupação. O OpenSSH documenta que o endereço da rede local não é confiável para configurações sensíveis à segurança, especialmente em redes configuradas por DHCP. Ele é aceitável para ajustes de conveniência. Não o use para decidir se um agente recebe uma identidade mais privilegiada, ignora um bastion ou acessa a produção.

## Renderize a conexão antes de autorizá-la

`ssh -G` é a forma mais rápida de transformar a configuração SSH, que está em texto, em algo testável. Ele imprime a configuração que o SSH usará depois de processar as regras `Host` e `Match` e encerra sem abrir uma conexão.

Execute-o com o alias e os argumentos exatos que o agente usará. Não teste apenas uma versão manualmente simplificada do comando.

```sh
ssh -G prod-deploy | egrep '^(hostname|user|port|proxyjump|proxycommand|identityfile|identitiesonly|canonicalizehostname) '
```

Para uma revisão séria, salve a saída completa como um fixture no repositório responsável pela automação. Use um arquivo de configuração com nome explícito para que o teste não herde silenciosamente as configurações pessoais de um desenvolvedor:

```sh
ssh -F ./agent-ssh-config -G prod-deploy > ./testdata/prod-deploy.effective
```

Revise o fixture quando a configuração mudar. Um diff útil detecta alterações em `hostname`, `user`, `proxyjump` ou na lista de identidades antes que elas cheguem ao fluxo de aprovação. Um diff ruidoso da configuração completa ainda é melhor do que confiar em uma seção que alguém colou em um pull request.

Use `ssh -vvv` apenas depois que `ssh -G` mostrar os valores esperados. Os logs detalhados da conexão ajudam a confirmar quais chaves de host e métodos de autenticação o SSH realmente tenta, mas misturam decisões de configuração com ruído de rede. Primeiro, `-G` responde: «o que esta configuração diz?». Essa é a pergunta que você precisa resolver antes de investigar a conectividade.

Teste as variações de forma deliberada:

```sh
ssh -F ./agent-ssh-config -G prod-deploy
ssh -F ./agent-ssh-config -G -l ops prod-deploy
ssh -F ./agent-ssh-config -G ops@prod-deploy
ssh -F ./agent-ssh-config -G prod-deploy.prod.example.net
```

Os resultados devem permanecer dentro do limite de autoridade esperado ou falhar. Se uma substituição de usuário mudar a conta, se uma forma totalmente qualificada ignorar o bastion ou se um nome curto ganhar outra identidade depois da canonicalização, você encontrou um caminho de configuração que vale a pena fechar.

Verifique também os arquivos incluídos. `Include` pode fazer com que o `~/.ssh/config` visível seja apenas a porta de entrada para um diretório cheio de regras geradas por máquinas, pela empresa ou por projetos. Revise a saída efetiva usando a mesma conta local e o mesmo caminho de configuração que executarão o agente. Testar no seu shell enquanto o agente usa outra conta cria uma falsa sensação de segurança.

## Mantenha a configuração SSH do agente pequena e específica

A melhor configuração SSH para um agente autônomo de programação geralmente não é a sua configuração pessoal com alguns comentários acrescentados. Configurações pessoais acumulam atalhos, exceções do cliente, aliases antigos, comportamentos ligados à rede local, agentes encaminhados e identidades que foram convenientes em algum momento. Um agente precisa de um catálogo restrito de conexões.

Crie um arquivo de configuração dedicado que contenha apenas aliases aprovados e os jump hosts necessários para apoiá-los. Aponte o agente ou seu wrapper de execução para esse arquivo com `-F`. Dê a cada alias uma única função, um `HostName`, `User`, rota e intenção de identidade explícitos. Mantenha a lógica condicional fora dele, a menos que você consiga mostrar por que um alias estático não seria suficiente.

Um exemplo compacto:

```sshconfig
Host prod-bastion
    HostName bastion.prod.example.net
    User jump
    IdentityFile ~/.ssh/prod_bastion_ed25519
    IdentitiesOnly yes

Host prod-deploy
    HostName api-01.prod.example.net
    User deploy
    ProxyJump prod-bastion
    IdentityFile ~/.ssh/prod_deploy_ed25519
    IdentitiesOnly yes

Host staging-deploy
    HostName api-01.staging.example.net
    User deploy
    IdentityFile ~/.ssh/staging_deploy_ed25519
    IdentitiesOnly yes
```

Isso repete informações. Ótimo. O arquivo informa ao revisor o significado de cada conexão sem exigir que ele execute mentalmente a precedência de curingas e o estado condicional. 

Não confunda um arquivo de configuração dedicado com um mecanismo de políticas. Ele não prova que um comando é seguro depois que a sessão é aberta. Ele torna a conexão de transporte concreta o bastante para ser revisada: este alias, este endpoint, este usuário, esta rota, esta identidade. Esse é um limite útil.

A autorização por sessão do Sallyport e seus registros de atividade oferecem aos operadores um ponto de controle humano e uma trilha das ações do agente, mas a configuração SSH ainda fornece os fatos por trás da ação. Se `prod-deploy` puder se transformar em vários caminhos de rede ou contas, a configuração já tornou a aprovação menos confiável.

Antes de permitir que um agente use um alias SSH, renderize-o, inspecione cada jump host e teste as variantes de linha de comando que o agente pode produzir. Se a conexão efetiva surpreender você uma vez, presuma que ela surpreenderá alguém no pior momento possível. Corrija o alias até que ele se pareça com uma aprovação que uma pessoa possa realmente conceder.
