> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Segurança do Fetcher

> O modelo de segurança do Fetcher: uma chave-mestra expandida em quatro chaves derivadas, mensagens assinadas amarradas ao tenant e à rota, criptografia de credenciais e de resultados, validação de host e isolamento de tenant.

O Fetcher guarda credenciais de bancos de dados que ele não possui, e movimenta linhas que saíram deles. Esta página descreve o que protege cada uma dessas coisas, e o que cabe ao operador fazer.

## Uma chave-mestra, quatro chaves derivadas

***

`APP_ENC_KEY` é a única chave que você fornece. Gere-a com `make generate-master-key`, que produz um valor de 32 bytes codificado em base64. Defina o mesmo valor no Manager e no Worker.

O Fetcher nunca usa essa chave diretamente. Ele a expande com HKDF-SHA256 (RFC 5869) em quatro chaves independentes, uma por finalidade.

| Chave derivada                | Usada para                                                             | Rótulo de derivação             |
| ----------------------------- | ---------------------------------------------------------------------- | ------------------------------- |
| Credencial                    | Criptografia AES-256-GCM das senhas de fontes de dados em repouso.     | `fetcher-credentials-v1`        |
| HMAC interno                  | Assinatura de toda mensagem entre o Manager e o Worker.                | `fetcher-internal-hmac-v1`      |
| HMAC externo                  | Assinatura dos resultados de extração, para verificação por terceiros. | `fetcher-external-hmac-v1`      |
| Criptografia de armazenamento | Criptografia AES-GCM do resultado armazenado.                          | `fetcher-storage-encryption-v1` |

A separação é o ponto. Um consumidor que tem a chave externa consegue conferir a assinatura de um resultado. Ele não consegue descriptografar uma credencial armazenada, e não consegue forjar uma mensagem entre os dois serviços.

<Warning>
  **Uma chave-mestra ruim interrompe o serviço.** Uma chave não definida, um base64 inválido ou um valor com menos de 32 bytes encerra o processo na inicialização. O log traz `master key too short: got 0 bytes, minimum 32 required`. O Fetcher não tem fallback em texto claro.
</Warning>

## Versão de chave e rotação

***

`APP_ENC_KEY_VERSION` rotula a chave em vigor. Todo registro de conexão guarda a versão que criptografou a senha dele, então o operador sabe a qual chave um registro pertence. Incremente a versão quando trocar a chave-mestra.

Duas consequências acompanham uma troca de chave-mestra:

1. **Credenciais armazenadas.** Uma conexão criptografada sob a chave anterior pertence à chave anterior. Registre essas conexões de novo sob a nova chave.
2. **Verificação externa.** A chave HMAC externa muda junto com a chave-mestra. Derive a nova chave e entregue-a a todo consumidor que confere assinaturas. Resultados anteriores verificam contra a chave anterior.

Gere a chave externa com `make derive-key KEY="<sua-chave-mestra-base64>"`. A ferramenta também lê `APP_ENC_KEY` do ambiente, ou a chave da entrada padrão, e imprime uma chave hexadecimal de 64 caracteres.

## Credenciais em repouso

***

Uma senha de fonte de dados nunca chega ao MongoDB em texto claro. O Manager a criptografa com AES-256-GCM sob a chave de credencial derivada, e então armazena o texto cifrado e a versão da chave.

Fontes de dados internas declaradas por `DATASOURCE_{NAME}_*` são a exceção deliberada. Elas vêm do ambiente do próprio operador, e o Fetcher as marca como internas com uma versão de chave vazia.

## Resultados em repouso

***

O Worker protege um resultado armazenado em dois passos:

1. Ele assina o JSON em texto claro com HMAC-SHA256 sob a chave externa derivada, e registra o algoritmo e a assinatura junto com o resultado.
2. Ele criptografa o payload com AES-GCM sob a chave de armazenamento derivada, com um nonce aleatório novo de 12 bytes, e armazena o resultado codificado em base64.

A assinatura cobre o texto claro, então um consumidor verifica os dados que recebeu, e não o envelope em volta deles. O repositório traz um guia de verificação em `scripts/crypto/derive-key/verification-guide.md`.

O modo direct devolve as linhas inline, sem criptografia. O Engine as reporta como texto claro e anexa um digest SHA-256 sobre os bytes exatos.

## Mensagens assinadas entre os serviços

***

