Écrire des politiques Rego dans un éditeur n’a de valeur que si elles s’exécutent au bon endroit au bon moment. Ce guide couvre la chaîne complète : évaluation locale avec le CLI opa, tests unitaires automatisés, intégration dans un pipeline CI/CD avec Conftest, et déploiement en admission controller Kubernetes avec Gatekeeper.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Installer OPA et évaluer une politique avec
opa eval - Déboguer une règle
undefinedavec--explain full - Écrire des tests unitaires Rego avec fixtures et
with input as - Intégrer Conftest dans un pipeline GitHub Actions
- Déployer un ConstraintTemplate + Constraint dans Kubernetes via Gatekeeper
Prérequis
Section intitulée « Prérequis »- Syntaxe de base de Rego
- Données et itération
- Règles et fonctions
- Un cluster Kubernetes pour la section Gatekeeper (minikube ou kind suffit)
Installer OPA
Section intitulée « Installer OPA »# Linux / macOS (binaire statique, sans dépendance)curl -Lo opa https://openpolicyagent.org/downloads/latest/opa_linux_amd64chmod +x opa && sudo mv opa /usr/local/bin/
# macOS avec Homebrewbrew install opa
# Vérificationopa versionopa eval : évaluer une politique
Section intitulée « opa eval : évaluer une politique »opa eval est le point d’entrée pour tester n’importe quelle expression Rego sur un input.
opa eval \ --input manifest.json \ --data policies/ \ "data.kubernetes.admission.deployment.violations"Options utiles :
| Option | Rôle |
|---|---|
--input fichier.json | Document soumis à évaluation (input) |
--data chemin/ | Fichiers .rego ou .json chargés dans data |
--format pretty | Sortie lisible (défaut : JSON brut) |
--explain full | Trace complète de l’évaluation (débogage) |
--strict | Active les vérifications strictes (recommandé) |
-b bundle/ | Charge un bundle OPA |
Déboguer avec --explain
Section intitulée « Déboguer avec --explain »Quand une règle retourne undefined sans raison évidente, --explain full trace chaque étape d’unification :
opa eval \ --input manifest.json \ --data policies/ \ --explain full \ --format pretty \ "data.kubernetes.admission.deployment.allow"La sortie montre quelle expression a échoué en premier dans le corps de chaque règle. C’est le premier réflexe à avoir avant de modifier le code.
Évaluer une expression inline
Section intitulée « Évaluer une expression inline »Pas besoin d’un fichier pour tester une expression simple :
# Tester une fonction built-inopa eval 'startswith("registry.example.com/api:1.0", "registry.example.com/")'
# Inspecter la structure d'un inputopa eval --input manifest.json 'input.spec.template.spec.containers'opa test : tests unitaires
Section intitulée « opa test : tests unitaires »Rego intègre un framework de tests. Un fichier de test est un fichier .rego ordinaire dont les règles commencent par test_.
Structure d’un fichier de test
Section intitulée « Structure d’un fichier de test »package kubernetes.admission.deployment_test
import rego.v1import data.kubernetes.admission.deployment
# --- Fixtures ---
manifest_valide := { "kind": "Deployment", "metadata": { "name": "api", "namespace": "production", "labels": {"app": "api", "team": "platform", "env": "prod"} }, "spec": {"template": {"spec": { "containers": [{ "name": "api", "image": "registry.example.com/api:1.4.2", "securityContext": {"readOnlyRootFilesystem": true} }] }}}}
manifest_image_latest := json.patch(manifest_valide, [{ "op": "replace", "path": "/spec/template/spec/containers/0/image", "value": "nginx:latest"}])
manifest_sans_label := json.patch(manifest_valide, [{ "op": "remove", "path": "/metadata/labels/app"}])
# --- Tests ---
test_allow_manifest_valide if { deployment.allow with input as manifest_valide}
test_deny_image_latest if { not deployment.allow with input as manifest_image_latest count(deployment.violations with input as manifest_image_latest) > 0}
test_message_image_latest if { violations := deployment.violations with input as manifest_image_latest some msg in violations contains(msg, "nginx:latest")}
test_deny_label_manquant if { not deployment.allow with input as manifest_sans_label}Lancer les tests
Section intitulée « Lancer les tests »# Tous les tests du répertoireopa test policies/ lib/ --verbose
# Un fichier spécifiqueopa test policies/deployment_test.rego policies/deployment.rego lib/
# Avec couverture de codeopa test policies/ lib/ --coverageSortie avec --verbose :
PASS: test_allow_manifest_valide (1.2ms)PASS: test_deny_image_latest (0.8ms)PASS: test_message_image_latest (0.9ms)PASS: test_deny_label_manquant (0.7ms)--------------------------------------------------------------------------------PASS: 4/4Conftest : validation en CI/CD
Section intitulée « Conftest : validation en CI/CD »Conftest est un outil CLI qui applique des politiques Rego à n’importe quel fichier de configuration : manifests Kubernetes, plans Terraform, Dockerfiles, fichiers GitHub Actions, etc.
Installation
Section intitulée « Installation »# Linuxcurl -Lo conftest https://github.com/open-policy-agent/conftest/releases/latest/download/conftest_Linux_x86_64.tar.gztar xzf conftest_Linux_x86_64.tar.gz && sudo mv conftest /usr/local/bin/
# macOSbrew install conftestStructure de projet Conftest
Section intitulée « Structure de projet Conftest »Conftest attend les politiques dans un dossier policy/ par convention. Le namespace utilisé est main par défaut.
projet/├── policy/│ ├── kubernetes.rego│ ├── terraform.rego│ └── lib/│ └── helpers.rego├── manifests/│ └── deployment.yaml└── main.tfPolitiques Conftest
Section intitulée « Politiques Conftest »Conftest reconnaît trois règles spéciales : deny, warn et violation. deny bloque avec code de sortie non nul. warn avertit sans bloquer.
package main
import rego.v1
# Bloquantdeny contains msg if { input.kind == "Deployment" some c in input.spec.template.spec.containers endswith(c.image, ":latest") msg := sprintf("[ERREUR] conteneur '%v' : tag latest interdit", [c.name])}
# Non bloquantwarn contains msg if { input.kind == "Deployment" not input.metadata.labels.team msg := "[AVERTISSEMENT] label 'team' recommandé mais absent"}Valider des fichiers
Section intitulée « Valider des fichiers »# Un manifestconftest test manifests/deployment.yaml
# Plusieurs manifestsconftest test manifests/
# Un plan Terraform (après terraform show -json)terraform show -json plan.tfplan > plan.jsonconftest test --parser json plan.json --policy policy/terraform.rego
# Un Dockerfileconftest test Dockerfile --policy policy/docker.regoSortie :
FAIL - manifests/deployment.yaml - main - [ERREUR] conteneur 'api' : tag latest interditWARN - manifests/deployment.yaml - main - [AVERTISSEMENT] label 'team' recommandé mais absent
2 tests, 0 passed, 1 warning, 1 failureIntégration GitHub Actions
Section intitulée « Intégration GitHub Actions »name: Policy Check
on: [push, pull_request]
permissions: {}
jobs: conftest: runs-on: ubuntu-latest steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: persist-credentials: false
- name: Install Conftest run: | curl -Lo conftest.tar.gz \ https://github.com/open-policy-agent/conftest/releases/latest/download/conftest_Linux_x86_64.tar.gz tar xzf conftest.tar.gz sudo mv conftest /usr/local/bin/
- name: Validate Kubernetes manifests run: conftest test manifests/ --policy policy/
- name: Validate Terraform plan run: | # Suppose que le plan JSON est déjà généré conftest test --parser json plan.json --policy policy/terraform.regoLe job échoue automatiquement si une règle deny est déclenchée. Les warn apparaissent dans les logs sans bloquer le pipeline.
Gatekeeper : admission controller Kubernetes
Section intitulée « Gatekeeper : admission controller Kubernetes »OPA Gatekeeper déploie OPA comme webhook d’admission dans Kubernetes. Chaque ressource créée ou modifiée dans le cluster passe par vos politiques avant d’être acceptée.
Installation
Section intitulée « Installation »kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/release-3.17/deploy/gatekeeper.yamlVérifiez que les pods sont prêts :
kubectl get pods -n gatekeeper-systemLe modèle en deux ressources
Section intitulée « Le modèle en deux ressources »Gatekeeper introduit deux CRDs :
ConstraintTemplate: contient la logique Rego et définit un nouveau type de ressource Kubernetes.Constraint: instancie ce type en ciblant des ressources spécifiques avec des paramètres.
ConstraintTemplate
Section intitulée « ConstraintTemplate »apiVersion: templates.gatekeeper.sh/v1kind: ConstraintTemplatemetadata: name: k8srequiredregistryspec: crd: spec: names: kind: K8sRequiredRegistry validation: openAPIV3Schema: type: object properties: registres_autorises: type: array items: type: string targets: - target: admission.k8s.gatekeeper.sh rego: | package k8srequiredregistry
import rego.v1
violation contains {"msg": msg} if { some c in input.review.object.spec.template.spec.containers registre := split(c.image, "/")[0] not registre in input.parameters.registres_autorises msg := sprintf( "conteneur '%v' : registre '%v' non autorisé", [c.name, registre] ) }kubectl apply -f constrainttemplate-image-registry.yaml
# Vérifiez que le CRD est bien créékubectl get constrainttemplate k8srequiredregistryConstraint
Section intitulée « Constraint »apiVersion: constraints.gatekeeper.sh/v1beta1kind: K8sRequiredRegistrymetadata: name: registry-autorise-productionspec: match: kinds: - apiGroups: ["apps"] kinds: ["Deployment", "StatefulSet", "DaemonSet"] namespaces: ["production", "staging"] parameters: registres_autorises: - "registry.example.com" - "gcr.io/mon-projet"kubectl apply -f constraint-image-registry-prod.yamlTestez la contrainte en appliquant un Deployment avec une image non conforme :
kubectl run test-nginx \ --image=nginx:latest \ --namespace=production \ --dry-run=server
# Résultat attendu :# Error: admission webhook "validation.gatekeeper.sh" denied the request:# [registry-autorise-production] conteneur 'test-nginx' : registre 'docker.io' non autoriséMode audit
Section intitulée « Mode audit »Gatekeeper peut aussi auditer les ressources déjà déployées et reporter les violations sans les bloquer. C’est indispensable lors d’un déploiement progressif.
spec: enforcementAction: dryrun # warn | deny | dryrun# Voir les violations détectées en mode auditkubectl get k8srequiredregistry registry-autorise-production -o json \ | jq '.status.violations'Récapitulatif : quel outil pour quel besoin
Section intitulée « Récapitulatif : quel outil pour quel besoin »| Besoin | Outil |
|---|---|
| Tester une expression Rego localement | opa eval |
| Tests unitaires automatisés | opa test |
| Valider des manifests / IaC en CI/CD | Conftest |
| Contrôle d’admission Kubernetes | Gatekeeper |
| Autorisation microservices / API | OPA server (API REST) |
| Distribution centralisée de politiques | OPA Bundles |
À retenir
Section intitulée « À retenir »opa eval --explain fullest le premier outil de débogage quand une règle retourneundefined.- Les tests unitaires Rego utilisent
with input as fixture— pas de mock, pas de stub, juste de la substitution d’input. - Conftest utilise
deny/warndans le namespacemainet s’intègre directement dans un pipeline sans infrastructure supplémentaire. - Gatekeeper sépare la logique (ConstraintTemplate) du ciblage (Constraint) : vous pouvez réutiliser le même template pour différents namespaces ou clusters.
- Commencez toujours par
enforcementAction: dryrunen production — auditez avant de bloquer.