Lab : Application de Politiques Kubernetes avec OPA Conftest en CI/CD

Vue d’ensemble

Les manifestes Kubernetes mal configurés sont l’une des principales causes d’incidents de sécurité en production. Un conteneur s’exécutant en tant que root, un tag d’image non épinglé, une limite de ressources manquante ou un réseau hôte exposé peuvent chacun ouvrir la porte à une escalade de privilèges, un épuisement des ressources ou un mouvement latéral à l’intérieur de votre cluster.

Le problème est que ces mauvaises configurations sont invisibles jusqu’au moment du déploiement — ou pire, jusqu’à ce qu’un attaquant les exploite. La solution est de décaler la sécurité vers la gauche (shift left) et de détecter les violations de politiques avant que les manifestes n’atteignent le cluster.

Dans ce lab pratique, vous utiliserez Conftest — un framework de test construit sur le moteur Open Policy Agent (OPA) — pour écrire des politiques Rego qui valident les manifestes Kubernetes. Vous intégrerez ensuite ces vérifications dans GitHub Actions et GitLab CI afin que chaque pull request soit automatiquement analysée pour détecter les violations.

À la fin de ce lab, vous disposerez de :

  • Une bibliothèque de politiques Rego réutilisables couvrant les tags d’images, les contextes de sécurité, les limites de ressources et l’accès au niveau de l’hôte.
  • Des tests unitaires pour ces politiques utilisant opa test.
  • Des pipelines CI/CD fonctionnels qui bloquent les manifestes non sécurisés et fournissent des messages de violation clairs et exploitables.

Prérequis

Avant de commencer, assurez-vous de disposer des outils et connaissances suivants :

  • CLI conftest installé — installez avec Homebrew :
    brew install conftest

    Vous pouvez également télécharger le binaire depuis la page des releases de Conftest.

  • kubectl et un cluster de test (optionnel) — si vous souhaitez vérifier que vos manifestes corrigés se déploient correctement, démarrez un cluster local avec minikube start ou kind create cluster.
  • Un dépôt de test — créez un nouveau dépôt Git ou utilisez un dépôt existant. Nous construirons tous les fichiers à partir de zéro.
  • Connaissances de base en YAML et Kubernetes — vous devez être à l’aise avec la lecture des manifestes Deployment, Service et Pod.

Configuration de l’environnement

Commencez par créer la structure du projet et un ensemble de manifestes Kubernetes intentionnellement non sécurisés. Ceux-ci serviront de fixtures de test tout au long de chaque exercice.

Structure du projet

conftest-k8s-lab/
├── k8s/
│   ├── deployment-latest-tag.yaml
│   ├── deployment-run-as-root.yaml
│   ├── deployment-no-limits.yaml
│   ├── service-loadbalancer.yaml
│   └── pod-host-network.yaml
└── policy/

Créez les répertoires :

mkdir -p conftest-k8s-lab/k8s conftest-k8s-lab/policy
cd conftest-k8s-lab

Manifeste 1 — Deployment avec un tag d’image non épinglé

Créez k8s/deployment-latest-tag.yaml :

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-latest
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web-latest
  template:
    metadata:
      labels:
        app: web-latest
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          ports:
            - containerPort: 80

Ce manifeste utilise nginx:latest, ce qui signifie que chaque pull pourrait silencieusement introduire un binaire différent dans votre cluster.

Manifeste 2 — Deployment s’exécutant en tant que root

Créez k8s/deployment-run-as-root.yaml :

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-root
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web-root
  template:
    metadata:
      labels:
        app: web-root
    spec:
      containers:
        - name: nginx
          image: nginx:1.25.4
          ports:
            - containerPort: 80

Aucun securityContext n’est défini, donc le conteneur s’exécute par défaut en tant que root — un vecteur d’escalade de privilèges bien connu.

Manifeste 3 — Deployment sans limites de ressources

Créez k8s/deployment-no-limits.yaml :

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-no-limits
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web-no-limits
  template:
    metadata:
      labels:
        app: web-no-limits
    spec:
      containers:
        - name: nginx
          image: nginx:1.25.4
          ports:
            - containerPort: 80

Sans limites de CPU et de mémoire, un seul pod défaillant peut affamer l’ensemble du nœud.

Manifeste 4 — Service de type LoadBalancer

Créez k8s/service-loadbalancer.yaml :

