Sécuriser l'accès à AWS depuis vos Pods Kubernetes avec IRSA

Accéder à l’API d’AWS depuis des Pods Kubernetes (k8s) a longtemps reposé sur l’utilisation d’un utilisateur Identity and Access Management (IAM) qui nécessite de créer une clé d’accès avec un ID et une clé secrète pour être utilisée. Ces deux éléments (l’ID et la clé secrète) devaient donc être injectés dans l’environnement de votre Pod pour que ce dernier puisse accéder à l’API d’AWS programmatiquement. La présence de cette clé d’accès pose évidemment des soucis de sécurité :

  • Il ne faut pas qu’elle soit accessible en clair (utilisation des secrets k8s) par les applications ;
  • Il ne faut pas qu’elle puisse être récupérée par une autre application lancée sur le cluster k8s ;
  • Il faut procéder à sa rotation régulièrement, ce qui peut amener des problématiques assez complexes pour mettre à jour les applications utilisant cette clé sans interruption de service.

Vous aimeriez en finir avec la présence de ces clés d’accès AWS dans l’environnement de vos Pods sur k8s pour vous simplifier la vie et apporter plus de sécurité ? Allons-y !

Table des matières

Utiliser des rôles IAM depuis des Pods ?

A notre plus grande joie, AWS a annoncé fin 2019 l’arrivée d’une solution intégrée au service EKS (Elastic Kubernetes Service) afin d’utiliser des roles IAM directement depuis des Pods. Cette solution est communément appelée IAM Roles for Service Accounts (IRSA). Comment est-ce possible ? Et surtout, comment ça marche ?

IRSA fonctionne comme les instance profiles du service AWS Elastic Cloud Computing (EC2). Au lieu de distribuer des identifiants AWS (couple access key/secret key) dans les conteneurs ou bien d’utiliser le rôle d’une instance EC2, on peut désormais associer un rôle IAM à un service account Kubernetes. Ce service account peut ensuite être utilisé par des Pods.

Avant de rentrer plus en détails dans IRSA, il est important de faire quelques rappels sur le fonctionnement d’IAM et du service Security Token Service (STS).

IAM : user versus role

Les aficionados d’AWS et d’IAM savent certainement qu’il existe 2 principaux types d’identité sur AWS : les utilisateurs (user) et les rôles (role). Un role est similaire à un user dans le fait qu’il a des politiques d’autorisation qui explicitent ce qu’il peut ou ne peut pas faire mais la principale différence est qu’il n’est pas associé à une unique personne. Il peut être endossé par toute entité qui en aurait besoin dès le moment que la bonne relation de confiance (trust policy) a été mise en place dans le role. En plus, il n’a pas de mot de passe ou de clés d’accès qui lui sont associés ! En effet, un role fournit des informations d’identification temporaires grâce au service STS.

Quelques explications sur l’opération AssumeRole de STS

STS fournit une API qui permet d’endosser ou d’assumer un role connue sous le nom AssumeRole. Il est important pour le suite de comprendre comment fonctionne cette opération.

Supposons qu’un user IAM fu ait le droit d’assumer un role IAM bar. Le role bar possède des policies lui permettant d’interagir avec d’autres services AWS. Par ailleurs, il possède une trust policy qui autorise le user fu à l’utiliser :

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

A partir de là, voilà comment fonctionne un AssumeRole STS :

assume_role

Les roles étaient déjà très présents dans de nombreux services AWS : EC2 (Elastic Compute Cloud), Lambda, RDS (Relational Database Service)... mais malheureusement auparavant pas utilisable nativement avec des Pods dans k8s. Des projets open source ont donc vu le jour pour pâtir de cette limitation comme kube2iam ou encore kiam avant qu’AWS n’intègre sa propre solution au service EKS. Cette solution, c’est amazon-eks-pod-identity-webhook qui est désormais directement intégrée dans le control plane d’un cluster EKS. Cette solution, qu’on découvrira un peu plus en détails après, va permettre de faire usage d’une API assez récente au sein du service STS pour assumer un role IAM depuis des Pods.

Une API STS qui permet aux Pods de récupérer des identifiants de session AWS ?

Avant de pouvoir assumer un role IAM, les Pods vont utiliser l’API STS AssumeRoleWithWebIdentity. Cette API, exactement comme l’API AssumeRole présentée précédemment, renvoie un ensemble d’identifiants de sécurité temporaires. La différence est que l’entité appelant cette API s’est au préalable authentifiée auprès d’un fournisseur d’identité (web identity provider) compatible avec le protocole OpenID Connect (OIDC).

