Récupérer l'ID d'instance EC2 via le Service de Métadonnées : Pourquoi IMDSv2 est Indispensable

Vous écrivez un script de démarrage sur une instance EC2 et vous avez besoin de l'ID de l'instance — sans le coder en dur, sans appel API externe. Le réflexe naturel est d'interroger le service de métadonnées local. Mais si votre script utilise encore IMDSv1, vous exposez potentiellement votre infrastructure à une classe d'attaques bien documentée que IMDSv2 a été conçu pour éliminer.

Résumé (TL;DR) : IMDSv1 vs IMDSv2 pour Récupérer l'ID d'Instance EC2

AspectIMDSv1IMDSv2
Mécanisme d'authentificationAucun — requête GET directeToken de session obligatoire (TTL configurable)
Résistance aux SSRFNon — une requête suffitOui — nécessite un PUT préalable avec en-tête spécifique
Commande principalecurl http://169.254.169.254/latest/meta-data/instance-idObtenir un token puis interroger avec l'en-tête X-aws-ec2-metadata-token
Recommandation AWSDéprécié pour nouveaux déploiementsRecommandé — peut être rendu obligatoire par configuration
Support des types d'instancesTousTous (disponible depuis novembre 2019)

Comment Fonctionne le Service de Métadonnées d'Instance EC2 (IMDS)

L'IMDS est un endpoint HTTP local accessible uniquement depuis l'intérieur de l'instance, à l'adresse de lien-local 169.254.169.254. Ce n'est pas un service AWS régional — c'est un composant de l'hyperviseur qui répond aux requêtes de l'instance hôte. Aucun paquet ne quitte l'hôte physique pour atteindre cet endpoint.

L'ID d'instance, le type d'instance, la région, les credentials IAM temporaires associés au rôle attaché — tout cela est exposé via ce service. C'est précisément pour cette raison que la sécurité du mécanisme d'accès compte autant.

sequenceDiagram participant Script participant IMDS as IMDS (169.254.169.254) Note over Script,IMDS: IMDSv1 — Requête directe (non sécurisée) Script->>IMDS: GET /latest/meta-data/instance-id IMDS-->>Script: i-1234567890abcdef0 Note over Script,IMDS: IMDSv2 — Token de session obligatoire Script->>IMDS: PUT /latest/api/token
(X-aws-ec2-metadata-token-ttl-seconds: 21600) IMDS-->>Script: TOKEN_VALUE Script->>IMDS: GET /latest/meta-data/instance-id
(X-aws-ec2-metadata-token: TOKEN_VALUE) IMDS-->>Script: i-1234567890abcdef0
  1. IMDSv1 (flux du haut) : une simple requête GET suffit. Aucune preuve d'intention, aucun token. Si une application sur l'instance est vulnérable aux SSRF, un attaquant peut forcer cette requête depuis l'extérieur.
  2. IMDSv2 (flux du bas) : le client doit d'abord émettre un PUT vers /latest/api/token avec l'en-tête X-aws-ec2-metadata-token-ttl-seconds. Ce PUT ne peut pas être déclenché par une redirection HTTP classique, ce qui brise la chaîne d'exploitation SSRF.
  3. Token de session : le token retourné est valide pour la durée TTL spécifiée (entre 1 et 21 600 secondes). Il est ensuite passé dans chaque requête de métadonnées via l'en-tête X-aws-ec2-metadata-token.

Pourquoi IMDSv1 est Dangereux : Le Vecteur SSRF Expliqué

IMDSv1 repose sur un modèle de confiance implicite : si la requête arrive sur l'interface réseau de l'instance, elle est considérée légitime. Ce modèle s'effondre dès qu'une application web tourne sur l'instance et accepte des URLs fournies par l'utilisateur.

Imaginez un proxy HTTP interne qui accepte une URL cible en paramètre. Un attaquant passe http://169.254.169.254/latest/meta-data/iam/security-credentials/ comme URL. Le proxy fait la requête localement, récupère les credentials IAM temporaires, et les renvoie à l'attaquant. IMDSv1 n'a aucun moyen de distinguer cette requête d'une requête légitime.

IMDSv2 casse ce vecteur parce que le PUT initial avec l'en-tête X-aws-ec2-metadata-token-ttl-seconds ne peut pas être émis via une redirection HTTP standard. La plupart des bibliothèques HTTP et des proxies ne propagent pas les en-têtes personnalisés lors des redirections vers des domaines différents, et un PUT vers une adresse de lien-local depuis un contexte SSRF est structurellement plus difficile à déclencher.

Ce n'est pas une protection absolue contre tous les scénarios SSRF, mais c'est une défense en profondeur significative documentée par AWS.

Récupérer l'ID d'Instance avec IMDSv2 : Commandes Complètes

Voici le flux complet pour récupérer l'ID d'instance depuis un script shell tournant sur l'instance. L'étape du token est obligatoire avec IMDSv2 — ne la sautez pas même si l'instance accepte encore IMDSv1 en mode permissif.

Méthode Shell (Bash)

