L’emplacement des journaux d’audit de Kubernetes dépend de qui gère votre plan de contrôle. Sur un cluster autogéré, ils sont sous forme de fichier JSON-lines sur le nœud du plan de contrôle, à l’emplacement pointé par –audit-log-path. Sur EKS, ils vont vers CloudWatch Logs, sur AKS vers un espace de travail Log Analytics ou un compte de stockage, et sur GKE vers Cloud Audit Logs. Une chose est certaine: la journalisation d’audit doit être activée. Sur les clusters autogérés et EKS, elle est désactivée jusqu’à ce que quelqu’un l’active.
Le journal d’audit enregistre chaque requête à l’API Kubernetes: qui a exécuté kubectl exec dans quel pod, qui a lu quel secret, qui s’est lié à cluster-admin. Prime Core a 93 règles de détection pour les données d’audit de Kubernetes, cartographiées sur 220 techniques MITRE ATT&CK. Parmi elles : exec dans les conteneurs en cours d’exécution (T1609), déploiement de conteneurs malveillants (T1610) et lecture de crédentiels via l’API des conteneurs (T1552.007).
Avant de commencer
Est-ce activé ?
| Plateforme | Où vérifier |
|---|---|
| Autogéré (kubeadm et similaire) | –audit-policy-file et –audit-log-path sur le serveur API; avec kubeadm, dans /etc/kubernetes/manifests/kube-apiserver.yaml |
| EKS | Cluster → Observabilité → journalisation du plan de contrôle, type de journal « audit » |
| AKS | Paramètres de diagnostic sur le cluster, catégories kube-audit ou kube-audit-admin |
| GKE | Activé par défaut pour l’activité administrateur ; la journalisation de l’accès aux données pour Kubernetes est facultative |
Si ce n’était pas activé, rien à exporter pour le passé, et le reste de ce guide concerne la prochaine fois.
Le détail dépend de la politique. Au niveau Métadonnées, vous voyez qui a fait quoi à quel objet. Au niveau Requête ou RéponseRequête, vous voyez également les corps, par exemple la spécification de pod qui demandait privileged: true. Sachez lequel vous avez avant de chercher.
Prévoyez du volume. Les contrôleurs et comptes de service parlent constamment à l’API. Sur AKS, kube-audit-admin n’inclut pas les appels get et list en lecture seule, ce qui maintient la taille raisonnable mais cache aussi les lectures de secrets.
Exportez-le
Cluster autogéré, sur un nœud de plan de contrôle :
# confirmez d'abord le chemin
sudo grep -- '--audit-log-path' /etc/kubernetes/manifests/kube-apiserver.yaml
sudo cat /var/log/kubernetes/audit/audit.log > k8s_audit.jsonl
Les fichiers tournés (de –audit-log-maxbackup) sont à côté avec un horodatage dans le nom. Incluez-les si la fenêtre remonte.
EKS, depuis CloudWatch Logs :
aws logs filter-log-events --log-group-name /aws/eks/my-cluster/cluster
--log-stream-name-prefix kube-apiserver-audit
--start-time $(date -d '2026-10-19T00:00:00Z' +%s000) --end-time $(date -d '2026-10-20T00:00:00Z' +%s000)
--output json | jq -c '.events[].message | fromjson' > eks_audit_1019.jsonl
Chaque événement CloudWatch enveloppe l’entrée d’audit en tant que chaîne ; fromjson la désenveloppe. La syntaxe date -d est GNU ; sur macOS, calculez les horodatages millisecondés autrement.
AKS, depuis Log Analytics (tables spécifiques aux ressources) :
az monitor log-analytics query -w <workspace-id>
--analytics-query "AKSAuditAdmin | where TimeGenerated between (datetime(2026-10-19) .. datetime(2026-10-20))"
--output json > aks_audit_1019.json
GKE, depuis Cloud Audit Logs :
gcloud logging read 'resource.type="k8s_cluster" AND logName:"cloudaudit.googleapis.com" AND timestamp>="2026-10-19T00:00:00Z" AND timestamp<"2026-10-20T00:00:00Z"'
--project=my-project --format=json | jq -c '.[]' > gke_audit_1019.jsonl
À rechercher
| Requête | Pourquoi cela compte |
|---|---|
| création sur pods/exec (objectRef.subresource: exec) | Quelqu’un a ouvert un terminal dans un conteneur en cours d’exécution |
| création d’un ClusterRoleBinding pour cluster-admin | Escalade de privilèges vers un contrôle total |
| obtenir ou lister sur des secrets par une identité inhabituelle | Collecte de crédentiels |
| Pods créés avec privileged, hostPath ou hostNetwork | Une étape vers l’évasion vers le nœud |
| user.username: system:anonymous avec une réponse 2xx | Accès anonyme qui ne devrait pas fonctionner |
| Rafales de 403 depuis un compte de service | Un jeton volé testant ses permissions |
Télécharger, assainir et examiner dans LogTotal
- Télécharger. Ouvrir logtotal.com et déposer dans le fichier .jsonl.
- Assainir. [what gets masked: usernames, service account names, source IPs, namespaces, object names]. Look it over before you continue.
- Examiner.
Quand ça tourne mal
| Symptôme | Cause probable | Fix |
|---|---|---|
| Pas de fichier d’audit sur le plan de contrôle | Le serveur API n’a pas de politique d’audit configurée | Attendu; configurez-le pour l’avenir |
| Groupe de journaux EKS ou flux d’audit manquants | Le type de journal du plan de contrôle « audit » n’est pas activé | Activez-le pour l’avenir |
| Chaque ligne est une longue chaîne échappée | Enveloppement CloudWatch | Désenveloppez avec fromjson, comme ci-dessus |
| Vous pouvez voir qui a changé un pod, mais pas comment | La politique est au niveau Métadonnées | Augmentez le niveau pour les ressources sensibles |
| Aucune lecture de secrets dans les données AKS | kube-audit-admin exclut get et list | Collectez kube-audit si vous en avez besoin |
FAQ
Les journaux de conteneurs ne suffisent-ils pas?
Non. Les journaux de conteneurs montrent ce qu’une application a imprimé. Le journal d’audit montre ce que les personnes et comptes de service ont fait au cluster. Différentes questions, différents journaux.
Puis-je lire le fichier d’audit sur un cluster géré?
Non. Sur EKS, AKS et GKE, vous n’avez pas accès aux nœuds du plan de contrôle. Le service de journalisation du fournisseur est le seul passage.