Dans notre contexte Kubernetes, cet identity provider (IdP) n’est autre que l’API Kubernetes elle-même. Depuis la version 1.12 de Kubernetes, l’API k8s est désormais en mesure de générer un token JSON compatible OIDC qui contient l’identité d’un ServiceAccount Kubernetes et ce token peut être monté en tant que volume de type projected dans un Pod. Grâce à la solution d’Amazon amazon-eks-Pod-identity-webhook, la génération d’un token OIDC et le montage des volumes projected sur les Pods est totalement automatisée (on reviendra sur le fonctionnement dans Kubernetes plus en détails après). Le token OIDC permet ensuite aux Pods d’appeler l’API STS AssumeRoleWithWebIdentity.

Voilà le workflow avec les informations qu’on a actuellement :

sts_irsa

Pour que les applications déployées dans les Pods puissent gérer les credentials AWS ainsi que leurs renouvellements, il est préférable d’utiliser dans la mesure du possible les librairies officielles AWS pour éviter des surprises d’authentification.

Pour simplifier, j’ai volontairement omis un élément important à faire dans AWS IAM. Cet élément, c’est ce qui va permettre de valider le token OIDC qu’un Pod va envoyer à STS. Cela s’appelle un provider IAM OIDC.

Comment des Pods peuvent-ils endosser un role IAM ?

Le provider OIDC doit être créé directement dans AWS IAM. À sa création, il établit une relation de confiance entre l’IdP Kubernetes (compatible OIDC pour rappel) et le compte AWS dans lequel on le crée. Repartons du workflow précédent avec l’opération sts:AssumeRoleWithWebIdentity et complétons le avec le provider IAM OIDC :

irsa_workflow

Pour comprendre le workflow précédent, il faut avoir quelques connaissances sur le fonctionnement du protocole OIDC.

OIDC est une couche d’identité au-dessus du protocole OAuth 2.0. Il utilise JSON Web Token (JWT) et permet d’authentifier des utilisateurs sur des sites web et des applications sans avoir besoin de posséder ou de gérer des couples utilisateur/mots de passe.

Quand AWS STS va recevoir le token JWT OIDC envoyé par le Pod k8s, la mécanique est la suivante :

  1. AWS STS vérifie s’il a la clé publique identifiée par l’attribut Key ID (kid) dans le header JWT.
  2. (optionnel) S’il ne reconnaît pas la clé, AWS STS va récupérer la configuration OIDC du provider en appelant le endpoint /.well-known/openid-configuration. Voilà un exemple de réponse :
{
  "issuer": "https://oidc.eks.eu-west-1.amazonaws.com/id/XXXXXXXXX",
  "jwks_uri": "https://oidc.eks.eu-west-1.amazonaws.com/id/XXXXXXXXX/keys",
  "authorization_endpoint": "urn:kubernetes:programmatic_authorization",
  "response_types_supported": [
    "id_token"
  ],
  "subject_types_supported": [
    "public"
  ],
  "claims_supported": [
    "sub",
    "iss"
  ],
  "id_token_signing_alg_values_supported": [
    "RS256"
  ]
}

Cet endpoint fournit plusieurs éléments de configuration du serveur OpenID. L’un des éléments de réponse est jwks_uri, il contient un autre endpoint qui contient l’URI du provider OIDC suffixé par /keys.

  1. (optionnel) AWS STS va ensuite appeler le endpoint récupéré juste avant en /keys pour accéder aux clés publiques publiées par le provider OIDC.
  2. Une fois que AWS STS a les clés publiques du provider OIDC, il est en mesure de valider le contenu du token OIDC.

Voilà, vous connaissez désormais le fonctionnement intrinsèque de IRSA. Bon, maintenant, faisons un peu de pratique pour mettre en application ce dont on a parlé jusqu’à présent !

Mise en place de IRSA sur un cluster AWS EKS

L’ensemble du code présenté ci-après se trouve sur ce repository GitHub.

Pour mettre en place IRSA sur AWS, j’ai utilisé les blueprints AWS EKS pour Terraform. Ce repository GitHub est maintenu par AWS. Il contient un ensemble de modules Terraform qui permettent de rapidement mettre en place un cluster EKS.

Il est tout à fait possible d’utiliser IRSA sur un cluster Kubernetes non EKS, il suffira pour cela de déployer manuellement le webhook qui est intégré dans le control plane EKS amazon-eks-pod-identity-webhook.

Dans les exemples de code que vous trouverez par la suite, de nombreuses lignes de code seront omises par rapport au code source pour se concentrer sur IRSA et non pas les à-côtés. Vous pouvez vous référer au repository GitHub pour avoir l’ensemble du code.

Pour créer l’infrastructure sur AWS, il suffit de suivre les indications dans le README.md du repository git.

Création d’un cluster EKS et de son provider IAM associé

Cette partie du code présenté se trouve dans le dossier terraform/05_eks_cluster du projet git.

Après avoir au préalable créer un VPC (Virtual Private Cloud) via le module Terraform VPC opensource, il est possible de créer un cluster EKS de cette façon :

module "eks_blueprints" {
  source = "github.com/aws-ia/terraform-aws-eks-blueprints?ref=v4.16.0"

  # EKS CLUSTER
  cluster_name       = var.project
  cluster_version    = "1.23"
  vpc_id             = module.eks_vpc.vpc_id
  private_subnet_ids = module.eks_vpc.private_subnets
  
  ...
  
  # VOLUNTARILY DISABLE IRSA IN BLUEPRINTS
  enable_irsa = false

  ...
}

Vous remarquerez que j’ai volontairement désactivé IRSA à l’appel de ce module enable_irsa = false afin de vous montrer comment créer un provider IAM OIDC via les ressources Terraform des providers AWS et TLS. Cela va vous permettre de comprendre ce qui se passe derrière les rideaux :

locals {
  eks_oidc_issuer_url = "https://${module.eks_blueprints.eks_oidc_issuer_url}"
}

# NOTE: Those two resources can be created through the AWS EKS bluprints with 'enable_irsa' parameter
# I chose to create them here for demonstration purposes so you may know how IRSA works
data "tls_certificate" "eks_cluster" {
  url = local.eks_oidc_issuer_url
}

resource "aws_iam_openid_connect_provider" "oidc_provider" {
  url             = data.tls_certificate.eks_cluster.url
  client_id_list  = ["sts.amazonaws.com"]
  thumbprint_list = [data.tls_certificate.eks_cluster.certificates[0].sha1_fingerprint]
  tags            = local.tags
}

Un provider OpenID Connect repose en grande partie sur la RFC JWT. Les différentes claims dont nous allons parler par la suite font justement référence aux claims présentes dans la RFC. Pour en créer un, plusieurs arguments sont nécessaires :

  • url : c’est l’URL du fournisseur d’identité, c’est celle qui est générée pour le cluster EKS qu’on a créé précédemment. Cela correspond à l’”iss” claim (issuer claim) de la RFC. iss permet d’identifier l’entité qui a émis un token JWT.
  • client_id_list : c’est la liste des IDs des clients, aussi connus sous le nom de audiences. Cela fait référence à l’”aud” claim (audience claim) dans la RFC. Quand une application va se connecter au provider OIDC, elle va établir une valeur pour l’identifier. Cette valeur sera passée dans le client_id dans les requêtes OAuth. Dans notre cas, l’ID du client sera ”sts.amazonaws.com” car c’est le service STS qui va interagir avec le provider IAM OIDC.
  • thumbprint_list : c’est la liste des empreintes des autorités de certification (CA) intermédiaires. Généralement, on fournit ici l’empreinte qui a signé le certificat utilisé par l’IdP externe compatible OIDC (EKS dans notre cas).

Déploiement des premiers addons sur le cluster EKS

Cette partie est déployée via le code qui se trouve dans le dossier terraform/10_eks_resources du projet git.

Une fois les addons déployés sur le cluster EKS, allons regarder ce que Terraform a déployé sur le cluster EKS dans le namespace kube-system :

> kubectl get pods -n kube-system
NAME                                                       READY   STATUS    RESTARTS   AGE
aws-node-ghp8s                                             1/1     Running   0          10h
aws-node-sv9bm                                             1/1     Running   0          10h
aws-node-vlm89                                             1/1     Running   0          10h
cluster-proportional-autoscaler-coredns-6fcfcd685f-86w4r   1/1     Running   0          10h
coredns-5f7ff554cb-kll22                                   1/1     Running   0          10h
coredns-5f7ff554cb-q98nt                                   1/1     Running   0          10h
kube-proxy-2b48v                                           1/1     Running   0          10h
kube-proxy-2j2z4                                           1/1     Running   0          10h
kube-proxy-xqlfb                                           1/1     Running   0          10h

