Policy as code com OPA: governança de infraestrutura como código versionado

1. Introdução ao Policy as Code e OPA

A governança de infraestrutura tradicionalmente dependia de checklists manuais, revisões em planilhas e auditorias pós-implantação. Esse modelo mostrou-se frágil em ambientes cloud-native, onde mudanças acontecem dezenas de vezes ao dia. O Policy as Code (PaC) surge como resposta: trata-se da prática de definir regras de conformidade, segurança e autorização como artefatos de software — versionados, testáveis e automatizados.

O Open Policy Agent (OPA) é o motor de políticas open-source mais adotado nesse contexto. Mantido pela CNCF, o OPA é agnóstico a stack: funciona com Kubernetes, Terraform, APIs REST, Docker, Envoy e praticamente qualquer sistema que precise tomar decisões baseadas em políticas. Seu diferencial está na linguagem declarativa Rego, que permite expressar regras complexas de forma concisa.

Os benefícios são diretos: políticas versionadas em Git permitem rastreabilidade total, revisão via Pull Requests, testes automatizados e consistência entre ambientes de desenvolvimento, staging e produção.

2. Conceitos Fundamentais do OPA

No OPA, toda decisão é modelada como uma consulta a um conjunto de regras escritas em Rego. O fluxo básico é:

  • input: dados da requisição (ex.: um JSON com recurso e ação)
  • data: dados externos carregados (ex.: listas de usuários, configurações de rede)
  • output: resultado booleano (allow/deny) ou estruturado

A estrutura mínima de uma política em Rego:

package example.authz

default allow = false

allow {
    input.method == "GET"
    input.path == "/public"
}

allow {
    input.method == "POST"
    input.user.role == "admin"
}

A diferença entre tipos de políticas é sutil mas importante:
- Autorização: decide se uma ação é permitida (quem pode fazer o quê)
- Validação: verifica se um recurso está em conformidade (ex.: tags obrigatórias)
- Conformidade: checa aderência a regulamentações (ex.: dados não podem sair de região específica)

3. Integração com Infraestrutura como Código (IaC)

Uma das aplicações mais imediatas do OPA é validar planos do Terraform antes do apply. Usando a ferramenta Conftest, podemos escrever políticas que inspecionam o HCL gerado.

Exemplo de política que bloqueia buckets S3 públicos:

package main

deny[msg] {
    input.kind == "aws_s3_bucket"
    input.value.acl == "public-read"
    msg = sprintf("Bucket %s não pode ter ACL pública", [input.value.name])
}

Para executar:

conftest test --policy policy/ terraform/plan.json

Em pipelines CI/CD, essa validação funciona como gatekeeping automático:

# .github/workflows/terraform.yml
jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - run: terraform plan -out=plan.tfplan
      - run: terraform show -json plan.tfplan > plan.json
      - run: conftest test --policy policy/ plan.json

Se a política falhar, o pipeline para e o engenheiro precisa corrigir antes de prosseguir.

4. Versionamento e Ciclo de Vida das Políticas

Políticas OPA devem ser tratadas como código de primeira classe. A prática recomendada é:

  • Armazenar em repositório Git dedicado ou em diretório policy/ no mesmo repositório do IaC
  • Usar versionamento semântico nos bundles (ex.: v1.2.3)
  • Escrever testes unitários em Rego

Exemplo de teste para a política de buckets:

package main

test_bucket_public {
    deny with input as {"kind": "aws_s3_bucket", "value": {"name": "test", "acl": "public-read"}}
}

test_bucket_private {
    not deny with input as {"kind": "aws_s3_bucket", "value": {"name": "test", "acl": "private"}}
}

Execução dos testes:

opa test ./policy/ -v

Pull Requests para políticas devem incluir:
- Descrição clara da regra
- Casos de teste cobrindo cenários positivos e negativos
- Impacto estimado (quantos recursos existentes seriam afetados)

5. Casos de Uso Práticos em Microsserviços e Kubernetes

No ecossistema Kubernetes, o Gatekeeper atua como um Admission Controller baseado em OPA. Ele intercepta requisições à API e aplica políticas antes que os recursos sejam persistidos.

Política que exige label app em todos os Pods:

package k8s.requiredlabels

violation[{"msg": msg}] {
    input.request.kind.kind == "Pod"
    not input.request.object.metadata.labels.app
    msg = "Pod deve ter label 'app' definida"
}

Para aplicar no cluster:

kubectl apply -f constraint-template.yaml
kubectl apply -f constraint.yaml

Outro caso comum é o controle de registros de imagens:

package k8s.allowedregistries

violation[{"msg": msg}] {
    container := input.request.object.spec.containers[_]
    not startswith(container.image, "registry.empresa.com/")
    msg = sprintf("Imagem %s não é de registro autorizado", [container.image])
}

6. Operacionalização: Deploy, Monitoramento e Escalabilidade

Para ambientes de produção, o OPA pode rodar como servidor HTTP standalone, recebendo requisições e respondendo decisões em milissegundos.

Configuração básica do servidor:

opa run --server --set=decision_logs.console=true --bundle policy/

A distribuição de bundles pode ser feita via:

  • HTTP: OPA faz polling periódico em um endpoint que serve o bundle
  • Sistemas de arquivos: montagem de volume com as políticas
  • Styra DAS: plataforma gerenciada que oferece UI, versionamento e auditoria

Métricas importantes para monitoramento:

  • opa_http_request_duration_seconds: latência das avaliações
  • opa_evaluator_count: número de avaliações por segundo
  • opa_cache_hit_ratio: eficiência do cache de decisões

Para bundles grandes, recomenda-se warm-up: carregar políticas antes de aceitar tráfego real.

7. Desafios e Boas Práticas

A linguagem Rego tem curva de aprendizado íngreme. Dicas para mitigar:

  • Usar opa eval --format pretty para depurar expressões isoladas
  • Habilitar --log-level debug durante desenvolvimento
  • Dividir políticas complexas em pacotes menores e reutilizáveis

Gerenciamento de dependências entre políticas e dados externos:

# Carregar dados de times autorizados
data_teams := data.external.teams

allow {
    input.team == data_teams[_]
}

Boas práticas essenciais:

  • Simplicidade: uma política deve fazer uma coisa bem feita
  • Cobertura de testes: pelo menos 80% de cobertura nas regras críticas
  • Documentação: cada política deve ter comentário explicando o objetivo e o contexto
  • Revisão: nunca mergear políticas sem aprovação de pelo menos dois pares

8. Conclusão e Tendências Futuras

Adotar Policy as Code com OPA transforma a governança de infraestrutura de um processo reativo e manual para algo proativo, automatizado e auditável. Cada política se torna um artefato versionado, testado e revisado como qualquer outro código. Os ganhos incluem redução de incidentes de segurança, conformidade contínua com regulamentações e rastreabilidade completa de decisões.

O ecossistema evolui rapidamente: OPA já está sendo usado no edge computing, em políticas orientadas a eventos com Kafka e em service meshes como Istio para autorização granular. Ferramentas como Conftest e Styra DAS ampliam o alcance para IaC e gerenciamento centralizado.

Para começar: escolha uma política simples (ex.: "proibir buckets públicos"), escreva em Rego, integre ao pipeline de CI/CD e expanda gradualmente. A jornada de governança como código começa com o primeiro teste passando.

Referências