Skip to main content
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. 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.
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.

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.
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.

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


Configuração

Cada variável de ambiente, por componente.

Implantação

Dependências, retenção no armazenamento, escala e checagens de inicialização.

Observabilidade

Sondas, comportamento de drenagem, métricas e tracing.

Conexões

Registre, teste e use uma conexão.