Pular para o conteúdo principal
O ChatCLI guarda em disco, sob ~/.chatcli, suas sessões, transcrições, histórico de prompts, memória de longo prazo, contextos de conhecimento e anexos. Tudo isso é cifrado por padrão com AES-256-GCM. Não há nada a configurar: no primeiro início o ChatCLI cria uma chave, guarda no keychain do sistema operacional e cifra todos os stores com ela. Quem copiar seu diretório ~/.chatcli, um backup dele ou a imagem de um disco roubado leva texto cifrado. Suas conversas não vão junto.
A criptografia em repouso protege os dados em disco. Um processo rodando como o seu usuário, com o ChatCLI destravado, ainda lê o que o ChatCLI lê. Ela complementa a criptografia de disco inteiro (FileVault, LUKS, BitLocker), não a substitui.

O que é cifrado

Cada conteúdo cifrado fica vinculado ao próprio caminho e ao tenant (dados autenticados), então um arquivo copiado para outro store ou outro tenant não abre lá. As credenciais em auth-profiles.json (OAuth e API keys) já eram cifradas, com uma chave própria. Essa chave agora também fica no keychain. Não cifrados, de propósito:
  • o contador do orçamento diário, costs/daily-spend.json, que é lido antes de qualquer chave ser necessária;
  • as exportações que você pede (/session export, /memory export, /context export), que são arquivos para levar a outro lugar (veja Exportações);
  • a trilha de auditoria encadeada por hash (CHATCLI_AUDIT_LOG_PATH), selada linha a linha só com uma chave de CHATCLI_ENCRYPTION_KEY: é um arquivo que operadores enviam a um pipeline de logs;
  • os checkpoints do coder, que são cópias dos arquivos do projeto que já estão em disco em texto puro;
  • o diretório de rascunho de uma sessão de agente, que é removido quando a sessão termina.

Onde fica a chave

O ChatCLI guarda um segredo no repositório de credenciais do sistema operacional. A chave que cifra seus dados é derivada dele (HKDF-SHA256), assim como uma chave separada para o store de credenciais. As duas vêm do mesmo segredo, mas são criptograficamente separadas. Onde não há keychain (um servidor, um contêiner, Linux sem secret-tool, ou CHATCLI_KEYCHAIN_BACKEND=file), o segredo fica no arquivo ~/.chatcli/.auth-key, com modo 0600. Os dados continuam cifrados, mas quem copiar esse arquivo junto com os dados consegue abri-los. O /config security avisa nesse caso. Para uma proteção maior ali, defina CHATCLI_ENCRYPTION_KEY a partir de um gerenciador de segredos. Depois que a chave vai para o keychain, um marcador ao lado de onde ficava o arquivo de chave (~/.chatcli/.auth-key.keychain) registra isso. A partir daí o ChatCLI nunca cria uma chave nova para esta instalação: um contexto que não alcança o keychain (uma sessão SSH, um contêiner, um cron com CHATCLI_KEYCHAIN_BACKEND=file) recebe um erro em vez de uma chave nova que deixaria seus dados órfãos, e um arquivo de chave que apareça depois (um backup restaurado) não substitui a chave do keychain. CHATCLI_KEYCHAIN_BACKEND escolhe o store:
  • auto (padrão): o keychain onde houver um, o arquivo nos demais casos.
  • keychain: sempre o keychain.
  • file: sempre o arquivo.
Trocar entre eles nunca muda a chave, então nada quebra e nada se perde. Mudar para file depois que a chave foi para o keychain grava a mesma chave em ~/.chatcli/.auth-key (o item do keychain é mantido), e voltar lê a chave do keychain de novo.

Guarde uma chave de recuperação

