Aller au contenu
Conteneurs & Orchestration medium
🔐 Alerte sécurité — Incident supply chain Trivy : lire mon analyse de l'attaque

Audit Logs Kubernetes - Tracer toutes les actions du cluster

18 min de lecture

Les logs d’audit Kubernetes enregistrent chaque requête à l’API Server pour la traçabilité et l’investigation de sécurité. Ils répondent aux questions “qui a fait quoi, quand, et via quelle méthode”. Ce guide vous montre comment configurer une politique d’audit, activer les logs sur l’API Server, et analyser les événements pour détecter les comportements suspects ou reconstituer un incident.

  • Accès à la configuration de l’API Server (fichiers manifests ou flags)
  • Pour les clusters managés (EKS/GKE/AKS) : accès à la console cloud
  • Compréhension des ressources Kubernetes (pods, secrets, configmaps)

L’audit se compose de trois éléments :

Flux d'audit Kubernetes : requête API vers API Server avec Audit Policy vers backend d'audit

  1. Audit Policy : définit quels événements capturer et à quel niveau de détail
  2. API Server : applique la politique et génère les événements
  3. Backend : stocke les logs (fichier local ou webhook vers système externe)

Chaque règle de la politique spécifie un niveau qui détermine la quantité d’information enregistrée :

NiveauCe qui est enregistréUsage
NoneRienExclure des ressources du logging (éviter le bruit)
MetadataMetadata de la requête (user, timestamp, resource, verb) mais pas le bodyAudit de base, faible volume
RequestMetadata + body de la requêteVoir ce qui a été envoyé
RequestResponseMetadata + requête + réponseDebug complet, volume élevé

Un événement peut être enregistré à différentes étapes de son traitement :

StageMomentUsage
RequestReceivedDès réception, avant traitementLogging exhaustif
ResponseStartedHeaders de réponse envoyés (watch/long-running)Requêtes longues
ResponseCompleteRéponse terminéeStandard, le plus utilisé
PanicSi l’API Server panicDebugging uniquement
/etc/kubernetes/audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
# Règle par défaut si aucune autre ne match
omitStages:
- "RequestReceived" # Évite les doublons
rules:
# Les règles sont évaluées dans l'ordre, première qui match gagne
# 1. Ne pas logger les health checks (bruit)
- level: None
users: ["system:kube-probe", "system:serviceaccount:kube-system:kube-proxy"]
resources:
- group: ""
resources: ["endpoints", "services"]
# 2. Secrets/ConfigMaps/TokenRequests : Metadata uniquement (jamais le contenu)
# IMPORTANT : RequestResponse exposerait les valeurs sensibles dans les logs !
- level: Metadata
resources:
- group: ""
resources: ["secrets", "configmaps", "serviceaccounts/token"]
- group: authentication.k8s.io
resources: ["tokenreviews"]
omitStages:
- "RequestReceived"
# 4. Logger les modifications RBAC
- level: RequestResponse
resources:
- group: "rbac.authorization.k8s.io"
resources: ["roles", "rolebindings", "clusterroles", "clusterrolebindings"]
# 5. Logger les actions sur pods au niveau Metadata
- level: Metadata
resources:
- group: ""
resources: ["pods", "pods/exec", "pods/portforward"]
# 6. Règle par défaut : Metadata pour tout le reste
- level: Metadata

Pour l’examen CKS, voici une politique simple mais fonctionnelle :