# Étape 1 : Obtenir un token de session IMDSv2 (TTL de 21600 secondes = 6 heures)
TOKEN=$(curl -s -X PUT \
  'http://169.254.169.254/latest/api/token' \
  -H 'X-aws-ec2-metadata-token-ttl-seconds: 21600')

# Étape 2 : Utiliser le token pour récupérer l'ID d'instance
INSTANCE_ID=$(curl -s \
  -H "X-aws-ec2-metadata-token: $TOKEN" \
  'http://169.254.169.254/latest/meta-data/instance-id')

echo "Instance ID : $INSTANCE_ID"

Si la commande retourne une chaîne vide ou une erreur HTTP 401, l'instance est configurée pour exiger IMDSv2 et votre token n'a pas été correctement obtenu. Vérifiez que le PUT s'exécute bien avant le GET.

Vérifier d'Autres Métadonnées Utiles avec le Même Token

# Région de l'instance (disponible dans le document d'identité)
REGION=$(curl -s \
  -H "X-aws-ec2-metadata-token: $TOKEN" \
  'http://169.254.169.254/latest/meta-data/placement/region')

# Type d'instance
INSTANCE_TYPE=$(curl -s \
  -H "X-aws-ec2-metadata-token: $TOKEN" \
  'http://169.254.169.254/latest/meta-data/instance-type')

echo "Région : $REGION"
echo "Type : $INSTANCE_TYPE"

Méthode Python (boto3 non requis)

🔽 Cliquer pour afficher le script Python complet
import urllib.request

def get_imdsv2_token(ttl_seconds=21600):
    req = urllib.request.Request(
        'http://169.254.169.254/latest/api/token',
        method='PUT',
        headers={'X-aws-ec2-metadata-token-ttl-seconds': str(ttl_seconds)}
    )
    with urllib.request.urlopen(req, timeout=2) as response:
        return response.read().decode('utf-8')

def get_instance_metadata(path, token):
    req = urllib.request.Request(
        f'http://169.254.169.254/latest/meta-data/{path}',
        headers={'X-aws-ec2-metadata-token': token}
    )
    with urllib.request.urlopen(req, timeout=2) as response:
        return response.read().decode('utf-8')

token = get_imdsv2_token()
instance_id = get_instance_metadata('instance-id', token)
print(f'Instance ID : {instance_id}')

Forcer IMDSv2 sur une Instance EC2 : Configuration et Vérification

Récupérer l'ID d'instance avec IMDSv2 dans vos scripts est bien. Mais si l'instance accepte encore IMDSv1, n'importe quel autre processus sur la machine peut contourner votre bonne pratique. La vraie protection consiste à désactiver IMDSv1 au niveau de l'instance.

Vérifier l'état actuel de l'IMDS sur une instance

aws ec2 describe-instances \
  --instance-ids i-1234567890abcdef0 \
  --query 'Reservations[*].Instances[*].MetadataOptions' \
  --output table \
  --region us-east-1

Le champ HttpTokens indique l'état : optional signifie que IMDSv1 est encore accepté, required signifie que seul IMDSv2 fonctionne.

Passer une instance existante en mode IMDSv2 obligatoire

aws ec2 modify-instance-metadata-options \
  --instance-id i-1234567890abcdef0 \
  --http-tokens required \
  --http-endpoint enabled \
  --region us-east-1

Cette modification prend effet immédiatement sans redémarrage. Les processus qui utilisaient IMDSv1 recevront désormais un HTTP 401 — c'est le signal que la migration n'est pas complète.

Appliquer IMDSv2 par défaut sur tous les nouveaux lancements dans un compte

aws ec2 modify-instance-metadata-defaults \
  --http-tokens required \
  --region us-east-1

Ce paramètre s'applique aux nouvelles instances lancées dans la région spécifiée. Les instances existantes ne sont pas affectées — il faut les modifier individuellement ou via une automatisation.

