8 min de leitura

Riscos do encaminhamento de agente SSH em desenvolvimento com IA

Os riscos do encaminhamento de agente SSH aumentam nos fluxos de trabalho com IA. Entenda como hosts remotos reutilizam sua autoridade de assinatura, como desativá-la e quais padrões SSH são mais seguros.

Riscos do encaminhamento de agente SSH em desenvolvimento com IA

É fácil subestimar os riscos do encaminhamento de agente SSH porque a chave privada permanece na máquina do desenvolvedor. Isso é verdade, mas não basta. Um host remoto que recebe um socket de agente encaminhado pode pedir ao agente local que assine desafios de autenticação SSH. Para cada sistema que aceita essa identidade, o host remoto talvez consiga agir como você enquanto esse acesso durar.

O desenvolvimento com assistência de IA torna esse erro mais fácil de cometer e mais difícil de perceber. Um agente de programação pode abrir shells remotos, executar comandos de deploy, inspecionar repositórios e seguir uma configuração SSH escrita anos atrás para uma sessão interativa. Se o agente alcançar uma máquina que tenha seu socket encaminhado, o limite de segurança já mudou. Desative o encaminhamento por padrão e dê aos trabalhos remotos identidades próprias e restritas quando eles realmente precisarem passar por outro host.

Um agente encaminhado pode autenticar-se além do primeiro host

O encaminhamento de agente SSH expõe um serviço de assinatura, não uma cópia da chave privada. Seu ssh-agent local mantém uma ou mais identidades privadas. Quando você se conecta com o encaminhamento ativado, o SSH cria um socket na máquina remota e retransmite as solicitações de assinatura pela conexão criptografada até o agente local.

Essa diferença costuma levar a decisões ruins sobre risco. As pessoas ouvem «a chave nunca sai do meu laptop» e concluem que a máquina remota não tem nada que valha a pena atacar. Os bytes privados podem continuar locais, mas a autenticação SSH não exige que a máquina remota possua esses bytes. Ela precisa de uma assinatura válida sobre uma solicitação de autenticação. O socket encaminhado oferece um meio de obtê-la.

O manual do OpenSSH ssh_config(5) descreve ForwardAgent de forma clara e alerta que usuários capazes de contornar as permissões de arquivo no host remoto podem acessar o agente encaminhado. Na prática, isso significa que a própria conta remota, um processo executado por essa conta, um administrador ou um invasor que obtenha controle suficiente pode usar o socket. O acesso root no host remoto encerra a discussão sobre permissões do socket.

A RFC 4252 descreve a autenticação SSH por chave pública como uma assinatura sobre dados específicos da conexão. O servidor valida essa assinatura comparando-a com uma chave pública autorizada. Um host remoto comprometido não pode transformar o agente em um serviço genérico de assinatura para documentos arbitrários, mas pode solicitar as assinaturas SSH necessárias para tentar logins SSH em outros lugares. Essa é exatamente a capacidade que um invasor deseja se sua identidade funcionar no controle de código-fonte, em hosts de produção ou em sistemas internos de administração.

O erro mais comum se parece com isto:

  1. Um desenvolvedor se conecta a build.example.net com ssh -A porque essa máquina precisa acessar um repositório privado.
  2. O agente local do desenvolvedor aparece no host de build por meio de SSH_AUTH_SOCK.
  3. Um script de build, uma dependência comprometida ou outro usuário com acesso suficiente pede a esse socket uma assinatura para git.example.net ou para um host interno.
  4. O destino aceita a chave pública do desenvolvedor e registra a nova conexão como se tivesse sido feita pelo desenvolvedor.

O servidor SSH do destino vê uma assinatura criptográfica legítima. Ele não consegue saber se uma pessoa iniciou a conexão em seu laptop ou se um processo na primeira máquina remota a solicitou por meio do encaminhamento. Os logs do servidor identificam a chave aceita e o endereço de origem, mas não recuperam essa distinção perdida.

A herança de configuração cria exposição acidental

A maior parte dos encaminhamentos inseguros começa na configuração SSH, não em uma decisão consciente durante uma sessão arriscada. Uma única seção antiga, como Host * com ForwardAgent yes, pode aplicar-se a todos os hosts acessados por um desenvolvedor, uma ferramenta de terminal ou um agente de programação. Ela também se aplica quando a ferramenta chama ssh em um script, sem que ninguém veja um aviso.