/etc/kubernetes/audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
omitStages:
- "RequestReceived"
rules:
# Ignorer les endpoints health
- level: None
nonResourceURLs:
- "/healthz*"
- "/readyz*"
- "/livez*"
# Secrets, ConfigMaps, tokens : Metadata uniquement (pas le contenu)
- level: Metadata
resources:
- group: ""
resources: ["secrets", "configmaps", "serviceaccounts/token"]
- group: authentication.k8s.io
resources: ["tokenreviews"]
# RBAC : RequestResponse pour traçabilité complète
- level: RequestResponse
resources:
- group: "rbac.authorization.k8s.io"
# Metadata pour tout le reste
- level: Metadata
rules:
- level: Metadata
# Filtrer par utilisateur
users: ["admin", "system:serviceaccount:default:myapp"]
userGroups: ["system:authenticated"]
# Filtrer par verbe
verbs: ["create", "update", "delete"]
# Filtrer par ressource
resources:
- group: "" # core API group
resources: ["pods", "services"]
- group: "apps"
resources: ["deployments"]
# Filtrer par namespace
namespaces: ["production", "finance"]
# URLs non-ressources (healthz, metrics)
nonResourceURLs: ["/api*", "/version"]
# Stages à omettre pour cette règle
omitStages: ["RequestReceived"]
  1. Créer le fichier de politique

    Fenêtre de terminal
    sudo mkdir -p /etc/kubernetes/audit
    sudo vim /etc/kubernetes/audit/audit-policy.yaml

    Coller la politique YAML.

  2. Modifier le manifest de l’API Server

    Fenêtre de terminal
    sudo vim /etc/kubernetes/manifests/kube-apiserver.yaml

    Ajouter les flags :

    spec:
    containers:
    - command:
    - kube-apiserver
    # ... autres flags existants ...
    - --audit-policy-file=/etc/kubernetes/audit/audit-policy.yaml
    - --audit-log-path=/var/log/kubernetes/audit/audit.log
    - --audit-log-maxage=30 # Rétention en jours
    - --audit-log-maxbackup=10 # Nombre de fichiers à conserver
    - --audit-log-maxsize=100 # Taille max en Mo avant rotation
  3. Ajouter les volumes et volumeMounts

    spec:
    containers:
    - volumeMounts:
    # ... mounts existants ...
    - mountPath: /etc/kubernetes/audit
    name: audit-policy
    readOnly: true
    - mountPath: /var/log/kubernetes/audit
    name: audit-logs
    volumes:
    # ... volumes existants ...
    - name: audit-policy
    hostPath:
    path: /etc/kubernetes/audit
    type: DirectoryOrCreate
    - name: audit-logs
    hostPath:
    path: /var/log/kubernetes/audit
    type: DirectoryOrCreate
  4. Créer le répertoire de logs

    Fenêtre de terminal
    sudo mkdir -p /var/log/kubernetes/audit
  5. Vérifier le redémarrage de l’API Server

    Fenêtre de terminal
    # L'API Server redémarre automatiquement (kubelet surveille /etc/kubernetes/manifests)
    kubectl get pods -n kube-system | grep api
    # Vérifier les logs
    sudo tail -f /var/log/kubernetes/audit/audit.log | jq .
/etc/kubernetes/manifests/kube-apiserver.yaml (extrait)
apiVersion: v1
kind: Pod
metadata:
name: kube-apiserver
namespace: kube-system
spec:
containers:
- name: kube-apiserver
command:
- kube-apiserver
- --advertise-address=10.0.0.10
- --allow-privileged=true
- --authorization-mode=Node,RBAC
# ... autres flags ...
- --audit-policy-file=/etc/kubernetes/audit/audit-policy.yaml
- --audit-log-path=/var/log/kubernetes/audit/audit.log
- --audit-log-maxage=7
- --audit-log-maxbackup=5
- --audit-log-maxsize=100
volumeMounts:
- mountPath: /etc/kubernetes/audit
name: audit-policy
readOnly: true
- mountPath: /var/log/kubernetes/audit
name: audit-logs
volumes:
- hostPath:
path: /etc/kubernetes/audit
type: DirectoryOrCreate
name: audit-policy
- hostPath:
path: /var/log/kubernetes/audit
type: DirectoryOrCreate
name: audit-logs

Pour envoyer les événements vers un système externe (SIEM, Elasticsearch) :

/etc/kubernetes/audit/audit-webhook-config.yaml
apiVersion: v1
kind: Config
clusters:
- name: audit-webhook
cluster:
server: https://siem.example.com/k8s-audit
certificate-authority: /etc/kubernetes/pki/ca.crt
contexts:
- name: audit-webhook
context:
cluster: audit-webhook
current-context: audit-webhook

Flags API Server pour webhook :

Fenêtre de terminal
--audit-webhook-config-file=/etc/kubernetes/audit/audit-webhook-config.yaml
--audit-webhook-initial-backoff=5s
--audit-webhook-batch-max-size=1000
{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "RequestResponse",
"auditID": "abc123",
"stage": "ResponseComplete",
"requestURI": "/api/v1/namespaces/default/secrets",
"verb": "create",
"user": {
"username": "admin",
"groups": ["system:masters", "system:authenticated"]
},
"sourceIPs": ["10.0.0.50"],
"userAgent": "kubectl/v1.30.0",
"objectRef": {
"resource": "secrets",
"namespace": "default",
"name": "my-secret",
"apiVersion": "v1"
},
"responseStatus": {
"code": 201
},
"requestObject": {
"kind": "Secret",
"data": { "password": "***" }
},
"stageTimestamp": "2025-06-19T10:30:00Z"
}
Fenêtre de terminal
# Toutes les créations de secrets
cat audit.log | jq 'select(.verb=="create" and .objectRef.resource=="secrets")'
# Actions d'un utilisateur spécifique
cat audit.log | jq 'select(.user.username=="suspicious-user")'
# Accès refusés (403)
cat audit.log | jq 'select(.responseStatus.code==403)'
# Toutes les actions sur un namespace
cat audit.log | jq 'select(.objectRef.namespace=="production")'
# Exec dans des pods
cat audit.log | jq 'select(.objectRef.subresource=="exec")'
# Top 10 des utilisateurs les plus actifs
cat audit.log | jq -r '.user.username' | sort | uniq -c | sort -rn | head -10
# Actions des 5 dernières minutes
cat audit.log | jq --arg d "$(date -u -d '5 minutes ago' +%Y-%m-%dT%H:%M:%SZ)" \
'select(.stageTimestamp > $d)'
Fenêtre de terminal
# Exemple : qui a modifié le RBAC hier ?
cat audit.log | jq --arg start "2025-06-18T00:00:00Z" --arg end "2025-06-19T00:00:00Z" \
'select(
.objectRef.apiGroup=="rbac.authorization.k8s.io" and
.verb!="get" and .verb!="list" and .verb!="watch" and
.stageTimestamp > $start and .stageTimestamp < $end
) | {time: .stageTimestamp, user: .user.username, verb, resource: .objectRef.resource, name: .objectRef.name}'

