DevOps Admin

Compliance como Código: OPA, Conftest e Policy Enforcement em Kubernetes na Prática Já leu

O Que é Compliance como Código Compliance como Código é um paradigma que transforma políticas e padrões de conformidade em código executável, permitindo que sistemas sejam validados automaticamente contra regras de negócio, segurança e governança. Em vez de manuais em PDF ou checklists manuais, você define suas políticas em linguagens de programação específicas e as aplica de forma contínua no seu pipeline de infraestrutura. No contexto de Kubernetes, isso significa garantir que seus manifestos YAML, configurações de rede, permissões RBAC e deployments estejam sempre em conformidade com os padrões corporativos antes mesmo de serem deployados. Essa abordagem reduz riscos de segurança, evita configurações incorretas e torna a auditoria muito mais simples, já que tudo fica rastreável e versionado no seu repositório Git. OPA (Open Policy Agent): Fundamentos e Arquitetura OPA é um mecanismo de decisão de políticas agnóstico de domínio desenvolvido pela CNCF. Ele usa uma linguagem declarativa chamada Rego para expressar políticas complexas de uma forma legível e testável.

O Que é Compliance como Código

Compliance como Código é um paradigma que transforma políticas e padrões de conformidade em código executável, permitindo que sistemas sejam validados automaticamente contra regras de negócio, segurança e governança. Em vez de manuais em PDF ou checklists manuais, você define suas políticas em linguagens de programação específicas e as aplica de forma contínua no seu pipeline de infraestrutura.

No contexto de Kubernetes, isso significa garantir que seus manifestos YAML, configurações de rede, permissões RBAC e deployments estejam sempre em conformidade com os padrões corporativos antes mesmo de serem deployados. Essa abordagem reduz riscos de segurança, evita configurações incorretas e torna a auditoria muito mais simples, já que tudo fica rastreável e versionado no seu repositório Git.

OPA (Open Policy Agent): Fundamentos e Arquitetura

OPA é um mecanismo de decisão de políticas agnóstico de domínio desenvolvido pela CNCF. Ele usa uma linguagem declarativa chamada Rego para expressar políticas complexas de uma forma legível e testável. OPA funciona como um servidor que recebe dados em JSON, avalia-os contra suas políticas e retorna decisões estruturadas.

Como OPA Funciona

OPA recebe uma requisição contendo um JSON com o contexto que deve ser validado. Você define regras em Rego que analisam esse JSON e produzem uma decisão booleana ou estruturada. A força do OPA está na sua capacidade de trabalhar com qualquer tipo de dado: configurações Kubernetes, requisições HTTP, eventos de auditoria ou até artefatos de container.

Um exemplo simples de política em Rego que garante que todo Pod tenha um securityContext definido:

package kubernetes.admission

deny[msg] {
    input.request.kind.kind == "Pod"
    not input.request.object.spec.securityContext
    msg := "Pods devem ter securityContext definido"
}

Neste código, a regra deny é ativada quando o objeto sendo avaliado é um Pod e ele não possui securityContext. Se a condição for verdadeira, a política retorna uma mensagem de negação.

Instalando e Configurando OPA

Para instalar OPA em seu ambiente local, você pode usar o gerenciador de pacotes ou baixar o binário diretamente:

# macOS usando Homebrew
brew install opa

# Linux - fazer download do binário
curl -L -o opa https://openpolicyagent.org/downloads/latest/opa_linux_x86_64
chmod +x opa
sudo mv opa /usr/local/bin/

Para testar uma política rapidamente, você pode usar o REPL do OPA:

opa run --server

Isso inicia um servidor OPA na porta 8181. Você pode então fazer requisições POST para /v1/data/<seu-pacote>/<sua-regra> com um JSON contendo seus dados.

Exemplo Prático: Política de Imagens

Uma política comum é garantir que todas as imagens de container tenham tags explícitas e venham de registries autorizados:

