Pular para o conteúdo principal
Este guia realiza o deploy completo do stack do AgentEye em um cluster Kubernetes dedicado:
  • ClickHouse 24.8 — armazenamento canônico de eventos e análises de avaliações (StatefulSet com volume persistente de 100Gi). Obrigatório: o servidor se recusa a iniciar sem ele.
  • PostgreSQL 16 — armazenamento relacional/de metadados para organizações, chaves de API, usuários, dashboards, consultas salvas e autenticação (StatefulSet com volume persistente de 50Gi)
  • Redis 7.2 — cache compartilhado e backend de rate-limit opcionais; o servidor e o dashboard degradam de forma elegante se estiver indisponível
  • AgentEye Server — API em Rust para ingestão de eventos, analytics e gerenciamento de chaves (2 réplicas)
  • AgentEye Dashboard — UI web em Next.js (2 réplicas)
  • AI assistant (serviço agent) — assistente opcional somente leitura no dashboard, na porta 9100; inativo até que um endpoint LLM seja configurado
  • Traefik (público) — controlador de ingress para tráfego do coletor, protegido com mTLS
  • Traefik (dashboard) — controlador de ingress para o dashboard, restrito a VPN/lista de IPs permitidos
  • cert-manager — certificados TLS e CA para mTLS
  • Backup CronJob — dump combinado diário de PostgreSQL + ClickHouse às 03:00 UTC
  • Cert Renewal Monitor — alertas quando certificados de cliente estão próximos do vencimento
Tempo estimado: 60—90 minutos para um primeiro deploy. Para o modelo de deploy gerenciado, onde a Exosphere cuida de tudo isso em seu nome, consulte enterprise-docs/managed-deployment.md.

Pré-requisitos

Execute cada comando de verificação antes de começar. Todas as verificações devem passar.
RequisitoMínimoComando de VerificaçãoEsperado
Cluster Kubernetes1.27+kubectl versionServer Version >= v1.27
Kustomize (incluído no kubectl)Kustomize v1.14+ (incluso no kubectl 1.27+)kubectl kustomize --helpExibe texto de uso
Helmv3helm versionVersion:"v3.x.x"
RBAC cluster-adminkubectl auth can-i create namespacesyes
StorageClass padrãokubectl get storageclassPelo menos uma linha marcada como (default)
Suporte a LoadBalancerDependente do cloud (EKS, GKE, AKS oferecem suporte por padrão)
GitHub PATecho $AGENTEYE_TOKENNão vazio (consulte enterprise-docs/github-token.md)
opensslopenssl versionOpenSSL 1.x ou 3.x
Bucket de armazenamento em nuvemPara backups de PostgreSQL + ClickHouse (S3, GCS ou Azure Blob)
Dimensionamento do cluster: Mínimo de 3 nós, 4 vCPU / 8 GB RAM cada. Consulte enterprise-docs/managed-deployment.md para os requisitos completos.

Executar todas as verificações de uma vez

Formato do deploy

O endpoint de ingestão é servido em um hostname que você controla (ex.: ingest.sua-empresa.example). O cert-manager solicita um certificado TLS publicamente confiável da Let’s Encrypt via HTTP-01, de modo que os coletores verificam o certificado do servidor em relação ao repositório de confiança do sistema, sem fixação de CA por cliente. O endpoint do dashboard funciona da mesma forma: é servido em um segundo hostname que você controla (ex.: agenteye.sua-empresa.example), apontando para o LoadBalancer do Traefik do dashboard, e o cert-manager emite o certificado Let’s Encrypt por meio desse LoadBalancer. Os navegadores recebem um certificado confiável sem avisos.
A emissão e renovação de certificados são validadas via HTTP-01, portanto ambos os LoadBalancers devem estar acessíveis pela internet pública na porta 80. Se você precisar restringir o LoadBalancer do dashboard por IP, coordene previamente um solver DNS-01 com o suporte — caso contrário, as renovações falham silenciosamente e o certificado expira.

Obter os Manifestos

Teste:
Esperado: o arquivo existe. Se não existir, o clone falhou — verifique seu AGENTEYE_TOKEN. Estrutura de diretórios:
A base contém todos os recursos necessários para um deploy completo, incluindo os certificados Let’s Encrypt para os dois hostnames públicos que você configura na Fase 3.1. Um overlay modifica a base para um ambiente específico (ex.: tags de imagem personalizadas, limites de recursos, configuração de variáveis de ambiente). O diretório third-party contém arquivos de valores Helm para infraestrutura externa.
Monitoramento de saúde (opcional): a probe de readiness do servidor já reflete a saúde do Postgres + ClickHouse, e third-party/robusta/ adiciona alertas de falha de pod nativos do Kubernetes para o Slack, de forma opcional. Consulte enterprise-docs/health-monitoring.md.

Fase 1 — Infraestrutura de Terceiros (~30 min)