A configuração do OpenSSH tem outro ponto delicado: para cada parâmetro, o cliente geralmente usa o primeiro valor que encontra. Uma regra ampla colocada antes de uma regra específica pode anular a exceção que você pensou ter escrito. Não confie em uma inspeção rápida de ~/.ssh/config. Pergunte ao SSH qual configuração ele vai usar.

Execute isto na máquina local antes de conectar:

ssh -G deploy.internal.example | grep '^forwardagent '

Um resultado seguro é:

forwardagent no

ssh -G mostra a configuração efetiva do cliente depois de processar os arquivos e as opções da linha de comando. Ele não abre uma conexão. Por isso, é útil em verificações de configuração e em um script de teste que leia uma lista de hosts sensíveis.

Defina uma regra explícita de negação por padrão perto do final do arquivo de configuração relevante. Coloque as exceções específicas antes dela, porque o OpenSSH usa o primeiro valor correspondente:

Host docs-bastion.example
    ForwardAgent yes

Host *
    ForwardAgent no

Este exemplo ainda concede uma exceção perigosa, portanto ela precisa ter um motivo e um responsável. O objetivo é tornar essa exceção visível e limitá-la a um host, em vez de aplicá-la silenciosamente a todo ambiente novo.

Para uma conexão pontual, force a configuração segura mesmo que um arquivo de configuração diga o contrário:

ssh -o ForwardAgent=no [email protected]

A forma mais curta, ssh -a [email protected], faz a mesma coisa. Use uma delas ao conectar-se a uma máquina que você ainda não analisou, a um host temporário de suporte, a um ambiente de treinamento ou a um sistema administrado por um fornecedor.

Não confunda IdentitiesOnly yes com um controle de encaminhamento. Essa opção afeta quais identidades o cliente SSH oferece ao autenticar-se em um servidor. Ela não impede que o SSH crie um socket de agente no lado remoto. Da mesma forma, remover SSH_AUTH_SOCK de um shell não é uma política completa. Um processo filho pode herdar outro ambiente, e uma configuração SSH pode reativar o encaminhamento na conexão seguinte.

Os fluxos de IA multiplicam os caminhos que precisam ser revisados

Um agente de programação com IA não precisa ter intenção maliciosa para tornar o encaminhamento perigoso. Basta ter permissão para executar um comando que encontre seus hábitos SSH existentes. Os agentes seguem instruções do repositório, executam scripts de build, usam hosts de desenvolvimento remoto e repetem comandos com pequenas variações. Esses comportamentos são normais. Eles se tornam arriscados quando o ambiente lhes dá uma identidade de desenvolvedor reutilizável.

O caminho preocupante costuma ser indireto. Seu agente local inicia uma sessão SSH em uma máquina de desenvolvimento. Essa sessão encaminha seu agente por causa de uma regra de configuração global. O agente de programação executa um script do repositório na máquina de desenvolvimento. O script baixa uma dependência ou abre uma segunda conexão SSH. A segunda conexão pode usar o socket que a primeira sessão colocou ali.

Isso é pior do que uma pessoa digitando um único git fetch, porque um agente pode fazer muitas chamadas de ferramentas sem parar para questionar por que um shell remoto precisa acessar um destino sem relação aparente. O agente também pode encontrar instruções em um repositório que mandam usar determinado alias de host. Esse alias pode esconder um ProxyCommand, uma regra Match ou uma regra de encaminhamento herdada, fora da visão do operador.

Trate estas permissões separadamente:

  • Permissão para um agente abrir um shell remoto.
  • Permissão para esse shell remoto alcançar outro destino SSH.
  • Permissão para o segundo destino aceitar a identidade do desenvolvedor.
  • Permissão para o agente provocar a segunda conexão.

As equipes costumam juntar as quatro em «o agente precisa de SSH». Essa frase não descreve o limite de segurança. Um shell remoto e uma capacidade de assinatura reutilizável têm consequências diferentes e exigem decisões separadas.

Verifique como o processo do agente é iniciado. Se ele herdar SSH_AUTH_SOCK de um terminal interativo, talvez já tenha acesso às identidades do agente local para autenticação SSH direta. Se depois se conectar a um host com o encaminhamento ativado, esse host ganhará uma segunda rota até essas identidades. Um wrapper que limpe a variável de ambiente pode reduzir o uso acidental, mas não substitui uma configuração SSH segura nem uma identidade separada para automação.

