Azure DevOps, kurumsal Google Cloud müşterileri ve geliştiriciler arasında yaygın kullanılan bir CI/CD platformu. Bir Azure Pipelines iş akışının Google Cloud’da kaynak oluşturması ya da değiştirmesi gerektiğinde, örneğin Google Cloud API’lerini çağırırken, Artifact Registry’ye container image gönderirken, bir GKE cluster’ını güncellerken ya da Terraform ile altyapı deploy ederken, önce Google Cloud’a kimlik doğrulaması yapması gerekiyor.
Geleneksel yöntem, uzun ömürlü bir JSON service account anahtarını dışa aktarıp Azure Pipeline Library’deki güvenli dosyalarda ya da Azure Key Vault’ta saklamaktı. Bu yaklaşım bir kimlik yönetimi problemini bir gizli bilgi (secret) yönetimi problemine dönüştürüyordu. Anahtar sızarsa güvenlik riski oluşturuyordu; üstelik Google Cloud güvenlik önerilerine uyarak constraints/iam.disableServiceAccountKeyCreation organizasyon politikasıyla anahtar oluşturmayı kapatan kurumlardaki geliştiricileri tamamen engelliyordu.
Azure DevOps Service Connection’lardaki OpenID Connect (OIDC) desteği ve Google Cloud Workload Identity Federation ile Azure Pipelines’tan Google Cloud’a tek bir service account anahtarı dışa aktarmadan, saklamadan ya da döndürmeden kimlik doğrulaması yapılabiliyor.

