Cloud Intelligence™Cloud Intelligence™

Cloud Intelligence™

Workload Identity FederationでGitLabパイプラインからGoogle Cloudへ安全にアクセス

By Chimbu ChinnaduraiSep 1, 20236 min read

このページはEnglishDeutschEspañolFrançaisItalianoPortuguêsでもご覧いただけます。

Secure-access-to-GCP-services-in-GitLab-Pipelines-with-Workload-Identity-Federation-DoiT-International

GitLabパイプラインのようなGCP外のCI/CD環境からGoogle Cloudのサービスを利用する場合、従来はサービスアカウントキーなど有効期限の長い認証情報を使ってGoogle Cloudへ認証する必要がありました。しかしこの方式には、次のようなセキュリティ上の課題があります。

  • 認証情報の長期露出: サービスアカウントキーは有効期限が長く、通常は手動で失効またはローテーションするまで有効なままです。これらのキーをソースコードリポジトリ、設定ファイル、CI/CD環境に保存していると、それらが侵害された際に不正アクセスを受けるリスクが高まります。
  • 権限昇格: サービスアカウントキーには、Google Cloud内でさまざまな処理を実行できるよう広範な権限が付与されているケースが少なくありません。攻撃者にキーを奪われると、本来そのアプリケーションやworkloadに必要な範囲を超えて、広範なリソースへアクセスされる恐れがあります。
  • 認証情報の管理: サービスアカウントキーの定期的なローテーションはセキュリティのベストプラクティスとして欠かせません。しかし手動でのローテーションは煩雑でミスも起こりやすく、セキュリティの抜け穴につながりかねません。
  • 監査と追跡可能性の限界: サービスアカウントキーを利用していると、特定の操作を個々のユーザーやサービスに紐づけることが難しくなります。粒度が粗いため監査の妨げとなり、操作の発生源をたどるのが困難になります。

GCPのWorkload Identity Federationは、こうしたセキュリティ上の懸念を解消し、既存のIDプロバイダー(IdP)を使ってGoogle Cloud Platform(GCP)へ認証できるようにする仕組みです。GitLabパイプラインでも有効で、別途サービスアカウントや認証情報を管理せずとも、GitLabの認証情報のままGCPへ認証できます。

GCPのWorkload Identity Federationを構成する主な要素は次のとおりです。

  • IDプロバイダー(IdP): ユーザーを認証し、認証情報を発行するシステムです。GCPはActive Directory Federation Services(ADFS)、Okta、Azure Active Directoryのほか、OpenID Connect(OIDC)またはSAML 2.0に対応したIDプロバイダーを幅広くサポートしています。
  • Workload Identityプール: 外部IDを管理するためのエンティティです。Google Cloudのリソースにアクセスする必要があるGoogle Cloud以外の環境ごとに、新しいプールを作成することを推奨します。
  • サービスアカウント: GCPでは、workloadを表す存在としてサービスアカウントが使われます。リソースへアクセスするには、プール内のIDにサービスアカウントへのアクセス権を付与します。付与後、これらのIDはそのサービスアカウントがアクセス可能なGoogle Cloudサービスを利用できるようになります。
  • フェデレーショントークン: IdPが発行し、サービスアカウントトークンと交換するためのトークンです。これによりworkloadは、サービスアカウントとしてGCPに認証できます。

本記事では、GCPでWorkload Identity Federationを構成し、GitLabパイプラインから短命トークンを使ってGCPサービスへ安全にアクセスする手順を解説します。

前提条件

  • 対象プロジェクトでWorkload Identity Pool Admin(roles/iam.workloadIdentityPoolAdmin)とService Account Admin(roles/iam.serviceAccountAdmin)のロールを保有していること。
  • 以下のAPIを有効化してください。
#Update $GCP_PROJECT_ID value
gcloud services enable cloudresourcemanager.googleapis.com \
iam.googleapis.com \
iamcredentials.googleapis.com \
sts.googleapis.com \
--project $GCP_PROJECT_ID
  • GitLabアカウント。お持ちでない場合はこちらから新規作成してください。