apiVersion: v1
kind: Service
metadata:
  name: web-lb
spec:
  type: LoadBalancer
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 80

Un service LoadBalancer sans annotations peut exposer des charges de travail sur l’internet public dans les environnements cloud.

Manifeste 5 — Pod avec accès au réseau hôte

Créez k8s/pod-host-network.yaml :

apiVersion: v1
kind: Pod
metadata:
  name: debug-pod
spec:
  hostNetwork: true
  containers:
    - name: debug
      image: busybox:1.36
      command: ["sleep", "3600"]

hostNetwork: true donne au pod un accès complet à la pile réseau du nœud, contournant entièrement les network policies.

Exercice 1 : Écrire votre première politique Rego — Pas de tags latest

Votre première politique refusera toute image de conteneur qui utilise le tag :latest ou omet un tag entièrement (ce qui résout également vers latest).

Étape 1 — Créer la politique

Créez policy/tags.rego :

package main

import future.keywords.in

deny[msg] {
  input.kind == "Deployment"
  container := input.spec.template.spec.containers[_]
  image := container.image
  not contains(image, ":")
  msg := sprintf("Container '%s' uses image '%s' without a tag. Pin to a specific version.", [container.name, image])
}

deny[msg] {
  input.kind == "Deployment"
  container := input.spec.template.spec.containers[_]
  image := container.image
  endswith(image, ":latest")
  msg := sprintf("Container '%s' uses the ':latest' tag in image '%s'. Pin to a specific version.", [container.name, image])
}

Étape 2 — Exécuter Conftest sur le manifeste non sécurisé

conftest test k8s/deployment-latest-tag.yaml

Sortie attendue :

FAIL - k8s/deployment-latest-tag.yaml - main - Container 'nginx' uses the ':latest' tag in image 'nginx:latest'. Pin to a specific version.

1 test, 0 passed, 0 warnings, 1 failure

Étape 3 — Corriger le manifeste

Éditez k8s/deployment-latest-tag.yaml et modifiez la ligne de l’image :

          image: nginx:1.25.4

Exécutez Conftest à nouveau :

conftest test k8s/deployment-latest-tag.yaml

Sortie attendue :

1 test, 1 passed, 0 warnings, 0 failures

Comprendre la structure Rego

Chaque fichier de politique Rego utilisé par Conftest suit un schéma simple :

  • package main — Conftest recherche le package main par défaut. Vous pouvez modifier cela avec --namespace.
  • deny[msg] — un ensemble de règles. Si toutes les conditions dans le corps de la règle s’évaluent à vrai, la règle se déclenche et ajoute msg à l’ensemble des violations.
  • input — représente le document YAML testé. Conftest le parse automatiquement en un objet JSON.
  • sprintf — formate un message d’erreur lisible qui apparaît dans les logs CI.

Exercice 2 : Pas de conteneurs s’exécutant en tant que root

Les conteneurs qui s’exécutent en tant que root peuvent modifier le système de fichiers, installer des paquets et — combinés à un exploit du noyau — s’échapper vers l’hôte. Cette politique applique deux contrôles : runAsNonRoot: true et allowPrivilegeEscalation: false.

Étape 1 — Créer la politique

Créez policy/security_context.rego :

package main

deny[msg] {
  input.kind == "Deployment"
  container := input.spec.template.spec.containers[_]
  not container.securityContext.runAsNonRoot == true
  msg := sprintf("Container '%s' must set securityContext.runAsNonRoot to true.", [container.name])
}

deny[msg] {
  input.kind == "Deployment"
  container := input.spec.template.spec.containers[_]
  not container.securityContext.allowPrivilegeEscalation == false
  msg := sprintf("Container '%s' must set securityContext.allowPrivilegeEscalation to false.", [container.name])
}

Étape 2 — Tester sur le manifeste non sécurisé

conftest test k8s/deployment-run-as-root.yaml

Sortie attendue :

FAIL - k8s/deployment-run-as-root.yaml - main - Container 'nginx' must set securityContext.runAsNonRoot to true.
FAIL - k8s/deployment-run-as-root.yaml - main - Container 'nginx' must set securityContext.allowPrivilegeEscalation to false.

1 test, 0 passed, 0 warnings, 2 failures

Étape 3 — Corriger le manifeste