Falco peut analyser les audit logs Kubernetes pour des détections avancées. Voir le guide Falco pour la configuration du plugin K8s Audit.

Sur les clusters managés, les audit logs sont gérés par le fournisseur cloud. Vous ne pouvez généralement pas personnaliser la politique d’audit, mais les logs sont automatiquement centralisés et consultables via les outils natifs.

AWS EKS envoie les audit logs vers CloudWatch Logs. Par défaut, seuls les logs API Server et Authenticator sont activés.

Fenêtre de terminal
# Activer les audit logs (control plane logging)
eksctl utils update-cluster-logging \
--cluster my-cluster \
--enable-types audit,api,authenticator \
--region eu-west-1

Ou via AWS CLI :

Fenêtre de terminal
aws eks update-cluster-config \
--name my-cluster \
--logging '{"clusterLogging":[{"types":["audit","api","authenticator"],"enabled":true}]}'

Consulter les logs :

Fenêtre de terminal
# Les logs sont dans le groupe /aws/eks/<cluster>/cluster
aws logs filter-log-events \
--log-group-name /aws/eks/my-cluster/cluster \
--log-stream-name-prefix kube-apiserver-audit \
--filter-pattern '{ $.verb = "create" && $.objectRef.resource = "secrets" }'
Fenêtre de terminal
# Vérifier les erreurs
sudo journalctl -u kubelet | grep -i apiserver | tail -50
# Erreurs YAML courantes
sudo cat /etc/kubernetes/manifests/kube-apiserver.yaml | yq .

Causes fréquentes :

SymptômeCauseSolution
”audit policy file not found”Chemin incorrect ou fichier absentVérifier le path et les permissions
”invalid audit policy”YAML invalideValider le YAML avec yq . policy.yaml ou un linter
CrashLoopBackOff API ServerVolume mount incorrectVérifier hostPath et mountPath
Fenêtre de terminal
# Vérifier que l'audit est actif
ps aux | grep kube-apiserver | grep audit
# Les flags doivent apparaître
# --audit-policy-file=/etc/kubernetes/audit/audit-policy.yaml
# --audit-log-path=/var/log/kubernetes/audit/audit.log
# Vérifier les permissions du répertoire
ls -la /var/log/kubernetes/audit/
# Générer une action pour créer des logs
kubectl create secret generic test-audit --from-literal=key=value
kubectl delete secret test-audit

Exclure le bruit

Utiliser level: None pour les health checks, metrics, et reads fréquents.

RequestResponse avec parcimonie

Réserver ce niveau aux secrets, RBAC, et pods/exec.

Rotation des logs

Configurer maxage, maxbackup, maxsize pour éviter de remplir le disque.

Centraliser les logs

Utiliser un webhook vers SIEM/Elasticsearch pour la rétention longue.

ConceptDescription
Audit PolicyFichier YAML définissant quoi logger et à quel niveau
NiveauxNone < Metadata < Request < RequestResponse
StagesRequestReceived, ResponseStarted, ResponseComplete, Panic
Backend fichier--audit-log-path pour logs locaux
Backend webhookPour envoyer vers systèmes externes (SIEM)
Rotation--audit-log-maxage/maxbackup/maxsize

Falco Runtime Security

Détecter les comportements suspects en temps réel. Configurer Falco

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

10 questions
8 min.
70% requis

Informations

  • Le chronomètre démarre au clic sur Démarrer
  • Questions à choix multiples, vrai/faux et réponses courtes
  • Vous pouvez naviguer entre les questions
  • Les résultats détaillés sont affichés à la fin

Lance le quiz et démarre le chronomètre

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn