Aller au contenu
Sécurité medium

Vault AWS : credentials IAM dynamiques

18 min de lecture

Vault AWS secrets engine génère des credentials IAM temporaires à la demande. Plus d'access keys permanentes dans le code : chaque workload obtient ses propres credentials, valides quelques heures maximum.

Ce guide couvre les trois types de credentials AWS que Vault peut émettre et leur cas d'usage.

Une access key AWS permanente ne porte aucune date d'expiration : elle reste valide tant que personne ne la supprime dans IAM. Le moteur AWS de Vault remplace ce modèle par une émission à la demande, où chaque credential est rattaché à un lease et cesse de fonctionner à l'expiration du TTL. Le tableau ci-dessous compare ce que vous perdez et ce que vous gagnez sur les quatre points qui comptent : durée de vie, distribution, rotation et traçabilité.

Access keys permanentesAvec Vault AWS
Durée de vie illimitéeTTL 1-12h max
Partagées via secrets/env varsGénérées à la demande
Rotation manuelle rareRotation automatique par TTL
Compromission = accès permanentCompromission = accès limité dans le temps
Audit : "qui a cette clé ?"Audit : "quel workload a demandé quand"
  • Vault installé et démarré
  • Accès admin pour configurer le moteur
  • Compte AWS avec permissions IAM pour créer des credentials

Types de credentials : iam_user vs assumed_role vs federation_token

Section intitulée « Types de credentials : iam_user vs assumed_role vs federation_token »

Vault peut émettre trois types de credentials AWS, et ce choix se fait au niveau du rôle Vault via le paramètre credential_type. Il n'est pas modifiable après coup sans recréer le rôle, et il détermine à la fois la durée de vie maximale des credentials et ce que Vault peut faire à la révocation. Lisez ce tableau en partant de la colonne cas d'usage :

TypeComment ça marcheTTL typiqueCas d'usage
iam_userVault crée un user IAM + access key∞ (mais lease Vault)Legacy, permissions complexes
assumed_roleVault assume un rôle IAM via STS1-12h (borne AWS)Recommandé - standard
federation_tokenVault génère un token fédéréJusqu'à 36hConsole AWS, accès humain

Le moteur AWS n'est pas actif par défaut dans Vault, il faut le monter explicitement. Sans option -path, il se monte sur le chemin aws/ : tous les chemins de ce guide (aws/config/root, aws/roles/…, aws/creds/…) en découlent. Si vous devez gérer plusieurs comptes AWS, montez une instance du moteur par compte avec -path=aws-prod, -path=aws-dev, et adaptez les chemins ainsi que les policies en conséquence.

Fenêtre de terminal
vault secrets enable aws

Vault a besoin de credentials pour appeler les API AWS. Deux options :

Fenêtre de terminal
vault write aws/config/root \
access_key="AKIAIOSFODNN7EXAMPLE" \
secret_key="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" \
region="eu-west-1"

Si vous avez configuré aws/config/root avec une access key statique, faites-la tourner immédiatement après : Vault génère une nouvelle clé pour ce même user IAM et oublie l'ancienne valeur, qui reste éventuellement connue de la personne qui a saisi la commande.

Fenêtre de terminal
vault write -force aws/config/rotate-root

Un rôle Vault décrit ce que le moteur AWS a le droit d'émettre : le credential_type, la cible IAM et les TTL. Tant qu'aucun rôle n'existe, vault read aws/creds/<nom> échoue, même avec une configuration root valide. Les trois onglets ci-dessous montrent la même opération pour les trois credential_type : lisez celui qui correspond au mode que vous avez retenu, les paramètres ne sont pas interchangeables.

Le rôle Vault référence un rôle IAM existant dans AWS :

Fenêtre de terminal
vault write aws/roles/deploy \
credential_type="assumed_role" \
role_arns="arn:aws:iam::123456789012:role/DeployRole" \
default_sts_ttl="1h" \
max_sts_ttl="4h"

Prérequis AWS : le rôle DeployRole doit avoir une trust policy permettant à Vault (via son rôle ou user) de l'assumer :

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:user/vault-aws"
},
"Action": "sts:AssumeRole"
}
]
}

L'émission passe par une lecture du chemin aws/creds/<nom du rôle>, et non par une écriture : chaque vault read produit un nouveau jeu de credentials et un nouveau lease. Rejouer la commande ne renvoie donc pas la valeur précédente, elle en crée une de plus, ce qui compte quand le rôle est en iam_user (chaque lecture crée un user IAM) ou quand AWS limite le nombre de sessions.

