DevOpsFacile
AccueilParcours de formationCertificationsModulesCheat SheetÀ Propos
DevOpsFacile

Une plateforme d'apprentissage complète pour maîtriser les pratiques DevOps modernes, du débutant à l'expert.

contact@devopsfacile.fr

Formation

  • Parcours de formation
  • Modules

Informations

  • À Propos
  • Conditions d'utilisation
  • Confidentialité
  • Mentions légales

© 2026 DevOps Facile. Tous droits réservés.

Fait avec pour la communauté DevOps

ModulesSécurité DevOps - Avancé04 - Open Policy Agent : compliance as code avec Rego

Détails

  • 45 minutes
  • Avancé

Objectifs

  • Comprendre le rôle d'OPA comme moteur de règles de conformité
  • Écrire des règles Rego pour valider des manifestes Kubernetes
  • Intégrer OPA/Gatekeeper dans un cluster Kubernetes
  • Bloquer les déploiements qui violent les politiques de sécurité
Module Sécurité DevOps - Avancé

Exercice 04 : Open Policy Agent : compliance as code avec Rego

🎯 Objectifs

À la fin de cet exercice, vous serez capable de :

  • ✅ Écrire des règles Rego pour valider une politique de sécurité
  • ✅ Tester des règles Rego avec l'outil opa eval
  • ✅ Installer OPA Gatekeeper sur un cluster Kubernetes
  • ✅ Créer des ConstraintTemplate et Constraint Gatekeeper
  • ✅ Bloquer les déploiements sans securityContext ou sans resource limits

Durée estimée : 45 minutes

Difficulté : ⭐⭐⭐☆☆ (Avancé)

Prérequis : Cluster Kubernetes (minikube), kubectl, notions YAML K8s


📖 Contexte

OPA (Open Policy Agent) est un moteur de règles génériques. Il reçoit des données (un manifeste Kubernetes, une requête API, une config Terraform) et évalue si elles respectent des règles écrites en Rego, son langage déclaratif.

Gatekeeper est l'intégration officielle d'OPA dans Kubernetes. Il s'intercale dans le flux d'admission des ressources : quand vous faites kubectl apply, Gatekeeper évalue les règles avant d'accepter ou de refuser la ressource.


📋 Énoncé

Écrivez des politiques de sécurité avec Rego et intégrez-les dans Kubernetes via Gatekeeper.


🧭 Déroulement de l'exercice

Tâche 1 : Installer OPA CLI et tester Rego

bash
# Installer OPA CLI
curl -sSL -o /tmp/opa https://github.com/open-policy-agent/opa/releases/latest/download/opa_linux_amd64_static
chmod +x /tmp/opa && sudo mv /tmp/opa /usr/local/bin/opa

opa version

Créez votre première règle Rego :

bash
mkdir opa-demo && cd opa-demo

# Règle : interdire les containers qui tournent en root
cat > no-root-policy.rego << 'EOF'
package kubernetes.admission

# La règle "deny" est évaluée pour chaque ressource admise
# Si elle retourne un message, la ressource est rejetée
deny[msg] {
  # S'applique uniquement aux Pods
  input.request.kind.kind == "Pod"

  # Pour chaque container dans la spec
  container := input.request.object.spec.containers[_]

  # Vérifier si runAsNonRoot n'est PAS défini à true
  not container.securityContext.runAsNonRoot == true

  # Message d'erreur retourné à l'utilisateur
  msg := sprintf(
    "Container '%v' doit avoir securityContext.runAsNonRoot: true",
    [container.name]
  )
}

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

  # Vérifier que des resource limits sont définies
  not container.resources.limits.cpu

  msg := sprintf(
    "Container '%v' doit définir resources.limits.cpu",
    [container.name]
  )
}
EOF

Tâche 2 : Tester les règles Rego localement

Créez des inputs de test (manifestes JSON) :

bash
# Pod NON conforme (sans securityContext, sans resources)
cat > bad-pod.json << 'EOF'
{
  "request": {
    "kind": {"kind": "Pod"},
    "object": {
      "metadata": {"name": "bad-pod"},
      "spec": {
        "containers": [
          {
            "name": "app",
            "image": "nginx:latest"
          }
        ]
      }
    }
  }
}
EOF

# Pod conforme
cat > good-pod.json << 'EOF'
{
  "request": {
    "kind": {"kind": "Pod"},
    "object": {
      "metadata": {"name": "good-pod"},
      "spec": {
        "containers": [
          {
            "name": "app",
            "image": "nginx:1.27-alpine",
            "securityContext": {
              "runAsNonRoot": true,
              "runAsUser": 1000,
              "allowPrivilegeEscalation": false,
              "readOnlyRootFilesystem": true
            },
            "resources": {
              "limits": {"cpu": "100m", "memory": "128Mi"},
              "requests": {"cpu": "50m", "memory": "64Mi"}
            }
          }
        ]
      }
    }
  }
}
EOF

