Les quatre guides précédents couvrent l’écriture et l’exécution de politiques Rego. Ce dernier guide aborde la question de l’industrialisation : comment structurer, documenter, versionner et distribuer des politiques à l’échelle d’une organisation avec plusieurs équipes et plusieurs clusters.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Migrer un projet existant vers
rego.v1et intégreropa fmten pre-commit - Annoter les règles avec
# METADATApour documenter et filtrer - Construire, signer et distribuer un bundle OPA via un registre OCI
- Structurer une bibliothèque organisationnelle avec séparation code / données
- Utiliser
everypour exprimer une propriété universelle sur une collection
Prérequis
Section intitulée « Prérequis »- OPA en pratique :
opa eval,opa test, Conftest, Gatekeeper - Un registre OCI accessible (GHCR, Harbor, Docker Hub) pour la section bundles
rego.v1 et migration
Section intitulée « rego.v1 et migration »rego.v1 est le mode d’écriture recommandé depuis OPA 0.59. Un seul import active toutes les fonctionnalités modernes et lève les ambiguïtés syntaxiques des versions précédentes.
import rego.v1Ce que rego.v1 change concrètement :
| Comportement | Avant rego.v1 | Avec rego.v1 |
|---|---|---|
Mot-clé in | Optionnel (import séparé) | Activé par défaut |
Mot-clé every | Optionnel (import séparé) | Activé par défaut |
if dans les têtes de règle | Facultatif | Obligatoire |
contains pour règles partielles | Facultatif | Obligatoire |
| Variables non utilisées | Avertissement | Erreur |
Migration d’un fichier existant
Section intitulée « Migration d’un fichier existant »OPA peut réécrire automatiquement les fichiers vers rego.v1 :
opa fmt --rego-v1 --write policies/opa fmt reformate aussi l’indentation et l’espacement. Lancez-le systématiquement avant chaque commit — ou mieux, intégrez-le comme hook pre-commit.
repos: - repo: local hooks: - id: opa-fmt name: opa fmt entry: opa fmt --write language: system files: \.rego$ - id: opa-check name: opa check entry: opa check --strict language: system files: \.rego$Annotations et métadonnées
Section intitulée « Annotations et métadonnées »Les annotations Rego sont des blocs de commentaires structurés en YAML placés juste avant une règle ou un package. Elles servent à la documentation, aux outils d’analyse statique et à la génération automatique de documentation.
# METADATA# title: Image doit provenir d'un registre autorisé# description: |# Vérifie que toutes les images des conteneurs proviennent d'un# registre interne approuvé. Le tag `latest` est interdit en production.# authors:# - stephane-robert# custom:# severity: HIGH# category: supply-chain# remediation: "Utiliser registry.example.com/<image>:<version>"package kubernetes.policies.images
import rego.v1Les annotations peuvent aussi s’appliquer à une règle individuelle :
# METADATA# title: Tag latest interdit# description: Le tag latest ne permet pas de garantir la reproductibilité des déploiements.# related_resources:# - ref: https://docs.docker.com/develop/dev-best-practices/# custom:# severity: HIGHdeny contains msg if { some c in input.spec.template.spec.containers endswith(c.image, ":latest") msg := sprintf("conteneur '%v' : tag latest interdit", [c.name])}Exploiter les annotations
Section intitulée « Exploiter les annotations »# Lister toutes les règles annotées d'un répertoireopa inspect --annotations --format json policies/ | jq '.[].annotations'
# Extraire les règles de sévérité HIGHopa inspect --annotations --format json policies/ \ | jq '[.[] | select(.annotations.custom.severity == "HIGH")]'Les annotations sont exploitées par Gatekeeper (affichage dans les messages de refus), par les outils de documentation automatique comme Regal et par les pipelines qui veulent filtrer les politiques par catégorie ou sévérité.
Regal : linter pour Rego
Section intitulée « Regal : linter pour Rego »Regal est le linter officiel pour Rego. Il détecte les erreurs de style, les patterns dépréciés et les problèmes de performance.
# Installationbrew install styrainc/packages/regal
# Linter un répertoireregal lint policies/
# Avec configuration personnaliséeregal lint --config .regal/config.yaml policies/Exemple de configuration .regal/config.yaml :
rules: style: opa-fmt: level: error use-assignment-operator: level: error imports: prefer-package-imports: level: warning testing: test-outside-test-package: level: errorIntégrez Regal dans le pre-commit et la CI aux côtés de opa fmt et opa test.
Bundles OPA
Section intitulée « Bundles OPA »Un bundle est une archive .tar.gz qui regroupe des fichiers .rego et des données JSON/YAML. C’est le format standard pour distribuer des politiques à des instances OPA distantes.
Structure d’un bundle
Section intitulée « Structure d’un bundle »bundle/├── .manifest # métadonnées du bundle├── lib/│ └── kubernetes.rego├── policies/│ ├── images.rego│ ├── security.rego│ └── labels.rego└── data/ └── registres.json # données de référenceLe fichier .manifest déclare la version et les racines :
{ "revision": "v1.4.2", "roots": ["lib", "policies", "data"], "metadata": { "required_capabilities": { "builtins": [{ "name": "rego.v1" }] } }}Construire et publier un bundle
Section intitulée « Construire et publier un bundle »# Construire le bundleopa build \ --bundle \ --output bundle-v1.4.2.tar.gz \ lib/ policies/ data/
# Vérifier le contenutar tzf bundle-v1.4.2.tar.gzDistribuer via un registre OCI
Section intitulée « Distribuer via un registre OCI »OPA supporte nativement la distribution de bundles depuis un registre compatible OCI (Harbor, GHCR, Docker Hub…).
# Publier sur GHCRopa push \ --bundle bundle-v1.4.2.tar.gz \ ghcr.io/mon-org/opa-policies:v1.4.2
# Vérifieropa pull ghcr.io/mon-org/opa-policies:v1.4.2Configurer OPA pour consommer un bundle
Section intitulée « Configurer OPA pour consommer un bundle »bundles: politique-organisation: resource: ghcr.io/mon-org/opa-policies:latest polling: min_delay_seconds: 60 max_delay_seconds: 120 signing: keyid: "cle-verification"
decision_logs: console: trueopa run --server --config-file opa-config.yamlOPA télécharge le bundle au démarrage et le recharge périodiquement. Les instances distantes reçoivent automatiquement les nouvelles versions sans redémarrage.
Signer les bundles
Section intitulée « Signer les bundles »En production, signez vos bundles pour garantir leur intégrité. OPA vérifie la signature avant de charger un bundle.
# Générer une paire de clésopa keys generate --algorithm ES256 --id cle-prod
# Signer le bundleopa build \ --bundle \ --signing-key cle-prod \ --output bundle-signe.tar.gz \ lib/ policies/
# Vérifier la signatureopa bundle verify \ --verification-key cle-prod.pub \ bundle-signe.tar.gzLa clé publique est embarquée dans la configuration OPA des instances consommatrices. Tout bundle non signé ou signé avec une clé inconnue est rejeté.
Structurer une bibliothèque organisationnelle
Section intitulée « Structurer une bibliothèque organisationnelle »À l’échelle d’une organisation, une bibliothèque de politiques suit généralement cette structure :
policies-org/├── .manifest├── lib/│ ├── kubernetes/│ │ ├── helpers.rego # fonctions utilitaires génériques│ │ ├── images.rego # helpers liés aux images│ │ └── security.rego # helpers liés au securityContext│ └── terraform/│ └── helpers.rego├── policies/│ ├── kubernetes/│ │ ├── images/│ │ │ ├── required_registry.rego│ │ │ ├── required_registry_test.rego│ │ │ └── no_latest_tag.rego│ │ └── security/│ │ ├── no_privileged.rego│ │ └── readonly_rootfs.rego│ └── terraform/│ └── no_public_bucket.rego└── data/ ├── registres_autorises.json └── namespaces_sensibles.jsonDonnées de référence dans data/
Section intitulée « Données de référence dans data/ »Les données qui changent sans modifier le code (listes blanches, paramètres par environnement) vivent dans des fichiers JSON chargés dans data.
{ "registres_autorises": [ "registry.example.com", "ghcr.io/mon-org" ]}# Référencement dans une politiquedeny contains msg if { some c in input.spec.template.spec.containers registre := split(c.image, "/")[0] not registre in data.registres_autorises msg := sprintf("registre '%v' non autorisé", [registre])}Modifier la liste blanche ne nécessite pas de toucher au code Rego — seulement au JSON, puis de publier un nouveau bundle.
Versionnement et CI
Section intitulée « Versionnement et CI »name: Release bundle
on: push: tags: ["v*"]
permissions: contents: read packages: write
jobs: release: runs-on: ubuntu-latest steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: persist-credentials: false
- name: Install OPA run: | curl -Lo opa https://openpolicyagent.org/downloads/latest/opa_linux_amd64 chmod +x opa && sudo mv opa /usr/local/bin/
- name: Lint run: regal lint policies/ lib/
- name: Format check run: opa fmt --fail policies/ lib/
- name: Tests run: opa test policies/ lib/ --coverage
- name: Build bundle run: | opa build --bundle \ --signing-key ${{ secrets.OPA_SIGNING_KEY }} \ --output bundle-${{ github.ref_name }}.tar.gz \ lib/ policies/ data/
- name: Push to GHCR run: | opa push \ --bundle bundle-${{ github.ref_name }}.tar.gz \ ghcr.io/${{ github.repository_owner }}/opa-policies:${{ github.ref_name }} opa push \ --bundle bundle-${{ github.ref_name }}.tar.gz \ ghcr.io/${{ github.repository_owner }}/opa-policies:latestLe mot-clé every
Section intitulée « Le mot-clé every »every est disponible avec rego.v1. Il exprime qu’une condition doit être vraie pour tous les éléments d’une collection — l’inverse de l’itération implicite qui exprime qu’il existe un élément satisfaisant la condition.
# Vrai si TOUS les conteneurs ont une image conformetoutes_images_conformes if { every c in input.spec.template.spec.containers { startswith(c.image, "registry.example.com/") not endswith(c.image, ":latest") }}Sans every, il faudrait combiner une compréhension et count :
# Équivalent sans every — moins lisibletoutes_images_conformes if { non_conformes := [c | some c in input.spec.template.spec.containers not startswith(c.image, "registry.example.com/") ] count(non_conformes) == 0}every est réservé aux cas où vous voulez explicitement affirmer une propriété universelle. Pour collecter les violations et les reporter, la compréhension reste plus adaptée.
À retenir
Section intitulée « À retenir »- Adoptez
rego.v1sur tous les nouveaux fichiers et migrez les existants avecopa fmt --rego-v1 --write. - Les annotations
# METADATAdocumentent les règles de façon exploitable paropa inspect, Regal et Gatekeeper. - Un bundle est la brique de distribution standard : une archive versionnée, signée, publiée sur un registre OCI.
- Séparez code Rego (dans
.rego) et paramètres variables (dansdata/*.json) pour changer les listes blanches sans toucher aux politiques. everypour les assertions universelles, compréhensions pour les violations — les deux sont complémentaires.- Regal +
opa fmt+opa testen pre-commit et CI garantissent la qualité du code avant distribution.
Prochaines étapes
Section intitulée « Prochaines étapes »Le parcours Rego est terminé. Pour aller plus loin :