Fenêtre de terminal
vault read aws/creds/deploy

Sortie (pour assumed_role) :

Key Value
--- -----
lease_id aws/creds/deploy/abcd1234
lease_duration 1h
lease_renewable true
access_key ASIAIOSFODNN7EXAMPLE
secret_key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
security_token FwoGZXIvYXdzEBY...
arn arn:aws:sts::123456789012:assumed-role/DeployRole/vault-token-xyz

Ce qui se passe :

  1. Vault appelle sts:AssumeRole avec le rôle IAM configuré
  2. AWS retourne des credentials STS temporaires
  3. Vault crée un lease et retourne les credentials
  4. L'application utilise ces credentials
  5. À expiration, les credentials STS deviennent invalides (côté AWS)

Le CLI AWS et les SDK lisent ces trois variables d'environnement avant le fichier ~/.aws/credentials : un profil déjà configuré sur la machine est donc ignoré tant qu'elles sont définies.

Fenêtre de terminal
export AWS_ACCESS_KEY_ID="ASIAIOSFODNN7EXAMPLE"
export AWS_SECRET_ACCESS_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
export AWS_SESSION_TOKEN="FwoGZXIvYXdzEBY..."
aws s3 ls

Un static role ne crée rien : il prend en charge un user IAM qui existe déjà et se contente d'en faire tourner l'access key selon la période que vous fixez. L'identité reste donc la même dans CloudTrail et dans vos policies IAM, seule la clé change. C'est le seul mode qui donne une access key sans session token, ce qui explique qu'on y recoure pour des outils incapables de gérer STS.

Fenêtre de terminal
vault write aws/static-roles/ci-user \
name="ci-user" \
username="ci-pipeline-user" \
rotation_period="24h"

Lecture :

Fenêtre de terminal
vault read aws/static-creds/ci-user

Différence avec dynamic :

  • Même user IAM (ci-pipeline-user)
  • Access key rotée tous les 24h
  • Pas de session token

Révoquer, dans Vault, veut dire fermer un lease. Ce que cela produit côté AWS dépend entièrement du credential_type : Vault peut supprimer une entité IAM qu'il a créée, mais il ne peut pas rappeler une session STS déjà émise. Distinguer les deux évite la fausse sécurité de croire qu'un vault lease revoke coupe l'accès instantanément dans tous les cas.

Le lease_id est celui renvoyé lors de l'émission : sans lui, la commande n'a rien à révoquer.

Fenêtre de terminal
vault lease revoke aws/creds/deploy/abcd1234

Ce qui se passe selon le type :

  • iam_user : Vault supprime l'access key et l'user IAM
  • assumed_role : Vault marque le lease comme révoqué (les credentials STS expirent naturellement, pas de révocation AWS)
  • federation_token : idem assumed_role

L'option -prefix révoque d'un coup tous les leases émis sous ce chemin : c'est le geste de réaction à incident, sans confirmation ni retour en arrière possible.

Fenêtre de terminal
vault lease revoke -prefix aws/creds/deploy