Workload Identity Federationのセットアップ

  • ステップ1: Workload Identityプールを作成します。
#Update $GCP_PROJECT_ID value
gcloud iam workload-identity-pools create gitlab-demo-wip \
--location="global" \
--description="Gitlab demo workload Identity pool" \
--display-name="gitlab-demo-wip"
--project=$GCP_PROJECT_ID

gitlab-ci-cd

workload identity pool

gitlab

workload identity pool configuration

  • ステップ2: GitLab用のWorkload Identityプールプロバイダーを追加し、属性条件(Attribute conditions)を使って、このプールで認証できるIDを絞り込みます。
  • 属性マッピングはWorkload Identity Federationを構成するうえで重要な設定です。外部IDプロバイダーが発行する認証情報の属性を、subjectemailといったGoogle Cloud側の属性に対応づけられます。プロバイダーによっては、これらの属性を「クレーム(claims)」と呼ぶこともあります。
  • 外部IDプロバイダーごとに公開される属性は異なります。AWSについてはGoogleが既定のマッピングを用意しており、一般的なシナリオの大半をカバーします。独自のマッピングを指定することも可能です。
  • GitLabのようなOIDCプロバイダーの場合は、マッピングを自分で指定します。マッピングを構築するには、各プロバイダーのドキュメントで認証情報に含まれる属性一覧を確認してください。GitLabであれば、IDトークンのペイロードを参照すると、各GitLab IDトークンに含まれるクレームを確認できます。

下記の属性条件は、筆者の個人GitLab名前空間に属するIDのみに認証を限定するものです。表示中の名前空間がグループか個人かを判別する方法は、GitLabの名前空間ドキュメントを参照してください。

#Update GITLAB_NAMESPACE_PATH value
gcloud iam workload-identity-pools providers create-oidc gitlab-identity-provider --location="global" \
--workload-identity-pool="gitlab-demo-wip" \
--issuer-uri="https://gitlab.com" \
--allowed-audiences=https://gitlab.com \
--attribute-mapping="google.subject=assertion.sub,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" \
--attribute-condition="assertion.namespace_path.startsWith(\"$GITLAB_NAMESPACE_PATH\")" \
--project=$GCP_PROJECT_ID

ci

sample gcloud command result

pipeline

gitlab provider added to the workload identity pool

gitlab

gitlab identity provider configuration

  • この時点で、GitLab CI/CDジョブからGoogle Cloudへの認証は可能になりますが、Google Cloud上の権限(認可)はまだ何も付与されていません。
  • ステップ3: GitLab外部IDが借用(impersonate)できるサービスアカウントを作成します。
#Create a service account
gcloud iam service-accounts create gitlab-wif-demo --project=$GCP_PROJECT_ID
#Add sample permissions to the Service account
gcloud projects add-iam-policy-binding $GCP_PROJECT_ID \
--member=serviceAccount:gitlab-wif-demo@${GCP_PROJECT_ID}.iam.gserviceaccount.com \
--role=roles/storage.admin
  • ステップ4: GitLab外部IDにサービスアカウントの借用権限を付与し、GitLab CI/CDジョブがサービスアカウント借用を経由してGoogle Cloudで認可されるようにします。このステップでは、サービスアカウント自体に対するIAM権限を付与し、外部IDがそのサービスアカウントとして振る舞えるようにします。

下記のコマンドは、プール内のすべてのIDがサービスアカウント借用によりGCPリソースへアクセスできるようにするものです。実運用では、属性に応じて借用可能な外部IDを限定することを推奨します。

ロール付与の代表的なシナリオは、https://cloud.google.com/iam/docs/workload-identity-federation#impersonationを参照してください。

PROJECT_NUMBER=$(gcloud projects describe $(gcloud config get-value core/project) --format=value\(projectNumber\) --project $GCP_PROJECT_ID)
gcloud iam service-accounts add-iam-policy-binding gitlab-wif-demo@${GCP_PROJECT_ID}.iam.gserviceaccount.com \
--role=roles/iam.workloadIdentityUser \
--member="principalSet://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/gitlab-demo-wip/*"

