Skip to main content
Em ambientes de produção, nem toda remediação automática deve ser executada sem supervisão humana. O Approval Workflow do ChatCLI permite definir políticas que controlam quais planos de remediação precisam esperar por um humano, quantas aprovações eles exigem e em quais janelas de mudança (change windows) uma decisão pode ser aplicada.

Por que Approval Workflows são Essenciais

Segurança

Previne que remediação automática cause impacto maior que o problema original (ex: rollback acidental em produção)

Compliance

Cada requisição, decisão e expiração fica registrada no CR ApprovalRequest e como AuditEvent.

Confiança

Equipes adotam AIOps mais facilmente quando sabem que ações críticas requerem aprovação humana.
Sem approval workflows, uma IA que detecta um falso positivo pode executar um rollback desnecessário, afetando um deployment saudável. Com approval policies, planos de alto impacto ficam parados até que um humano valide a análise e o blast radius.

Visão Geral do Fluxo

O operator não envia notificação quando um ApprovalRequest é criado. As NotificationPolicies são disparadas por mudanças de estado do Issue, não por requisições de aprovação. Acompanhe com kubectl get approvalrequests -A, pelo dashboard web, ou crie alertas com as métricas abaixo para saber que há uma requisição esperando.

ApprovalPolicy CRD

A ApprovalPolicy (short name ap) define regras que decidem quais planos de remediação precisam de aprovação e como essa aprovação é obtida. Ela só vale para planos do próprio namespace: o operator lista as ApprovalPolicies habilitadas no namespace do RemediationPlan (o namespace do Issue), nunca entre namespaces.

Campos do Spec

ApprovalRule

Cada regra define um par match + mode com configurações específicas.

ApprovalMatch

Define quais remediações são cobertas por esta regra. A lógica é AND entre campos e OR dentro de cada campo. Campo vazio casa com tudo, então uma regra com match vazio casa com qualquer plano.
Não existe combinação do tipo “a regra mais restritiva prevalece”. Dentro de uma policy vale a primeira regra que casar e as demais são ignoradas, então coloque as regras mais rígidas primeiro. Se houver várias ApprovalPolicies habilitadas no mesmo namespace, a ordem em que elas são avaliadas não é garantida; mantenha uma policy por namespace, ou faça os matches não se sobreporem.

Três Modos de Aprovação

Auto: uma regra auto sem autoApproveConditions que casa significa “este plano não precisa de aprovação desta policy”. Nenhum ApprovalRequest é criado e o plano segue (o tier do cluster e o decision engine, quando habilitados, ainda o avaliam).Como vale a primeira regra que casar, uma regra auto também encobre todas as regras abaixo dela para os planos que ela casa.Com autoApproveConditions, a regra para o plano num ApprovalRequest, e o controller de aprovação o aprova automaticamente (status.autoApproved: true, decisão de auto-policy) só quando todas as condições valem. Caso contrário, a requisição espera uma decisão humana como numa regra manual, e continua expirando pelo timeoutMinutes:
A confiança vem do AIInsight do Issue; um AIInsight ausente conta como confiança 0, então as condições não são atendidas e um humano decide.

ChangeWindowSpec

A change window é definida por regra (rules[].changeWindow), não no nível da policy. Ela só afeta as requisições geradas por aquela regra. Não existem datas de blackout nem exceção para severidade crítica. A janela controla quando uma aprovação tem efeito, venha a decisão de onde vier (annotation, API REST ou dashboard):
  • Decisões são registradas a qualquer hora, e uma rejeição tem efeito na hora.
  • O relógio do timeout só corre com a janela aberta, então uma requisição aberta de madrugada guarda o timeoutMinutes inteiro para quando os aprovadores puderem agir.
  • Uma requisição que já tem as aprovações necessárias e só espera a janela não expira. Ela recebe a condition ChangeWindow=False (reason OutsideChangeWindow) e vira Approved quando a janela abre (reverificado a cada minuto); aprovações dentro da janela gravam ChangeWindow=True (WithinChangeWindow).
Uma janela que nunca abre (um timezone desconhecido, nenhum dia válido em allowedDays, ou startHour igual a endHour) é registrada no log, bloqueia a aprovação, e a requisição expira pelo relógio de parede.

ApprovalRequest CRD

O ApprovalRequest (short name ar) é criado pelo RemediationReconciler quando um plano precisa esperar. O nome é sempre approval-<nome-do-plano>, ele fica no namespace do plano e pertence ao RemediationPlan (apagar o plano apaga a requisição).

Campos do Spec

Raiz

BlastRadiusAssessment

ApprovalEvidence

Status

Estados do ApprovalRequest