Também inspecione as instruções do agente e os wrappers de automação em busca de ssh -A, scp -A ou de um alias que se expanda para essas opções. scp e sftp dependem das configurações do transporte SSH, portanto um hábito de encaminhamento pode se espalhar muito além do comando que o criou. Coloque a decisão de encaminhamento no lugar correto: na definição da conexão, com um padrão explícito de não.

Um jump host não precisa do seu agente

Muitos desenvolvedores ativam o encaminhamento porque precisam atravessar um bastion antes de alcançar um sistema interno. Era uma solução comum quando o único modelo conveniente era «entrar no bastion e depois executar SSH novamente». Ela continua popular porque funciona rapidamente durante a configuração. Também transforma o bastion em uma máquina capaz de reutilizar sua identidade.

Use ProxyJump quando o primeiro host só precisar transportar o tráfego. O cliente local pode autenticar-se no host final enquanto cria um túnel pelo jump host, sem encaminhar um socket de agente para esse host.

Host engineering-bastion
    HostName bastion.example
    User developer
    ForwardAgent no

Host release-host
    HostName release.internal.example
    User deploy
    ProxyJump engineering-bastion
    ForwardAgent no

Com essa configuração, o cliente SSH local estabelece a conexão SSH final por meio do bastion. O bastion transporta o tráfego criptografado. Ele não recebe um SSH_AUTH_SOCK remoto que possa usar para solicitar assinaturas ao seu agente.

Teste a rota, em vez de presumir que a configuração significa o que você espera:

ssh -vvv release-host

Na saída de depuração, procure a conexão do proxy jump e confirme que não há indicação de encaminhamento do agente. Depois de entrar no host final, inspecione o ambiente remoto:

printf 'SSH_AUTH_SOCK=%s\n' "${SSH_AUTH_SOCK:-}"
ssh-add -l

Uma variável de socket vazia é o resultado esperado quando você desativou intencionalmente o encaminhamento. Se ssh-add -l informar que não há conexão com um agente de autenticação, isso também é compatível com a ausência de um agente encaminhado. Não faça essas verificações somente no host final ao investigar. Faça-as em cada salto interativo onde alguém possa ter ativado o encaminhamento.

Há casos legítimos em que o jump host precisa autenticar-se em outro host, como em uma operação de release controlada. Isso significa que o jump host precisa de uma identidade própria de deploy ou de uma identidade de carga de trabalho de curta duração. Não significa que ele deva pegar emprestadas todas as identidades carregadas no agente do laptop de um desenvolvedor.

A automação remota precisa de uma identidade própria

Veja cada chamada SSH do agente
O registro de atividades documenta cada chamada SSH no log de auditoria criptografado e encadeado por hash.

Uma máquina remota de build, um host de deploy ou uma ferramenta de IA deve autenticar-se como a carga de trabalho que recebeu, não como o desenvolvedor que por acaso iniciou a sessão. Essa mudança de arquitetura elimina a necessidade de encaminhamento, em vez de apenas torná-lo menos conveniente.

Uma identidade de carga de trabalho deve conceder acesso somente aos serviços que essa carga precisa usar. Para um repositório de código, use uma identidade de deploy limitada ao repositório quando o serviço oferecer esse recurso. Para um destino SSH, autorize uma chave pública dedicada para uma conta dedicada e limite os comandos ou as permissões dessa conta quando o servidor permitir. Em uma configuração de SSH baseada em certificados, emita certificados de curta duração com principals correspondentes à função da carga de trabalho.

Os certificados SSH podem restringir o acesso, mas não são mágicos. O principal de um certificado controla quais contas o aceitam somente se o servidor verificar os principals corretamente. Um período de validade curto limita por quanto tempo uma assinatura pode autenticar, mas um processo comprometido ainda pode usá-la durante essa janela. Revise a configuração do servidor que confia na autoridade certificadora e as regras de conta que usam esses principals.

Não reutilize a chave pública pessoal de um desenvolvedor como identidade «temporária» para um worker de CI ou agente remoto. Isso mantém o registro de auditoria ambíguo. Quando um registro de autenticação informa que a chave pessoal fez login, não é fácil determinar se foi o desenvolvedor, um job de build ou um shell remoto comprometido usando o encaminhamento.

Para ações HTTP e SSH controladas por agentes, outra opção é manter as credenciais em um gateway local de ações e devolver ao agente apenas o comando ou o resultado da API. O Sallyport usa esse modelo no macOS: seu cofre guarda a chave SSH e o helper sp-ssh executa a ação SSH sem entregar a credencial ao agente.

O limite útil é operacional, não apenas uma descrição. O agente solicita uma ação nomeada, o gateway aplica a credencial e o agente recebe a saída. O agente não recebe um socket de agente que possa passar a um processo remoto sem relação. Assim, as aprovações e os registros têm significado, porque correspondem a uma ação, não a uma capacidade aberta de pedir assinaturas futuras.

Os pedidos de confirmação reduzem a exposição, mas não corrigem a confiança

Às vezes, uma tarefa curta de manutenção realmente exige encaminhamento e ainda não existe uma identidade dedicada. Nesse caso, encaminhe o mínimo possível de autoridade de assinatura e torne cada uso restante visível. Isso é um controle temporário, não uma arquitetura permanente.

Inicie um socket de agente separado, em vez de encaminhar o agente que contém sua coleção diária de identidades. Adicione apenas a identidade necessária para a tarefa de manutenção, com uma validade curta e exigência de confirmação:

ssh-agent -a "$HOME/.ssh/maintenance-agent.sock" > "$HOME/.ssh/maintenance-agent.env"
. "$HOME/.ssh/maintenance-agent.env"
ssh-add -c -t 900 ~/.ssh/maintenance_ed25519
ssh -o ForwardAgent=yes [email protected]

ssh-add -c pede confirmação antes de o agente assinar. -t 900 remove a identidade depois de 15 minutos. Consulte o manual ssh-add(1) da versão do OpenSSH instalada, porque o comportamento da confirmação depende do agente local e da interface usada pelo usuário.

Use um shell separado para essa tarefa. Quando o trabalho terminar, remova a identidade e encerre o agente:

ssh-add -D
ssh-agent -k

Essa sequência impede solicitações posteriores por meio desse socket temporário. Ela não revoga assinaturas já emitidas, conexões já autenticadas nem cópias de dados que um processo remoto já tenha obtido. Feche a sessão remota e verifique os destinos aos quais essa identidade podia acessar.

O OpenSSH também oferece restrições de destino por meio de ssh-add -h nas versões que incluem esse recurso. Essas restrições podem limitar para quais caminhos de host um agente assina, com base nas chaves de host em known_hosts. Vale avaliá-las em um ambiente controlado, mas elas acrescentam dependências de configuração que as equipes frequentemente deixam de manter. Um arquivo known_hosts desatualizado ou incompleto pode transformar uma medida de segurança em uma interrupção justamente no pior momento. Teste com o caminho exato do salto e os aliases de host usados pela automação.

Não dependa do cansaço causado pelos avisos como limite de segurança. Um host comprometido pode pedir assinaturas repetidamente e indicar destinos parecidos com a infraestrutura normal. Se os operadores aprovarem os avisos rapidamente para encerrar um incidente, a confirmação protegerá menos do que imaginam. Uma identidade restrita e uma validade curta dão ao aviso um raio de impacto menor.

Os logs precisam distinguir sessões de ações SSH

Devolva resultados, não credenciais
O Sallyport executa a ação SSH e devolve o resultado sem passar as credenciais ao agente.

Os logs de autenticação SSH informam que uma chave se autenticou em um servidor. Raramente informam por que a assinatura foi solicitada ou se o encaminhamento de agente abriu o caminho. Se você permite ações remotas automatizadas, capture informações suficientes para reconstruir quem iniciou o agente, qual processo recebeu aprovação, qual destino ele contatou e qual ação solicitou.

Mantenha os registros de sessão separados dos registros de ação. Um registro de sessão responde qual processo do agente recebeu acesso e quando esse acesso terminou. Um registro de ação responde qual comando SSH ou chamada de API foi executado com esse acesso. Misturar tudo em um único log genérico torna as investigações lentas, porque o operador precisa deduzir uma cadeia de causa e efeito a partir de fragmentos.

