wlls / devsecops / opa-gatekeeper-kubernetes
devsecops

Como configurar OPA Gatekeeper no Kubernetes

wander·19 de set.·4 min de leitura

Objetivo

Um cluster Kubernetes sem controle de admissão aceita pods sem resources.limits, imagens em :latest e namespaces sem label de time — não porque alguém decidiu que está tudo bem, mas porque nada barra isso antes do objeto ser aceito. OPA Gatekeeper resolve isso aplicando políticas como código no momento da admissão.

Este guia mostra como instalar o Gatekeeper, criar uma primeira política e validar que ela está funcionando. Não cobre modelagem de políticas complexas em Rego nem integração com pipelines de CI — isso fica para um próximo artigo.

Premissas

  • Cluster Kubernetes com acesso de administrador (permissão para instalar CRDs e webhooks).
  • Helm 3.x instalado localmente.
  • Antes de aplicar em produção, confira a versão do Gatekeeper compatível com a sua versão de Kubernetes na documentação oficial — a matriz de compatibilidade muda entre releases e não está fixada aqui.
  • Os comandos e manifestos abaixo seguem a documentação oficial e os templates da gatekeeper-library, mas não foram executados neste ambiente. Mensagens de erro e campos de status mostrados são exemplos do comportamento esperado, não capturas reais — valide na sua versão antes de aplicar em produção.

Implementação

Instalar o Gatekeeper via Helm

helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm repo update

helm install gatekeeper gatekeeper/gatekeeper \
  --namespace gatekeeper-system \
  --create-namespace

Confirme que os pods do controller chegaram a Running antes de continuar:

kubectl get pods -n gatekeeper-system

Se algum pod ficar em CrashLoopBackOff, veja os logs (kubectl logs -n gatekeeper-system <pod>) antes de prosseguir — nessa etapa, isso costuma indicar falta de permissão para instalar os webhooks de admissão.

Criar a política: exigir label obrigatória em namespace

Gatekeeper separa a definição da regra (ConstraintTemplate, em Rego) da aplicação dela (Constraint, que define o escopo). O exemplo a seguir exige que todo Namespace tenha a label team:

apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: requiredlabels
spec:
  crd:
    spec:
      names:
        kind: RequiredLabels
      validation:
        openAPIV3Schema:
          type: object
          properties:
            labels:
              type: array
              items:
                type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package requiredlabels

        violation[{"msg": msg}] {
          required := input.parameters.labels
          provided := input.review.object.metadata.labels
          missing := required[_]
          not provided[missing]
          msg := sprintf("label obrigatória ausente: %v", [missing])
        }

Essa sintaxe Rego segue o padrão usado nos templates públicos da gatekeeper-library. Se a sua versão do Gatekeeper exigir Rego v1 (import rego.v1 e if), ajuste a regra de acordo.

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: RequiredLabels
metadata:
  name: require-team-label
spec:
  enforcementAction: dryrun
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Namespace"]
    excludedNamespaces: ["kube-system", "gatekeeper-system"]
  parameters:
    labels: ["team"]

Dois pontos nesse manifesto costumam ser esquecidos e causar incidente:

  • enforcementAction: dryrun — na primeira aplicação, a constraint só registra violações, sem bloquear nada. Isso permite ver o impacto antes de decidir bloquear de verdade.
  • excludedNamespaces — sem excluir kube-system e o próprio gatekeeper-system, a política pode acabar bloqueando objetos internos do cluster e do próprio controller.

Validação

Com a constraint em dryrun, revise as violações registradas sem que nada seja bloqueado:

kubectl get requiredlabels require-team-label -o yaml

O campo status.violations lista os namespaces que não atendem à política. Revise essa lista antes de mudar enforcementAction para deny.

Depois de confirmar que o comportamento em dryrun está de acordo com o esperado, mude para deny e teste criando um namespace sem a label:

kubectl create namespace teste-sem-label

Com enforcementAction: deny, essa requisição deve ser rejeitada pelo admission controller, com uma mensagem citando a violação definida no Rego (label obrigatória ausente: team).

Limitações relevantes

  • Não é retroativo. Objetos criados antes da constraint entrar em vigor não são revalidados automaticamente. O Gatekeeper tem um mecanismo de auditoria (kubectl get constraints) que lista violações em objetos já existentes, mas isso é auditoria, não bloqueio.
  • Rego tem curva de aprendizado. Para políticas simples (labels, limits, proibir :latest), vale usar os templates prontos da gatekeeper-library antes de escrever Rego do zero.
  • Isto não substitui teste em ambiente de homologação. Qualquer política nova deveria passar por dryrun em um cluster de não produção antes de ir para produção com deny.

Próximo passo

Para aplicar mais de uma política, comece adaptando os templates prontos da gatekeeper-library em vez de escrever Rego para cada caso — isso reduz a superfície de erro e mantém a política alinhada com o que a comunidade já testou e mantém.

#kubernetes#opa#policy-as-code