O REPL lembra disso uma vez, no primeiro início depois que seus dados são cifrados. O keychain guarda a única cópia da chave padrão. Se ela se perder — sistema reinstalado, keychain resetado, máquina nova — os stores cifrados não abrem mais. Guarde uma cópia fora da máquina uma vez:
O comando mostra a chave de recuperação (só num terminal interativo; ela nunca vai para o log). Guarde-a num gerenciador de senhas, não num arquivo ao lado dos dados. Em qualquer máquina, defini-la como CHATCLI_ENCRYPTION_KEY abre todo store cifrado com a chave padrão:
É também esse valor que um cron, um contêiner ou uma sessão SSH sem acesso ao keychain precisam. Um arquivo de recuperação em vez da chave crua. Se preferir um arquivo que possa ficar num pendrive ou na nuvem:
Ele pede uma senha duas vezes (mínimo de 12 caracteres) e grava a chave de recuperação cifrada com ela (Argon2id + AES-256-GCM). O arquivo não abre nada sem a senha, então guarde os dois em lugares diferentes. Numa máquina nova, ou depois de reinstalar:
Ele pede a senha e move seus dados para a chave do keychain desta máquina; a chave nunca é exibida nem digitada.

Escolhendo a chave você mesmo

CHATCLI_ENCRYPTION_KEY tem precedência sobre o keychain. Use quando a chave precisa vir de fora da máquina:
  • servidores e a gateway em produção;
  • Kubernetes, onde o operator a injeta a partir de um Secret (spec.features.encryptionKeyRef);
  • CI;
  • compartilhar stores cifrados entre máquinas.
Não é um caminho sem volta. O ChatCLI sempre tem a própria chave no keychain, separada da sua. O /config security use-keychain abre cada arquivo com a sua chave e grava de novo com a chave do keychain (ele não copia a sua chave para o keychain); depois disso, remova a variável. O ChatCLI cifra com uma chave por vez (a sua enquanto a variável estiver definida, a do keychain nos demais casos), mas quando um arquivo não abre com essa chave ele tenta a outra, então um arquivo cifrado com qualquer uma das duas continua abrindo. Um segredo com 32 caracteres ou mais é usado diretamente. Um mais curto é tratado como frase-senha e fortalecido com Argon2id. Guarde-o num gerenciador de segredos: dados cifrados com ele não abrem sem ele.
O chatcli server nunca cria uma chave sozinho; no Kubernetes a chave mora num Secret. Veja Kubernetes.

Kubernetes

O chatcli server nunca inventa uma chave sozinho: uma chave criada dentro de um contêiner se perderia no próximo restart, enquanto os stores ficam num volume. No Kubernetes a chave mora num Secret, e a criptografia em repouso fica ligada por padrão nos dois caminhos de implantação.
  • Uma chave fornecida por extraEnv ou por um Secret em envFrom sempre vence: o servidor só lê o Secret da chave quando CHATCLI_ENCRYPTION_KEY está vazia.
  • Para desligar: security.encryptionAtRest: false (chart) ou spec.features.encryptionAtRest: false (operator).
  • Um Secret de chave apagado nunca é substituído pelas suas costas. Se o Secret sumir mas os stores do servidor já tiverem dados cifrados, o servidor não cria chave nova e não sobe; o operator, que registra ter criado o Secret (anotação platform.chatcli.io/atrest-key-created), interrompe o reconcile com um erro em vez de recriá-lo. Restaure o Secret do seu backup para recuperar. Para recomeçar descartando os dados cifrados, apague os stores (e, com o operator, remova a anotação).
  • Faça backup do Secret da chave junto com os dados do PVC (Velero, ou o seu gerenciador de segredos).

Atualizando de uma versão anterior

As versões anteriores gravavam tudo em texto puro, a menos que CHATCLI_ENCRYPTION_KEY estivesse definida. O primeiro início de uma versão com criptografia ligada por padrão migra seus dados:
  1. A chave é criada e guardada no keychain.
  2. Um arquivo ~/.chatcli/.auth-key existente é movido para o keychain quando o keychain ainda não tem chave. O arquivo só é removido depois que o keychain devolve a mesma chave. Se o keychain já tiver uma chave diferente (outra instalação pode depender dela), nada se move automaticamente: o arquivo continua em uso e o keychain fica intocado. O /config security use-keychain faz a troca a pedido, depois de conferir a chave do arquivo e guardar o valor do keychain como auth-key.previous.
  3. Todo store ainda em texto puro é cifrado em segundo plano. Cada arquivo é trocado de forma atômica, então uma passada interrompida não perde nada e o próximo início continua de onde parou.
    • Arquivos modificados nos últimos 10 minutos ficam para o próximo início, porque outra janela do ChatCLI pode estar gravando neles. De todo modo, quem grava cifra os próprios arquivos no próximo save.
    • Comandos curtos (chatcli -p) migram uma parte dos arquivos a cada execução.
  4. Quando tudo está cifrado, o ChatCLI registra isso e para de verificar.