Azure DevOps için neden Workload Identity Federation?
- Ayrıntılı kapsam: Workload Identity Pool ve Provider’lar, Azure DevOps OIDC token’ı ile Google Cloud IAM izinleri arasında ayrıntılı attribute eşlemeleri ve Common Expression Language (CEL) koşulları tanımlamayı sağlıyor. Dışa aktarılmış bir JSON anahtarı ya hep ya hiç türünde bir kimlik bilgisiyken, Workload Identity Federation kimlik doğrulamayı belirli bir Azure DevOps organizasyonu, projesi ve service connection’ıyla sınırlıyor. Ayrıca Azure DevOps’ta service connection üzerinde pipeline onayları ve branch kontrolleri uygulanabiliyor.
- Kısa ömürlü kimlik bilgileri: Statik JSON anahtarlarının aksine Workload Identity Federation, her işe özel Azure DevOps OIDC JWT’sini (
$idToken) Google Cloud Security Token Service (STS) üzerinden kısa ömürlü bir OAuth 2.0 access token ile değiştiriyor. Bu kimlik bilgileri varsayılan olarak bir saat sonra geçersiz oluyor; bu da ele geçirilmiş bir build ortamının verebileceği zararı ciddi şekilde sınırlıyor. - Minimum yönetim yükü: Statik anahtarların her pipeline’da güvenli şekilde saklanması, denetlenmesi ve döndürülmesi gerekiyor. Workload Identity Federation ile kimlik bilgileri her pipeline işi için ihtiyaç anında üretiliyor; ilk kurulumdan sonra döndürülecek ya da yönetilecek hiçbir statik secret kalmıyor.
1. adım: Azure DevOps’ta Workload Identity service connection oluşturun
Azure DevOps pipeline OIDC token’larını Azure Resource Manager (ARM) service connection’ları üzerinden ürettiği için Workload identity federation için yapılandırılmış bir ARM service connection oluşturuluyor.
İpucu: Sadece Google Cloud’a deploy ediyorsam Azure aboneliğine ihtiyacım var mı? Hayır. Kimlik türü olarak “App registration or managed identity (manual)” seçilirse Azure DevOps, aktif bir Azure aboneliği gerektirmeden oluşturma ekranında OIDC Issuer ve Subject identifier değerlerini hemen üretiyor. Kurumunuz Azure DevOps’u zaten Microsoft Entra ID ve bir Azure aboneliğine bağladıysa “App registration (automatic)” seçeneğini de kullanabilirsiniz.
- Azure DevOps organizasyonunuza giriş yapıp projenizi seçin.
- Sol alt köşedeki Project settings → Service connections (Pipelines altında) bölümüne girin.
- New service connection‘a tıklayın, Azure Resource Manager‘ı seçip Next‘e tıklayın.
- Bağlantıyı manuel ya da otomatik iş akışıyla yapılandırın.
Seçenek A: Manuel (Azure aboneliği gerekmiyor)
- Identity type altında App registration or managed identity (manual) seçin.
- Credential altında Workload identity federation seçin.
- Bir service connection adı girin (örneğin
google-cloud-wif). Sadece belirli pipeline’lara yetki vermek istiyorsanız “Grant access permission to all pipelines” kutusunu işaretlemeyin. - Next‘e tıklayın ve Workload Identity federation details altında üretilen Issuer ve Subject identifier değerlerini kopyalayıp saklayın. Azure aboneliği olmadan manuel bağlantıyı kaydetmek için Entra Tenant ID’nizi girin, Subscription ID ve Application client ID için
00000000-0000-0000-0000-000000000000yer tutucu GUID’lerini kullanın ve Save Without Verification‘a tıklayın.
Seçenek B: Otomatik (Microsoft Entra ID ve Azure aboneliği kullanılıyor)
- Identity type altında App registration (automatic) seçin ve Credential’ı Workload identity federation yapın.
- Aboneliğinizi (ve isteğe bağlı olarak resource group’u) seçin, service connection adını (
google-cloud-wif) girin ve Save‘e tıklayın. - Yeni oluşturulan
google-cloud-wifbağlantısını açıp Overview sekmesinden Issuer ve Subject identifier değerlerini kopyalayın.
Azure DevOps Issuer, Subject ve Audience formatları
Microsoft, Azure DevOps Workload Identity Federation service connection’larını eski vstoken.dev.azure.com issuer’ından Microsoft Entra v2.0 issuer’ına (login.microsoftonline.com) geçirdi. Azure DevOps organizasyonunuzun ya da service connection’ınızın ne zaman oluşturulduğuna bağlı olarak iki OIDC formatından birini görürsünüz:
| Format | OIDC Issuer (iss) | OIDC Audience (aud) | OIDC Subject (sub) | Uzunluk ve Google Cloud etkisi |
|---|---|---|---|---|
| Microsoft Entra Issuer (Kasım 2025’ten beri varsayılan) | https://login.microsoftonline.com/<TENANT_ID>/v2.0 | fb60f99c-7a34-4190-8149-302f77469936 (api://AzureADTokenExchange için Entra v2.0 App ID) | /eid1/c/pub/t/<TENANT_B64>/a/<APP_B64>/sc/<ORG_ID>/<SC_ID> | Yaklaşık 138 bayt. CEL ile ayıklanmazsa (assertion.sub.extract('/sc/{sc_id}')) Google Cloud’un 127 baytlık google.subject sınırını aşıyor. |
| Eski Azure DevOps Issuer (Temmuz 2026’da kullanımdan kaldırıldı, Temmuz 2027’de tamamen sona eriyor) | https://vstoken.dev.azure.com/<ORG_ID> | api://AzureADTokenExchange | sc://<ORG_NAME>/<PROJECT_NAME>/<CONNECTION_NAME> | Yaklaşık 40-60 bayt; 127 bayt sınırına doğrudan sığıyor. |
Aşağıdaki 2. adımdaki gcloud yapılandırması, --allowed-audiences="api://AzureADTokenExchange,fb60f99c-7a34-4190-8149-302f77469936" ve tek bir CEL ifadesi kullanarak iki formatı da sorunsuz şekilde destekliyor.
2. adım: Google Cloud’da Workload Identity Federation’ı kurun
Şimdi Google Cloud’u, Azure DevOps service connection’ınızın ürettiği OIDC token’larına güvenecek şekilde yapılandırıyoruz.
Ortam değişkenlerini ayarlayın ve gerekli API’leri etkinleştirin. Hedef projenizde kimliği doğrulanmış Google Cloud CLI (gcloud) ile bir terminal açın, Azure DevOps’tan kopyaladığınız Issuer ve Subject identifier değerleriyle aşağıdaki değişkenleri tanımlayın. Ardından IAM, Security Token Service (STS) ve Resource Manager API’lerini etkinleştirin:
export PROJECT_ID="your-gcp-project-id"
export PROJECT_NUMBER=$(gcloud projects describe "${PROJECT_ID}" --format="value(projectNumber)")
export POOL_ID="azure-devops-pool"
export PROVIDER_ID="azure-devops-provider"
export SERVICE_ACCOUNT_NAME="my-service-account"
# Paste the exact Issuer and Subject identifier from your Azure DevOps Service Connection:
export ADO_ISSUER_URI="https://login.microsoftonline.com/YOUR_TENANT_ID/v2.0"
export ADO_FULL_SUBJECT="/eid1/c/pub/t/YOUR_TENANT_B64/a/YOUR_APP_B64/sc/YOUR_ORG_ID/YOUR_SC_ID"
# Enable required Google Cloud APIs
gcloud services enable \
iam.googleapis.com \
iamcredentials.googleapis.com \
sts.googleapis.com \
cloudresourcemanager.googleapis.com \
--project="${PROJECT_ID}"Google Cloud service account’unu oluşturun ve en az yetki ilkesiyle rol verin. Azure DevOps pipeline’ınız için ayrı bir service account oluşturun ve ona sadece iş yükünüzün ihtiyaç duyduğu IAM rollerini verin (örneğin secret okumak için roles/secretmanager.secretAccessor ya da Cloud Storage bucket’larını yönetmek için roles/storage.admin):
gcloud iam service-accounts create "${SERVICE_ACCOUNT_NAME}" \
--project="${PROJECT_ID}" \
--display-name="Azure DevOps Workload Identity Service Account"
export SA_EMAIL="${SERVICE_ACCOUNT_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"
# Grant resource permissions to the Service Account (follow least privilege)
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
--member="serviceAccount:${SA_EMAIL}" \
--role="roles/secretmanager.secretAccessor"Workload Identity Pool ve OIDC Provider’ı oluşturun. Google Cloud’un google.subject attribute’ü en fazla 127 bayt olabiliyor. Microsoft Entra tabanlı Azure DevOps subject değerleri 138 bayt uzunluğunda olduğu ve Entra v2.0 OIDC token’ları aud claim’inde api://AzureADTokenExchange yerine Microsoft’un birinci taraf uygulama GUID’ini (fb60f99c-7a34-4190-8149-302f77469936) kullandığı için OIDC provider’da üç kontrol yapılandırılıyor:
--allowed-audiences: Google Cloud STS’nin hem Microsoft Entra v2.0 hem de eski Azure DevOps issuer’larından gelen token’ları kabul etmesi için iki audience değerini de içeriyor.--attribute-mapping: Yeni Entra tabanlı bağlantılarda benzersiz<ORG_ID>/<SC_ID>son ekini (73 bayt)google.subject‘e ayıklamak içinassertion.sub.contains('/sc/') ? assertion.sub.extract('/sc/{sc_id}') : assertion.subCEL ifadesini kullanıyor; eskisc://...subject’lerini olduğu gibi geçiriyor.--attribute-condition: Herhangi bir token değişimine izin verilmeden önceassertion.sub == '${ADO_FULL_SUBJECT}'koşulunu, kısaltılmamış 138 baytlıksubclaim’inin tamamına karşı değerlendiriyor.
Workload Identity Pool ve OIDC Provider’ı oluşturmak için:
# 1. Create the Workload Identity Pool
gcloud iam workload-identity-pools create "${POOL_ID}" \
--project="${PROJECT_ID}" \
--location="global" \
--display-name="Azure DevOps Pool"
# 2. Create the OIDC Provider with CEL extraction, full subject condition, and both Entra v2.0 + legacy audiences
gcloud iam workload-identity-pools providers create-oidc "${PROVIDER_ID}" \
--project="${PROJECT_ID}" \
--location="global" \
--workload-identity-pool="${POOL_ID}" \
--display-name="Azure DevOps OIDC Provider" \
--issuer-uri="${ADO_ISSUER_URI}" \
--allowed-audiences="api://AzureADTokenExchange,fb60f99c-7a34-4190-8149-302f77469936" \
--attribute-mapping="google.subject=assertion.sub.contains('/sc/') ? assertion.sub.extract('/sc/{sc_id}') : assertion.sub" \
--attribute-condition="assertion.sub == '${ADO_FULL_SUBJECT}'"Azure DevOps kimliğinin service account’u taklit etmesine izin verin. Eşlenen subject değerini (Microsoft Entra issuer’ları için <ORG_ID>/<SC_ID>, eski issuer’lar için sc://...) hesaplayın ve tekil principal:// önekiyle service account üzerinde roles/iam.workloadIdentityUser rolünü bağlayın:
# Compute the mapped google.subject value (<= 127 bytes)
if [[ "${ADO_FULL_SUBJECT}" == *"/sc/"* ]]; then
export MAPPED_SUBJECT="${ADO_FULL_SUBJECT#*/sc/}"
else
export MAPPED_SUBJECT="${ADO_FULL_SUBJECT}"
fi
echo "Mapped google.subject (${#MAPPED_SUBJECT} bytes): ${MAPPED_SUBJECT}"
# Grant roles/iam.workloadIdentityUser on the Service Account to the federated principal
gcloud iam service-accounts add-iam-policy-binding "${SA_EMAIL}" \
--project="${PROJECT_ID}" \
--role="roles/iam.workloadIdentityUser" \
--member="principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${POOL_ID}/subject/${MAPPED_SUBJECT}"Önemli: /subject/${MAPPED_SUBJECT}‘e başvururken her zaman tekil principal:// kullanın, principalSet:// değil. principalSet:// sadece özel attribute’leri (/attribute.<name>/<value>), grupları (/group/<value>) ya da havuzdaki tüm kimlikleri (/*) eşleştirirken geçerli.
3. adım: Azure Pipelines’tan Google Cloud’a kimlik doğrulayın
Workload Identity Federation her iki tarafta da yapılandırıldıktan sonra Azure Pipelines işleriniz hiçbir anahtar saklamadan kimlik doğrulaması yapabiliyor. İki yaygın kullanım şekli var: gcloud’un kimliğini doğrulayıp kısa ömürlü bir OAuth 2.0 access token ile Google Cloud REST API’lerini doğrudan çağırmak ya da GOOGLE_APPLICATION_CREDENTIALS‘ı ayarlayarak Terraform ve Google Cloud istemci kütüphanelerinin otomatik kimlik doğrulaması yapmasını sağlamak.
Seçenek 1: gcloud CLI ile kimlik doğrulama ve REST API çağırma. Aşağıdaki pipeline’da addSpnToEnvironment: true ayarlı AzureCLI@2 görevi, imzalı OIDC JWT’sini $idToken içinde sunuyor. Betik $idToken‘ı $(Pipeline.Workspace) altında yerel bir dosyaya kaydediyor, gcloud iam workload-identity-pools create-cred-config ile bir external account kimlik bilgisi yapılandırma dosyası üretiyor ve Secret Manager API’sini çağırmak için kısa ömürlü bir OAuth 2.0 access token alıyor:
# azure-pipelines.yml
trigger:
- main
pool:
vmImage: 'ubuntu-latest'
variables:
ADO_SERVICE_CONNECTION: 'google-cloud-wif'
GCP_PROJECT_ID: 'your-gcp-project-id'
GCP_PROJECT_NUMBER: '123456789012'
GCP_WIF_POOL: 'azure-devops-pool'
GCP_WIF_PROVIDER: 'azure-devops-provider'
GCP_SERVICE_ACCOUNT: 'my-service-account@your-gcp-project-id.iam.gserviceaccount.com'
GOOGLE_APPLICATION_CREDENTIALS: '$(Pipeline.Workspace)/.gcp_wif_credentials.json'
OIDC_TOKEN_FILE: '$(Pipeline.Workspace)/.ado_oidc_token.jwt'
steps:
- task: AzureCLI@2
displayName: 'Authenticate to Google Cloud via Workload Identity Federation'
inputs:
azureSubscription: $(ADO_SERVICE_CONNECTION)
addSpnToEnvironment: true
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
set -euo pipefail
if [ -z "${idToken:-}" ]; then
echo "ERROR: idToken is empty. Ensure the service connection uses Workload Identity Federation and addSpnToEnvironment is true."
exit 1
fi
printf "%s" "$idToken" > "$(OIDC_TOKEN_FILE)"
chmod 600 "$(OIDC_TOKEN_FILE)"
# Generate the Google Cloud external_account credential configuration file
gcloud iam workload-identity-pools create-cred-config \
"projects/$(GCP_PROJECT_NUMBER)/locations/global/workloadIdentityPools/$(GCP_WIF_POOL)/providers/$(GCP_WIF_PROVIDER)" \
--service-account="$(GCP_SERVICE_ACCOUNT)" \
--credential-source-file="$(OIDC_TOKEN_FILE)" \
--output-file="$(GOOGLE_APPLICATION_CREDENTIALS)"
# Authenticate the gcloud CLI
gcloud auth login --cred-file="$(GOOGLE_APPLICATION_CREDENTIALS)" --quiet
gcloud auth list
# Mint a short-lived OAuth 2.0 access token and call a Google Cloud REST API (e.g., Secret Manager)
ACCESS_TOKEN=$(gcloud auth application-default print-access-token)
curl -sS "https://secretmanager.googleapis.com/v1/projects/$(GCP_PROJECT_ID)/secrets/my-secret/versions/latest:access" \
--header "Authorization: Bearer ${ACCESS_TOKEN}"Seçenek 2: Application Default Credentials ile istemci kütüphaneleri ve Terraform. GOOGLE_APPLICATION_CREDENTIALS, $(Pipeline.Workspace) içinde üretilen Workload Identity Federation yapılandırma dosyasını gösterdiği için Google Cloud Application Default Credentials (ADC) üzerine kurulu her araç, yani Go, Python, Java, Node.js ve .NET istemci kütüphaneleri ile Terraform, OIDC token değişimini arka planda otomatik yapıyor. Kodda ya da provider bloğunda hiçbir değişiklik gerekmiyor. Örneğin credentials alanı olmayan bir main.tf:
# main.tf — No "credentials" attribute needed; Terraform automatically uses GOOGLE_APPLICATION_CREDENTIALS
terraform {
required_version = ">= 1.5.0"
required_providers {
google = {
source = "hashicorp/google"
version = ">= 5.0"
}
}
}
provider "google" {
project = var.project_id
region = "us-central1"
}
resource "google_storage_bucket" "demo_bucket" {
name = var.bucket_name
location = "US"
uniform_bucket_level_access = true
}Ardından azure-pipelines.yml dosyasında Workload Identity Federation kimlik doğrulama adımından sonra Terraform adımlarını ekleyin:
# Add these steps after the "Authenticate to Google Cloud via Workload Identity Federation" step:
- task: TerraformInstaller@1
displayName: 'Install Terraform'
inputs:
terraformVersion: 'latest'
- script: |
set -euo pipefail
terraform init
terraform plan \
-var="project_id=$(GCP_PROJECT_ID)" \
-var="bucket_name=ado-wif-demo-$(GCP_PROJECT_ID)-$(Build.BuildId)" \
-out=tfplan
terraform apply -auto-approve tfplan
displayName: 'Terraform Init, Plan, and Apply'Not: Azure aboneliği olmadan manuel service connection mı kullanıyorsunuz? AzureCLI@2 görevi, inline betiği çalıştırmadan önce her zaman Microsoft Entra ID’ye karşı az login --service-principal çalıştırıyor. Manuel bağlantıyı Azure aboneliğiniz olmadığı için yer tutucu GUID’lerle kaydettiyseniz, OIDC token’ı doğrudan Azure DevOps’un yerleşik $(System.OidcRequestUri) REST endpoint’inden isteyen bir Bash@3 adımı kullanın:
jobs:
- job: AuthenticateToGCP
uses:
endpoints:
- $(ADO_SERVICE_CONNECTION)
steps:
- task: Bash@3
displayName: 'Fetch Azure DevOps OIDC Token & Configure Google Cloud WIF'
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
inputs:
targetType: 'inline'
script: |
set -euo pipefail
OIDC_URL="$(System.OidcRequestUri)?api-version=7.1&serviceConnectionId=$(ADO_SERVICE_CONNECTION_ID)"
ID_TOKEN=$(curl -sS -X POST -H "Authorization: Bearer ${SYSTEM_ACCESSTOKEN}" \
-H "Content-Type: application/json" -d '{}' "${OIDC_URL}" | jq -r '.oidcToken')
printf "%s" "${ID_TOKEN}" > "$(OIDC_TOKEN_FILE)"
chmod 600 "$(OIDC_TOKEN_FILE)"
gcloud iam workload-identity-pools create-cred-config \
"projects/$(GCP_PROJECT_NUMBER)/locations/global/workloadIdentityPools/$(GCP_WIF_POOL)/providers/$(GCP_WIF_PROVIDER)" \
--service-account="$(GCP_SERVICE_ACCOUNT)" \
--credential-source-file="$(OIDC_TOKEN_FILE)" \
--output-file="$(GOOGLE_APPLICATION_CREDENTIALS)"Azure DevOps’tan Google Cloud’a uzun ömürlü JSON anahtarı olmadan kimlik doğrulamak, çok bulutlu CI/CD ortamlarındaki en yaygın kimlik bilgisi sızıntısı kaynaklarından birini ortadan kaldırıyor. Rehberin en değerli kısmı bence Entra v2.0 issuer’ına geçişle ortaya çıkan 138 baytlık subject sorununu CEL ile çözen bölüm; bu, dokümantasyonda kolay bulunmayan ve kurulumu sessizce başarısız kılabilen bir detay. Eski vstoken.dev.azure.com issuer’ının Temmuz 2027’de tamamen kalkacağını da hesaba katarak, bugün kurulacak yapılandırmanın iki formatı da destekleyecek şekilde yapılması mantıklı. Daha fazlası için Workload Identity Federation dokümantasyonuna ve en iyi uygulamalar sayfasına bakabilirsiniz.


