Introduction
Kubernetes, en tant que système open source, vise à simplifier le déploiement, la mise à l’échelle et la gestion des conteneurs d’application. Doté de son propre système de gestion d’identités, Kubernetes offre un accès basé sur les rôles (RBAC) qui permet à des utilisateurs, des groupes ou des comptes de service d’interagir avec les ressources du cluster. De plus, il est possible d’attribuer des rôles à des pods, des déploiements, des répliques et d’autres objets Kubernetes, avec la possibilité d’appliquer ces rôles à un espace de noms spécifique ou à l’ensemble du cluster. Pour les processus de calcul et les applications s’exécutant dans les conteneurs au sein d’un pod, le rôle Kubernetes leur permet d’interagir avec l’API de Kubernetes depuis le pod correspondant. Par conséquent, chaque application hérite du rôle attribué à son pod d’exécution. Lorsque nous déployons notre cluster dans AWS, le contrôle du control panel nous échappe car il est géré par AWS, et notre responsabilité se limite à la gestion des worker nodes et de leurs objets. Toutefois, nous conservons la capacité de gérer les rôles RBAC du cluster via l’API Kubernetes. La question qui se pose alors est la suivante : comment autorisons-nous les applications exécutées dans Amazon EKS à interagir avec d’autres services AWS ?
Amazon propose plusieurs solutions pour répondre à ce besoin. L’une d’entre elles est EKS Pod Identity, qui fournit des clés d’authentification aux conteneurs d’un pod en utilisant un compte de service associé à un rôle IAM. Les rôles IAM pour les comptes de service (IAM Role for Service Account) fonctionnent sur le même principe.
Depuis 2014, AWS EKS prend en charge cette fonctionnalité en intégrant l’authentification vers AWS via un fournisseur d’identité qui fournit des clés JSON Web Token (JWT) Open Identity Connect (OIDC). Le fournisseur d’identité géré par Amazon EKS génère des paires de clés de signature, renouvelées toutes les 7 jours. L’agent kubelet sur chaque nœud récupère ces clés et les stocke dans le pod, en veillant à leur rotation. Les clés sont ensuite montées sur le pod grâce à la fonctionnalité de projection de volume d’un compte de service Kubernetes.
Dans ce tutoriel, nous allons mettre en place un rôle IAM AWS pour le compte de service Kubernetes dans un cluster Amazon EKS.
Prérequis
La configuration d’un rôle IAM pour le service account kubernetes sur EKS nécessite les ressources suivantes :
- Un utilisateur IAM avec le rôle
Administrateur
sur votre compte AWS. kubectl
: l’outil de ligne de commande pour gérer un cluster Kubernetes.- Un cluster Kubernetes Amazon EKS. Vous pouvez le déployer en suivant ce tutoriel AWS.
- La configuration d’un profil Fargate (Optionnel). guide.
Tuto
Les rôles IAM pour les comptes de service offrent les intérêts suivants :
- Moindre privilège : il n’octroie que les permissions IAM définies qu’aux pods qui utilisent le compte de service.
- Isolement des informations d’identification : Les conteneurs d’un Pod ne peuvent accéder qu’aux informations d’identification du rôle IAM associé à leur compte de service spécifique. Ils ne peuvent pas accéder aux informations d’identification d’autres conteneurs dans d’autres Pods.
- Capacité d’audit – La journalisation des événements et des accès est disponible via AWS CloudTrail.
La prise en charge des identités fédérées à l’aide d’OpenID Connect (OIDC) permet d’authentifier les appels d’API AWS avec les fournisseurs d’identité pris en charge et de recevoir un jeton web OIDC JSON valide (JWT). Ce jeton est utilisé pour authentifier les interactions avec les services AWS pour Amazon EKS. Par défaut un fournisseur OIDC est créé à la création d’un cluster EKS. Vous pouvez vérifier qu’il existe bien dans votre cluster :
https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html
cluster_name=forge-cluster
oidc_id=$(aws eks describe-cluster --name $cluster_name --query "cluster.identity.oidc.issuer" --output text | cut -d '/' -f 5)
echo $oidc_id
Vérifier ensuite qu’un fournisseur IAM OIDC avec l’identitifiant du fournisseur de votre cluster existe dans votre compte.
aws iam list-open-id-connect-providers | grep $oidc_id | cut -d "/" -f4
Si aucune sortie n’est retournée alors il est nécessaire de créer un fournisseur IAM OIDC pour votre cluster. Il peut être créé avec l’utilitaire eksctl
.
eksctl utils associate-iam-oidc-provider --cluster $cluster_name --approve
Si vos préférences se rapproche de la console AWS, elle peut servir pour procéder à la vérification.
Depuis la console AWS accéder à votre cluster
Sélectionner l’onglet Overview et copier l’OpenID Connect provider URL
Accéder à la console IAM et choisissez Identity providers depuis la barre latérale
Si un fournisseur est listé et correspond à l’URL du fournisseur de votre cluster, aucune action n’est requise de votre part.
Sinon cliquer sur Ajouter un fournisseur
Pour le type, sélectionnez OpenID Connect
Pour l’url du fournisseur, collez l’url préalablement copiée
Cliquer sur Get thumbprint
Renseigner l’audience avec la valeur :
sts.amazonaws.com
Cliquer sur Ajouter un fournisseur
Une fois qu’un fournisseur IAM OIDC a été ajouté, vous le verrez dorénavant dans la liste des fournisseurs d’identité.
Le principe de l’IRSA est d’attaché un rôle IAM à un compte de service Kubernetes. Nous allons commencer par créer la policy qui sera attaché au rôle. Partons du principe que nous souhaitons accéder à un bucket forge-tuto
depuis un de nos pods EKS déployé sur fargate. Le pod sera autorisé à récupérer les objets dans le bucket. Cela se traduit dans une stratégie IAM (IAM policy). Créer un fichier forge-policy.json
contenant la définition de la politique suivante.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": "arn:aws:s3:::forge-tuto"
},
{
"Sid": "List",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:GetObjectVersion"
],
"Resource": "arn:aws:s3:::forge-tuto/*"
}
]
}
A l’aide de l’invite de commande aws, créer la stratégie :
aws iam create-policy --policy-name bucket-irsa --policy-document file://forge-policy.json
L’objectif est de créer un compte de service Kubernetes, un rôle IAM et de les associer. Nous commencerons par le rôle IAM. Il faut définir une relation de confiance avec le fournisseur d’identité que nous avons paramétré plus tôt. La relation de confiance permettra au fournisseur d’assumer le rôle depuis le pod. Afin de définir cette relation de confiance, il faut récupérer des paramètres qui nous serons utiles durant sa création.
La politique d’accès aux buckets sera attachée à un rôle IAM. Ce rôle IAM sera associé à un objet service account dans l’API de kubernetes. La singularité de cette association est dans la relation de confiance (trust relationship) du rôle.
La relation de confiance est assignée à un rôle qui lui, fera la jonction entre l’API de Kubernetes et AWS. Par le biais de la communication entre l’objet service_account
de Kubernetes et l’API de AWS pour la réception de token. Elle n’autorise que le compte de service à utiliser le rôle pour l’audience du fournisseur d’identité.
Le service_account
permet aux invités du cluster ou ceux qui communiquent avec son control_plane
de s’authentifier à l’API Kubernetes. Comme les rôles, il confie la gestion opaque des clés de connexions au centre de contrôle comme AWS avec les instances profiles pour les instances EC2. Un système d’échange de clés avec rotation assure la sécurité avec les droits nécessaires assignés à l’identité. Ces droits s’appliquent de la même manière que avec le rôle AWS IAM pour les instances par le biais de aws-authenticator. AWS utilise OIDC JSON Web Token (JWT) pour fournir des clés de connexion de roles IAM temporaires, ce depuis 2014 avec le support des identités fédérées utilisant OpenID Connect (OIDC).
cat >my-service-account.yaml <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: forge-sa
namespace: forge
EOF
kubectl create namespace forge
kubectl apply -f my-service-account.yaml
# Vérifier la création avec cette commande
kubectl get sa -n forge
# NAME SECRETS AGE
# default 0 4d14h
# forge-sa 0 13h
Depuis l’invite de commande, les variables nécessaires à la création de la relation de confiance sont définies avec les commandes suivantes :
account_id=$(aws sts get-caller-identity --query "Account" --output text)
export AWS_REGION=eu-west-1
oidc_provider=$(aws eks describe-cluster --name forge-cluster --region $AWS_REGION --query "cluster.identity.oidc.issuer" --output text | sed -e "s/^https:\/\///")
export namespace=forge
export service_account=forge-sa
Par une policy qui autorise l’identité web à assumer le rôle, nous donnons la permission au fournisseur OIDC de notre compte d’utiliser le rôle. Ce rôle par les conditions de politique IAM peut être appliqué à un service_account
particulier ou à tous. Cet extrait de code permet de créer le fichier de définition de la trust-relationship
en utilisant les variables d’environnement.
cat >trust-relationship.json <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::$account_id:oidc-provider/$oidc_provider"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"$oidc_provider:aud": "sts.amazonaws.com",
"$oidc_provider:sub": "system:serviceaccount:$namespace:$service_account"
}
}
}
]
}
EOF
Vous pouvez créer le rôle avec le nom que vous souhaitez avec la trust-relationship
associée et lui attacher la politique
bucket-irsa.
# Création du rôle
$ aws iam create-role --role-name forge-role --assume-role-policy-document file://trust-relationship.json --description "Forge role for irsa"
# Association de la policy
$ aws iam attach-role-policy --role-name forge-role --policy-arn=arn:aws:iam::$account_id:policy/bucket-irsa
# Vérififcation
#$ aws iam get-role --role-name forge-role --query Role.AssumeRolePolicyDocument
#{
# "Version": "2012-10-17",
# "Statement": [
# {
# "Effect": "Allow",
# "Principal": {
# "Federated": "arn:aws:iam::xxxxxxx:oidc-provider/oidc.eks.eu-west-1.amazonaws.com/id/3C759632214CCF8D446FD23EE892A06DF"
# },
# "Action": "sts:AssumeRoleWithWebIdentity",
# "Condition": {
# "StringEquals": {
# "oidc.eks.eu-west-1.amazonaws.com/id/3C759632214CCF8D446FD23EE892A06DF:sub": "system:serviceaccount:default:forge-sa",
# "oidc.eks.eu-west-1.amazonaws.com/id/3C759632214CCF8D446FD23EE892A06DF:aud": "sts.amazonaws.com"
# }
# }
# }
# ]
#}
Maintenant que le rôle est créé, l’objet service_account
aussi et que le rôle l’autorise à l’utiliser, l’objet service_account
doit être informé du rôle par les métadonnées d’annotation. De plus vous pouvez définir le type de point de terminaison utilisé par le Service de Token de Sécurité (AWS STS). Soit le point de terminaison global soit celui régional avec moins de latence et une augmentation de la validité de la session du token.
# Remplacer les valeurs du rôle par le votre
kubectl annotate serviceaccount -n $namespace $service_account eks.amazonaws.com/role-arn=arn:aws:iam::$account_id:role/forge-role
# Vérifier l'annotation
kubectl describe sa $service_account -n forge
La configuration des identités effectuées nous pouvons tester que l’interaction depuis un pod que nous créerons avec le bucket s3. Nous passerons par un fichier de configuration pour créer un pod. Le cluster utiliser durant ce tutoriel a été créé avec un fargate profile pour un déploiement des pods sur fargate. Cela explique le label qui correspond au sélecteur du fargate profile avec le namespace default
.
cat >aws-cli-pod.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
name: aws-cli
namespace: forge
labels:
app: forge-tuto
spec:
serviceAccountName: forge-sa
containers:
- name: aws-cli
image: amazon/aws-cli:latest
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
restartPolicy: Always
EOF
$ kubectl apply -f aws-cli-pod.yaml
$ kubectl get pods -n forge
NAME READY STATUS RESTARTS AGE
aws-cli 1/1 Running 0 63s
Vous pouvez vérifier que votre pod utilise le rôle IAM approprié avec les actions autorisés pour s3. Commencer par ajouter des fichiers dans votre bucket. Puis depuis l’invite de commande avec votre cluster tenter de le récupérer avec ces commandes :
$ kubectl exec -it aws-cli -- aws sts get-caller-identity
{
"UserId": "AROA35YPIUYBEFMWHZFM:botocore-session-1705971562",
"Account": "xxxxxxxxxxx",
"Arn": "arn:aws:sts::xxxxxxxxx:assumed-role/forge-role/botocore-session-1705971562"
}
kubectl exec -it aws-cli -n forge -- aws s3 ls s3://forge-tuto
## Résultats
2024-04-09 21:46:07 69409 backend
Conclusion
En conclusion, l’intégration de Kubernetes avec les services AWS représente une avancée majeure dans le domaine du cloud computing. En combinant la puissance de Kubernetes pour la gestion des conteneurs avec les fonctionnalités robustes d’AWS, les entreprises bénéficient d’une plateforme flexible, évolutive et sécurisée pour le déploiement de leurs applications.
La mise en œuvre de fonctionnalités telles que les rôles IAM pour les comptes de service Kubernetes et EKS Pod Identity démontre l’engagement continu d’AWS à fournir des solutions de pointe pour répondre aux besoins de ses utilisateurs. Ces technologies permettent aux organisations d’assurer une gestion fine des accès, une isolation des ressources et une intégration transparente avec les autres services AWS.