Toda mensagem RabbitMQ que o Manager publica para o Worker carrega uma assinatura HMAC-SHA256 sob a chave interna derivada. A assinatura cobre mais do que o corpo. Ela amarra:

* o timestamp e a versão da assinatura,
* o identificador do tenant,
* o identificador do job,
* o exchange e a routing key,
* o corpo da mensagem.

Esse amarramento é o que barra o replay. Uma mensagem capturada e reenviada sob outro tenant falha na verificação, porque a assinatura cobre o identificador do tenant. A mesma mensagem reenviada em outro exchange ou outra routing key falha pelo mesmo motivo. O publicador também remove qualquer header de segurança fornecido por quem chama antes de assinar, então um cliente não consegue injetar o próprio.

O assinador recusa uma chave menor que 32 bytes, e compara assinaturas em tempo constante.

## Validação de host da fonte de dados

***

Um tenant que registra a própria conexão poderia apontá-la para a sua rede interna. Com `MULTI_TENANT_ENABLED=true`, o Fetcher checa o host antes de conectar.

A validação roda em duas camadas:

1. **Na leitura da requisição.** O Fetcher rejeita um literal de IP em uma faixa bloqueada, sem consulta de DNS.
2. **Na fábrica de fontes de dados.** O Fetcher checa o hostname contra uma blocklist que cobre `localhost`, nomes de metadados de nuvem e os sufixos `.local`, `.internal` e `.cluster.local`. Ele então resolve o hostname e checa todos os endereços que recebe de volta.

O Fetcher recusa um host bloqueado com um erro de host proibido. As faixas bloqueadas cobrem endereços de loopback, privados e de metadados de nuvem, e vivem em `lib-commons`, então todo produto Lerian compartilha uma lista só.

Fontes de dados internas configuradas pelo operador são isentas por construção. Elas vêm do seu ambiente, e não de uma requisição de tenant.

## Isolamento de tenant

***

O Engine coloca toda operação sob o escopo do identificador de tenant, e esse identificador é a única fronteira de isolamento que ele tem. Um identificador de tenant malformado falha antes de o Fetcher tocar qualquer recurso.

Em modo multi-tenant, cada tenant recebe o próprio banco de metadados, resolvido a partir das claims do JWT na requisição pelo middleware de tenant. O acesso falha de forma fechada. Uma requisição que carrega uma identidade de tenant sem banco de tenant resolvido retorna um erro em vez de ler o banco compartilhado.

<Warning>
  **A multi-tenancy exige autenticação.** O roteador do Manager se recusa a subir quando um middleware de tenant roda com a autenticação desligada, e reporta `tenant middleware requires effective authentication`. Ele também recusa quando `PLUGIN_AUTH_ENABLED=true` e o endereço de autenticação está em branco. Nos dois casos o serviço não inicia.
</Warning>

## Autenticação e superfícies de sonda

***

`PLUGIN_AUTH_ENABLED=true` coloca o middleware do Access Manager na frente da API. As requisições passam a carregar um bearer token, e o Fetcher autoriza cada operação contra um recurso e uma ação.

`/health`, `/readyz`, `/readyz/tenant/:id`, `/metrics` e `/version` montam antes desse middleware, então as sondas do Kubernetes e do balanceador de carga seguem sem autenticação.

## Erros nunca vazam material de conexão

***

O Fetcher descarta o erro bruto do driver na fronteira do Engine e devolve uma mensagem fixa no lugar. Um erro bruto de driver pode embutir uma DSN ou uma credencial, então quem chama vê `failed to connect to datasource` em vez da string que o driver produziu.

As falhas chegam classificadas em categorias estáveis — validação, não autorizado, proibido, limite excedido, conexão, tempo limite e outras — então um hospedeiro as mapeia para os próprios códigos de status sem interpretar texto.

## Próximos passos

***

<CardGroup cols={2}>
  <Card title="Configuração" icon="gear" href="/pt/fetcher/fetcher-configuration">
    Cada variável de ambiente, por componente.
  </Card>

  <Card title="Implantação" icon="server" href="/pt/fetcher/fetcher-deployment">
    Dependências, retenção no armazenamento, escala e checagens de inicialização.
  </Card>

  <Card title="Observabilidade" icon="chart-line" href="/pt/fetcher/fetcher-observability">
    Sondas, comportamento de drenagem, métricas e tracing.
  </Card>

  <Card title="Conexões" icon="plug" href="/pt/fetcher/fetcher-connections">
    Registre, teste e use uma conexão.
  </Card>
</CardGroup>