package kubernetes.admission

import data.lib.utils

deny[msg] {
    input.request.kind.kind == "Pod"
    container := input.request.object.spec.containers[_]

    # Verifica se a imagem possui tag
    not contains(container.image, ":")
    msg := sprintf("Container %v deve ter tag explícita (não use 'latest')", [container.name])
}

deny[msg] {
    input.request.kind.kind == "Pod"
    container := input.request.object.spec.containers[_]

    # Verifica registries autorizados
    allowed_registries := ["docker.io", "gcr.io", "registry.empresa.com"]
    registry := split(container.image, "/")[0]

    not utils.contains_array(registry, allowed_registries)
    msg := sprintf("Registry %v não é autorizado", [registry])
}

Conftest: Integrando OPA com Seu Pipeline

Conftest é uma ferramenta de linha de comando que simplifica o teste de configurações contra políticas OPA. Ele recebe arquivos YAML, JSON, Terraform, Dockerfile e outros formatos, valida-os contra suas regras Rego e retorna os resultados de forma clara. Conftest é perfeito para executar validações em seu CI/CD antes que qualquer mudança chegue ao Kubernetes.

Instalando Conftest

# macOS
brew install conftest

# Linux usando curl
curl -JLO https://github.com/open-policy-agent/conftest/releases/download/v0.46.0/conftest_0.46.0_Linux_x86_64.tar.gz
tar xf conftest_0.46.0_Linux_x86_64.tar.gz
sudo mv conftest /usr/local/bin/

Estrutura de Projeto com Conftest

Uma estrutura típica para organizar suas políticas:

projeto-kubernetes/
├── policies/
│   ├── security/
│   │   ├── pod_security.rego
│   │   ├── network_policy.rego
│   │   └── rbac.rego
│   ├── compliance/
│   │   ├── labels_obrigatorios.rego
│   │   └── resource_limits.rego
│   └── utils.rego
├── manifests/
│   ├── deployment.yaml
│   ├── service.yaml
│   └── ingress.yaml
└── tests/
    └── policies_test.rego

Exemplo: Política de Labels Obrigatórios

Crie o arquivo policies/compliance/labels_obrigatorios.rego:

package main

# Labels obrigatórios em todos os recursos
required_labels := ["app", "version", "owner"]

deny[msg] {
    # Verifica todos os tipos de recursos
    resource_type := input.kind
    resource_type != "Namespace"  # Namespaces têm suas próprias regras

    # Obtém os labels do metadata
    labels := object.get(input.metadata, "labels", {})

    # Verifica se cada label obrigatório existe
    missing := [label | 
        label := required_labels[_]
        not labels[label]
    ]

    count(missing) > 0
    msg := sprintf(
        "Resource %v/%v está faltando labels: %v",
        [input.kind, input.metadata.name, missing]
    )
}

Agora crie um manifesto para testar:

# manifests/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: minha-app
  labels:
    app: minha-app
    version: "1.0"
    owner: devops-team
spec:
  replicas: 3
  selector:
    matchLabels:
      app: minha-app
  template:
    metadata:
      labels:
        app: minha-app
        version: "1.0"
        owner: devops-team
    spec:
      containers:
      - name: app
        image: myapp:1.2.3
        resources:
          requests:
            memory: "64Mi"
            cpu: "100m"
          limits:
            memory: "128Mi"
            cpu: "200m"

Execute a validação:

conftest test manifests/deployment.yaml -p policies/

Se algum label obrigatório estivesse faltando, Conftest retornaria um erro claro indicando exatamente qual label está ausente e em qual recurso.

Integrando Conftest no Pipeline GitHub Actions

name: Validate Kubernetes Manifests

on:
  pull_request:
    paths:
      - 'manifests/**'
      - 'policies/**'

jobs:
  conftest:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - uses: instrumenta/conftest-action@master
        with:
          files: manifests/
          policy: policies/
          options: -o json