1.1 Instalar o cert-manager

O cert-manager gerencia os certificados TLS para HTTPS e a CA privada usada para certificados de cliente mTLS.
Teste:
Esperado: 3 pods todos em Runningcert-manager, cert-manager-cainjector, cert-manager-webhook.
Esperado: pelo menos certificates.cert-manager.io, clusterissuers.cert-manager.io, issuers.cert-manager.io. Se falhar: Pods em CrashLoopBackOff geralmente indicam que os CRDs não foram instalados. Execute novamente com --set crds.install=true. Se os pods do webhook falharem na readiness, aguarde 30 segundos e verifique novamente — eles podem levar um momento para iniciar.

1.2 Instalar o Traefik — Controlador de Ingestão Público

Esta instância do Traefik lida com o tráfego dos coletores em um LoadBalancer externo. Ela encerra o TLS e aplica o mTLS (verificação de certificado de cliente) no endpoint de ingestão.
Teste:
Esperado: 1 pod em Running.
Esperado: a IngressClass existe (não é a classe padrão). Se falhar: Verifique kubectl describe pod -n traefik-public <pod-name> para erros de pull de imagem ou restrições de recursos.

1.3 Instalar o Traefik — Controlador do Dashboard

Esta instância do Traefik serve o dashboard em um LoadBalancer dedicado, restrito por lista de IPs permitidos.
Dois mecanismos de lista de permissões estão disponíveis para esta instância. Este guia usa values-dashboard.yaml, que restringe o acesso com o campo portável service.loadBalancerSourceRanges. Um values-internal.yaml paralelo também é fornecido para ambientes AWS que preferem a anotação service.beta.kubernetes.io/aws-load-balancer-source-ranges. Escolha um e use-o de forma consistente; os passos abaixo assumem values-dashboard.yaml.
Antes de instalar, edite third-party/traefik/values-dashboard.yaml para definir os IPs de origem permitidos. O campo loadBalancerSourceRanges controla quais IPs podem acessar o dashboard. Por padrão, está definido como 0.0.0.0/0 (todos os IPs); restrinja-o à sua VPN, escritório ou IPs de egresso conhecidos.

Permitir um único IP

Permitir múltiplos IPs

Adicione uma entrada por IP ou bloco CIDR. O sufixo /32 corresponde a um único endereço IPv4; um bloco CIDR (ex.: /24) corresponde a um intervalo. Você pode misturar IPs individuais e intervalos livremente:
Dicas ao manter a lista:
  • Mantenha uma entrada por linha e adicione um comentário curto # identificando o proprietário ou a finalidade de cada IP; é isso que os operadores futuros usam para decidir se uma entrada ainda é necessária.
  • Sempre use notação CIDR. Um IP sem sufixo como 203.0.113.10 é rejeitado pelo provedor de nuvem; use 203.0.113.10/32.
  • Para intervalos IPv6, use o equivalente /128 (endereço único) ou CIDR maior, ex.: 2001:db8::1/128. Nem todos os provedores de nuvem suportam intervalos de origem IPv6; consulte a documentação do LoadBalancer do seu provedor.
  • A lista funciona como um OR: o tráfego é permitido se a origem corresponder a qualquer entrada.
Após editar o arquivo, prossiga para o helm install abaixo. Se o controlador já estiver instalado, execute helm upgrade com os mesmos parâmetros ou faça um patch no Service em tempo de execução (próxima seção).

Atualizar a lista de permissões em tempo de execução

Você pode alterar os IPs permitidos sem um upgrade do Helm fazendo um patch diretamente no Service. O patch substitui a lista inteira; sempre inclua todos os IPs que deseja manter, não apenas o novo. Para substituir a lista por um novo conjunto de IPs:
Para adicionar um IP com segurança sem perder as entradas existentes, leia a lista atual primeiro e depois faça o patch com o conjunto combinado:
Patches em tempo de execução não são persistidos de volta em values-dashboard.yaml. Para manter a alteração em futuros upgrades do Helm, atualize também o arquivo de valores e faça o commit.
Em seguida, instale:
Teste:
Esperado: 1 pod em Running.
Esperado: a IngressClass existe.

1.4 Aguardar os LoadBalancers

Ambas as instâncias do Traefik precisam de IPs externos antes de prosseguir.
Teste: Ambos os serviços exibem um EXTERNAL-IP (não <pending>). Se ainda estiver pendente, observe a atribuição:
Pressione Ctrl+C quando o IP aparecer. A atribuição de IP geralmente leva 2—5 minutos. Se falhar: <pending> após 10 minutos geralmente indica que o provedor de nuvem não consegue provisionar um LoadBalancer. Verifique: tags de sub-rede (o EKS requer kubernetes.io/role/elb), configuração da VPC, cotas de serviço e se a anotação correta de LB interno está definida para a instância interna.

Fase 2 — Criar Secrets (~10 min)

Todos os secrets são criados manualmente antes do deploy da aplicação. Isso garante que valores sensíveis nunca apareçam em arquivos de manifesto.

2.1 Criar o namespace

Teste:
Esperado: status Active.

2.2 Secret de pull de imagem

Este secret autentica com ghcr.io para fazer pull das imagens de container do AgentEye. Consulte enterprise-docs/github-token.md para saber como gerar seu PAT.
Teste:
Esperado: kubernetes.io/dockerconfigjson. Teste (detalhado) — verifique se o token consegue de fato fazer pull das imagens: Use a tag de imagem do server fixada no kustomization.yaml do seu overlay (atualmente v0.0.1-beta.48 tanto no overlay acme incluído quanto no deploy base). Substitua a tag abaixo pela que você está implantando para que esta verificação não fique desatualizada entre releases:
Esperado: ok impresso nos logs. Se falhar: ErrImagePull ou 401 Unauthorized significa que o PAT é inválido ou não tem o escopo read:packages. Verifique novamente enterprise-docs/github-token.md.

2.3 Credenciais do PostgreSQL

Importante: Usamos -hex (não -base64) para gerar a senha. A saída Base64 pode conter +, / e =, que quebram a string de conexão DATABASE_URL. Consulte enterprise-docs/troubleshooting.md para mais detalhes.
Armazene POSTGRES_PASSWORD no seu gerenciador de secrets imediatamente. Você precisará dele se precisar restaurar a partir de um backup ou conectar diretamente ao banco de dados.
Teste:
Esperado: o secret existe.
Esperado: 48 (24 bytes hex = 48 caracteres).

2.4 Chave de API admin

A chave admin é a credencial de bootstrap. O servidor a registra (upsert) a cada inicialização com todas as permissões. Use-a para criar chaves de coletor com escopo na Fase 7. Consulte enterprise-docs/api-keys.md para o modelo completo de permissões.
Armazene ADMIN_KEY no seu gerenciador de secrets imediatamente.
Teste:
Esperado: o secret existe.

2.5 Configuração de autenticação (login no dashboard)

O dashboard usa email + OTP para login de usuários. Sem este secret, o servidor ainda inicia e o caminho de API com ADMIN_KEY continua funcionando, mas nenhum usuário pode fazer login pela UI. Todas as chaves são referenciadas como optional: true no manifesto base, portanto secrets parciais (ou nenhum secret) são aceitáveis; o servidor utiliza os padrões documentados como fallback. Agrupar tudo em um único secret agenteye-auth mantém a superfície de autenticação rotacionável em um único lugar.
ChaveFinalidade
ADMIN_EMAILUsuário admin de bootstrap. Registrado (upsert) a cada inicialização com todas as permissões e protegido contra exclusão/edição de permissões via dashboard. Sem ele, nenhum admin é criado e o primeiro login é impossível.
ALLOWED_EMAILSLista de permissões separada por vírgulas. Suporta endereços exatos (user@example.com) e curingas de domínio (*@example.com). Sem ela, nenhum usuário pode fazer login ou ser criado.
SMTP_HOST, SMTP_PORT, SMTP_USERNAME, SMTP_PASSWORD, SMTP_FROMRelay SMTP para envio de códigos OTP. Se SMTP_HOST não estiver definido, os códigos OTP são registrados no stdout do servidor em vez de enviados por email (útil para testes iniciais). Forneça todas as chaves SMTP juntas para entrega real de emails.
SMTP_TLSUm de starttls (padrão), tls ou none.
DEFAULT_ORG_NAME, DEFAULT_ORG_SLUGOpcional. Dê à organização default integrada um nome de exibição amigável e slug de URL para que fique em ex.: /acme em vez de /default. Aplicado apenas na primeira inicialização; depois de renomear a organização com agenteye-orgctl org rename (ver §7.6), esses valores são ignorados. O slug deve ter 1—40 caracteres alfanuméricos minúsculos com hífens internos simples. Deixe ambos sem definir para manter o default genérico.
Armazene as credenciais SMTP no seu gerenciador de secrets.
Teste:
Esperado: as chaves que você preencheu aparecem na saída.

2.6 Chave de isolamento de organização multi-tenant (opcional)

Pule esta etapa para um deploy single-tenant; o servidor roda com um padrão de desenvolvimento integrado e serve bem a única organização default. Antes de criar uma segunda organização, defina um ORG_CH_SECRET forte e estável: a senha do ClickHouse de cada organização é derivada como HMAC(ORG_CH_SECRET, org_id), portanto o padrão de desenvolvimento público resultaria em credenciais por organização deriváveis publicamente. O comando agenteye-orgctl org create (ver §7.6 Provisionar organizações) se recusa a executar enquanto o servidor ainda estiver usando o padrão de desenvolvimento integrado.
O servidor lê isso via uma secretKeyRef opcional, portanto um cluster single-tenant que nunca o criar ainda inicializa normalmente. Mantenha o valor estável e idêntico em todas as réplicas; rotacioná-lo invalida a senha ClickHouse derivada de cada organização até que a reconciliação na inicialização reprovisionne os usuários (um rolling restart com o valor consistente em todos os lugares resolve). Consulte deploy/base/server/secret.example.yaml.
Armazene ORG_CH_SECRET no seu gerenciador de secrets e não o rotacione sem necessidade.