Pour le moment, nous n’avons déployé que des composants de base que l’on trouve sur un cluster EKS :

  • VPC CNI (Container Network Interface) : ce addon déploie les Pods aws-node-* qui sont responsables de créer des ENI (Elastic Network Interface) dans AWS pour associer des adresses IP aux Pods et aux services Kubernetes ;
  • Core DNS : ces Pods font office de serveurs DNS dédié au cluster Kubernetes ;
  • Kube proxy : ces Pods permettent la communication réseau entre les Pods.

IRSA en action sur le addon VPC CNI

Allons regarder plus en détails l’un des Pods aws-node pour comprendre comment il est en mesure de créer des ENI (donc des adresses IP) sur le compte AWS via IAM pour tous les Pods d’un cluster EKS.

Tous les exemples YAML présentés ci-après ont été épurés pour se concentrer sur IRSA.

Le ServiceAccount Kubernetes aws-node

Regardons en premier lieu la définition du ServiceAccount utilisé par les Pods aws-node via la commande kubectl get sa aws-node -n kube-system -oyaml :

apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789123:role/aws-eks-irsa-aws-node-irsa
  name: aws-node
  namespace: kube-system

L’élément important sur le ServiceAccount est l’annotation eks.amazonaws.com/role-arn qui a pour valeur l’ARN (Amazon Resource Name) du role IAM. Derrière les rideaux, c’est le webhook Amazon EKS Pod Identity dont on a parlé un peu plus tôt dans cet article qui va utiliser cette annotation pour modifier la spec des Pods qui utilisent ce ServiceAccount.

Le role IAM associé au ServiceAccount

Allons regarder de plus près le role IAM aws-eks-irsa-aws-node-irsa créé et plus particulièrement son assume role policy (ou trust policy) qui permet de définir ses relations de confiance :

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::123456789123:oidc-provider/oidc.eks.eu-west-3.amazonaws.com/id/XXXXXXXXX"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringLike": {
                    "oidc.eks.eu-west-3.amazonaws.com/id/XXXXXXXXX:sub": "system:serviceaccount:kube-system:aws-node",
                    "oidc.eks.eu-west-3.amazonaws.com/id/XXXXXXXXX:aud": "sts.amazonaws.com"
                }
            }
        }
    ]
}

On note plusieurs choses :

  • le principal autorisé, c’est à dire l’entité pouvant être authentifiée, est une entité fédérée qui correspond à l’ARN du provider IAM OIDC créé précédemment ;
  • l’action IAM autorisée est sts:AssumeRoleWithWebIdentity, c’est l’action qui est appelée par un Pod configuré avec IRSA
  • plusieurs conditions doivent être remplies pour assumer le role :
    • le sub (subject claim) doit avoir la valeur system:serviceaccount:kube-system:aws-node. Le Suject Claim, dans la RFC JWT, permet d’identifier l’entité qui est le sujet du JWT. Ici, c’est l’entité est le ServiceAccount Kubernetes.
    • l’aud (audience claim) que l’on a déjà croisé précédemment dans la configuration du provider IAM OIDC doit avoir la valeur sts.amazonaws.com.

La spécification des Pods aws-node

Le webhook va ajouter pas mal de choses dans la spec des Pods aws-node. Regardons l’un des Pods avec la commande kubectl get Pod aws-node-ghp8s -n kube-system -oyaml :

apiVersion: v1
kind: Pod
metadata:
  name: aws-node-ghp8s
  namespace: kube-system
spec:
  serviceAccount: aws-node
  serviceAccountName: aws-node
  containers:
  - name: aws-node
    image: 602401143452.dkr.ecr.eu-west-3.amazonaws.com/amazon-k8s-cni:v1.10.4-eksbuild.1
    env:
    - name: AWS_STS_REGIONAL_ENDPOINTS
      value: regional
    - name: AWS_DEFAULT_REGION
      value: eu-west-3
    - name: AWS_REGION
      value: eu-west-3
    - name: AWS_ROLE_ARN
      value: arn:aws:iam::123456789123:role/aws-eks-irsa-aws-node-irsa
    - name: AWS_WEB_IDENTITY_TOKEN_FILE
      value: /var/run/secrets/eks.amazonaws.com/serviceaccount/token
    volumeMounts:
    - mountPath: /var/run/secrets/eks.amazonaws.com/serviceaccount
      name: aws-iam-token
      readOnly: true
  volumes:
  - name: aws-iam-token
    projected:
      defaultMode: 420
      sources:
      - serviceAccountToken:
          audience: sts.amazonaws.com
          expirationSeconds: 86400
          path: token