Mettez à jour k8s/deployment-run-as-root.yaml pour inclure un contexte de sécurité sur chaque conteneur :

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-root
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web-root
  template:
    metadata:
      labels:
        app: web-root
    spec:
      containers:
        - name: nginx
          image: nginx:1.25.4
          ports:
            - containerPort: 80
          securityContext:
            runAsNonRoot: true
            allowPrivilegeEscalation: false

Exécutez Conftest à nouveau — les deux règles passent maintenant.

Exercice 3 : Exiger des limites de ressources

Sans limites de ressources, un seul conteneur peut consommer tout le CPU et la mémoire du nœud, provoquant des défaillances en cascade sur des charges de travail non liées. De nombreux référentiels de conformité (SOC 2, CIS Benchmarks) exigent des limites explicites.

Étape 1 — Créer la politique

Créez policy/resources.rego :

package main

deny[msg] {
  input.kind == "Deployment"
  container := input.spec.template.spec.containers[_]
  not container.resources.limits.cpu
  msg := sprintf("Container '%s' must define resources.limits.cpu.", [container.name])
}

deny[msg] {
  input.kind == "Deployment"
  container := input.spec.template.spec.containers[_]
  not container.resources.limits.memory
  msg := sprintf("Container '%s' must define resources.limits.memory.", [container.name])
}

Étape 2 — Tester sur le manifeste non sécurisé

conftest test k8s/deployment-no-limits.yaml

Sortie attendue :

FAIL - k8s/deployment-no-limits.yaml - main - Container 'nginx' must define resources.limits.cpu.
FAIL - k8s/deployment-no-limits.yaml - main - Container 'nginx' must define resources.limits.memory.

1 test, 0 passed, 0 warnings, 2 failures

Étape 3 — Corriger le manifeste

Ajoutez des limites de ressources à k8s/deployment-no-limits.yaml :

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-no-limits
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web-no-limits
  template:
    metadata:
      labels:
        app: web-no-limits
    spec:
      containers:
        - name: nginx
          image: nginx:1.25.4
          ports:
            - containerPort: 80
          resources:
            requests:
              cpu: "100m"
              memory: "128Mi"
            limits:
              cpu: "250m"
              memory: "256Mi"

Exécutez Conftest à nouveau — les vérifications de CPU et de mémoire passent.

Exercice 4 : Refuser l’accès privilégié à l’hôte

Les pods qui demandent un accès au niveau de l’hôte — hostNetwork, hostPID, hostIPC ou un contexte de sécurité privilégié — s’exécutent effectivement en dehors du sandbox du conteneur. Un pod compromis avec l’un de ces drapeaux peut voir tout le trafic sur le nœud, s’attacher à d’autres processus ou s’échapper entièrement vers l’hôte.

Étape 1 — Créer la politique

Créez policy/host_access.rego :

package main

deny[msg] {
  input.kind == "Pod"
  input.spec.hostNetwork == true
  msg := sprintf("Pod '%s' must not use hostNetwork: true.", [input.metadata.name])
}

deny[msg] {
  input.kind == "Pod"
  input.spec.hostPID == true
  msg := sprintf("Pod '%s' must not use hostPID: true.", [input.metadata.name])
}

deny[msg] {
  input.kind == "Pod"
  input.spec.hostIPC == true
  msg := sprintf("Pod '%s' must not use hostIPC: true.", [input.metadata.name])
}

deny[msg] {
  input.kind == "Pod"
  container := input.spec.containers[_]
  container.securityContext.privileged == true
  msg := sprintf("Container '%s' in Pod '%s' must not run in privileged mode.", [container.name, input.metadata.name])
}

deny[msg] {
  input.kind == "Deployment"
  input.spec.template.spec.hostNetwork == true
  msg := sprintf("Deployment '%s' must not use hostNetwork: true.", [input.metadata.name])
}

deny[msg] {
  input.kind == "Deployment"
  container := input.spec.template.spec.containers[_]
  container.securityContext.privileged == true
  msg := sprintf("Container '%s' in Deployment '%s' must not run in privileged mode.", [container.name, input.metadata.name])
}

Étape 2 — Tester sur le pod non sécurisé

conftest test k8s/pod-host-network.yaml

Sortie attendue :

FAIL - k8s/pod-host-network.yaml - main - Pod 'debug-pod' must not use hostNetwork: true.

1 test, 0 passed, 0 warnings, 1 failure

Étape 3 — Corriger le manifeste