A passada em segundo plano roda só com a chave padrão do keychain. Com CHATCLI_ENCRYPTION_KEY definida (um servidor, o operator, ou você que já tinha ativado antes), nada é regravado pelas suas costas: cada store é cifrado no próximo save, e o /config security reseal cifra o resto quando você pedir. A passada só mexe nos arquivos que cada store lê cifrados; uma exportação, uma nota ou um repositório que você guarde nessas pastas fica intocado, e cada arquivo mantém a data de modificação. Seus dados continuam abrindo durante e depois da migração: um arquivo em texto puro é lido como está e cifrado no próximo save. Para cifrar tudo de uma vez em vez de esperar, rode:
Uma versão anterior do ChatCLI não lê os stores cifrados: ela não sabe onde a chave está. Para voltar a uma delas, primeiro regrave os stores em texto puro com a versão nova:
Com a criptografia desligada, o reseal decifra os stores em vez de cifrá-los. Depois instale a versão anterior, e mantenha CHATCLI_ENCRYPTION_KEY=off enquanto usar a nova.

Verificando o estado

O /config security mostra: Indisponível significa que a chave não pôde ser lida: um keychain do macOS travado numa sessão SSH, ou um Linux com secret-tool mas sem sessão de desktop. O ChatCLI então grava os dados novos em texto puro e não abre os arquivos cifrados até a chave voltar a ficar acessível. Ele nunca gera uma chave nova nesse estado, porque uma chave nova deixaria órfãos os dados cifrados com a antiga. Destrave o keychain, ou defina CHATCLI_KEYCHAIN_BACKEND=file em máquinas que nunca têm sessão de desktop.

Rotacionando a chave

Da chave padrão do keychain para uma chave sua: defina CHATCLI_ENCRYPTION_KEY e rode /config security reseal. A chave do keychain continua abrindo o que cifrou, e o reseal move todos os stores para a chave nova. De uma chave sua de volta para a chave do keychain: com CHATCLI_ENCRYPTION_KEY ainda definida, rode /config security use-keychain. Ele cifra de novo todos os stores com a chave do keychain (a sua chave não é copiada para lugar nenhum); depois remova a variável do seu ambiente. Se esquecer de remover, nada quebra: os dados novos voltam a ser cifrados com a sua chave, e os arquivos cifrados com qualquer uma das duas continuam abrindo. De uma CHATCLI_ENCRYPTION_KEY para outra:
  1. Coloque a chave nova em CHATCLI_ENCRYPTION_KEY e a antiga em CHATCLI_ENCRYPTION_KEY_PREVIOUS (lista separada por vírgulas).
  2. Rode /config security reseal. Todos os stores são regravados com a chave nova.
  3. Quando ele não reportar erros, remova CHATCLI_ENCRYPTION_KEY_PREVIOUS.

Desligando

As gravações novas saem em texto puro. Os arquivos que já estavam cifrados continuam abrindo com a chave do keychain, então desligar a criptografia nunca te tranca para fora dos seus próprios dados. Para regravar também os stores existentes em texto puro, rode /config security reseal com ela desligada.

Exportações

Exportações são arquivos para levar a outro lugar, então saem em texto puro (modo 0600) e o comando avisa: Uma exportação em texto puro importa em qualquer lugar. Guarde-a com o mesmo cuidado que os dados que ela contém e apague-a quando não precisar mais.

Relacionados

Para o que fazer quando algo dá errado — keychain travado, máquina nova, um cron, um downgrade — veja Dados cifrados: proteger e recuperar.

Visão geral de segurança

Cada camada de proteção e o seu estado.

Gerenciamento de sessões

Sessões, autosave e o journal de transcrição.