2.7 Verificar todos os secrets

Saída esperada (entre quaisquer secrets padrão):
Os quatro secrets principais (agenteye-admin-key, agenteye-auth, agenteye-image-pull, agenteye-postgres) devem estar presentes antes de continuar. agenteye-org-ch-secret é necessário apenas para deploys multi-tenant (ver §2.6).

Fase 3 — Deploy da Aplicação (~5 min)

3.1 Configurar os hostnames públicos

O cert-manager precisa dos hostnames de ingestão e do dashboard antes de poder solicitar os certificados Let’s Encrypt. Copie o template e defina ambos:
domain.env está no .gitignore; fica local a cada deploy. O build do kustomize falha explicitamente se alguma das chaves estiver ausente.
O DNS deve resolver primeiro. Você não precisa apontar o DNS para os LBs agora (eles não existem até que a Fase 1.2 esteja concluída), mas a emissão ACME no passo 3.2 continuará tentando até que cada hostname resolva para seu LoadBalancer. Você pode definir o DNS agora (usando os hostnames dos LBs capturados na Fase 1.4) ou prosseguir e adicionar os registros na Fase 4.

3.2 Aplicar os manifestos

Aplique a base diretamente para uma instalação nova, ou um overlay se você já criou um para este ambiente (overlays apenas fixam tags de imagem, variáveis de ambiente e limites de recursos; eles herdam os certs e o roteamento da base):
O overlay inclui a base automaticamente; aplique um, não ambos.

3.3 Aguardar os pods

A espera está limitada aos pods principais do data-plane. Os pods opcionais agent (assistente de IA) e redis sobem junto com eles; o assistente permanece inativo até que você forneça seu endpoint LLM (consulte enterprise-docs/assistant.md), e o Redis é um cache de melhor esforço, portanto nenhum dos dois precisa estar Ready para a plataforma servir tráfego. Teste:
Esperado (os pods opcionais agent e redis também aparecem e atingem Running):
Se falhar:
Status do PodCausa ProvávelComando de Debug
ImagePullBackOffSecret de pull de imagem inválido ou PAT incorretokubectl describe pod <name> -n agenteye
CrashLoopBackOffVariáveis de ambiente incorretas (ex.: DATABASE_URL)kubectl logs <name> -n agenteye
PendingCPU/memória insuficiente ou sem nós disponíveiskubectl describe pod <name> -n agenteye (verifique Events)

3.4 Verificar armazenamento

Esperado, ambos com status Bound:
PVCCapacidadeUtilizado por
postgres-data-postgres-050GiArmazenamento relacional/de metadados do PostgreSQL
clickhouse-data-clickhouse-0100GiArmazenamento de analytics de eventos + avaliações do ClickHouse
Um PVC redis-data-redis-0 (1Gi) também aparece para o cache opcional. Se falhar: Pending significa que nenhuma StorageClass consegue provisionar o volume. Verifique kubectl get storageclass e assegure que existe uma padrão. Para produção, utilize no overlay uma StorageClass de SSD rápido para o volume do ClickHouse (ex.: gp3 na AWS, pd-ssd no GCP); o throughput de compactação sofre com discos lentos.

3.5 Verificar certificados

Esperado: 3 certificados, todos Ready: True:
NomeEmissorFinalidade
mtls-caselfsignedCA privada para emissão de certificados de cliente mTLS (validade de 10 anos)
ingest-tlsletsencrypt-prodCertificado TLS público para o endpoint de ingestão (90 dias, renovação automática)
dashboard-tlsletsencrypt-prodCertificado TLS público para o dashboard (90 dias, renovação automática)
Se ingest-tls ou dashboard-tls não estiver Ready: Execute kubectl describe certificate <name> -n agenteye e leia os Events. As causas comuns são:
  • DNS ainda não aponta para o LB. A Let’s Encrypt resolve o hostname e acessa a porta 80 para validar — INGEST_DOMAIN deve resolver para o LB público e DASHBOARD_DOMAIN para o LB do dashboard. Enquanto o CNAME/Alias não propagar, o pedido fica pending. Quando o DNS estiver correto, o cert-manager tenta novamente automaticamente (não é necessário excluir o Certificate).
  • Hostname não substituído. Se dnsNames ainda exibe INGEST_DOMAIN_PLACEHOLDER / DASHBOARD_DOMAIN_PLACEHOLDER, você pulou o passo 3.1 — crie base/certificates/domain.env e aplique novamente.
  • O Traefik do dashboard não consegue servir o desafio (somente para dashboard-tls). A instância do Traefik do dashboard deve ser instalada com o arquivo de valores incluído (Fase 1.2), que habilita o provedor de Ingress com escopo que serve o solver HTTP-01 do cert-manager. Uma instância instalada sem ele deixa o desafio sem rota e o pedido pending indefinidamente.