Supprimez la ligne hostNetwork: true de k8s/pod-host-network.yaml :

apiVersion: v1
kind: Pod
metadata:
  name: debug-pod
spec:
  containers:
    - name: debug
      image: busybox:1.36
      command: ["sleep", "3600"]

Exécutez Conftest — le pod passe maintenant toutes les vérifications d’accès à l’hôte.

Exercice 5 : Tester les politiques avec opa test

Les politiques sont du code, et le code a besoin de tests. Sans tests, vous ne pouvez pas être sûr qu’une politique détecte ce qu’elle devrait, ni qu’un futur refactoring n’introduise un faux positif qui bloque des déploiements légitimes.

Étape 1 — Créer les cas de test

Créez policy/tags_test.rego :

package main

test_latest_denied {
  input := {
    "kind": "Deployment",
    "spec": {
      "template": {
        "spec": {
          "containers": [
            {
              "name": "app",
              "image": "nginx:latest"
            }
          ]
        }
      }
    }
  }
  count(deny) > 0
}

test_no_tag_denied {
  input := {
    "kind": "Deployment",
    "spec": {
      "template": {
        "spec": {
          "containers": [
            {
              "name": "app",
              "image": "nginx"
            }
          ]
        }
      }
    }
  }
  count(deny) > 0
}

test_pinned_allowed {
  input := {
    "kind": "Deployment",
    "spec": {
      "template": {
        "spec": {
          "containers": [
            {
              "name": "app",
              "image": "nginx:1.25.4"
            }
          ]
        }
      }
    }
  }
  count(deny) == 0
}

Étape 2 — Exécuter les tests

opa test policy/ -v

Sortie attendue :

policy/tags_test.rego:
data.main.test_latest_denied: PASS (1.234ms)
data.main.test_no_tag_denied: PASS (0.567ms)
data.main.test_pinned_allowed: PASS (0.432ms)
--------------------------------------------------------------------------------
PASS: 3/3

Pourquoi tester les politiques est important

Dans un contexte CI/CD, un faux négatif signifie qu’un manifeste non sécurisé passe à travers les mailles du filet, tandis qu’un faux positif bloque un déploiement légitime et érode la confiance des développeurs dans le pipeline. En écrivant des cas de test explicites pour les entrées autorisées et refusées, vous obtenez une suite de régression qui s’exécute en millisecondes et garantit que vos politiques se comportent correctement à mesure que la bibliothèque de règles grandit.

Prenez l’habitude d’ajouter un fichier *_test.rego pour chaque nouveau fichier de politique. Exécutez opa test policy/ -v dans le cadre de votre pipeline CI aux côtés de conftest test.

Exercice 6 : Intégrer Conftest dans GitHub Actions

Avec les politiques écrites et testées, l’étape suivante est de les connecter à votre pipeline CI afin que chaque pull request soit automatiquement validée.

Étape 1 — Créer le workflow

Créez .github/workflows/policy-check.yml :

name: Kubernetes Policy Check

on:
  pull_request:
    paths:
      - "k8s/**"
      - "policy/**"
  push:
    branches: [main]
    paths:
      - "k8s/**"
      - "policy/**"