gitlab

service account connected to the workload identity pool

GitLabパイプラインでWorkload Identity Federationの設定をテストする

ここまでの手順で、筆者の個人GitLab名前空間に属するIDを信頼するようWorkload Identityプールを設定しました。GitLabアカウント側の設定変更は不要で、CI/CDジョブごとにWorkload Identity Federationを有効化できます。要件に合わせて柔軟にカスタマイズしてください。

  • ステップ5: 空のGitLabプロジェクトを新規作成するか、既存のプロジェクトを利用します。

gitlab

gitlab repo

  • ステップ6: .gitlab-ci.ymlというファイルを作成し、下記のテンプレートを使ってGitLabパイプラインを設定します。GitLabパイプラインの詳細はCI/CDパイプラインのドキュメントを参照してください。
#Update the $GCP_PROJECT_NAME and $GCP_PROJECT_NUMBER values
variables:
GCP_PROJECT_NAME: $GCP_PROJECT_NAME
GCP_WORKLOAD_IDENTITY_PROVIDER: "projects/$GCP_PROJECT_NUMBER/locations/global/workloadIdentityPools/gitlab-demo-wip/providers/gitlab-identity-provider"
SERVICE_ACCOUNT_EMAIL: "gitlab-wif-demo@$GCP_PROJECT_NAME.iam.gserviceaccount.com"
stages:
- gcp_wif_demo
.gcp_wif_auth: &gcp_wif_auth
#id_tokens to create JSON web tokens (JWT) to authenticate with third party services.This replaces the CI_JOB_JWT_V2
id_tokens:
GITLAB_OIDC_TOKEN:
aud: https://gitlab.com
before_script:
- apt-get update && apt-get install -yq jq
#Get temporary credentials using the ID token
- |
PAYLOAD=$(cat <<EOF
{
"audience": "//iam.googleapis.com/${GCP_WORKLOAD_IDENTITY_PROVIDER}",
"grantType": "urn:ietf:params:oauth:grant-type:token-exchange",
"requestedTokenType": "urn:ietf:params:oauth:token-type:access_token",
"scope": "https://www.googleapis.com/auth/cloud-platform",
"subjectTokenType": "urn:ietf:params:oauth:token-type:jwt",
"subjectToken": "${GITLAB_OIDC_TOKEN}"
}
EOF
)
- |
FEDERATED_TOKEN=$(curl -s -X POST "https://sts.googleapis.com/v1/token" \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--data "${PAYLOAD}" \
| jq -r '.access_token'
)
#Use the federated token to impersonate the service account linked to workload identity pool
#The resulting access token is stored in CLOUDSDK_AUTH_ACCESS_TOKEN environment variable and this will be passed to the gcloud CLI
- |
export CLOUDSDK_AUTH_ACCESS_TOKEN=$(curl -s -X POST "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/${SERVICE_ACCOUNT_EMAIL}:generateAccessToken" \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "Authorization: Bearer ${FEDERATED_TOKEN}" \
--data '{"scope": ["https://www.googleapis.com/auth/cloud-platform"]}' \
| jq -r '.accessToken'
)
gcloud_test:
<<: *gcp_wif_auth
stage: gcp_wif_demo
image: gcr.io/google.com/cloudsdktool/google-cloud-cli:441.0.0
script:
- gcloud config set project ${GCP_PROJECT_NAME}
- gcloud storage ls

workload

.gitlab-ci.yml

  • GitLab CI/CDパイプラインは、デフォルトで新規コミットがプッシュされた際に自動実行されます。実行結果はBuild → Pipelinesから確認してください。

gcp

gitlab pipeline trigger status

workload

gitlab job sample log

ジョブログを見ると、Workload Identity Federationの一環として発行された短命トークンによって、認証と認可が想定どおりに機能していることが確認できます。

Workload Identity Federationは、GitLabパイプラインのセキュリティを高め、組織全体のセキュリティ態勢を強化するうえで非常に有用なサービスです。まだ導入していない方は、サービスアカウントキーに代えて、ぜひパイプラインに取り入れてみてください。