Se mtls-ca não estiver Ready: o próprio cert-manager está com problemas. Verifique novamente os pods do cert-manager do passo 1.1.

3.6 Verificar CronJobs

Esperado:
NomeAgendamentoFinalidade
agenteye-backup0 3 * * *Backup diário de Postgres + ClickHouse às 03:00 UTC
cert-renewal-check0 3,15 * * *Alertas de vencimento de certificado às 03:00 e 15:00 UTC

3.7 Verificar se o servidor iniciou corretamente

Teste: Procure por uma linha de inicialização indicando que o servidor está escutando na porta 8080. Não deve haver erros de conexão com o banco de dados (o servidor requer que tanto o PostgreSQL quanto o ClickHouse estejam acessíveis antes de reportar Ready). Se falhar: A causa mais comum é um POSTGRES_PASSWORD contendo caracteres não seguros para URL que quebram o DATABASE_URL. Consulte enterprise-docs/troubleshooting.md.

3.8 Verificar se o dashboard conectou ao servidor

Teste: Procure por Ready na saída sem erros ECONNREFUSED ou similares. Se falhar: Verifique se o Service server existe (kubectl get svc server -n agenteye) e se AGENTEYE_SERVER_URL está definido como http://server:8080 no deployment do dashboard.

Fase 4 — Acesso à Rede (~5 min)

4.1 Obter os endereços dos LoadBalancers

No AWS EKS, os LoadBalancers retornam um hostname em vez de um IP. Substitua .ip por .hostname nos comandos acima.
Teste:
Ambos devem ser não vazios.

4.2 Apontar o DNS para os LoadBalancers

Crie registros DNS para que os hostnames de base/certificates/domain.env resolvam para seus LoadBalancers — INGEST_DOMAIN para o LB Traefik público e DASHBOARD_DOMAIN para o LB Traefik do dashboard:
  • AWS Route 53: Registro A com Alias = Yes, alvo = o hostname do LB. Não use A → IP simples; os IPs do ELB são rotacionados.
  • Qualquer outro provedor: CNAME do hostname para o hostname do LB.
Verifique:
Deve retornar os mesmos endereços que $PUBLIC_IP e $INTERNAL_IP respectivamente (ou, no EKS, resolver para os mesmos hostnames *.elb.amazonaws.com). Quando o DNS resolver, o cert-manager concluirá os pedidos ACME pendentes da Fase 3.5 em um minuto. Execute novamente kubectl get certificates -n agenteye até que tanto ingest-tls quanto dashboard-tls exibam Ready: True.

4.3 Acessar o endpoint de ingestão

O endpoint de ingestão público aplica mutual TLS, portanto toda requisição (incluindo /health) deve apresentar um certificado de cliente. Você emite seu primeiro certificado de cliente na Fase 5; se você já tiver um, verifique a acessibilidade agora:
Esperado: {"status":"ok"}. O -k não é necessário — o certificado do servidor encadeia para uma CA pública para INGEST_DOMAIN, portanto valida em relação ao repositório de confiança do sistema. Acesse o endpoint de ingestão pelo hostname INGEST_DOMAIN (que corresponde ao certificado emitido), não pelo IP/hostname bruto do LoadBalancer. O endpoint do dashboard é servido em DASHBOARD_DOMAIN com um certificado publicamente confiável e não está atrás de mTLS, portanto nenhum -k e nenhum certificado de cliente são necessários:
Acesse o dashboard pelo seu hostname, não pelo endereço bruto do LB — o certificado está vinculado a DASHBOARD_DOMAIN, portanto o endereço bruto exibe um erro de incompatibilidade de nome de certificado. Se falhar: Se o curl travar, verifique se o LB está acessível a partir da sua máquina (VPN, grupos de segurança, regras de firewall). Um erro de handshake certificate required no hostname de ingestão significa que nenhum certificado de cliente foi apresentado; conclua a Fase 5 primeiro. Um erro de validação TLS no hostname de ingestão significa que o certificado do servidor ainda não terminou de ser emitido; volte à Fase 3.5 e resolva o problema lá.

Fase 5 — Emitir Certificados de Cliente mTLS (~10 min por cluster)

Os coletores se autenticam com dois fatores: um certificado de cliente (camada de transporte, prova que a requisição vem de um cluster autorizado) e uma chave de API (camada de aplicação, prova que a requisição é de um coletor com permissão events:add). Uma chave vazada é inútil sem o certificado; um certificado roubado é inútil sem uma chave válida.