# Tester le pod non conforme (doit retourner des violations)
echo "=== Test pod non conforme ==="
opa eval --data no-root-policy.rego --input bad-pod.json "data.kubernetes.admission.deny"

# Tester le pod conforme (doit retourner un tableau vide)
echo "=== Test pod conforme ==="
opa eval --data no-root-policy.rego --input good-pod.json "data.kubernetes.admission.deny"

Indice : opa eval retourne le résultat de l'évaluation. Pour le pod non conforme, vous devriez voir 2 messages dans le tableau deny. Pour le pod conforme, le tableau doit être vide [].

Vérification : Le pod non conforme génère 2 messages de violation.


Tâche 3 : Installer Gatekeeper sur le cluster

bash
# Installer Gatekeeper (nécessite un cluster Kubernetes)
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/release-3.17/deploy/gatekeeper.yaml

# Attendre que Gatekeeper soit prêt
kubectl wait --for=condition=available deployment/gatekeeper-controller-manager \
  -n gatekeeper-system --timeout=120s

kubectl get pods -n gatekeeper-system

Tâche 4 : Créer une ConstraintTemplate

Une ConstraintTemplate définit la règle Rego et crée un nouveau type Kubernetes :

bash
cat > constraint-template-runasnonroot.yaml << 'EOF'
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8srequirerunasnonroot
spec:
  crd:
    spec:
      names:
        kind: K8sRequireRunAsNonRoot
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequirerunasnonroot

        violation[{"msg": msg}] {
          container := input.review.object.spec.containers[_]
          not container.securityContext.runAsNonRoot == true
          msg := sprintf(
            "Container '%v' : securityContext.runAsNonRoot doit être true",
            [container.name]
          )
        }

        # Vérifier aussi les initContainers
        violation[{"msg": msg}] {
          container := input.review.object.spec.initContainers[_]
          not container.securityContext.runAsNonRoot == true
          msg := sprintf(
            "InitContainer '%v' : securityContext.runAsNonRoot doit être true",
            [container.name]
          )
        }
EOF

kubectl apply -f constraint-template-runasnonroot.yaml

Tâche 5 : Créer et tester des Constraints

Une Constraint instancie la règle sur des namespaces spécifiques :

bash
# Activer la règle sur le namespace "production"
cat > constraint-runasnonroot.yaml << 'EOF'
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequireRunAsNonRoot
metadata:
  name: require-run-as-non-root
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    namespaces: ["production"]  # S'applique uniquement à "production"
  enforcementAction: deny  # deny | warn | dryrun
EOF

kubectl apply -f constraint-runasnonroot.yaml

# Créer le namespace production
kubectl create namespace production

# Tenter de créer un pod non conforme (doit échouer)
kubectl run bad-pod --image=nginx:latest -n production
# → Error: container 'bad-pod' : securityContext.runAsNonRoot doit être true

# Créer un pod conforme (doit réussir)
cat << 'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: good-pod
  namespace: production
spec:
  containers:
    - name: app
      image: nginx:1.27-alpine
      securityContext:
        runAsNonRoot: true
        runAsUser: 101
        allowPrivilegeEscalation: false
EOF

Vérification : Le pod bad-pod est refusé, le pod good-pod est accepté.


✅ Vérification du résultat

  • opa eval retourne 2 violations pour bad-pod.json
  • opa eval retourne 0 violations pour good-pod.json
  • Gatekeeper est installé et ses pods sont Running
  • kubectl run bad-pod --image=nginx -n production est bloqué par Gatekeeper
  • Le pod conforme avec securityContext.runAsNonRoot: true est accepté

💡 À retenir

OPA et Gatekeeper implémentent le compliance as code :

Développeur : kubectl apply
      ↓
Gatekeeper (Admission Webhook)
      ↓
OPA évalue les règles Rego
      ↓
Accepté ✅ ou Rejeté ❌ avec message d'erreur

Les règles Gatekeeper remplacent les vérifications manuelles dans les revues de code. Elles s'appliquent automatiquement à chaque déploiement.


✨ Solution Complète

rego
# Règle Rego : interdire les containers root
package k8snoroot

violation[{"msg": msg}] {
  container := input.review.object.spec.containers[_]
  not container.securityContext.runAsNonRoot == true
  msg := sprintf("Container '%v' doit avoir runAsNonRoot: true", [container.name])
}
bash
# Tester localement avant de déployer
opa eval --data ma-regle.rego --input mon-pod.json "data.k8snoroot.violation"
Retour au module

Sur cette page

  • 🎯 Objectifs
  • 📖 Contexte
  • 📋 Énoncé
  • 🧭 Déroulement de l'exercice
  • Tâche 1 : Installer OPA CLI et tester Rego
  • Tâche 2 : Tester les règles Rego localement
  • Tâche 3 : Installer Gatekeeper sur le cluster
  • Tâche 4 : Créer une ConstraintTemplate
  • Tâche 5 : Créer et tester des Constraints
  • ✅ Vérification du résultat
  • 💡 À retenir
  • ✨ Solution Complète