~/.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 deCHATCLI_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.
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:CHATCLI_ENCRYPTION_KEY abre todo store cifrado com a chave padrão:
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.
/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
Ochatcli 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
extraEnvou por um Secret emenvFromsempre vence: o servidor só lê o Secret da chave quandoCHATCLI_ENCRYPTION_KEYestá vazia. - Para desligar:
security.encryptionAtRest: false(chart) ouspec.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 queCHATCLI_ENCRYPTION_KEY estivesse definida. O primeiro início de uma versão com criptografia ligada por padrão migra seus dados:
- A chave é criada e guardada no keychain.
- Um arquivo
~/.chatcli/.auth-keyexistente é 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-keychainfaz a troca a pedido, depois de conferir a chave do arquivo e guardar o valor do keychain comoauth-key.previous. - 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.
- Quando tudo está cifrado, o ChatCLI registra isso e para de verificar.
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: definaCHATCLI_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:
- Coloque a chave nova em
CHATCLI_ENCRYPTION_KEYe a antiga emCHATCLI_ENCRYPTION_KEY_PREVIOUS(lista separada por vírgulas). - Rode
/config security reseal. Todos os stores são regravados com a chave nova. - Quando ele não reportar erros, remova
CHATCLI_ENCRYPTION_KEY_PREVIOUS.
Desligando
/config security reseal com ela desligada.
Exportações
Exportações são arquivos para levar a outro lugar, então saem em texto puro (modo0600) 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.