5.1 Emitir um certificado

Cada cluster que executa coletores precisa do seu próprio certificado de cliente. No diretório dos manifestos:
Substitua <cluster-name> por um identificador significativo (ex.: us-east-1-prod, staging). Teste: O script exibe ==> Done! e lista os arquivos de saída.
Esperado: Ready: True. Arquivos de saída em issued/<cluster-name>/:
ArquivoFinalidade
client.crtCertificado de cliente (validade de 90 dias)
client.keyChave privada do cliente
ca.crtCertificado CA para verificação do servidor
collector-mtls-secret.yamlSecret Kubernetes pronto para aplicar no cluster do coletor

5.1b Entrega alternativa: AWS Secrets Manager

Se o consumidor do certificado é um Pod Kubernetes que precisa de client.crt e client.key em disco — o caso típico ao executar o agenteye-collector como sidecar no pod da sua aplicação — envie o pacote de certificados para o AWS Secrets Manager. O pod da aplicação então o monta via Secrets Store CSI Driver com IRSA, e a rotação de certificados é totalmente automatizada.
Na reexecução (renovação), o script chama PutSecretValue no mesmo secret, de modo que o ARN e o nome permanecem estáveis. O CSI Driver obtém a nova versão na próxima poll de rotação e reescreve os arquivos dentro do pod. Pré-requisitos:
  • CLI aws v2 autenticado na sua conta AWS.
  • jq instalado.
  • Variável de ambiente AWS_REGION definida.
  • Permissões IAM na sua identidade chamadora (restrinja Resource a arn:aws:secretsmanager:<region>:<account>:secret:agenteye/mtls-client/*):
    • secretsmanager:CreateSecret
    • secretsmanager:DescribeSecret
    • secretsmanager:PutSecretValue
    • secretsmanager:TagResource
O que o script faz neste modo:
PassoAção
1Emite/reextrai o certificado via cert-manager (mesmo que o modo padrão).
2Chama DescribeSecret em agenteye/mtls-client/<cluster-name> para decidir entre criar ou atualizar.
3Na primeira execução: CreateSecret com um payload JSON de três chaves (client.crt, client.key, ca.crt), com a tag AgentEyeCluster=<cluster-name>. Nas execuções subsequentes: PutSecretValue para publicar uma nova versão; tag atualizada via TagResource.
4Exclui issued/<cluster-name>/ somente após um upload bem-sucedido. Em caso de falha, o diretório é preservado para que você possa tentar novamente.
Se o secret estiver agendado para exclusão, o script falha com um erro claro informando para executar aws secretsmanager restore-secret --secret-id agenteye/mtls-client/<cluster-name> antes de tentar novamente. Para a configuração completa do pod (SecretProviderClass, setup IRSA, comportamento de rotação, troubleshooting), consulte enterprise-docs/single-pod-deployment.md.

5.2 Verificar se o certificado funciona

Teste o certificado emitido contra o ingress mTLS:
Esperado: {"status":"ok"} Se falhar:
ErroCausaSolução
certificate requiredCertificado não sendo apresentadoVerifique os caminhos dos arquivos no comando curl
bad certificateIncompatibilidade de CAVerifique se mtls-ca-issuer emitiu o certificado: kubectl describe certificate mtls-client-<name> -n agenteye
connection refusedHostname incorreto ou LB inacessívelVerifique /etc/hosts ou DNS

5.3 Entregar ao cluster do coletor

Envie collector-mtls-secret.yaml para a equipe que opera o cluster do coletor. Eles aplicam:
Em seguida, configure o coletor para montar o secret e usar os caminhos do certificado:
Consulte enterprise-docs/collector-installation.md para a configuração completa do coletor, incluindo montagens de volumes no Kubernetes. Teste (no cluster do coletor):
Esperado: o secret existe com 3 chaves de dados (client.crt, client.key, ca.crt).

5.4 Ciclo de vida do certificado

PropriedadeValor
Validade do certificado de cliente90 dias
Renovação automáticacert-manager renova 15 dias antes do vencimento
Validade da CA10 anos
Alertas de vencimentoCronJob alerta 30 dias antes do vencimento (Fase 6)
O cert-manager renova automaticamente o certificado no cluster AgentEye, mas o certificado renovado deve ser reenviado ao cluster do coletor. Execute novamente issue-client-cert.sh e reaplique collector-mtls-secret.yaml antes que o certificado antigo expire. Se você estiver usando --save-to aws-secrets-manager (ver §5.1b), execute o mesmo comando novamente. O script chama PutSecretValue no mesmo secret; os pods que montam o secret via Secrets Store CSI Driver obtêm a nova versão na próxima poll de rotação (padrão: a cada hora), sem necessidade de reiniciar o pod.

5.5 Revogar um certificado

Para bloquear imediatamente o acesso do coletor de um cluster:
Teste: O comando curl do passo 5.2 agora falha com um erro de handshake TLS.

Fase 6 — Monitoramento de Renovação de Certificados (~2 min)

Um CronJob integrado é executado a cada 12 horas (03:00 e 15:00 UTC) e verifica todos os certificados de cliente com o rótulo agenteye.io/cert-type=mtls-client. Ele alerta quando algum certificado está a 30 dias do vencimento.

6.1 Habilitar notificações no Slack (opcional)

Sem este secret, o CronJob ainda executa e registra o status dos certificados no stdout. Teste:
Esperado: o secret existe.

6.2 Testar o CronJob

Esperado: uma lista de certificados com seus status de vencimento. Se o webhook do Slack estiver configurado, verifique o canal Slack para a mensagem de alerta. Se falhar: Verifique o RBAC — a ServiceAccount do CronJob precisa de permissões get, list nos recursos Certificate do cert-manager. Verifique com: kubectl describe role cert-renewal-check -n agenteye. Limpe o job de teste:

Fase 7 — Verificar End-to-End

Esta fase confirma que todo o pipeline funciona: verificação de saúde, criação de chaves, ingestão de eventos e exibição no dashboard.
Nota: Os exemplos abaixo acessam o endpoint de ingestão pelo endereço bruto do LoadBalancer (${PUBLIC_IP}) por conveniência, razão pela qual passam -k; o certificado do servidor está vinculado a INGEST_DOMAIN, não ao IP do LB, portanto a verificação de hostname é ignorada. O endpoint de ingestão aplica mutual TLS em todos os caminhos, portanto toda chamada também deve apresentar um certificado de cliente (--cert/--key). Para validar também o certificado público, direcione para https://ingest.sua-empresa.example/... em vez de ${PUBLIC_IP} e remova o -k.

7.1 Verificação de saúde

Esperado: {"status":"ok"} com HTTP 200.

7.2 Criar chaves de coletor com escopo

A chave admin é para bootstrap e gerenciamento. Crie chaves dedicadas com permissão events:add para os coletores:
Teste: A resposta inclui "id", "name": "prod-collector", "permissions": ["events:add"], "created_at". Teste: Verifique se a chave aparece na lista de chaves:
Esperado: prod-collector aparece na resposta. Consulte enterprise-docs/api-keys.md para a referência completa de gerenciamento de chaves.

7.3 Ingerir um evento de teste

Esperado: {"accepted":1,"skipped":0} com HTTP 200. Se falhar:
Status HTTPCausa
401Chave de API inválida ou ausente
403Chave sem permissão events:add
Erro de handshake TLSProblema com certificado de cliente — consulte o troubleshooting da Fase 5

7.4 Verificar se o evento aparece no dashboard

Abra https://agenteye.sua-empresa.example (seu DASHBOARD_DOMAIN) em um navegador. O certificado é publicamente confiável, portanto não há avisos.
Se o LoadBalancer do dashboard estiver restrito por lista de IPs e você não conseguir se conectar, verifique se seu IP está permitido:
Lembre-se de que a Let’s Encrypt renova o certificado do dashboard via HTTP-01 na porta 80, e os intervalos de origem se aplicam a todo o LoadBalancer — antes de restringi-lo a intervalos corporativos, coordene um solver DNS-01 com o suporte, ou as renovações falharão silenciosamente.
Teste: O evento de smoke-test deve aparecer na lista de eventos com session test e agent smoke-test. Se falhar: Verifique os logs do dashboard (kubectl logs -n agenteye -l app=dashboard --tail=50). Verifique se AGENTEYE_SERVER_URL e AGENTEYE_API_KEY estão definidos corretamente.

7.5 Testar o CronJob de backup

Esperado: Backup created: agenteye-YYYYMMDD-HHMMSS.tar.gz (NNN) nos logs; o arquivo agrega o dump do Postgres e as tabelas do ClickHouse.
A etapa de upload para S3 é incluída no CronJob e é executada sempre que BACKUP_BUCKET estiver definido (a base inclui um valor padrão de bucket). É ignorada somente quando BACKUP_BUCKET está vazio ou literalmente PLACEHOLDER. Aponte-o para seu próprio bucket e conceda acesso de escrita à ServiceAccount agenteye-backup antes de depender dele (consulte a seção Backups abaixo).
Limpeza:

7.6 Provisionar organizações (multi-tenant)

Pule esta etapa para um deploy single-tenant; todos os dados residem na organização default integrada e nada aqui é necessário. Se você estiver executando múltiplos tenants isolados, organizações e seus membros são criados com a CLI agenteye-orgctl. Ela é incluída dentro da imagem do servidor (junto com agenteye-server) e você a executa dentro do Deployment server existente com kubectl exec; não há pod, Job ou Deployment separado, e nenhuma API HTTP ou botão no dashboard para o ciclo de vida do tenant. Executá-la no pod do servidor significa que ela reutiliza o DATABASE_URL, CLICKHOUSE_URL e o ORG_CH_SECRET do §2.6 do pod.
Pré-requisito: conclua o §2.6 primeiro. org create se recusa a executar enquanto o servidor ainda estiver usando o ORG_CH_SECRET de desenvolvimento integrado, e o usuário ClickHouse por organização que ele provisiona depende de esse secret ser forte e estável.
Criar uma organização e adicionar seu primeiro admin:
O novo membro recebe um OTP no primeiro login no dashboard e depois opera inteiramente pela UI sob o prefixo de URL da organização (ex.: /acme/...). Outros comandos (execute da mesma forma com kubectl -n agenteye exec deploy/server -- agenteye-orgctl …):
ComandoO que faz
org listLista organizações e seus estados.
org rename --slug <slug> --name <novo nome>Renomeia uma organização (slug inalterado).
org delete --slug <slug>Soft-delete + remove o usuário ClickHouse da organização; dados retidos.
org purge --slug <slug>Exclusão irreversível de dados; a organização deve ter sido deleted primeiro; nunca a organização default.
member list --org <slug>Lista membros e suas permissões.
member update --org <slug> --email <email> [--set ...] [--add ...] [--remove ...]Altera as permissões de um membro.
member remove --org <slug> --email <email>Remove um membro da organização.
Os conjuntos de permissões integrados são admin, standard e read-only. As chaves de API por organização ainda são criadas no dashboard/API pelos membros da organização (o §7.2 mostra a API de chaves); somente o ciclo de vida de organização + membro é exclusivo do operador. Referência completa e exemplo prático: enterprise-docs/tenant-management.md.

Checklist Pós-Deploy

Use este checklist para confirmar que tudo está funcionando. Cada item deve ser verificado antes de entregar aos coletores.
  • Todos os pods em Running no namespace agenteye
  • PVC do PostgreSQL vinculado (50Gi) e PVC do ClickHouse vinculado (100Gi)
  • Todos os 3 certificados Ready: True
  • Ambos os IPs do LoadBalancer atribuídos
  • DNS ou /etc/hosts configurado e resolvendo
  • /health retorna HTTP 200
  • Teste de certificado mTLS aprovado (curl com certificado de cliente para /health)
  • Chave de coletor com escopo criada e testada
  • Evento de teste ingerido (accepted: 1)
  • Evento visível no dashboard
  • Certificados de cliente emitidos para cada cluster de coletor
  • CronJob de backup testado manualmente
  • CronJob de renovação de certificados testado manualmente
  • Webhook do Slack para alertas de certificados configurado (opcional)
  • Bucket de backup configurado no overlay (ver abaixo)
  • Chave admin e senha do Postgres armazenadas no gerenciador de secrets

Backups

Um único CronJob agenteye-backup é executado diariamente às 03:00 UTC. Ele faz dump de ambos os armazenamentos: PostgreSQL (estado relacional) e ClickHouse (as tabelas de analytics events + evaluations), em um único arquivo comprimido no pod, e então o envia para o armazenamento de objetos que você configura no seu overlay. Cada execução produz um objeto, agenteye-<timestamp>.tar.gz, que descompactado contém:
O ClickHouse é lido via sua API HTTP (o mesmo endpoint que o servidor usa), portanto o job não precisa de cliente ClickHouse. Apenas as duas tabelas físicas são despejadas; o servidor recria todas as views (agent_sessions, os aliases analytics.*) e políticas de linha na inicialização, portanto essas tabelas representam o quadro completo.

Configurar upload para nuvem

O CronJob de backup inclui a etapa de upload para S3 (aws s3 cp) já configurada, e a base define um BACKUP_BUCKET padrão que você deve substituir pelo seu próprio bucket. Na AWS: você apenas define BACKUP_BUCKET para o seu bucket e concede acesso de escrita à ServiceAccount agenteye-backup via IRSA — sem necessidade de alterar o script. No GCP / Azure: você deve substituir a linha aws s3 cp incluída no script do CronJob pelo comando correspondente abaixo — não apenas adicionar o seu, porque o aws s3 cp restante é executado sob set -eu e falha o job.
CloudComando de Upload
AWS S3aws s3 cp /tmp/${FILENAME} s3://${BACKUP_BUCKET}/${FILENAME} (padrão incluído)
GCP Cloud Storagegsutil cp /tmp/${FILENAME} gs://${BACKUP_BUCKET}/${FILENAME}
Azure Blobaz storage blob upload -f /tmp/${FILENAME} -c backups -n ${FILENAME}
Um objeto por execução significa que uma regra de ciclo de vida do bucket (ex.: “excluir após 30 dias”) limpa backups completos de forma