Blog

Kyverno sur OpenShift : Policy as Code pour la gouvernance Kubernetes

OpenShift
Kyverno
Security
Policy as Code
Gouvernance

Implémentation de Kyverno sur OpenShift pour enforcer des politiques de sécurité, valider les ressources, muter les configurations et générer des objets automatiquement — une alternative native Kubernetes aux PodSecurityPolicies.

28 février 2025

Kyverno : les politiques Kubernetes en YAML

Kyverno est un moteur de politiques cloud-native conçu spécifiquement pour Kubernetes. Contrairement à OPA/Gatekeeper qui requiert Rego (un langage de requête dédié), Kyverno exprime ses politiques directement en YAML — le même langage que les manifests Kubernetes.

Kyverno agit comme un admission controller Kubernetes et opère en trois modes :

  • Validate — refuse les ressources qui ne respectent pas les règles
  • Mutate — modifie automatiquement les ressources à la création/mise à jour
  • Generate — crée automatiquement des ressources liées (ex. NetworkPolicy par namespace)

Sur OpenShift, Kyverno complète les Security Context Constraints (SCC) en apportant une gouvernance métier fine que les SCC ne couvrent pas.


Installation via Helm

helm repo add kyverno https://kyverno.github.io/kyverno/
helm repo update

oc create namespace kyverno

# Installation en mode HA (3 replicas)
helm install kyverno kyverno/kyverno \
  --namespace kyverno \
  --set replicaCount=3 \
  --set admissionController.replicas=3 \
  --set backgroundController.replicas=2 \
  --set cleanupController.replicas=2 \
  --set reportsController.replicas=2 \
  --version 3.3.0

Vérifier l’installation :

oc get pods -n kyverno
oc get clusterpolicy

ClusterPolicy vs Policy

  • ClusterPolicy — s’applique à tous les namespaces
  • Policy — s’applique uniquement dans le namespace où elle est définie
# Anatomie d'une ClusterPolicy
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: ma-politique
  annotations:
    policies.kyverno.io/title: Titre lisible
    policies.kyverno.io/description: Description de la politique
    policies.kyverno.io/severity: medium    # low | medium | high | critical
spec:
  validationFailureAction: Enforce    # Enforce | Audit
  background: true                    # Vérifier aussi les ressources existantes
  rules:
    - name: nom-de-la-regle
      match:
        any:
          - resources:
              kinds: [Pod]
      validate:
        message: "Message d'erreur affiché à l'utilisateur"
        pattern:
          spec:
            # Pattern à respecter

Politiques de validation essentielles

Interdire les conteneurs privileged

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: disallow-privileged-containers
  annotations:
    policies.kyverno.io/title: Disallow Privileged Containers
    policies.kyverno.io/severity: high
spec:
  validationFailureAction: Enforce
  background: true
  rules:
    - name: privileged-containers
      match:
        any:
          - resources:
              kinds: [Pod]
      exclude:
        any:
          - resources:
              namespaces: [kyverno, openshift-*, kube-*]
      validate:
        message: "Privileged containers are not allowed."
        pattern:
          spec:
            =(initContainers):
              - =(securityContext):
                  =(privileged): "false"
            containers:
              - =(securityContext):
                  =(privileged): "false"

Forcer les limites de ressources

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-resource-limits
  annotations:
    policies.kyverno.io/severity: medium
spec:
  validationFailureAction: Enforce
  background: true
  rules:
    - name: check-resource-limits
      match:
        any:
          - resources:
              kinds: [Pod]
      exclude:
        any:
          - resources:
              namespaces: [kube-system, openshift-*, kyverno]
      validate:
        message: "Resource limits (CPU and memory) are required for all containers."
        pattern:
          spec:
            containers:
              - resources:
                  limits:
                    memory: "?*"
                    cpu: "?*"
                  requests:
                    memory: "?*"
                    cpu: "?*"

Interdire les images :latest

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: disallow-latest-tag
  annotations:
    policies.kyverno.io/severity: medium
spec:
  validationFailureAction: Enforce
  background: true
  rules:
    - name: require-image-tag
      match:
        any:
          - resources:
              kinds: [Pod]
      exclude:
        any:
          - resources:
              namespaces: [kube-system, openshift-*]
      validate:
        message: "Using ':latest' tag or no tag is not allowed. Specify an explicit image tag."
        foreach:
          - list: "request.object.spec.containers"
            pattern:
              image: "!*:latest & ?*:*"

Politiques de mutation

Ajouter automatiquement des labels

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: add-default-labels
spec:
  rules:
    - name: add-labels-to-pods
      match:
        any:
          - resources:
              kinds: [Pod]
      mutate:
        patchStrategicMerge:
          metadata:
            labels:
              +(managed-by): kyverno
              +(app.kubernetes.io/managed-by): kyverno

Injecter des tolérances pour les nœuds dédiés

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: add-gpu-toleration
spec:
  rules:
    - name: add-toleration
      match:
        any:
          - resources:
              kinds: [Pod]
              namespaces: [gpu-workloads]
      mutate:
        patchStrategicMerge:
          spec:
            tolerations:
              - (key): nvidia.com/gpu
                +(effect): NoSchedule
                +(operator): Exists

Définir une registry de confiance

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: replace-image-registry
spec:
  rules:
    - name: replace-docker-hub
      match:
        any:
          - resources:
              kinds: [Pod]
      mutate:
        foreach:
          - list: "request.object.spec.containers"
            patchStrategicMerge:
              spec:
                containers:
                  - (name): "{{ element.name }}"
                    image: "{{ regex_replace_all('^docker.io/', '{{element.image}}', 'registry.entreprise.com/proxy-dockerhub/') }}"

Generate : créer des ressources automatiquement

Kyverno peut générer automatiquement des ressources dans chaque nouveau namespace.

Générer une NetworkPolicy par défaut

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: generate-default-networkpolicy
spec:
  rules:
    - name: default-deny-ingress
      match:
        any:
          - resources:
              kinds: [Namespace]
      exclude:
        any:
          - resources:
              namespaces: [kube-system, openshift-*, kyverno]
      generate:
        apiVersion: networking.k8s.io/v1
        kind: NetworkPolicy
        name: default-deny-ingress
        namespace: "{{request.object.metadata.name}}"
        synchronize: true           # Resynchronise si la policy est supprimée
        data:
          spec:
            podSelector: {}
            policyTypes:
              - Ingress

Générer un ResourceQuota par namespace

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: generate-namespace-quota
spec:
  rules:
    - name: create-quota
      match:
        any:
          - resources:
              kinds: [Namespace]
              selector:
                matchLabels:
                  team: "?*"
      generate:
        apiVersion: v1
        kind: ResourceQuota
        name: default-quota
        namespace: "{{request.object.metadata.name}}"
        synchronize: true
        data:
          spec:
            hard:
              requests.cpu: "4"
              requests.memory: 8Gi
              limits.cpu: "8"
              limits.memory: 16Gi
              persistentvolumeclaims: "10"
              pods: "50"

Vérification de conformité (PolicyReport)

Kyverno génère des PolicyReports qui permettent d’auditer la conformité des ressources existantes sans bloquer les déploiements.

# Voir les rapports par namespace
oc get policyreport -n mon-app

# Voir les rapports cluster-wide
oc get clusterpolicyreport

# Détail d'un rapport
oc get policyreport -n mon-app -o yaml | \
  yq '.results[] | select(.result == "fail")'

Mode Audit vs Enforce

En production, commencer par Audit pour mesurer l’impact avant de passer à Enforce :

# Passer toutes les policies en Audit d'abord
for policy in $(oc get clusterpolicy -o name); do
  oc patch $policy \
    --type=json \
    -p '[{"op":"replace","path":"/spec/validationFailureAction","value":"Audit"}]'
done

# Vérifier les violations sans bloquer
oc get clusterpolicyreport -o json | \
  jq '[.items[].results[] | select(.result=="fail")] | length'

Conclusion

Kyverno apporte une couche de gouvernance essentielle sur OpenShift, complémentaire aux SCC. Son approche YAML-native le rend accessible aux équipes qui maîtrisent Kubernetes sans nécessiter d’apprentissage d’un nouveau langage. La combinaison Validate + Mutate + Generate couvre l’ensemble du cycle de vie des ressources, tandis que les PolicyReports offrent une visibilité continue sur la conformité du cluster.