Em um servidor SSH, revise os registros normais de autenticação depois de qualquer evento suspeito de encaminhamento. O local exato depende do sistema operacional e da configuração do serviço, mas lugares comuns incluem entradas do journal do sistema e o log de autenticação do daemon SSH. Procure a impressão digital da chave pública aceita, o nome da conta, o endereço de origem e o horário. Compare esses dados com o histórico da sessão no primeiro host remoto.

Não tire conclusões definitivas de um endereço IP. Uma conexão encaminhada pode vir de uma máquina de build, de um bastion, de um gateway de tradução de endereços de rede ou de uma rede overlay privada. O servidor consegue determinar de onde veio a conexão TCP, mas não quem iniciou a solicitação de assinatura na máquina do desenvolvedor.

Registros que evidenciem adulteração só ajudam se o sistema os gravar fora do controle do agente. Um processo capaz de editar seu próprio histórico de ações pode apagar o segundo salto suspeito antes que alguém o examine. O Sallyport registra sessões de agentes e chamadas individuais em um log de auditoria criptografado e encadeado por hash, e sp audit verify pode conferir essa cadeia offline sem uma chave do cofre.

Seja qual for a ferramenta escolhida, teste o registro com uma autorização recusada real e um comando SSH bem-sucedido real. Confirme que ele informa a execução do agente, o destino, a referência ou impressão digital da credencial, o resultado e o horário. Logs que apenas dizem «ferramenta concluída» não respondem a uma pergunta de incidente sobre reutilização de identidade.

Trate uma exposição como abuso de autorização, não como roubo automático da chave

Identifique as execuções aprovadas do agente
O registro de sessões documenta as execuções do agente e permite revogar uma execução imediatamente.

Se você descobrir que encaminhou um agente para um host em que não confia, responda como se esse host pudesse ter usado sua identidade enquanto a sessão existiu. Não espere provas de que ele extraiu uma chave privada. O risco relevante é a autenticação não autorizada, e a chave privada talvez nunca tenha saído da sua máquina.

Primeiro, impeça o uso futuro. Feche todas as sessões SSH nesse host, remova a identidade exposta do agente e desative a regra de encaminhamento específica do host. Se a identidade estava carregada em um agente compartilhado, não execute ssh-add -D automaticamente em um dia de trabalho e declare o problema resolvido. Isso pode interromper sessões legítimas e deixar a chave pública afetada autorizada em vários servidores.

Depois, remova ou revogue a autorização nos destinos que a identidade alcança. Em configurações comuns de chaves autorizadas, remova a chave pública das contas em que ela não deve mais funcionar e substitua-a por uma nova onde necessário. Para certificados SSH, revogue o certificado de acordo com os procedimentos da sua autoridade certificadora e do servidor, ou deixe um certificado de curta duração expirar se puder confirmar que a janela de exposição é aceitável. Para acesso a repositórios, revogue ou substitua a credencial de deploy ou de usuário correspondente pelos controles normais do serviço.

Investigue uma janela de tempo delimitada: desde quando o encaminhamento ficou disponível até o fim da sessão remota ou até o momento em que o agente local deixou de aceitar solicitações. Revise os registros de autenticação dos destinos, o histórico do shell remoto quando ele for confiável, os registros dos jobs e os logs de ações. Preserve os logs antes de limpar o host remoto se houver suspeita de comprometimento.

Por fim, corrija o caminho que permitiu o problema. Se um ForwardAgent yes global causou o evento, alterar apenas a entrada do host comprometido deixará o próximo host desconhecido exposto. Se um fluxo de IA herdou um socket pessoal, dê a esse fluxo uma configuração de conexão explícita e uma identidade de carga de trabalho dedicada. O reparo deve tornar o caminho inseguro impossível por padrão, não apenas lembrar as pessoas de usar uma opção.

O padrão seguro deve funcionar mesmo sob pressão

O encaminhamento persiste porque reduz o atrito naquele momento. Um desenvolvedor precisa passar por mais um salto, um build precisa baixar algo privado ou um agente precisa concluir uma tarefa antes do prazo. Essas necessidades são reais. Elas não justificam colocar uma identidade de desenvolvedor amplamente confiável em todas as máquinas que por acaso estejam no caminho.

Defina ForwardAgent no globalmente. Use ProxyJump para bastions que servem apenas como transporte. Dê à automação remota uma identidade que indique o que ela pode fazer. Quando uma exceção temporária for inevitável, isole uma identidade, exija confirmação, defina uma expiração curta e remova-a quando a tarefa terminar.