jobs:
  conftest:
    name: Validate K8s Manifests
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Install Conftest
        run: |
          CONFTEST_VERSION="0.56.0"
          wget -q "https://github.com/open-policy-agent/conftest/releases/download/v${CONFTEST_VERSION}/conftest_${CONFTEST_VERSION}_Linux_x86_64.tar.gz"
          tar xzf "conftest_${CONFTEST_VERSION}_Linux_x86_64.tar.gz"
          sudo mv conftest /usr/local/bin/
          conftest --version

      - name: Install OPA
        run: |
          OPA_VERSION="v0.68.0"
          curl -L -o opa "https://openpolicyagent.org/downloads/${OPA_VERSION}/opa_linux_amd64_static"
          chmod +x opa
          sudo mv opa /usr/local/bin/
          opa version

      - name: Run policy unit tests
        run: opa test policy/ -v

      - name: Run Conftest against all manifests
        run: |
          echo "Scanning all Kubernetes manifests in k8s/ ..."
          FAILED=0
          for file in k8s/*.yaml; do
            echo ""
            echo "--- Testing: $file ---"
            if ! conftest test "$file" --policy policy/; then
              FAILED=1
            fi
          done
          if [ "$FAILED" -eq 1 ]; then
            echo ""
            echo "One or more manifests violated policy. Fix the issues above."
            exit 1
          fi
          echo ""
          echo "All manifests passed policy checks."

Étape 2 — Observer une PR échouée

Poussez une branche contenant les manifestes non sécurisés originaux. La sortie du pipeline ressemblera à ceci :

--- Testing: k8s/deployment-latest-tag.yaml ---
FAIL - k8s/deployment-latest-tag.yaml - main - Container 'nginx' uses the ':latest' tag in image 'nginx:latest'. Pin to a specific version.

--- Testing: k8s/deployment-run-as-root.yaml ---
FAIL - k8s/deployment-run-as-root.yaml - main - Container 'nginx' must set securityContext.runAsNonRoot to true.
FAIL - k8s/deployment-run-as-root.yaml - main - Container 'nginx' must set securityContext.allowPrivilegeEscalation to false.

--- Testing: k8s/pod-host-network.yaml ---
FAIL - k8s/pod-host-network.yaml - main - Pod 'debug-pod' must not use hostNetwork: true.

One or more manifests violated policy. Fix the issues above.
Error: Process completed with exit code 1.

Le statut de la PR passe au rouge avec des messages de violation clairs qui indiquent au développeur exactement quoi corriger et où.

Étape 3 — Observer une PR réussie

Corrigez tous les manifestes comme montré dans les exercices précédents, poussez à nouveau, et le pipeline passe :

--- Testing: k8s/deployment-latest-tag.yaml ---
1 test, 1 passed, 0 warnings, 0 failures

--- Testing: k8s/deployment-run-as-root.yaml ---
1 test, 1 passed, 0 warnings, 0 failures

--- Testing: k8s/deployment-no-limits.yaml ---
1 test, 1 passed, 0 warnings, 0 failures

All manifests passed policy checks.

Exercice 7 : Intégrer Conftest dans GitLab CI

Si votre équipe utilise GitLab, l’intégration est tout aussi simple. Ajoutez le job suivant à votre .gitlab-ci.yml :

Configuration complète fonctionnelle

stages:
  - validate

conftest-policy-check:
  stage: validate
  image: alpine:3.19
  variables:
    CONFTEST_VERSION: "0.56.0"
    OPA_VERSION: "v0.68.0"
  before_script:
    - apk add --no-cache curl wget tar
    - wget -q "https://github.com/open-policy-agent/conftest/releases/download/v${CONFTEST_VERSION}/conftest_${CONFTEST_VERSION}_Linux_x86_64.tar.gz"
    - tar xzf "conftest_${CONFTEST_VERSION}_Linux_x86_64.tar.gz"
    - mv conftest /usr/local/bin/
    - curl -L -o /usr/local/bin/opa "https://openpolicyagent.org/downloads/${OPA_VERSION}/opa_linux_amd64_static"
    - chmod +x /usr/local/bin/opa
  script:
    - echo "Running policy unit tests..."
    - opa test policy/ -v
    - echo "Running Conftest against all manifests..."
    - |
      FAILED=0
      for file in k8s/*.yaml; do
        echo ""
        echo "--- Testing: $file ---"
        if ! conftest test "$file" --policy policy/; then
          FAILED=1
        fi
      done
      if [ "$FAILED" -eq 1 ]; then
        echo ""
        echo "One or more manifests violated policy."
        exit 1
      fi
      echo ""
      echo "All manifests passed policy checks."
  rules:
    - changes:
        - k8s/**/*
        - policy/**/*
      when: always

Comportement réussite/échec

Le comportement est identique au workflow GitHub Actions. Lorsque des manifestes non sécurisés sont présents, le job échoue avec des messages de violation. Lorsque tous les manifestes sont conformes, le job passe avec un résumé propre. Le bloc rules garantit que le job ne s’exécute que lorsque les manifestes Kubernetes ou les fichiers de politique changent, minimisant ainsi le temps d’exécution du pipeline.

Avancé : Avertissements vs. refus

Toutes les violations de politique ne doivent pas bloquer un déploiement. Certaines sont des recommandations — des bonnes pratiques que vous souhaitez signaler sans casser le pipeline. Conftest prend en charge cette distinction grâce aux règles warn.

