Cloud AWS

GitLab CI vers AWS sans clé d’accès : la fédération OIDC

Remplacer les AWS_ACCESS_KEY_ID stockées dans GitLab par des identifiants STS de courte durée, émis job par job.

Une paire de clés IAM stockée dans les variables CI/CD d’un projet GitLab est un secret longue durée : elle ne tourne pas, elle fuit dans un printenv mal placé et elle donne les mêmes droits à une MR de test qu’au déploiement de production. La fédération OIDC supprime ce secret.

Le principe

Chaque job GitLab peut demander un jeton d’identité (id_tokens), un JWT signé par GitLab qui décrit le job : projet, branche, environnement, protection de la référence. AWS STS vérifie la signature de ce jeton puis échange le JWT contre des identifiants temporaires d’un rôle IAM avec AssumeRoleWithWebIdentity.

deploy:prod:
  id_tokens:
    AWS_ID_TOKEN:
      aud: sts.amazonaws.com
  variables:
    AWS_ROLE_ARN: arn:aws:iam::123456789012:role/gitlab-apply-prod
    AWS_WEB_IDENTITY_TOKEN_FILE: $CI_PROJECT_DIR/.aws-token
  before_script:
    - printf '%s' "$AWS_ID_TOKEN" > "$AWS_WEB_IDENTITY_TOKEN_FILE"
  script:
    - aws sts get-caller-identity

Le SDK AWS lit AWS_ROLE_ARN et AWS_WEB_IDENTITY_TOKEN_FILE tout seul : ni Terraform ni l’AWS CLI n’ont besoin d’autre configuration.

La politique de confiance fait tout le travail

Le rôle n’a de valeur que par sa condition sur le claim sub. Sans elle, n’importe quel projet gitlab.com peut l’assumer.

data "aws_iam_policy_document" "trust" {
  statement {
    actions = ["sts:AssumeRoleWithWebIdentity"]
    principals {
      type        = "Federated"
      identifiers = [aws_iam_openid_connect_provider.gitlab.arn]
    }
    condition {
      test     = "StringEquals"
      variable = "gitlab.com:aud"
      values   = ["sts.amazonaws.com"]
    }
    condition {
      test     = "StringLike"
      variable = "gitlab.com:sub"
      values   = ["project_path:mon-groupe/mon-projet:ref_type:branch:ref:main"]
    }
  }
}

Un rôle par niveau de confiance

  • plan : lecture seule, assumable depuis les MRs ;
  • apply review : limité au compte sandbox et aux ressources taguées de la MR ;
  • apply prod : assumable uniquement depuis main, branche protégée, sur un runner protégé.

Une MR ouverte depuis un fork ne doit jamais pouvoir assumer le rôle de production : c’est exactement ce que la condition ref:main garantit.

À vérifier avant de supprimer les clés

  1. Le provider OIDC est déclaré avec l’URL exacte de l’instance GitLab.
  2. Chaque rôle a une condition sub qui nomme le projet et la référence.
  3. La durée de session est courte (une heure suffit pour un apply).
  4. CloudTrail montre bien des AssumeRoleWithWebIdentity avec le RoleSessionName du job.

Ensuite seulement, désactiver puis supprimer les anciennes clés IAM.