graph TD A["Audit : describe-instances
HttpTokens = optional"] --> B["Test sur instance non critique"] B --> C{"Scripts compatibles
IMDSv2 ?"} C -- Oui --> D["modify-instance-metadata-options
http-tokens=required"] C -- Non --> E["Mettre à jour les scripts
et AMIs de base"] E --> D D --> F["modify-instance-metadata-defaults
pour nouveaux lancements"] F --> G["Surveillance AWS Config
ou CloudWatch"]
  1. Audit : identifier toutes les instances avec HttpTokens: optional via describe-instances.
  2. Test : modifier une instance non critique, vérifier que vos scripts fonctionnent avec IMDSv2.
  3. Migration : appliquer modify-instance-metadata-options sur le parc restant.
  4. Prévention : configurer modify-instance-metadata-defaults pour les futurs lancements.
  5. Surveillance : une métrique CloudWatch ou une règle AWS Config peut détecter les instances non conformes.

Diagnostic : Quand la Récupération de l'ID d'Instance Échoue

Voici le scénario que vous rencontrerez inévitablement en production : un script de démarrage qui fonctionnait depuis des mois commence à retourner une chaîne vide pour l'ID d'instance après une migration vers IMDSv2 obligatoire. Le script ne plante pas — il continue silencieusement avec une variable vide, et vous découvrez le problème quand une ressource est taggée avec une valeur nulle.

Le diagnostic réflexe est de vérifier les permissions IAM ou la connectivité réseau. Mauvaise piste — l'IMDS est local à l'hyperviseur, les Security Groups et les ACL réseau ne s'appliquent pas. Le vrai problème : le script utilisait IMDSv1 (un GET direct sans token), et l'instance est maintenant en mode required.

Reproduire et diagnostiquer depuis l'instance

# Test IMDSv1 — doit retourner 401 si HttpTokens=required
curl -v 'http://169.254.169.254/latest/meta-data/instance-id'

# Test IMDSv2 — doit retourner l'ID d'instance
TOKEN=$(curl -s -X PUT \
  'http://169.254.169.254/latest/api/token' \
  -H 'X-aws-ec2-metadata-token-ttl-seconds: 60')
curl -s \
  -H "X-aws-ec2-metadata-token: $TOKEN" \
  'http://169.254.169.254/latest/meta-data/instance-id'

Si le premier retourne 401 Unauthorized et le second retourne l'ID, votre instance est correctement configurée et c'est votre script qui doit être mis à jour. Si le second retourne aussi une erreur, vérifiez que l'endpoint IMDS est activé (HttpEndpoint: enabled) via describe-instances.

Identifier les instances qui utilisent encore IMDSv1 à l'échelle

aws ec2 describe-instances \
  --filters 'Name=metadata-options.http-tokens,Values=optional' \
  --query 'Reservations[*].Instances[*].[InstanceId,Tags[?Key==`Name`].Value|[0]]' \
  --output table \
  --region us-east-1

Ce filtre retourne toutes les instances où IMDSv1 est encore accepté dans la région. Utilisez-le comme point de départ pour votre audit de migration.

Récupérer l'ID d'Instance EC2 via AWS CLI (Hors Instance)

Si vous avez besoin de l'ID d'instance depuis l'extérieur — depuis un pipeline CI/CD ou un outil de gestion de configuration — l'IMDS n'est pas accessible. Utilisez l'AWS CLI avec les permissions appropriées.

# Lister les instances par nom de tag
aws ec2 describe-instances \
  --filters 'Name=tag:Name,Values=mon-serveur-app' \
             'Name=instance-state-name,Values=running' \
  --query 'Reservations[*].Instances[*].InstanceId' \
  --output text \
  --region us-east-1

Politique IAM minimale pour cette opération

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "ec2:DescribeInstances",
      "Resource": "*"
    }
  ]
}

L'action ec2:DescribeInstances ne supporte pas les restrictions au niveau de la ressource — "Resource": "*" est requis selon la référence d'autorisation de service AWS.

Conclusion et Prochaines Étapes pour Sécuriser l'Accès aux Métadonnées EC2

Récupérer l'ID d'instance EC2 depuis un script est trivial avec IMDSv2 — deux appels curl, un token, et vous avez ce qu'il vous faut. La vraie valeur n'est pas dans la commande elle-même, c'est dans la compréhension de pourquoi le mécanisme à deux étapes existe et ce qu'il protège.

Les prochaines actions concrètes :

  • Auditez votre parc avec le filtre metadata-options.http-tokens=optional pour identifier les instances exposées.
  • Mettez à jour vos scripts de démarrage, vos AMIs de base et vos configurations d'auto-scaling pour utiliser IMDSv2 systématiquement.
  • Activez IMDSv2 obligatoire sur les instances existantes via modify-instance-metadata-options.
  • Configurez modify-instance-metadata-defaults pour que les nouveaux lancements soient sécurisés par défaut.
  • Consultez la documentation officielle AWS sur la configuration de l'IMDS pour les options avancées.

Glossaire des Termes Clés

TermeDéfinition
IMDS (Instance Metadata Service)Service HTTP local accessible à 169.254.169.254 exposant les métadonnées de l'instance EC2 depuis l'hyperviseur.
IMDSv2Version 2 de l'IMDS introduisant un mécanisme de token de session obligatoire pour authentifier les requêtes de métadonnées.
SSRF (Server-Side Request Forgery)Classe d'attaque où un attaquant force un serveur à émettre des requêtes HTTP vers des ressources internes, potentiellement l'IMDS.
Adresse de lien-localPlage d'adresses IP (169.254.0.0/16) non routable sur Internet, utilisée pour la communication locale sur un segment réseau.
HttpTokensParamètre de configuration de l'IMDS : optional accepte IMDSv1 et v2, required n'accepte que IMDSv2.

Commentaires

Posts les plus consultés de ce blog

Groupes IAM AWS : Pourquoi Attacher les Politiques aux Groupes Plutôt qu'aux Utilisateurs

LSI vs GSI dans DynamoDB : choisir le bon index secondaire

NAT Gateway vs NAT Instance : Quelle solution choisir pour vos instances privées ?