Uma única rejeição basta para bloquear o plano, independentemente do número de aprovações. Um plano rejeitado ou expirado conta como tentativa de remediação falha: o Issue volta para Analyzing para gerar um novo plano enquanto houver tentativas (o que pode abrir um novo ApprovalRequest) e passa a Escalated ao atingir o máximo. Apagar o ApprovalRequest antes da decisão também faz o plano falhar; nunca o libera para rodar.

Blast Radius Calculator

Rodam dois cálculos, ambos informativos: nenhum deles bloqueia um plano sozinho.

Como Funciona

1

Avaliação gravada no spec (na criação da requisição)

Para um alvo Deployment, o calculador conta os pods que casam com o selector do Deployment (usando spec.replicas se nenhum for encontrado) e os Services do namespace cujo selector casa com as labels do pod template. Para outros kinds, ele conta os pods do namespace que têm owner reference com o nome do alvo e informa 0 services.
2

Nível de risco pela contagem de pods

3

Ajuste pelo tipo de ação

Uma ação RollbackDeployment sobe low para medium. Uma ação Custom sobe low ou medium para high. Os demais tipos não mudam o nível. Ingresses e downtime estimado não são calculados.
4

Annotations de predição (controller de aprovação)

Enquanto a requisição está Pending, o controller de aprovação roda o preditor de blast radius sobre a primeira ação do plano (checagens de PodDisruptionBudget, ResourceQuota, capacidade dos nodes e Services afetados) e grava o resultado em duas annotations do ApprovalRequest: platform.chatcli.io/blast-radius (resumo em texto) e platform.chatcli.io/blast-risk-level. Isso acontece uma vez por requisição. A API REST devolve as annotations da requisição, então o card de aprovação do dashboard mostra o nível de risco como um badge.

Integração com RemediationReconciler

Fluxo Completo

Quando um RemediationPlan está Pending, o RemediationReconciler passa por três gates, nesta ordem. O primeiro que parar o plano vence; os seguintes não rodam. O gate falha fechado. Se o Issue, o AIInsight ou as ApprovalPolicies não puderem ser lidos, ou o decision engine devolver erro, o plano continua Pending, um Event de Warning ApprovalGateUnavailable é registrado nele e o reconcile é tentado de novo com backoff; o plano nunca roda porque um gate deu erro. Se a criação do ApprovalRequest ou a anotação do plano falhar, o plano também continua Pending e é tentado de novo. Um ApprovalRequest que já existe com o mesmo nome é reaproveitado, não ignorado. Um plano cujo Issue pai não existe mais falha (“Parent issue not found; approval policies cannot be evaluated without it”) em vez de rodar sem gate. Um AIInsight ausente não é erro: a evidência leva confiança 0, o que só deixa as condições de auto-aprovação e o decision engine mais rígidos. O gate de tier do cluster segue a mesma regra: uma falha ao listar as ClusterRegistrations mantém o plano Pending e tenta de novo, e um CHATCLI_OPERATOR_CLUSTER_NAME que não casa com nenhuma ClusterRegistration retém o plano para aprovação manual sob a política cluster-tier, com o motivo Cluster name "<name>" (CHATCLI_OPERATOR_CLUSTER_NAME) is not registered: .... Com a variável vazia o gate de tier não se aplica.

Requisições sem ApprovalPolicy

O tier do cluster e o decision engine podem parar um plano mesmo sem nenhuma ApprovalPolicy. As requisições deles têm um policyRef sintético (cluster-tier ou decision-engine) e seguem sempre a mesma regra embutida: modo manual, um aprovador, timeout de 30 minutos, sem change window. Elas são aprovadas ou rejeitadas exatamente como qualquer outra requisição. O decision engine também deixa o veredito no plano como annotations: platform.chatcli.io/decision-mode, platform.chatcli.io/confidence, platform.chatcli.io/risk e platform.chatcli.io/decision-reason. Os limiares estão na página do Decision Engine.

Annotation de Controle

Quando um plano é parado, o reconciler grava platform.chatcli.io/approval-pending no RemediationPlan com o nome do ApprovalRequest:
A annotation é informativa. O gate é o estado WaitingApproval do plano mais o status do ApprovalRequest, que o reconciler sempre lê diretamente, então apagar a annotation não pula a aprovação. Na aprovação ou rejeição o controller de aprovação a remove; na rejeição ele também grava platform.chatcli.io/rejection-reason no plano. Uma requisição cuja ApprovalPolicy (ou regra) foi apagada nesse meio-tempo continua sendo avaliada, com o próprio requiredApprovers e timeoutMinutes, sem change window e sem aprovação automática: ela ainda precisa de um humano e ainda expira.

Como Aprovar

Via kubectl