Le webhook a muté le Pod pour ajouter plusieurs choses :

  • un volume de type projected nommé aws-iam-token contenant la configuration du token OIDC JWT avec :
    • son audience de la RFC JWT ayant pour valeur sts.amazonaws.com (la même valeur configurée dans le provider IAM OIDC qu’on a vu précédemment) ;
    • son expiration en secondes (ici 86 400).
  • le volume précédent est monté dans le container aws-node sur le chemin /var/run/secrets/eks.amazonaws.com/serviceaccount ;
  • plusieurs variables d’environnement ont été ajoutés dans l’environnement des containers, elles vont permettre de configurer les SDK AWS :
    • AWS_STS_REGIONAL_ENDPOINTS : les SDK AWS vont effectuer l'appel sts:AssumeRoleWithWebIdentity afin d'obtenir des informations d'identification à partir du point de terminaison STS régional, au lieu du point de terminaison global ;
    • AWS_DEFAULT_REGION et AWS_REGION : les SDK AWS vont cibler une région AWS spécifique ;
    • AWS_ROLE_ARN : les containers vont assumer ce role IAM dans le but de faire des actions autorisées par les policies du role sur l’API AWS.

IRSA en action sur une application personnalisée

Précédemment, nous avons constaté comment fonctionnait IRSA avec l’un des addons EKS. Les blueprints AWS ajoutent beaucoup d'abstractions sur la création des ressources sur AWS et sur Kubernetes. Pour mieux voir comment configurer IRSA sur une application personnalisée, nous allons déployer sur le cluster EKS une petite application ayant le droit de décrire les instances EC2 sur un compte AWS. Nous utiliserons pour ce faire Terraform et Helm.