Este workflow executa Conftest automaticamente toda vez que alguém abre um PR com mudanças em manifestos ou políticas, garantindo conformidade antes do merge.

Policy Enforcement em Kubernetes: Admission Controllers

Enquanto Conftest valida manifestos em tempo de build, você também precisa enforçar políticas em tempo de runtime. Kubernetes oferece dois mecanismos: Validating Admission Webhooks e Mutating Admission Webhooks. OPA integra-se perfeitamente nesse ecossistema através do Gatekeeper, um controlador específico para Kubernetes que executa políticas OPA.

O Que é Gatekeeper

Gatekeeper é um Kubernetes Admission Controller que intercepta requisições para criar ou modificar recursos e valida-as contra suas políticas OPA antes de permitir que a operação prossiga. Se uma política é violada, a requisição é rejeitada e o usuário recebe uma mensagem de erro clara.

Instalando Gatekeeper

# Adicione o repositório Helm
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts

# Instale o Gatekeeper
helm install gatekeeper/gatekeeper \
  --namespace gatekeeper-system \
  --create-namespace \
  --set enableExternalData=true \
  --set enableGeneratorResourceExpansion=true

Exemplo: Implementando uma Restrição de CPU e Memória

No Gatekeeper, você define ConstraintTemplates (templates de restrição) e depois cria instâncias delas (Constraints). A ConstraintTemplate define a lógica em Rego, e a Constraint especifica os parâmetros e objetivos.

Crie um arquivo constraint-template.yaml:

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

        violation[{"msg": msg}] {
            container := input.review.object.spec.containers[_]
            not container.resources.requests
            msg := sprintf("Container %v deve ter requests definidos", [container.name])
        }

        violation[{"msg": msg}] {
            container := input.review.object.spec.containers[_]
            not container.resources.limits
            msg := sprintf("Container %v deve ter limits definidos", [container.name])
        }

Agora crie a Constraint que aplica essa restrição:

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredResources
metadata:
  name: require-resources-all-pods
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    excludedNamespaces: ["kube-system", "kube-public"]

Quando você tentar criar um Pod sem resources definidos, Gatekeeper o rejeitará automaticamente:

$ kubectl apply -f pod-sem-resources.yaml
Error from server ([denied by require-resources-all-pods] 
Container nginx deve ter requests definidos): 
error when creating "pod-sem-resources.yaml": admission webhook 
"validation.gatekeeper.sh" denied the request

Auditoria sem Rejeição

Às vezes você quer monitorar violações sem bloquear deployments imediatamente. Configure o Gatekeeper em modo auditoria:

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredResources
metadata:
  name: require-resources-all-pods
spec:
  enforcementAction: audit  # ao invés de "deny"
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]

Com enforcementAction: audit, violações são registradas mas não bloqueiam operações. Isso é útil para um período de transição antes de ativar enforcement total.

Conclusão

Compliance como Código transforma governança de infraestrutura de um processo manual e propenso a erros em uma prática automatizada e auditável. Os três aprendizados principais são: (1) OPA e Rego fornecem a camada de decisão declarativa, permitindo expressar políticas complexas em código legível e testável; (2) Conftest integra validação de políticas no seu pipeline de CI/CD, capturando problemas antes do deployment; (3) Gatekeeper enforce políticas em runtime no Kubernetes, servindo como última linha de defesa contra configurações não-conformes.

Implementar essa stack não é apenas sobre segurança — é sobre confiabilidade. Quando suas políticas estão codificadas, versionadas e testadas, você elimina configurações manuais inconsistentes e cria um ambiente onde conformidade é a regra, não a exceção.

Referências

  1. Open Policy Agent Official Documentation
  2. Conftest GitHub Repository
  3. Gatekeeper: Policy Controller for Kubernetes
  4. Kubernetes Admission Controllers Documentation
  5. CNCF Policy as Code Whitepaper

Artigos relacionados