A forma recomendada de decidir é uma annotation no ApprovalRequest:
Formato da annotation:
O controller de aprovação (que consulta as requisições pendentes a cada 15 segundos) registra a decisão em status.decisions, depois remove a annotation (a decisão é gravada primeiro, então nunca se perde) e avalia a regra: quorum, change window, timeout. Uma segunda decisão do mesmo aprovador é ignorada. Num quorum, cada aprovador adiciona a annotation depois que a anterior foi consumida; se duas pessoas anotarem antes de o controller rodar, a segunda precisa de --overwrite e substitui a primeira.
O <aprovador> é o texto que for escrito: o operator não o confere com a identidade do usuário do Kubernetes. Restrinja update/patch em approvalrequests via RBAC às pessoas que podem aprovar.

Via REST API

A API REST do operator (porta 8090) expõe as requisições. A autenticação é pelo header X-API-Key; listar exige o papel viewer, aprovar/rejeitar exige operator. Passe ?namespace= para escolher o namespace; sem ele a requisição é procurada pelo nome em todos os namespaces.
A chamada registra uma decisão numa requisição Pending, exatamente como uma annotation: uma entrada em status.decisions com o aprovador, o motivo e um timestamp. Ela nunca define o estado por conta própria; o ApprovalReconciler avalia as decisões contra a regra (requiredApprovers, change window) e leva a requisição a Approved ou Rejected, então a resposta costuma ainda mostrar Pending e a nova entrada em decisions.
  • approver é obrigatório no corpo (400 quando vazio). O aprovador registrado é <nome digitado> (api-key: <identidade>), onde a identidade é o name da entrada da API key, senão o description, senão uma impressão digital key-<hash> (dev-mode no dev mode). Veja Autenticação Fail-Closed.
  • Um quorum conta API keys distintas: duas chamadas com a mesma chave contam uma vez, sejam quais forem os nomes digitados. Dê a cada aprovador a sua própria chave.
  • 409 quando a requisição não está mais Pending, ou quando a mesma chave já decidiu sobre ela. 404 quando a requisição não existe.
Resposta da API (exemplo):
Nessa representação, resource é o nome do Issue, action é a primeira ação solicitada e reason é o nome da policy. approvedBy, rejectedBy e decisionReason são derivados de decisions, e decidedAt é preenchido quando a requisição termina. O dashboard web usa os mesmos endpoints: ele pede o seu nome (lembrado no navegador) e mostra o progresso do quorum nas requisições que precisam de mais de um aprovador.

Via Slack

Não existe aprovação interativa pelo Slack. O operator não tem endpoint de callback do Slack e não publica requisições de aprovação em nenhum canal.

Exemplos YAML Completos

Sem Aprovação para Ações de Baixo Risco em Staging

Um plano com um rollback e um restart casa com a primeira regra e espera aprovação. Planos que não casam com nenhuma regra não são segurados por esta policy.

Quorum de 2 Aprovadores para Produção

Change Window Dias Úteis 9-18 UTC

Não existe exceção para incidentes críticos: um plano crítico gerado às 3h espera até as 9h como qualquer outro. Se incidentes críticos precisam ser tratados de madrugada, coloque acima da regra com janela uma regra sem changeWindow para severities: [critical].

Proteção de Rollback em Namespace Crítico

Como uma policy só cobre o próprio namespace, crie uma para cada namespace que quiser proteger (payments, auth, billing, …).

Auditoria e Compliance

As decisões feitas por annotation ficam registradas no status do ApprovalRequest:
As colunas padrão do kubectl get ar são Issue, Plan, State, Rule, Age. O RemediationReconciler também grava CRs AuditEvent do ciclo de vida: approval_requested quando um plano é parado, e approval_approved, approval_rejected ou approval_expired quando ele age sobre o resultado (correlationId = nome do Issue). Uma aprovação ou rejeição humana registra como actor do evento os aprovadores de status.decisions (actor.type: user, mais um detalhe approvers); uma auto-aprovação ou uma expiração é atribuída ao ApprovalReconciler. Veja Auditoria e Compliance. Os ApprovalRequests pertencem ao seu RemediationPlan e são apagados junto com ele, então exporte-os periodicamente se precisar de registros de longo prazo:
O status da ApprovalPolicy mantém totalApproved, totalRejected, totalExpired e totalAutoApproved (não mantidos para requisições sintéticas). Cada requisição finalizada é contada uma vez (a requisição é marcada com platform.chatcli.io/policy-counted), inclusive entre restarts do operator.

Métricas Prometheus

O sistema de aprovação expõe estas métricas no endpoint de métricas do operator (porta 8080): Não existe gauge de requisições pendentes; conte-as com kubectl get ar -A ou pela API REST (?state=Pending). Alertas Prometheus recomendados:

Próximo Passo

Notificações e Escalação

Sistema de notificações multi-canal e políticas de escalação

SLOs e SLAs

Gestão de Service Level Objectives com burn rate alerting

AIOps Platform

Deep-dive na arquitetura AIOps completa

K8s Operator

Configuração e CRDs do operator