Il faut d’abord créer le role IAM qui sera assumé par l’application. Ce role est créé dans [terraform/10_eks_resources/iam.tf](https://github.com/taufort/aws-eks-irsa/blob/main/terraform/10_eks_resources/iam.tf) et est attaché à une policy qui autorise l’action IAM ec2:DescribeInstances. Attardons nous sur le code Terraform de l’assume role policy qui contient la configuration IRSA :

data "aws_iam_policy_document" "aws_cli_describe_ec2_instances_assume_policy" {
  statement {
    effect = "Allow"
    principals {
      type = "Federated"
      identifiers = [
        data.terraform_remote_state.layer_05_eks_cluster.outputs.oidc_provider_arn
      ]
    }
    actions = [
      "sts:AssumeRoleWithWebIdentity"
    ]
    condition {
      test     = "StringEquals"
      variable = "${data.terraform_remote_state.layer_05_eks_cluster.outputs.oidc_provider_url_without_http_prefix}:aud"
      values   = ["sts.amazonaws.com"]
    }
    condition {
      test     = "StringEquals"
      variable = "${data.terraform_remote_state.layer_05_eks_cluster.outputs.oidc_provider_url_without_http_prefix}:sub"
      values   = ["system:serviceaccount:aws-eks-irsa:aws-cli"]
    }
  }
}

Dans cette trust policy, on autorise le provider OIDC du cluster EKS à effectuer sts:AssumeRoleWithWebIdentity et on vérifie que le subject du token JWT concerne le ServiceAccount aws-cli qui est déployé dans le namespace aws-eks-irsa.

Comme le role IAM est désormais créé, nous pouvons déployer un chart Helm contenant notre application personnalisée. Ce chart est assez succinct, il contient un Deployment lançant un container amazon/aws-cli et un ServiceAccount. On se connectera dans le container aws-cli pour exécuter une commande AWS CLI EC2. La magie d’IRSA sur EKS se fait via l’annotation eks.amazonaws.com/role-arn qui est présente sur le ServiceAccount dans le chart :

{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
  name: {{ include "aws-cli.serviceAccountName" . }}
  labels:
    {{- include "aws-cli.labels" . | nindent 4 }}
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::{{ .Values.awsAccountId }}:role/irsa/aws-cli-describe-ec2-instances
    {{- with .Values.serviceAccount.annotations }}
    {{- toYaml . | nindent 4 }}
    {{- end }}
  {{- end }}

Cette annotation contient une référence vers le role IAM qui a été créé par Terraform précédemment. Il ne reste plus qu’à déployer le chart Helm sur le cluster EKS dans le bon namespace :

helm upgrade -–install --create-namespace --namespace aws-eks-irsa --set awsAccountId=<YOUR_AWS_ACCOUNT_ID> aws-cli helm/aws-cli

Une fois le pod aws-cli créé, allons vérifier qu’IRSA fonctionne comme attendu :

# Exec into the pod
kubectl exec -n aws-eks-irsa -it $(kubectl get pods -n aws-eks-irsa -o=name) -- bash
# Once inside the aws-cli pod, try to describe EC2 instances ;)
aws ec2 describe-instances --filters Name=tag:aws:eks:cluster-name,Values=aws-eks-irsa

La commande AWS CLI devrait vous retourner dans un JSON la liste des instances EC2 de votre compte AWS dans la région eu-west-3.

Aller plus loin

IRSA pour du multi-comptes AWS ?

Imaginez un cas où on aurait 3 comptes AWS :

  • un compte AWS de services sur lequel on a déployé le cluster EKS avec IRSA
  • un compte AWS de staging
  • un compte AWS de production

On aimerait qu’un Pod sur le cluster EKS du compte AWS de services puisse créer une Lambda à la fois sur le compte AWS de staging et également le compte AWS de production. Et bien, sachez que IRSA peut tout à fait fonctionner sur ce cas d’usage.

Pour ce faire, il faut :

  • créer un provider OIDC dans chacun des comptes AWS de staging et de production. L’URL des providers sera celle du cluster EKS du compte AWS de services.
  • créer le même role IAM sur les comptes de staging et de production :
    • avec les bons droits IAM pour créer une Lambda
    • avec une assume role policy autorisant l’identité fédérée OIDC du cluster EKS pour l’action sts:AssumeRoleWithWebIdentity avec les bonnes conditions IAM comme nous avons vu précédemment
  • créer le ServiceAccount autorisé dans l’assume role policy des roles IAM et déployer un Pod dans le cluster EKS utilisant ce ServiceAccount.

On peut mettre à jour le schéma qu’on avait vu précédemment :

irsa_multi_aws_account

J’ai participé à la mise en place d’un cas d’usage IRSA multi-comptes AWS chez l’un de nos clients, Bedrock Streaming, pour une solution de CI/CD. Le cluster EKS est un cluster de runners GitHub Actions (GHA). Nous avons créé des modules Terraform pour facilement créer des roles IAM IRSA sur l’ensemble des comptes AWS de Bedrock. Les runners GHA sont déployés sur le cluster EKS via Helmfile. Toute l’abstraction mis en place pour la création des roles IAM et des runners GHA permet aux quelques 270 développeurs de Bedrock de créer facilement (en 1 ou 2 Pull Requests) leurs propres runners GHA avec des droits très limités sur IAM (toujours pour respecter le principe de moindre privilège).

IRSA avec du multi-clusters Kubernetes et multi-comptes AWS ?

Toujours chez Bedrock Streaming, nous avons fait en sorte que le cluster EKS GHA puisse être déployé en mode blue-green (sur un même compte AWS) de façon à nous simplifier la vie pour les mises à jour. Quand nous devions faire une montée de version Kubernetes par exemple, nous pouvions créer un nouveau cluster EKS GHA, le configurer, déployer les runners GHA dessus et une fois qu’il était prêt, nous effectuions la bascule de l’ancien cluster EKS vers le nouveau.

IRSA fonctionne dans ce genre de cas mais la gestion des ressources IAM devient plus complexe :

  • Il faut créer un provider OIDC pour chaque cluster Kubernetes ;
  • Si un role IAM peut être assumé par plusieurs clusters Kubernetes, sa trust policy doit être mise à jour pour établir une relation de confiance avec chaque provider OIDC. Avec plusieurs clusters Kubernetes, cela peut vite devenir ingérable.

Ces problématiques sont tracées dans cette issue GitHub.

Que retenir ?

J’espère que la magie d’IAM Roles for Service Accounts (IRSA) vous paraîtra désormais moins obscure.

Nous avons vu pas mal de choses ensemble : les différences entre un user et un role IAM, celles entre les opérations sts:AssumeRole et sts:AssumeRoleWithWebIdentity sur STS, on a gratté la surface d’OpenID Connect (la couche d’identité au-dessus du protocole OAuth 2.0) et nous avons également vu comment mettre en place IRSA sur un cluster EKS sur AWS. Maintenant, vous saurez comment éviter d’utiliser des users IAM dans l’environnement des Pods sur Kubernetes (i.e. supprimer les Access Key/Secret Key AWS des Pods) en les remplaçant par des roles IAM.

IRSA est encore imparfait à ce jour (7 décembre 2022) notamment dans la gestion du multi-clusters Kubernetes et du multi-comptes AWS.