Incident de sécurité ? Suspicion de compromission ? 09 71 18 27 69csirt@synacktiv.com

Forensic AWS EKS : sources de données et méthodes d'investigation

Rédigé par Théo Letailleur - 24/08/2026 - dans CSIRT - Téléchargement

Analyser une compromission sur Amazon EKS revient à reconstituer des preuves réparties sur trois couches : le control plane Kubernetes managé, les nodes workers et les services AWS environnants. Cet article cartographie les sources de données qu'un cluster EKS expose pour l'investigation numérique et le threat hunting, ainsi que l'outillage utilisé pour les corréler, du journal d'audit Kubernetes jusqu'à l'identité AWS des nodes.

Vous souhaitez améliorer vos compétences ? Découvrez nos sessions de formation ! En savoir plus

Dans le cadre de notre série Kubernetes Forensics, cet article s'appuie sur « Kubernetes Forensics 1/3: what the container » (fonctionnement interne des conteneurs et méthodologie d'analyse appliquée). Pour un contexte plus large, voir également « AWS Forensics: what you need to know », sur l'outillage d'investigation à travers AWS.

Introduction

Les clusters Kubernetes apparaissent désormais régulièrement dans les incidents traités par le CSIRT de Synacktiv. La technologie est intrinsèquement complexe : de nombreux composants interdépendants, et une couche d'abstraction importante dans les offres managées, où le client ne contrôle pas l'ensemble de la stack. La supervision et la sécurité sont fréquemment ajoutées tardivement, ce qui laisse aux analystes une visibilité limitée une fois l'intrusion survenue. Ces intrusions débutent de plus en plus au niveau applicatif : une injection de template Helm via un contrôleur GitOps tel qu'ArgoCD, par exemple, peut transformer une valeur de chart en exécution de charge de travail au sein du cluster (Paul Barbé, Charting your way in: Helm template injection, SSTIC 20261). Cet article ne revient pas sur la manière dont un cluster est compromis ; il se concentre sur ce que la compromission laisse derrière elle et sur la façon de l'investiguer.

L'investigation numérique sur Kubernetes reste par ailleurs une discipline relativement immature, contrainte par deux facteurs structurels : la volatilité des données (un pod supprimé ou redémarré emporte l'essentiel de son état) et la difficulté à localiser les artefacts au sein de clusters vastes et distribués. En pratique, l'issue d'une investigation EKS se joue largement avant l'incident, à travers la journalisation et la supervision mises en place. Cet article résume les sources de données qu'Amazon EKS expose et l'outillage utilisé pour les exploiter.

N.B. Cet article se concentre sur les sources de données et l'outillage natifs d'AWS. Les solutions tierces de sécurité runtime (Falco, Sysdig, Wiz et similaires) peuvent améliorer sensiblement la visibilité intra-conteneur, mais sortent du périmètre traité ici.

Amazon EKS en contexte

Amazon EKS est l'offre Kubernetes managée d'AWS. Le mode de déploiement détermine le niveau d'accès dont dispose un intervenant sur les nodes, et donc ce qui peut être collecté :

Amazon EKS : control plane managé par AWS, data plane appartenant au client
Amazon EKS en mode classique : le control plane est managé par AWS, le data plane (nodes EC2) appartient au client. Source : documentation AWS.
Mode Gestion des workers Accès aux nodes pour le forensic
EKS standard (groupes de nodes managés / auto-gérés) Client (les nodes sont des EC2) SSH ou SSM directement sur le worker
EKS Auto Mode2 AWS AMI Bottlerocket immuables qui interdisent SSH/SSM ; un pod de debug privilégié est requis. De plus, les nodes ont une durée de vie maximale de 21 jours.
Fargate3 AWS (une micro-VM par pod) Abstraction complète de l'hôte : aucun accès au node, et aucun moyen d'exécuter des agents par node (les DaemonSets tels que Fluent Bit ou l'agent runtime de GuardDuty ne s'exécutent pas sur Fargate)

