Compliance as code: OPA/Gatekeeper para políticas de segurança
1. Introdução ao Compliance as Code no Ecossistema Kubernetes
Em ambientes Kubernetes dinâmicos e multi-inquilinos, garantir conformidade com políticas de segurança torna-se um desafio complexo. Times de DevOps precisam assegurar que cada workload respeite regras específicas — desde restrições de privilégios até controle de registros de imagens — sem depender de revisões manuais ou scripts frágeis.
O conceito de "Compliance as Code" surge como resposta a essa necessidade: políticas de segurança são escritas como código, versionadas, testadas e aplicadas automaticamente. Diferente de políticas de rede (NetworkPolicies) ou RBAC, que controlam comunicação e acesso, as políticas de segurança declarativas atuam no momento da criação ou atualização de recursos, validando configurações antes que sejam persistidas.
O Open Policy Agent (OPA) é um motor de políticas open-source que permite escrever regras em uma linguagem declarativa chamada Rego. O Gatekeeper, por sua vez, é um admissão controller nativo do Kubernetes que integra o OPA ao cluster, interceptando requisições à API e tomando decisões de allow/deny com base nas políticas definidas.
2. Arquitetura e Componentes do OPA/Gatekeeper
A arquitetura do OPA/Gatekeeper segue um fluxo claro:
- Um usuário ou automatização envia uma requisição ao API Server (ex.:
kubectl apply -f pod.yaml) - O API Server encaminha a requisição ao Gatekeeper via webhook de admissão
- O Gatekeeper consulta o OPA, que avalia as políticas Rego configuradas
- O OPA retorna uma decisão:
allow(permitir) oudeny(negar) - O API Server aplica ou rejeita a requisição conforme a decisão
O OPA funciona como um motor genérico — pode ser usado fora do Kubernetes — enquanto o Gatekeeper fornece a integração específica para clusters, expondo as políticas como Custom Resource Definitions (CRDs). As políticas são definidas em dois níveis:
- ConstraintTemplate: define a regra Rego e os parâmetros que ela aceita
- Constraint: instancia o template com valores específicos e escopo (namespaces, labels, etc.)
3. Escrevendo Políticas com Rego: Sintaxe e Padrões Essenciais
Rego é uma linguagem declarativa baseada em lógica de predicados. Abaixo, um exemplo de política que proíbe containers com privileged: true:
package k8ssecurity
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
container.securityContext.privileged == true
msg := sprintf("Container %v é privilegiado, o que não é permitido", [container.name])
}
Para exigir readOnlyRootFilesystem, usamos:
package k8ssecurity
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not container.securityContext.readOnlyRootFilesystem == true
msg := sprintf("Container %v deve ter readOnlyRootFilesystem habilitado", [container.name])
}
Funções auxiliares como every permitem validar todos os elementos de uma lista:
package k8ssecurity
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
every env in container.env {
env.name != "SECRET_TOKEN"
}
msg := sprintf("Container %v não define a variável SECRET_TOKEN", [container.name])
}
O Rego também suporta validação de labels e annotations, usando input.review.object.metadata.labels ou input.review.object.metadata.annotations.
4. Instalação e Configuração do Gatekeeper no Cluster
A instalação pode ser feita via Helm ou manifestos YAML oficiais. Com Helm:
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm install gatekeeper/gatekeeper --namespace gatekeeper-system --create-namespace
Após a instalação, criamos um ConstraintTemplate. Exemplo para bloquear imagens de registros não aprovados:
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: k8sallowedrepos
spec:
crd:
spec:
names:
kind: K8sAllowedRepos
validation:
openAPIV3Schema:
type: object
properties:
repos:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sallowedrepos
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
image := container.image
not startswith(image, input.parameters.repos[_])
msg := sprintf("Container %v usa imagem %v de registro não aprovado", [container.name, image])
}
Em seguida, criamos a Constraint que aplica a regra ao cluster:
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRepos
metadata:
name: block-unauthorized-repos
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
parameters:
repos:
- "docker.io/minhaempresa/"
- "gcr.io/minhaempresa/"
5. Estratégias de Teste e Simulação de Políticas
Testar políticas Rego offline é essencial para evitar surpresas em produção. Use opa eval para simular avaliações:
opa eval --data policy.rego --input input.json "data.k8ssecurity.violation"
Para testes unitários, crie arquivos .rego com casos de teste:
package k8ssecurity
test_privileged_container {
input := {"review": {"object": {"spec": {"containers": [{"name": "test", "securityContext": {"privileged": true}}]}}}}
count(violation) == 1
}
test_non_privileged_container {
input := {"review": {"object": {"spec": {"containers": [{"name": "test", "securityContext": {"privileged": false}}]}}}}
count(violation) == 0
}
Execute com opa test . -v. Ferramentas como gatekeeper-policy-manager e kubectl gatekeeper ajudam a visualizar e simular políticas diretamente no cluster.
Em pipelines CI/CD, integre o OPA para validar manifestos antes do deploy:
- name: Validar políticas com OPA
run: |
opa eval --data policies/ --input manifests/deployment.yaml "data.k8ssecurity.violation"
6. Integração com Fluxos DevOps e GitOps
Armazene políticas como código em um repositório Git dedicado. Estruture assim:
policies/
├── templates/
│ └── k8sallowedrepos.yaml
├── constraints/
│ └── block-unauthorized-repos.yaml
├── tests/
│ └── policy_test.rego
└── README.md
Com ArgoCD ou Flux, sincronize automaticamente o repositório com o cluster. O Git se torna a única fonte da verdade para políticas de segurança.
Estratégias de rollout incluem dois modos:
- Auditoria (dry-run): as políticas registram violações mas não bloqueiam requisições
- Enforcement (deny): as políticas bloqueiam requisições que violam as regras
Para ativar o modo auditoria, use a anotação gatekeeper.sh/audit: "true" na Constraint. Monitore os resultados com kubectl get constraint e verifique a coluna TOTAL VIOLATIONS.
7. Monitoramento, Auditoria e Troubleshooting
O Gatekeeper expõe logs detalhados no namespace gatekeeper-system. Para identificar violações:
kubectl logs -n gatekeeper-system -l app=gatekeeper --tail=100 | grep "denied"
Métricas Prometheus estão disponíveis na porta 8888 do serviço gatekeeper-controller-manager-metrics. Principais métricas:
gatekeeper_constraints: total de constraints ativasgatekeeper_violations: violações por constraintgatekeeper_request_duration_seconds: latência das requisições
Para depuração, descreva a constraint e verifique eventos:
kubectl describe constraint K8sAllowedRepos block-unauthorized-repos
kubectl get events --field-selector involvedObject.kind=K8sAllowedRepos
Se uma política estiver gerando falsos positivos, ajuste o escopo da constraint ou adicione exceções via match.namespaces ou match.labelSelector.
8. Casos de Uso Avançados e Considerações de Produção
Em ambientes multi-cluster, o OPA pode operar em modo sidecar ou federado, compartilhando políticas entre clusters via GitOps. Ferramentas como Kyverno oferecem abordagem similar, enquanto Falco foca em detecção de runtime e Polaris em auditoria de configurações.
Limitações importantes para produção:
- Performance: políticas complexas com loops aninhados podem aumentar a latência. Use
everycom moderação e evite regras que percorrem todos os namespaces - Mutações vs. Validações: O Gatekeeper suporta mutações (v3.7+), mas mutações complexas podem causar loops. Prefira validações sempre que possível
- Exceções: para casos legítimos que precisam burlar políticas, use
match.excludedNamespacesou labels específicas nas constraints
Para tratamento de exceções, crie uma constraint separada que permita namespaces específicos:
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRepos
metadata:
name: allow-legacy-repos
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
namespaces:
- "legacy-system"
parameters:
repos:
- "docker.io/antigo-registro/"
O Compliance as Code com OPA/Gatekeeper transforma políticas de segurança em ativos gerenciáveis, testáveis e auditáveis, alinhando-se perfeitamente com práticas DevOps e GitOps. Ao tratar compliance como código, você ganha rastreabilidade, consistência e agilidade para adaptar regras conforme o ecossistema evolui.
Referências
- Open Policy Agent - Documentação Oficial — Guia completo da linguagem Rego, instalação e integrações do OPA
- Gatekeeper - Repositório Oficial — Código-fonte, exemplos de ConstraintTemplates e documentação de API
- Kubernetes - Webhooks de Admissão — Documentação oficial sobre admissão controllers e webhooks no Kubernetes
- Gatekeeper Policy Manager — Ferramenta para visualizar, gerenciar e simular políticas Gatekeeper em clusters
- Rego Playground — Ambiente interativo para testar políticas Rego online sem instalação local
- OPA Gatekeeper - Tutorial de Segurança — Artigo prático com exemplos de políticas de segurança para Kubernetes
- Compliance as Code com OPA e GitOps — Post do CNCF sobre integração de políticas com fluxos GitOps