Activer le moteur ne suffit pas : sans policy, un client authentifié reçoit permission denied sur aws/creds/deploy. La policy ci-dessous accorde le strict nécessaire, la capacité read sur un seul rôle, ce qui empêche un workload de piocher dans les credentials d'un autre rôle même s'il en connaît le nom. Notez qu'aucune capacité n'est donnée sur aws/roles/* : le porteur de cette policy consomme des credentials, il ne peut pas modifier la configuration du moteur.

policy-deploy.hcl
# Obtenir des credentials AWS pour le déploiement
path "aws/creds/deploy" {
capabilities = ["read"]
}
# Renouveler ses propres leases
path "sys/leases/renew" {
capabilities = ["update"]
}
Fenêtre de terminal
vault policy write deploy policy-deploy.hcl

C'est en CI/CD que le gain est le plus net : le pipeline n'a plus besoin d'un secret AWS stocké dans la plateforme, il obtient des credentials valables le temps du job. Les deux exemples suivants s'appuient sur l'auth JWT/OIDC de Vault, où c'est la plateforme CI qui atteste l'identité du workflow. Le rôle Vault (github-deploy, gitlab-deploy) doit exister côté Vault avec les bound claims correspondant au dépôt et à la branche, sinon le login est refusé.

Ce workflow ne stocke aucun secret AWS : le jeton OIDC de GitHub sert de preuve d'identité auprès de Vault, qui renvoie des credentials STS injectés dans l'environnement du job. La permission id-token: write est indispensable pour que GitHub émette ce jeton, et les actions sont épinglées par SHA pour qu'un tag déplacé côté fournisseur ne change pas le code exécuté.

name: Deploy to AWS
on:
push:
branches: [main]
permissions: {}
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Import Secrets from Vault
uses: hashicorp/vault-action@892a26828f195e65540a40b4768ae4571f51ebfc # v4.0.0
with:
url: https://vault.example.com
method: jwt
role: github-deploy
secrets: |
aws/creds/deploy access_key | AWS_ACCESS_KEY_ID ;
aws/creds/deploy secret_key | AWS_SECRET_ACCESS_KEY ;
aws/creds/deploy security_token | AWS_SESSION_TOKEN
- name: Deploy
run: |
aws s3 sync ./dist s3://my-app-bucket

Sans action dédiée, le job appelle directement le CLI Vault : le eval transforme la réponse JSON en trois export, ce qui suppose que vault et jq soient présents dans l'image du job.

deploy:
stage: deploy
script:
- export VAULT_ADDR="https://vault.example.com"
- export VAULT_TOKEN=$(vault write -field=token auth/jwt/login role=gitlab-deploy jwt=$CI_JOB_JWT)
- eval $(vault read -format=json aws/creds/deploy | jq -r '.data | "export AWS_ACCESS_KEY_ID=\(.access_key) AWS_SECRET_ACCESS_KEY=\(.secret_key) AWS_SESSION_TOKEN=\(.security_token)"')
- aws s3 sync ./dist s3://my-app-bucket

Les erreurs se répartissent en deux familles qu'il faut distinguer avant de chercher : celles renvoyées par Vault (permission denied, policy manquante) et celles renvoyées par AWS (AccessDenied, ExpiredToken), qui remontent au travers de Vault ou du CLI AWS. Le message d'origine vous dit donc de quel côté regarder : la policy Vault, ou la trust policy IAM.

SymptômeCause probableSolution
permission deniedPolicy Vault manquanteVérifier aws/creds/<role>
AccessDenied côté AWSTrust policy incorrecteVérifier sts:AssumeRole
ExpiredTokenTTL dépasséRenouveler ou obtenir de nouveaux creds
InvalidIdentityTokenHorloge désynchroniséeVérifier NTP sur Vault
User IAM non suppriméPermissions IAM manquantesVérifier iam:DeleteUser, iam:DeleteAccessKey

Enchaînez ces commandes dans l'ordre : chacune élimine une hypothèse, de la configuration du moteur jusqu'aux leases réellement ouverts. Notez que vault read aws/config/root ne renvoie jamais la secret key, seulement la région et l'access key.

Fenêtre de terminal
# Vérifier la configuration
vault read aws/config/root
# Lister les rôles
vault list aws/roles
# Vérifier un rôle spécifique
vault read aws/roles/deploy
# Tester une émission
vault read aws/creds/deploy
# Vérifier les leases actifs
vault list sys/leases/lookup/aws/creds/deploy

Le moteur AWS gère l'émission et le cycle de vie des credentials, rien de plus. Toute la partie IAM en amont (rôles cibles, policies, trust policies) reste à votre charge, et Vault ne vous alertera pas si elle est trop permissive : un rôle IAM AdministratorAccess émis en credentials temporaires reste un accès administrateur. Ce partage des responsabilités est la source d'erreur la plus fréquente sur ce moteur.

ResponsabilitéVaultVous
Générer des credentials STSRien à faire
Gérer les TTL et leasesRien à faire
Créer les rôles IAM cibles
Configurer les trust policies
Révoquer les credentials STS côté AWSN/A (expire naturellement)
Monitorer l'usage AWS✅ (CloudTrail)
  1. assumed_role : mode recommandé, pas de création d'entité IAM
  2. iam_user : Vault crée un user temporaire, plus de cleanup
  3. federation_token : pour la console AWS ou workloads spécifiques
  4. TTL courts : 1-4h, les credentials STS ne sont pas révocables
  5. Trust policy : le rôle IAM doit autoriser Vault à l'assumer
  6. Static role : rotation d'une clé existante (compromis pour legacy)
  7. Audit : Vault trace l'émission, CloudTrail trace l'utilisation

Ce site vous est utile ?

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

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn