Pourquoi utiliser Google Workload Identity ?
Objectifs de l'article
Dans un monde où la sécurité et l'efficacité des pipelines CI/CD sont primordiales, l'utilisation de Google Workload Identity afin de s'authentifier facilement et de manière sécurisée aux services de la GCP peut apporter des avantages significatifs.
Cet article vous guidera à travers chaque étape de cette intégration.
Nous utiliserons du code Terraform afin de tracer et d'automatiser la configuration, ce qui vous permettra également de récupérer facilement les actions effectuées.
Objectifs de l'article :
- Comprendre Google Workload Identity : Nous expliquerons ce qu'est Google Workload Identity et pourquoi il est aujourd'hui un choix de premier ordre dans l'authentification aux services Google.
- Configurer Google Workload Identity : Vous apprendrez à configurer un Workload Identity Pool Provider et un Workload Identity Pool en utilisant Terraform.
- Autoriser la CI/CD d'un repository à s'authentifier : Nous détaillerons comment créer, configurer un Service Account et le lier à un dépôt GitLab.
- Intégrer dans GitLab CI/CD : Vous verrez comment intégrer cette configuration dans vos pipelines CI/CD GitLab, avec des exemples de fichiers
.gitlab-ci.yml
.
Qu'est que Google Workload Identity exactement ?
Lien avec l'objectif de l'article
Pour bien comprendre l’intégration de Google Workload Identity dans un environnement GitLab CI/CD on-premise, il est essentiel de saisir les concepts de la fédération d’identité et leur application dans ce contexte.
Fédération d'identité : GitLab, ses utilisateurs et ses groupes
La fédération d’identité permet à des utilisateurs et groupes d’un système externe (comme GitLab) de s’authentifier et d’accéder à des ressources dans un autre système (comme Google Cloud) sans avoir à gérer des identités distinctes dans chaque système. Dans notre cas, GitLab et ses utilisateurs/groupes seront fédérés avec Google Cloud pour accéder aux ressources nécessaires à l’exécution des pipelines CI/CD.
Représentation dans Google Cloud : Workload Identity Pool et Pool Provider
Pour réaliser cette fédération d'identité, nous allons utiliser deux concepts clés de Google Cloud : le Workload Identity Pool et le Workload Identity Pool Provider.
- Workload Identity Pool : Un Workload Identity Pool est une collection d’identités externes qui peuvent être mappées à des identités Google Cloud. Il sert de conteneur pour les identités provenant de systèmes externes comme GitLab.
- Workload Identity Pool Provider : Un Provider au sein d’un Workload Identity Pool définit comment les identités externes sont mappées et authentifiées. Il décrit les protocoles d’authentification et les règles de mapping des identités.
Il est recommandé de n’avoir qu’un seul Pool Provider par Workload Identity Pool pour simplifier la gestion et éviter les conflits de configuration.
Choix du protocole d'authentification : OIDC
Nous allons utiliser le protocole OIDC (OpenID Connect), car GitLab, même en version on-premise, supporte ce protocole.
OIDC repose sur OAuth 2.0 et permet une authentification sécurisée. Google Workload Identity supporte aussi d’autres protocoles comme SAML et JWT, mais OIDC reste notre choix privilégié ici pour sa compatibilité avec GitLab.
Les Avantages de Workload Identity par rapport aux JSON Keys
L’utilisation de Google Workload Identity offre plusieurs avantages significatifs par rapport à l’ancienne méthode dépréciée basée sur les JSON Keys pour l’authentification dans Google Cloud.
- Sécurité renforcée
Les JSON Keys sont des clés statiques stockées sur des serveurs ou des machines, ce qui les rend vulnérables à des fuites accidentelles ou des accès non autorisés. En revanche, Workload Identity utilise une approche de fédération d’identité qui permet de limiter les accès temporaires et dynamiques.
La rotation automatique des tokens d’identification dans Workload Identity supprime la nécessité de gérer manuellement les clés d’accès, réduisant ainsi le risque d’attaques potentielles.
- Simplification de la gestion des identités
Avec Workload Identity, il n’est plus nécessaire de gérer des fichiers de clés ou de distribuer ces fichiers aux utilisateurs ou aux pipelines CI/CD. Tout est géré de manière transparente à travers le mapping des identités externes vers des comptes de service Google Cloud.
Les accès sont accordés via des permissions IAM standard sans manipulation des secrets, ce qui simplifie la gestion et l’audit.
- Moins de responsabilités pour l’infrastructure
Les JSON Keys nécessitent de suivre des pratiques strictes pour assurer qu’elles ne soient pas exposées (mises à jour régulières, stockage sécurisé). Workload Identity élimine ce fardeau en utilisant des jetons éphémères qui n’ont pas besoin d’être stockés à long terme.
4. Meilleure intégration avec les environnements cloud natifs
Workload Identity est mieux intégré aux workflows cloud modernes, notamment pour les environnements CI/CD, car il s’intègre directement aux fournisseurs d’identité comme GitLab, ce qui facilite la configuration et la maintenance à long terme.
En résumé
Google Workload Identity permet à des identités externes, comme celles de GitLab, de s’authentifier auprès de Google Cloud en tant que comptes de service via des protocoles sécurisés comme OIDC. Cette approche élimine la gestion des clés statiques (JSON Keys) en faveur de jetons temporaires, renforçant ainsi la sécurité. La configuration se fait via le Workload Identity Pool Provider, qui définit les règles d’authentification et permet une gestion simplifiée et intégrée des identités entre les environnements.
Configuration de Workload Identity
On établit le lien GCP - Gitlab
Pour intégrer Google Workload Identity avec GitLab dans un environnement privé, il est nécessaire de configurer le Workload Identity Pool et le Workload Identity Pool Provider afin de gérer de manière sécurisée l’authentification des pipelines GitLab. Voici le guide pas à pas de la configuration en utilisant Terraform.
Voici le lien vers un repository git public pour consulter les fichiers de configuration détaillés dans l'article.
Configuration du provider terraform Google
provider "google" {
project = var.google_project_id
region = var.google_region
default_labels = {
project = "gitlab-workload-identity"
}
}
Les variables google_project_id
et google_region
permettent de spécifier le projet et la région Google Cloud. Assurez-vous de les définir dans votre configuration :
variable "google_project_id" {
description = "Identifiant du projet GCP où le Workload Identity sera configuré"
type = string
}
variable "google_region" {
description = "Région du projet GCP"
type = string
default = "europe-west1" # ou la région de votre choix
}
Création du Workload Identity Pool
Le Workload Identity Pool agit comme un conteneur pour les identités GitLab externes, nous permettant de fédérer des identités GitLab dans Google Cloud.
# Create a pool of identity providers (GitLab)
resource "google_iam_workload_identity_pool" "gitlab_pool" {
workload_identity_pool_id = "private-gitlab-pool"
}
Ce pool, nommé private-gitlab-pool
, contiendra toutes les identités issues de GitLab, fédérées pour accéder aux ressources GCP.
Récupération de la clé publique GitLab
Comme le serveur GitLab est privé, google ne peut pas récupérer la clef publique depuis son infrastructure cloud. Ce n'est pas un problème si nous exécutons le code terraform depuis un environnement qui a accès au serveur Gitlab. Nous devons alors récupérer un fichier JSON Web Key Set (JWKS) pour permettre la vérification des jetons JWT provenant de GitLab. Ce fichier contient les clés publiques utilisées pour valider les signatures de ces jetons.
# Download JWKS file from GitLab (public key used to verify JWT token)
data "http" "jwks_gitlab" {
url = "${var.gitlab_url}/oauth/discovery/keys"
# Optional request headers
request_headers = {
Accept = "application/json"
}
}
La variable gitlab_url
est nécessaire pour définir l’URL de votre instance GitLab. Ajoutez cette variable dans votre fichier de configuration Terraform :
variable "gitlab_url" {
description = "URL de l'instance GitLab privée"
type = string
default = "https://my-private-gitlab.com"
}
Configuration du Workload Identity Pool Provider
Le Workload Identity Pool Provider gère la validation des identités provenant de GitLab. En définissant l’attribut oidc, nous précisons l’URL de l’émetteur GitLab et les clés pour valider les jetons JWT.
resource "google_iam_workload_identity_pool_provider" "gitlab_pool_provider" {
workload_identity_pool_id = google_iam_workload_identity_pool.gitlab_pool.workload_identity_pool_id
workload_identity_pool_provider_id = "private-gitlab-pool-provider"
attribute_mapping = {
"google.subject" = "assertion.sub", # Identifiant principal
"attribute.aud" = "assertion.aud",
"attribute.project_path" = "assertion.project_path",
"attribute.project_id" = "assertion.project_id",
"attribute.namespace_id" = "assertion.namespace_id",
"attribute.namespace_path" = "assertion.namespace_path",
"attribute.user_email" = "assertion.user_email",
"attribute.ref" = "assertion.ref",
"attribute.ref_type" = "assertion.ref_type",
}
oidc {
issuer_uri = var.gitlab_url
jwks_json = data.http.jwks_gitlab.response_body
}
}
Cette configuration mappe les attributs de GitLab vers des identités GCP via les attributs de l’objet attribute_mapping
. Le google.subject
est requis, et les autres attributs (aud
, project_id
, namespace_id
, etc.) permettent d’ajouter des détails supplémentaires à chaque identité.
Récupération des informations utiles
Enfin, nous ajoutons des outputs pour obtenir les informations de la configuration appliquée utiles dans les étapes suivantes pour référencer le Pool et le Pool Provider.
output "GCP_WORKLOAD_IDENTITY_PROVIDER" {
value = google_iam_workload_identity_pool_provider.gitlab_pool_provider.name
}
output "GCP_WORKLOAD_IDENTITY_POOL" {
value = google_iam_workload_identity_pool.gitlab_pool.name
}
En suivant ces étapes, le lien entre Google Cloud et GitLab est maintenant établi, permettant à GitLab de fédérer des identités vers GCP et d’accéder aux ressources Google de manière sécurisée.
De Gitlab vers un Service Account Google
Autoriser une identité Gitlab à utiliser un SA Google
Pour permettre aux jobs GitLab CI/CD d’accéder aux ressources Google Cloud via un Service Account (SA), nous configurons un module nommé workload-identity-account
. Ce module va faciliter la création d’un Service Account et la liaison avec une identité GitLab en utilisant Workload Identity.
Voici le lien vers le module.
Création du Service Account (SA)
Le Service Account est dédié aux jobs GitLab Runner pour s’authentifier dans GCP
resource "google_service_account" "sa" {
project = var.google_project_id
account_id = var.service_account_name
display_name = var.service_account_name
description = "Service account used by Gitlab Runner in order to authenticate to GCP"
}
Les variables google_project_id
et service_account_name
sont requises pour spécifier le nom du compte de service et dans quel projet GCP il sera créé.
variable "service_account_name" {
description = "The name of the service account to create"
type = string
}
variable "google_project_id" {
description = "The ID of the project in which the service account will be created"
type = string
}
Créer la liaison Workload Identity
attribute_mapping
pour autoriser des identités gitlab à utiliser des Service Accounts Google.Dans cet exemple on prendra simplement le project_path du projet gitlab.
Le Service Account est associé au Workload Identity Pool via une autorisation roles/iam.workloadIdentityUser
, permettant à une identité GitLab d’assumer le rôle défini pour accéder aux ressources :
# Create a workload identity binding for the service account
resource "google_service_account_iam_member" "workload_identity_binding" {
service_account_id = google_service_account.sa.id
role = "roles/iam.workloadIdentityUser"
member = "principalSet://iam.googleapis.com/${var.gitlab_pool_name}/attribute.project_path/${var.gitlab_project_path}"
}
L'attribut member
contient une référence au principalSet, identifiant unique pour les identités GitLab dans le Workload Identity Pool. La valeur ${var.gitlab_pool_name}
correspond au nom du pool GitLab configuré dans GCP, tandis que ${var.gitlab_project_path}
fait référence au chemin du projet GitLab. Cette configuration autorise spécifiquement les jobs exécutés sur ce projet GitLab à se faire passer pour le SA.
variable "gitlab_pool_name" {
description = "The name of the gitlab pool"
type = string
}
variable "gitlab_project_path" {
description = "The path of the gitlab project"
type = string
}
En pratique, dans GitLab CI/CD, ce lien permet à un job d’assumer l’identité du Service Account et d’accéder aux ressources sans JSON Key, rendant l’authentification plus sécurisée et simplifiée.
Tips : Impersonation du Service Account
Cette partie est facultative. Dans le but d'améliorer la flexibilité et assurer un fonctionnement identique en local et dans le CI/CD, nous autorisons le Service Account à s'utiliser lui-même 🧐 :
resource "google_service_account_iam_member" "impersonate" {
service_account_id = google_service_account.sa.id
role = "roles/iam.serviceAccountUser"
member = google_service_account.sa.member
}
resource "google_service_account_iam_member" "impersonate_token_creator" {
service_account_id = google_service_account.sa.id
role = "roles/iam.serviceAccountTokenCreator"
member = google_service_account.sa.member
}
Nous verrons par la suite un exemple avec du code terraform exécuté dans un job Gitlab CI/CD qui montrera tout l'intérêt de cette configuration.
Appel du module dans le code principal
Une fois le module workload-identity-account
configuré, nous pouvons l’invoquer dans le code principal Terraform pour créer un Service Account spécifique, le lier au projet GitLab et configurer les permissions nécessaires pour GitLab CI/CD.
Voici comment appeler le module dans le fichier principal :
module "workload-identity-account" {
for_each = var.project_path_to_sa
source = "./workload-identity-account"
google_project_id = var.google_project_id
service_account_name = each.value
gitlab_project_path = each.key
gitlab_pool_name = google_iam_workload_identity_pool.gitlab_pool.name
}
Dans cet appel :
for_each
itère sur une map avec en clef le path du projet gitlab et en valeur le nom du service account créé et lié à ce projet.source
pointe vers le chemin du module, ici./workload-identity-account
.google_project_id
etservice_account_name
définissent respectivement le projet GCP et le nom du Service Account.gitlab_project_path
est le chemin du projet GitLab auquel le Service Account sera associé.gitlab_pool_name
fait référence au nom du Workload Identity Pool, ici récupéré depuis le poolgitlab_pool
précédemment créé.
Voici la nouvelle variable nécessaire:
variable "project_path_to_sa" {
description = "Gitlab project path to SA name"
type = map(string)
}
Il ne reste plus qu'à configurer les variables nécessaires dans un fichier terraform.tfvars
par exemple exécuter le code Terraform
google_project_id = "my-google-project-id"
gitlab_url = "https://my-private-gitlab.com"
project_path_to_sa = {
"test/sandbox-workload-identity" = "gitlab-sandbox-wi"
}
terraform init
terraform apply
Une manière simple de s'authentifier en local au provider Google terraform est d'utiliser le cli de Google
gcloud
Ainsi si vous avez les accès nécessaires,
gcloud auth application-default login
permet de rapidement démarrer. Sinon vous pouvez vous référer à la documentation du provider Google : https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/getting_started#adding-credentialsPar défaut terraform utilise un backend local sauvegardé à l'endroit de l'exécution du code terraform. Il est recommendé d'utiliser un backend décentralisé pour pouvoir sécuriser et collaborer sur la stack mise en place. Vous pouvez vous référer à cette documentation : https://developer.hashicorp.com/terraform/language/backend
Dans la Gitlab CI/CD maintenant
Sans json_key !
Pour pouvoir réaliser l'authentification dans vos pipelines GitLab CI/CD, on va utiliser la variable d'environnement GOOGLE_APPLICATION_CREDENTIALS
comme avec une json_key mais en se basant sur l'id_token généré par Gitlab.
Pour cela on utilise un modèle de job .gcp-auth
qui génère un jeton d’authentification et configure l’environnement pour utiliser Workload Identity. Ensuite, on pourra réutiliser ce modèle de manière flexible dans d’autres jobs nécessitant une authentification GCP.
Créer le modèle .gcp-auth
Dans un fichier .gitlab-ci.yml
:
.gcp-auth:
id_tokens:
WORKLOAD_IDENTITY_TOKEN:
aud: https://iam.googleapis.com/## Remplacez ici par le nom du Workload Identity pool provider provenant de l'output Terraform `GCP_WORKLOAD_IDENTITY_PROVIDER` ##
variables:
GCP_WORKLOAD_IDENTITY_PROVIDER: ## Remplacez ici par `GCP_WORKLOAD_IDENTITY_PROVIDER` ##
GOOGLE_APPLICATION_CREDENTIALS: $CI_BUILDS_DIR/.workload_identity.wlconfig
before_script:
- |
if [ -z "${SERVICE_ACCOUNT}" ]; then
echo "Erreur : la variable SERVICE_ACCOUNT n’est pas définie. Veuillez définir une variable SERVICE_ACCOUNT avec l'email du service account à utiliser."
exit 1
fi
- |-
# Enregistre le jeton JWT dans un fichier
echo $WORKLOAD_IDENTITY_TOKEN > $CI_BUILDS_DIR/.workload_identity.jwt
# Configure les credentials dans un fichier JSON pour impersonate le Service Account
cat << EOF > $GOOGLE_APPLICATION_CREDENTIALS
{
"type": "external_account",
"audience": "//iam.googleapis.com/$GCP_WORKLOAD_IDENTITY_PROVIDER",
"subject_token_type": "urn:ietf:params:oauth:token-type:jwt",
"token_url": "https://sts.googleapis.com/v1/token",
"credential_source": {
"file": "$CI_BUILDS_DIR/.workload_identity.jwt"
},
"service_account_impersonation_url": "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/$SERVICE_ACCOUNT:generateAccessToken"
}
EOF
Dans ce job .gcp-auth
:
id_tokens
: configure un jeton jwt Gitlab pour le Workload Identity Pool Provider provisionné par terraform plus haut dans l'article. Le champ audience doit être mis à jour pour inclure le nom de votre Workload Identity Pool Provider.
GCP_WORKLOAD_IDENTITY_PROVIDER
est de la forme :projects/
PROJECT_NUMBER
/locations/global/workloadIdentityPools/
WORKLOAD_IDENTITY_POOL_NAME
/providers/
WORKLOAD_IDENTITY_POOL_PROVIDER_NAME
Avec dans notre cas :
WORKLOAD_IDENTITY_POOL_NAME
= private-gitlab-pool
WORKLOAD_IDENTITY_POOL_PROVIDER_NAME
= private-gitlab-pool
-providervariables
: définit les variables nécessaires, dontGCP_WORKLOAD_IDENTITY_PROVIDER
pour le nom complet du Pool Provider etGOOGLE_APPLICATION_CREDENTIALS
pour le fichier de configuration de GCP que l'on va généré dans lebefore_script
.before_script
: vérifie que la variableSERVICE_ACCOUNT
est bien définie, puis crée un fichier, localisé à l'endroit défini parGOOGLE_APPLICATION_CREDENTIALS
, configurant l’authentification à l’aide du Workload Identity pour impersonate le Service Account spécifié.
Utiliser .gcp-auth dans d’autres jobs
Ensuite, vous pouvez étendre ce modèle .gcp-auth
dans un job spécifique, comme un job Terraform plan :
tf-plan:
extends: .gcp-auth
variables:
SERVICE_ACCOUNT: gitlab-sandbox-wi@my-google-project-id.iam.gserviceaccount.com # Remplacez par l'email du Service Account à impersonate
image: hashicorp/terraform:1.9
script:
- terraform init
- terraform plan
Dans ce job tf-plan :
extends: .gcp-auth
: permet d’hériter de la configuration de .gcp-auth pour l’authentification.SERVICE_ACCOUNT
: définit l’email du Service Account à utiliser pour ce job.script
: exécute les commandes Terraform avec les permissions et le contexte de sécurité établis par le Workload Identity.
Résultat attendu
Avec cette configuration, chaque job CI/CD qui étend .gcp-auth
peut accéder de manière sécurisée aux ressources GCP en utilisant l’authentification dynamique du Workload Identity, sans JSON Key. Cela simplifie également la gestion de l’infrastructure et réduit les risques de sécurité, car il n’est plus nécessaire de stocker des clés d’accès statiques dans vos pipelines CI/CD.