Execute ssh -G contra os aliases de host usados pela equipe nesta semana. Essa pequena verificação encontra o erro silencioso de configuração antes que um processo remoto receba um serviço de assinatura que nunca deveria ter.

FAQ

Um servidor remoto pode roubar minha chave privada por meio do encaminhamento de agente SSH?

Geralmente, não. A máquina remota não consegue ler a chave privada de um socket de agente encaminhado comum, mas pode pedir ao seu agente local que assine desafios de autenticação enquanto a conexão estiver disponível. Essa capacidade de assinatura já basta para entrar em sistemas que aceitam essa identidade.

ssh -A ativa o encaminhamento de agente?

Não. ssh -A ativa explicitamente o encaminhamento, enquanto ssh -a o desativa nessa conexão. Um arquivo de configuração ainda pode causar surpresas, portanto confira o valor efetivo com ssh -G host | grep '^forwardagent '.

Preciso encaminhar o agente quando uso ProxyJump?

ProxyJump cria uma rota de transporte por um intermediário. Ele não exige que seu agente fique disponível para esse intermediário. Configure localmente a autenticação do destino final e mantenha ForwardAgent no. Trate o bastion como uma rota, não como uma estação de trabalho que precisa receber sua identidade.

IdentitiesOnly impede o encaminhamento do agente SSH?

IdentitiesOnly yes controla quais identidades o cliente SSH oferece durante a autenticação. Ele não impede o cliente de encaminhar um socket de agente depois do login. Defina ForwardAgent no separadamente.

ssh-add -c oferece proteção suficiente para agentes encaminhados?

Uma identidade que exige confirmação reduz o uso silencioso, porque o agente local pergunta antes de cada assinatura. Isso não torna seguro um host não confiável: o host pode criar vários avisos, e uma aprovação apressada ainda autoriza uma tentativa real de login. Use esse recurso como uma barreira temporária, não como seu modelo normal.

Como encaminhar um agente SSH com mais segurança em uma tarefa temporária?

Use um agente separado com apenas uma identidade de escopo restrito, defina uma validade curta, exija confirmação e encaminhe-o somente para um host específico durante uma tarefa breve. Remova a identidade quando o trabalho terminar. Um agente pessoal amplo, com várias chaves de longa duração, é a escolha errada para encaminhar.

Um agente de programação com IA pode usar indevidamente minha identidade SSH encaminhada?

A exposição depende do que o agente herdou e do que a conta remota consegue executar. Um agente que pode rodar comandos de shell pode chamar ssh, herdar SSH_AUTH_SOCK ou abrir uma sessão remota que receba um socket encaminhado. Dê ao agente um caminho de acesso remoto criado para essa finalidade, em vez da identidade interativa do desenvolvedor.

O que devo fazer se encaminhei meu agente SSH para um host não confiável?

Primeiro, remova a chave pública exposta dos sistemas onde ela concede acesso ou revogue o certificado, caso você use certificados SSH. Depois, examine os registros de autenticação nesses sistemas e troque a identidade se não for possível delimitar seu uso. Encerrar o agente local impede novas solicitações, mas não desfaz assinaturas já realizadas.

O encaminhamento de agente SSH é seguro em CI?

O encaminhamento pode funcionar em um runner de CI, mas dá à carga de trabalho do runner um caminho para solicitar assinaturas ao agente. Prefira uma credencial de deploy pertencente ao runner, um certificado de curta duração ou um gateway de ações que execute a operação SSH. O runner nunca deve pegar emprestada a identidade diária de um desenvolvedor.

Como verificar se o encaminhamento de agente SSH está ativo?

Execute ssh -G target | grep '^forwardagent ' no cliente para ver a configuração efetiva antes de conectar. No host remoto, uma variável SSH_AUTH_SOCK não vazia e uma saída utilizável de ssh-add -l indicam que há um agente disponível para a sessão. Confira os dois lados ao investigar um caminho suspeito.

Sallyport

O Sallyport executa chamadas de API e comandos SSH pelo seu agente de IA. As chaves ficam em um cofre local no seu Mac; você aprova cada execução e toda ação vai para um registro selado.

© 2026 Sallyport · Código aberto sob Apache-2.0 · Oleg Sotnikov