- o servidor ChatCLI, instalado com o Helm chart
chatcliou gerenciado pelo operator como umaInstance; - o operator, com sua API REST e o dashboard web.
Pré-requisitos
- Helm 3.8 ou mais recente (Helm 4 incluído),
kubectl,openssl. - Um namespace para o servidor (
chatcliabaixo) e permissão para criar Secrets nele. - Para os passos de certificado, o cert-manager ou a sua própria CA.
O modelo de segurança do servidor
Leia antes de escolher as configurações. A tabela explica o que cada controle cobre e o que não cobre.Passo 1: Escolher e criar a credencial
- Token compartilhado
- JWT HS256
- JWT RS256
- mTLS
CHATCLI_SERVER_TOKEN no Secret apontado por secrets.existingSecret, ou defina server.token, que o chart guarda num Secret e nunca passa como argumento de linha de comando. Na Instance: spec.server.token: {name: chatcli-token, key: token}.Passo 2: Certificados TLS
O certificado precisa cobrir o nome que os clientes discam. Uma Instance gerenciada pelo operator é discada como<instance>.<namespace>.svc.cluster.local, o que exige uma CA privada; veja Certificado TLS no setup do AIOps. Para um servidor acessado de fora do cluster por um nome público:
tls.existingSecret monta o Secret em /etc/chatcli/tls, e os caminhos do certificado e da chave assumem /etc/chatcli/tls/tls.crt e /etc/chatcli/tls/tls.key (defina certFile / keyFile só para outros nomes de arquivo). tls.enabled: true sem Secret e sem os dois caminhos faz a instalação falhar, em vez de servir texto puro:
Passo 3: Fazer o deploy do servidor com values endurecidos
Todas as chaves abaixo existem no schema do chart, que recusa chaves desconhecidas. O exemplo usa JWT HS256.RuntimeDefault, e atendem ao Pod Security Standard restricted. As probes usam /healthz na porta de métricas e uma verificação TCP na porta gRPC, que funcionam com TLS ligado.
replicaCount é maior que 1. Várias réplicas num único volume de sessões ReadWriteOnce não conseguem ser agendadas em nós diferentes. Use persistence.accessModes: [ReadWriteMany] com uma storage class que suporte isso, ou fique com uma réplica; ReadWriteOncePod com mais de uma réplica falha o render. Sem ReadWriteMany, o chart para o pod antigo antes de subir o novo a cada rollout (maxSurge: 0, maxUnavailable: 1), então um upgrade tem uma curta interrupção em vez de travar no volume; veja Rollouts no volume de sessões.Passo 4: Trilha de auditoria
ComCHATCLI_AUDIT_LOG_PATH (chart security.auditLogPath, Instance spec.server.security.auditLogPath), o servidor acrescenta uma linha JSON por RPC a um arquivo encadeado por hash. Cada linha registra o horário, a ação e o método, quem chamou (user:<subject> ou anonymous), o papel, o host de origem, o resultado (success, error ou denied) e a duração. O caminho precisa ser absoluto e ficar num volume gravável e persistente, como no passo 3. Numa Instance os únicos caminhos graváveis são volumes emptyDir, perdidos quando o pod reinicia, a menos que você ligue a persistência.
Para conferir que ninguém editou o arquivo, leia do volume (por exemplo, num pod auxiliar que monta o mesmo PVC) e rode, no REPL do chatcli:
AuditEvent, que você lê com kubectl get auditevents -A e exporta por GET /api/v1/audit/export. Ligue o log de auditoria do API server do Kubernetes para saber quem alterou recursos do ChatCLI.
Passo 5: Criptografia em repouso
ComCHATCLI_ENCRYPTION_KEY definido, o servidor criptografa o que grava em ~/.chatcli (sessões, histórico, memória e outros armazenamentos locais). Passe a chave a partir de um Secret, como no passo 3, ou com spec.features.encryptionKeyRef numa Instance. Não use o security.encryptionKey do chart: ele coloca a chave no spec do pod como valor aberto. A rotação está descrita em Segurança.
Passo 6: Controles de agente, pipeline e plugins
Isto só importa se o servidor roda trabalho de agente ou carrega plugins.-
Pipeline.
pipeline.enabled(Instancespec.pipeline.enabled) permite que clientes rodem o coder, o agente e ferramentas no servidor. Essas RPCs exigem papel admin. Deixe desligado a menos que precise. -
Allowlist de comandos.
stricté o modo padrão: só rodam os comandos da allowlist, eCHATCLI_AGENT_ALLOWLISTacrescenta outros (separados por,ou;). A lista embutida inclui shells e interpretadores comobash,python,nodeeeval, então ela não é uma sandbox. Contenha o pod: egress restrito na NetworkPolicy, sem RBAC do chart quando o watcher está desligado (rbac.create: false) e nada sensível nos volumes do pod. -
Plugins. Na carga, todo plugin precisa de uma assinatura destacada (
<plugin>.sig) que confira com uma chave pública em~/.chatcli/trusted-keys/. Plugins sem assinatura, e plugins numa máquina sem nenhuma chave confiável, são ignorados, a menos queCHATCLI_ALLOW_UNSIGNED_PLUGINS=true, que você nunca deve usar em produção. Um plugin cuja assinatura não confere é sempre ignorado.Num pod,~/.chatclié/home/chatcli/.chatcli. Monte as chaves públicas confiáveis em/home/chatcli/.chatcli/trusted-keyscomextraVolumes/extraVolumeMounts. Mantenha a chave privada fora do cluster.
Passo 7: Operator, API REST e dashboard
Chaves de API
X-API-Key, contra o Secret chatcli-operator-secrets (chave api-keys) no namespace do operator. Crie uma chave por time e papel (viewer, operator, admin) e tenha poucas chaves admin. Os comandos estão em Dashboard e chaves da API REST.As chaves são relidas a cada 30 segundos. Para revogar uma, tire-a do Secret. Apagar o Secret e também o ConfigMap chatcli-operator-config revoga todas as chaves em cerca de 30 segundos. Uma edição que deixa YAML inválido não revoga nada: o último conjunto de chaves válido continua em vigor e o operator registra o erro no log. Dê a cada aprovador a sua própria chave e preencha o name dela: as aprovações ficam registradas contra a chave, e um quorum conta cada chave uma vez.Nunca ligue o dev mode
security.devMode: true (CHATCLI_OPERATOR_DEV_MODE) faz a API REST aceitar qualquer chamada como admin enquanto não há chaves carregadas. A variável é lida com semântica booleana, sem diferenciar maiúsculas: true, TRUE, 1 e t a ligam, e o log de startup informa o mesmo modo que a API aplica. Mantenha em false.TLS na API REST
CORS continua fechado
security.corsAllowedOrigins. O dashboard é servido na mesma origem da API e não precisa disso.NetworkPolicy
networkPolicy.enabled: true no chart do operator, restrinja apiIngressFrom e metricsIngressFrom e mantenha egress: restricted. Os values estão no passo 1 do setup do AIOps.RBAC nos recursos do ChatCLI
DrainNode) e atualiza nós. Nenhum admission webhook confere o que os usuários enviam, então o RBAC do Kubernetes é o único controle sobre quem consegue fazer o operator agir. Dê create/update em remediationplans, runbooks, instances, chaosexperiments, approvalrequests e nos tipos de política só a quem deve ter esse poder. O chart pré-provisiona as ClusterRoles chatcli-role-viewer, chatcli-role-operator, chatcli-role-admin e chatcli-role-superadmin; faça os bindings você mesmo, porque nada as vincula automaticamente.Proteções da remediação
security.allowedDiagnosticCommandsacrescenta comandos à allowlist somente leitura doExecDiagnostic; todo o resto é recusado.security.allowedResourceTypesacrescenta tipos que a açãoApplyManifestpode criar. Ele amplia a lista embutida e nunca a restringe.security.logScrubPatternsacrescenta expressões regulares, separadas por vírgula, à limpeza aplicada aos logs e ao contexto que o operator envia ao LLM. Ele não limpa os logs do próprio operator.- Segure as ações arriscadas com uma ApprovalPolicy: veja o passo 9 do setup do AIOps.
Passo 8: Verificar as imagens
As imagens de release são assinadas com cosign (keyless) e trazem atestados de SBOM e proveniência.ghcr.io/diillson/chatcli-operator:1.212.1. Em produção, fixe as tags das imagens, ou os digests, em vez de latest.
Passo 9: Verificar o hardening
Só TLS 1.3, com o nome certo
O health responde sem credencial
-tls-client-cert e -tls-client-key.Chamadas sem credencial são recusadas
ca.crt é a CA do certificado do servidor (dispensável com uma CA pública). $JWT é um token do passo 1.A reflection está desligada
Configurações do pod
Isolamento de rede
As linhas de auditoria são gravadas
/config security verify-audit informa que a cadeia está íntegra.API REST do operator