Comment ça fonctionne

  • deny[msg] — une gate stricte. Si une règle deny se déclenche, conftest test retourne un code de sortie non nul et le pipeline échoue.
  • warn[msg] — un avis consultatif. Le message est affiché mais le code de sortie reste zéro, donc le pipeline passe.
  • conftest test --fail-on-warn — promeut optionnellement tous les avertissements en échecs. Utile lorsque vous souhaitez resserrer progressivement les politiques : commencez avec warn, et une fois que les équipes ont corrigé les violations existantes, passez à deny ou activez --fail-on-warn.

Créer une politique consultative

Créez policy/recommendations.rego :

package main

warn[msg] {
  input.kind == "Service"
  input.spec.type == "LoadBalancer"
  not input.metadata.annotations
  msg := sprintf("Service '%s' is of type LoadBalancer with no annotations. Consider adding cloud-provider-specific annotations for internal load balancers.", [input.metadata.name])
}

warn[msg] {
  input.kind == "Deployment"
  container := input.spec.template.spec.containers[_]
  not container.readinessProbe
  msg := sprintf("Container '%s' has no readinessProbe. Add one so Kubernetes can route traffic only to healthy pods.", [container.name])
}

warn[msg] {
  input.kind == "Deployment"
  container := input.spec.template.spec.containers[_]
  not container.livenessProbe
  msg := sprintf("Container '%s' has no livenessProbe. Add one so Kubernetes can restart unhealthy pods.", [container.name])
}

Tester la politique consultative

conftest test k8s/service-loadbalancer.yaml

Sortie attendue :

WARN - k8s/service-loadbalancer.yaml - main - Service 'web-lb' is of type LoadBalancer with no annotations. Consider adding cloud-provider-specific annotations for internal load balancers.

1 test, 1 passed, 1 warning, 0 failures

Remarque : le code de sortie est 0 — le pipeline passe toujours. Si vous souhaitez appliquer les avertissements :

conftest test k8s/service-loadbalancer.yaml --fail-on-warn

Maintenant le code de sortie est 1 et le pipeline échouerait.

Ce modèle vous permet de déployer de nouvelles politiques progressivement : introduisez-les comme avertissements, laissez aux équipes le temps de remédier, puis promouvez-les en refus.

Nettoyage

Lorsque vous avez terminé le lab, supprimez les ressources de test :

# Supprimer le répertoire du lab
rm -rf conftest-k8s-lab

# Si vous avez déployé des manifestes corrigés sur un cluster de test
kubectl delete -f k8s/ --ignore-not-found

# Si vous avez créé un cluster kind pour ce lab
kind delete cluster --name conftest-lab

Points clés à retenir

  • Décalez la sécurité vers la gauche de manière agressive. Détecter un manifeste mal configuré dans une pull request coûte des ordres de grandeur moins cher que de le découvrir après une brèche.
  • Conftest + Rego est un point d’entrée léger vers le policy-as-code. Vous n’avez pas besoin d’un serveur OPA complet ni d’une installation Gatekeeper pour commencer à appliquer des politiques — un simple binaire CLI et quelques fichiers Rego suffisent.
  • Testez vos politiques comme du code applicatif. Utilisez opa test avec des cas de test explicites positifs et négatifs pour prévenir les régressions dans votre bibliothèque de règles.
  • Utilisez les avertissements pour un déploiement progressif. Commencez les nouvelles politiques comme règles warn, partagez-les avec l’équipe, et promouvez-les en deny une fois les violations existantes résolues.
  • Des messages d’erreur exploitables sont essentiels. Utilisez sprintf dans chaque règle pour indiquer au développeur quel conteneur, quel champ et quoi faire. Des messages génériques « politique violée » érodent la confiance dans les gates CI.
  • Conservez les politiques dans le même dépôt que les manifestes. Co-localiser policy/ avec k8s/ signifie que les changements de politique passent par le même processus de revue que les changements d’infrastructure.

Prochaines étapes

Maintenant que vous disposez d’un pipeline Conftest fonctionnel, continuez à développer votre pratique de policy-as-code :

  • Policy as Code pour CI/CD : OPA et Rego — approfondissez le langage Rego, découvrez les imports de données, la gestion des bundles et la journalisation des décisions pour les pistes d’audit.
  • Patterns défensifs et atténuations — explorez le paysage plus large du durcissement des pipelines CI/CD, de la gestion des secrets à la signature des artefacts et l’application en runtime.