Sur un cluster standard, les nodes workers sont des instances EC2 qu'un intervenant peut atteindre via SSH ou SSM ; en Auto Mode ou Fargate, l'hôte est managé par AWS et l'accès direct au node n'est pas disponible. Déterminer le mode de compute est donc la première étape de triage, aux côtés de quelques questions pratiques : quelle télémétrie est réellement activée (journalisation d'audit du control plane, Container Insights, GuardDuty), et le pod suspect a-t-il déjà été supprimé ou redémarré, emportant son état avec lui.

Sources de données

Une investigation EKS s'appuie sur trois familles de logs, toutes centralisables dans CloudWatch : le control plane Kubernetes, le data plane (conteneurs et hôtes) et les services AWS environnants.

Flux de données de journalisation et de détection EKS
Le flux global : sources, collecteurs, CloudWatch ; GuardDuty ; CloudTrail, et les consoles d'investigation.

Logs du control plane

Par défaut, aucun de ces logs n'est activé. Cinq types de logs sont disponibles et s'activent par cluster via l'API de journalisation du control plane4, exportés au niveau de verbosité 2, comme le suggère la documentation :

aws eks update-cluster-config --name <cluster> --region <region> \
  --logging '{"clusterLogging":[{"types":["api","audit","authenticator","controllerManager","scheduler"],"enabled":true}]}'
Configuration de la journalisation du control plane EKS dans la console
La journalisation du control plane est optionnelle (opt-in), configurée sous l'onglet Observability du cluster.
Type Contenu Valeur DFIR
api Requêtes servies par l'API server (par exemple via kubectl) Élevée
audit Piste d'audit détaillée : identité, verbe, ressource, requestObject Centrale
authenticator Authentification (mapping IAM ↔ RBAC), spécifique à EKS Moyenne
controllerManager / scheduler État des contrôleurs et décisions d'ordonnancement Faible / très spécifique

Les cinq arrivent dans un unique log group, /aws/eks/[cluster]/cluster, sous forme de log streams distincts (kube-apiserver-audit-*, authenticator-*, etc.).

Log streams EKS
Log streams du control plane EKS

Le journal d'audit est la colonne vertébrale de l'investigation : il enregistre qui a fait quoi, sur quelle ressource, depuis quelle adresse IP source et avec quel user agent. Les champs pertinents sont user.username, verb, objectRef.resource, objectRef.namespace, objectRef.name, responseStatus.code, sourceIPs.0, userAgent et requestObject.*.  

Le contenu de requestObject varie selon le type de ressource concerné. Pour la création d'un pod, par exemple, il capture le manifeste complet soumis pour le pod : image, commande, variables d'environnement, volumes montés, et davantage. Pour un analyste forensic, c'est une vraie mine d'or.

GuardDuty EKS Protection5 consomme les logs d'audit EKS via son propre flux indépendant ; activer la journalisation d'audit du control plane vers CloudWatch n'est pas un prérequis pour GuardDuty, mais reste nécessaire pour une analyse et une rétention correctes.

Logs du data plane (Container Insights)

L'add-on EKS amazon-cloudwatch-observability6 déploie l'agent CloudWatch (métriques) et Fluent Bit7 (logs) en tant que DaemonSet. Fluent Bit achemine les logs du data plane vers trois log groups :

Log group Source
/aws/containerinsights/[cluster]/application Logs des conteneurs depuis /var/log/containers (stdout/stderr)
/aws/containerinsights/[cluster]/host Logs de l'OS du worker : /var/log/dmesg, /var/log/secure, /var/log/messages
/aws/containerinsights/[cluster]/dataplane journald pour kubelet, kube-proxy et le runtime de conteneurs

Un quatrième group, /aws/containerinsights/[cluster]/performance, contient les métriques système et réseau ; il est produit par l'agent CloudWatch plutôt que par Fluent Bit.

Les logs des conteneurs sont enrichis de métadonnées Kubernetes (kubernetes.namespace_name, kubernetes.pod_name, kubernetes.host), ce qui évite d'avoir à collecter (et localiser !) les logs node par node et pod par pod.

Log groups Container Insights créés pour le cluster dans CloudWatch
Les groups Container Insights, tels qu'ils apparaissent dans CloudWatch

Sources au niveau AWS

Source Rôle Notes
GuardDuty             Détection managée des menaces EKS Protection8 (analyse des logs d'audit) et le Runtime Monitoring optionnel9 (agent eBPF, syscalls)
CloudTrail10 Activité de l'API AWS

endpoint eks.amazonaws.com (administrateurs, outillage d'automatisation/IaC et principals de service AWS agissant sur le cluster)

endpoint eks-auth.amazonaws.com pour les pods assumant des rôles (via le Pod Identity Agent)

VPC Flow Logs11 Métadonnées réseau

Livrés vers CloudWatch Logs, S3 ou Firehose.

Note : attribuer un flux à un pod nécessite de corréler l'adresse IP de l'ENI avec un inventaire du cluster horodaté. Il n'existe pas de champ de contexte Kubernetes natif (seul ECS en possède un)

Les nodes et certains pods portent une identité AWS : le rôle IAM du node, ou IRSA12 / EKS Pod Identity13 pour les charges de travail. Lorsqu'un node ou un pod est compromis, cette identité peut être détournée sur d'autres ressources AWS, et le rôle du node est particulièrement sensible, car il peut lui-même distribuer des credentials pour les rôles des pods du cluster. CloudTrail conserve l'activité API correspondante. 

Sources d'événements au niveau AWS alimentant CloudWatch
GuardDuty, CloudTrail et VPC Flow Logs, centralisés dans CloudWatch.

Outillage d'investigation

CloudWatch Logs Insights

Logs Insights est la console utilisée pour interroger chaque log group avec un langage proche du SQL. Les requêtes génériques suivantes opèrent sur les logs d'audit EKS.

Actions mutantes, regroupées par identité :

fields @timestamp, user.username, verb, objectRef.resource, objectRef.namespace,
       responseStatus.code, sourceIPs.0, userAgent
| filter verb in ["create", "update", "patch", "delete"]
| sort @timestamp desc

Cette requête est volontairement large et renvoie beaucoup de résultats. La restreindre à un indicateur connu, tel qu'un ServiceAccount, une adresse IP source, ou un nom de pod ou de namespace issu d'un finding GuardDuty, limite les résultats à l'activité autour d'une identité suspectée. Par exemple, les résultats suivants en recherchant des namespaces spécifiques (jupyter) :

Résultats de la requête sur les actions mutantes
Résultats de la requête filtrée sur les actions mutantes

Une rafale d'objets SelfSubjectAccessReview et SelfSubjectRulesReview révèle une reconnaissance RBAC : un principal énumérant ses propres privilèges namespace par namespace, comme le fait kubectl auth can-i --list :

fields @timestamp, user.username, sourceIPs.0
| filter objectRef.resource in ["selfsubjectreviews", "selfsubjectrulesreviews"]
| stats count(*) as n by user.username, bin(1m)
| sort n desc
Une rafale de requêtes selfsubject peut révéler une reconnaissance RBAC
Une rafale de requêtes SelfSubjectRulesReview.

 

Modifications des rôles RBAC, l'étape pivot d'une escalade au sein du cluster. Le verbe escalate14 sur un rôle permet à un principal d'élargir ses propres permissions en éditant ce rôle. L'ensemble de règles appliqué est visible dans le requestObject :

fields @timestamp, user.username, objectRef.namespace, verb, objectRef.name, sourceIPs.0
| filter verb in ["update", "patch"]
| filter objectRef.resource in ["roles", "clusterroles"]
| sort @timestamp desc
Résultat de la requête Log Insights sur les requêtes de patch de rôle vers l'API
Résultat de la requête Log Insights sur les requêtes de patch de rôle vers l'API

L'ensemble de règles appliqué se lit dans l'événement brut.

Créations de pods refusées par Pod Security Admission (le code de résultat est HTTP 403), un indicateur fiable d'une tentative d'évasion :

fields @timestamp, user.username, objectRef.namespace, responseObject.message
| filter verb = "create" and objectRef.resource = "pods" and responseStatus.code = 403
| sort @timestamp desc
Une création de pod rejetée par Pod Security Admission
Le message responseStatus de l'enregistrement d'audit en donne la raison : le pod viole la politique PodSecurity du namespace (volumes hostPath).

Un compte de node évaluant ses propres permissions, ce qu'un kubelet légitime ne fait jamais :

fields @timestamp, user.username, verb, objectRef.resource, sourceIPs.0, userAgent
| filter user.username like "system:node:"
| filter objectRef.resource in ["selfsubjectrulesreviews", "selfsubjectaccessreviews"]
| sort @timestamp desc
Un node évaluant ses propres permissions
Un node évaluant de façon suspecte ses propres permissions, avec un user agent kubectl.

Au-delà de la piste d'audit, les groupes Container Insights contiennent les logs des charges de travail (applications) et des hôtes. Le même langage de requête s'applique, en utilisant les attributs Kubernetes enrichis (@entity.Attributes.K8s.Namespace, @entity.Attributes.K8s.Workload) ; filterIndex @data_source_name in ["amazon_eks"] restreint une recherche aux entrées provenant d'EKS.

Les logs applicatifs sont particulièrement utiles pour les composants placés en amont des charges de travail. Un reverse proxy ou un contrôleur d'ingress (par ex. Traefik) enregistre l'adresse IP source du client que les logs applicatifs en aval abandonnent souvent, ce qui permet d'attribuer une action à une adresse externe même lorsque le service cible ne journalise jamais qu'une adresse interne :

fields @timestamp, @entity.Attributes.K8s.Namespace, @entity.Attributes.K8s.Workload, log
| filter @entity.Attributes.K8s.Namespace = "<ingress-namespace>"
| sort @timestamp desc
Logs d'ingress centralisés via Container Insights
Les logs d'ingress collectés par Container Insights conservent l'adresse IP source du client et le chemin demandé, permettant ici de déterminer la source des requêtes de synchronisation ArgoCD.

Les logs d'hôte (/aws/containerinsights/[cluster]/host) couvrent le système d'exploitation du worker : filtrer sur sshd, sudo ou systemd fait ressortir une activité au niveau du node, telle qu'un service ajouté ou une connexion interactive.

fields @timestamp, @message
| filter (@message like "kubelet" and @message like "systemd" and @message like "Stopped") or (@message like "systemd" and @message like "Starting")
| sort @timestamp desc
Logs journald centralisés via Container Insights
Les logs journald collectés par Container Insights montrent ici une activité systemd : le service kubelet qui se recharge, puis un service suspect qui démarre...

 

GuardDuty

GuardDuty est fréquemment la première source d'alerte. Avec EKS Protection, chaque finding lié au cluster porte le contexte Kubernetes : cluster, namespace, pod, ServiceAccount, et l'adresse IP source de la requête API. Quelques findings représentatifs montrent ce que ce contexte apporte.

PrivilegeEscalation:Kubernetes/PrivilegedContainer signale un conteneur privilégié lancé avec un accès de niveau root. En soi, ce n'est pas suspect : les plugins CNI, les drivers CSI et les agents de supervision s'exécutent légitimement en privilégié, de sorte que la valeur du finding réside dans le contexte qu'il porte. Outre le nom du pod et le namespace, il nomme le ServiceAccount qui a créé le pod, et sa section Action expose l'appel API et l'adresse IP source à son origine. Un pod privilégié créé par un ServiceAccount applicatif, depuis une adresse IP inattendue, en dehors des namespaces d'infrastructure habituels, est ce qui distingue un déploiement de routine d'une piste qui mérite d'être creusée.

Un finding GuardDuty PrivilegeEscalation:Kubernetes/PrivilegedContainer
Un finding GuardDuty PrivilegeEscalation:Kubernetes/PrivilegedContainer
Contexte Kubernetes complet du finding GuardDuty
Le finding contient le cluster, le namespace, le pod et le ServiceAccount à l'origine de l'appel API.
Source de l'action API dans un finding GuardDuty
La section Action identifie la requête API et son adresse IP source, ici une adresse externe plutôt que celle du node.

Persistence:Kubernetes/ContainerWithSensitiveMount signale un conteneur démarré avec un chemin d'hôte sensible monté à l'intérieur. Le finding montre le montage dans la définition du conteneur, typiquement la racine du node / liée à un répertoire tel que /mnt, ce qui donne à un attaquant contrôlant le pod un moyen de modifier le node et d'établir une persistance.

Un finding ContainerWithSensitiveMount
Un finding GuardDuty ContainerWithSensitiveMount.

Exporter le finding GuardDuty au format JSON est un bon moyen d'obtenir l'intégralité des détails de la détection, y compris des champs que la console n'affiche pas :

Détails du montage hostPath détecté dans le finding
Le conteneur monte le système de fichiers racine du node, une primitive classique d'évasion de node et de persistance.

Execution:Runtime/ReverseShell est levé par Runtime Monitoring lorsqu'un shell avec une connexion réseau redirigée s'exécute dans un conteneur. Parce que l'agent eBPF fournit la filiation du processus, le finding remonte le processus bash jusqu'au pod exact dont il provient.

Un reverse shell a été détecté dans l'instance de node
Un reverse shell a été détecté dans l'instance de node
Le Runtime Monitoring d'EKS Protection donne des informations sur le pod affecté
Le Runtime Monitoring d'EKS Protection donne des informations sur le pod affecté
L'agent eBPF de GuardDuty trace le processus détecté et la connexion réseau suspecte
L'agent eBPF de GuardDuty trace le processus détecté et la connexion réseau suspecte

UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS (ou .InsideAWS) est un finding EC2/IAM plutôt qu'EKS, mais il est central dans les intrusions EKS : il signale que les credentials du rôle IAM du node ont été utilisés depuis une adresse IP externe, le signe d'une identité de node volée et rejouée en dehors du cluster (voir la section CloudTrail ci-dessous).

Credentials du rôle du node utilisés depuis un compte AWS externe
Credentials du rôle du node utilisés depuis un compte AWS externe.

Récapitulatif des quelques findings GuardDuty (liste non exhaustive) :

Finding Description
PrivilegeEscalation:Kubernetes/PrivilegedContainer Un pod privilégié, de capacité root, a été créé
Persistence:Kubernetes/ContainerWithSensitiveMount Un pod monte un chemin d'hôte sensible (évasion de node)
Execution:Runtime/ReverseShell Un reverse shell s'exécute dans un conteneur (Runtime Monitoring)
UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS|InsideAWS Les credentials du rôle du node ont été utilisés depuis une adresse IP externe

Deux limites méritent d'être notées. GuardDuty est une boîte noire : les règles de détection ne sont pas divulguées et ne peuvent pas être étendues, bien que la référence des types de findings15 documente le catalogue complet. Et le Runtime Monitoring16 (visibilité des syscalls via un agent de sécurité eBPF) est optionnel, déploie des pods supplémentaires et ne prend pas en charge les clusters EKS s'exécutant sur Fargate. Sans lui, la couverture intra-conteneur est partielle et les logs d'audit demeurent l'enregistrement principal au sein du cluster. Un finding est là toujours une piste à confirmer, jamais un verdict.

CloudTrail

Lorsqu'un attaquant obtient une identité de node (via l'IMDS) ou une identité de pod (via IRSA ou Pod Identity), les appels API AWS qui en résultent sont enregistrés par CloudTrail.

Activité de découverte CloudTrail depuis une identité de node volée
Appels API AWS en lecture seule émis depuis l'extérieur de l'egress du cluster : découverte de ressources cloud avec un token volé.

L'activité du rôle du node peut être isolée en excluant les subnets des nodes du cluster et l'egress de la NAT gateway :

fields @timestamp, eventName, sourceIPAddress, userAgent
| filter userIdentity.arn like "<node-role-name>"
| filter not (sourceIPAddress like /^10\.0\./) and sourceIPAddress != "<nat-gateway-eip>"   # node subnets (10.0.0.0/16) + NAT egress
| stats count(*) as n by eventName, sourceIPAddress
| sort n desc

Une rafale d'appels en lecture (Describe*, List*, Get*) depuis une adresse IP en dehors de l'egress du cluster, avec un user agent aws-cli, est caractéristique d'une découverte de ressources cloud à partir d'un token volé.

La source d'événements eks.amazonaws.com enregistre de la même manière les actions d'administrateur sur le cluster lui-même.

Événement CloudTrail sur la source eks.amazonaws.com
UserIdentity d'un administrateur Kubernetes sur un événement lié à la source eks.amazonaws.com (ListNodegroups)
Détails de l'événement eks CloudTrail ListNodegroups
Détails de l'événement eks CloudTrail ListNodegroups

kubectl

Avec un compte administrateur EKS, kubectl reste un moyen efficace de capturer le contexte en direct : rôles et bindings RBAC, la définition d'un pod suspect (kubectl get pod [pod id] -o yaml), les événements du cluster, et les ServiceAccounts. C'est la voie la plus rapide pour identifier une règle dangereuse telle que le verbe escalate sur les roles.

Acquisition au niveau du node

Sur un cluster standard, l'accès au worker via SSH ou SSM Session Manager17 permet une collecte au niveau système :

aws ssm start-session --target [node instance-id]

Lorsque ni SSH ni SSM ne sont disponibles, kubectl debug node/[node] planifie un pod qui monte le système de fichiers de l'hôte sous /host, donnant accès au node. C'est une voie de dernier recours plutôt qu'une option privilégiée : elle ajoute une charge de travail au node en cours d'analyse, laissant de nouvelles entrées create pods dans le journal d'audit. Lorsque aucun accès moins intrusif n'existe, elle doit être utilisée de façon délibérée et documentée.

Le node héberge les tokens de ServiceAccount des pods qui y sont planifiés, montés en tant que volumes projetés et cible fréquente des techniques de collecte d'identifiants : 

find /var/lib/kubelet/pods -path "*/kubernetes.io~projected/*/token" -type f

Au niveau Kubernetes, l'API de checkpoint du kubelet18 (en bêta depuis la v1.30 mais activée par défaut) peut figer l'état d'un conteneur dans une archive hors ligne sans le terminer. Elle repose sur CRIU via le runtime CRI, que les AMI optimisées pour EKS n'embarquent pas actuellement, de sorte que la technique n'est pas utilisable sur EKS à l'heure où nous écrivons. Nous prévoyons de traiter le checkpointing de conteneurs sur EKS dans un prochain article.

Cas d'usage : détecter une persistance au niveau du node

Une fois que l'attaquant atteint le node, la persistance est un objectif fréquent, et elle laisse des traces spécifiques à travers les sources ci-dessus. Parmi les mécanismes connus, le static pod19 se distingue : un manifeste déposé directement sur le node, que le kubelet récupère et exécute en dehors du workflow normal piloté par l'API.

Sur les AMI optimisées pour EKS, le kubelet ne surveille pas de répertoire manifests par défaut : staticPodPath est absent de sa configuration (/etc/kubernetes/kubelet/config.json), de sorte que la technique nécessite d'abord de le définir sur un répertoire (par exemple /etc/kubernetes/kubelet/manifests) puis de recharger/redémarrer le service. Ce prérequis est lui-même un artefact observable sur le node avant même que le pod n'existe.

Lorsque le kubelet charge un manifeste depuis /etc/kubernetes/manifests et démarre un conteneur de lui-même, il enregistre un mirror pod sur l'API server afin que le pod soit visible via kubectl. GuardDuty lève le finding Execution:Kubernetes/AnomalousBehavior.WorkloadDeployed correspondant (« a workload was launched in an unusual way »).

GuardDuty AnomalousBehavior.WorkloadDeployed pour un static pod
GuardDuty signale le static pod comme une charge de travail lancée de manière inhabituelle.
Les détails de la charge de travail Kubernetes indiquent le nom du mirror pod
Les détails de la charge de travail Kubernetes indiquent le nom du mirror pod, contenant l'adresse IP de l'instance du node

À partir de cette piste, le journal d'audit confirme le mécanisme : le pod est créé par une identité system:node: et porte l'annotation kubernetes.io/config.source = "file" (au lieu de "api"), preuve concluante d'un static pod placé directement sur le disque du node.

fields @timestamp, user.username, objectRef.name,
       `requestObject.metadata.annotations.kubernetes.io/config.source` as config_source
| filter verb = "create" and objectRef.resource = "pods"
| filter user.username like "system:node:"
| sort @timestamp desc
Enregistrement d'audit du mirror pod créé par le node
Le mirror pod est créé par une identité system:node: avec config.source = "file".

Approche d'investigation

Préparation

L'essentiel de l'issue de l'investigation se décide avant l'incident, car EKS n'émet presque aucune télémétrie pertinente par défaut.

La journalisation d'audit du control plane, avec une fenêtre de rétention correcte, produit la timeline au sein du cluster. Container Insights et solutions similaires ajoutent les logs des charges de travail et des hôtes. GuardDuty EKS Protection, avec le Runtime Monitoring apportant la visibilité intra-conteneur, fournit une détection managée. Enfin, CloudTrail enregistre l'activité au niveau AWS des administrateurs ainsi que des identités de node et de pod. 

Le durcissement réduit l'impact d'une compromission :

  • Les permission boundaries sur les rôles IAM du node et du pod limitent ce qu'une identité volée peut atteindre,
  • une politique Pod Security Admission20 restrictive sur les namespaces qui n'ont pas besoin de privilèges bloque les primitives habituelles d'évasion de node,
  • et des ServiceAccounts au moindre privilège limitent ce qu'un token compromis accorde.

Endiguement

Une fois une compromission détectée, l'endiguement interfère généralement avec la préservation des preuves. kubectl delete est le réflexe à éviter : supprimer ou redémarrer un pod détruit l'état du processus, la couche inscriptible (upper) et les tokens projetés dont dépend l'analyse, et un contrôleur peut immédiatement replanifier la charge de travail ailleurs.

L'isolation s'obtient mieux au niveau réseau, avec les NetworkPolicies et les Security Groups, tout en gardant les sondes de liveness et readiness satisfaites afin que le pod ne soit ni tué ni déplacé. Lorsqu'une identité AWS a été volée, cependant, révoquer ou faire tourner les credentials du rôle du node et les tokens de ServiceAccount fuités est ce qui coupe réellement l'accès de l'attaquant : l'isolation réseau seule n'y suffit pas, puisqu'un token volé peut être rejoué depuis n'importe où.

Les techniques d'endiguement natives à Kubernetes méritent leur propre traitement et seront couvertes dans un article dédié plus loin dans cette série.

Acquisition

La collecte est une course contre le cycle de vie du pod : la mémoire d'un pod en cours d'exécution, l'état de ses processus et sa couche inscriptible (UpperDir) disparaissent au moment où il redémarre, emportant avec eux les tokens de ServiceAccount projetés détenus sur son node, tandis que les logs CloudWatch centralisés sont durables et peuvent être récupérés plus tard.

Le pod vivant et ces tokens locaux au node passent donc en premier. Une session kubectl administrateur capture ensuite le contexte que les logs ne rendent pas toujours explicite : définitions RBAC, spécifications de pods, événements du cluster.

Analyse

L'investigation est guidée par deux pivots portés à travers les trois couches : l'identité agissante et l'adresse IP source.

  1. Un finding GuardDuty ou une anomalie signalée est le point d'entrée habituel, traité comme une piste plutôt que comme un verdict. Il met en évidence une identité (un user.username, un ServiceAccount, ou un ARN de rôle IAM) et une adresse IP source, et l'analyse se poursuit en suivant ces deux valeurs.
  2. Au sein du cluster, le journal d'audit reconstitue ce qu'a fait cette identité : reconnaissance (SelfSubjectRulesReview), modifications RBAC (escalate sur les roles), créations de pods, etc. Les logs applicatifs et d'hôte ajoutent la vue runtime et système : la requête d'exploitation à l'origine de l'accès initial (un log d'ingress ou de reverse-proxy conserve souvent la véritable adresse IP client), une connexion interactive ou un sudo sur le node. L'exécution de commandes intra-conteneur demeure l'angle mort que seuls le runtime monitoring ou un agent tiers comblent.
  3. Enfin, la question est de savoir si la compromission est restée dans le cluster ou a franchi le plan AWS. Les credentials du rôle du node rejoués depuis une adresse IP externe apparaissent sous le finding InstanceCredentialExfiltration et orientent l'investigation vers CloudTrail, où les appels API de cette identité sont isolés en excluant l'adresse interne légitime du node ; une identité de pod volée se poursuit de la même manière, sans finding GuardDuty dédié comme il en existe pour le rôle du node.

Joindre les trois couches sur leurs adresses IP sources, identités et horodatages partagés produit une timeline unique, ce qui transforme des événements isolés en une chaîne d'attaque.

Conclusion

Une investigation EKS dépend presque entièrement de la télémétrie disponible en amont. Avec la journalisation d'audit du control plane, Container Insights, GuardDuty et CloudTrail en place, CloudWatch Logs Insights et la corrélation des événements Kubernetes et cloud suffisent à reconstituer une chaîne d'attaque, du control plane jusqu'à l'identité AWS des nodes. GuardDuty fournit un point d'entrée pratique, mais les logs d'audit et une collecte rigoureuse demeurent les facteurs décisifs de l'analyse.

Les techniques observées peuvent être mappées sur la threat matrix for Kubernetes21 maintenue par Microsoft, qui est largement applicable à EKS.


Si votre organisation a besoin d'aide pour lever un doute ou répondre à un incident de sécurité, n'hésitez pas à contacter le CSIRT de Synacktiv.