【Google Cloud】GitHub Actionsで認証するためのシェル関数を作る

5236 語
26 分
【Google Cloud】GitHub Actionsで認証するためのシェル関数を作る

はじまり#

リサちゃん avatar
リサちゃん
この認証手順、長すぎじゃね!?
135ml avatar
135ml
関数にしてしまおう。

Google Cloudを使ったCI/CD認証方法の選択肢#

Google Cloudのリソースに対してCI/CDパイプラインから操作を行う場合、認証方法として主に2つの選択肢があります。

  1. サービスアカウントのJSON秘密鍵を使用する方法
    • 簡単に設定できる
    • キーをダウンロードしてGitHub Secretsに保存
    • セキュリティリスクが高い(キーが漏洩する可能性)
    • 定期的なキーのローテーションが必要
  2. Workload Identity連携を使用する方法
    • JSONキーを使用しない
    • 一時的な認証情報を使用するため安全
    • キーのローテーションが不要
    • 設定が少し複雑

今回は2つ目の「Workload Identity連携」を使って、GitHub Actionsから安全にGoogle Cloudリソースにアクセスするための設定方法を解説します。さらに、この設定を簡単に行えるようにシェル関数化します。

Workload Identity連携とは?#

Workload Identity連携は、外部IDプロバイダ(GitHub Actionsなど)からの一時的な認証情報を使用して、Google Cloudリソースにアクセスする仕組みです。これにより、長期間有効なサービスアカウントキーを使用せずに、安全に認証を行うことができます。

主なメリットは以下の通りです。

  • サービスアカウントキーを作成・管理する必要がない
  • 短期間だけ有効な認証情報を使用するため、セキュリティリスクが低減
  • キーのローテーションが不要
  • きめ細かいアクセス制御が可能

Workload Identity連携の仕組み#

Workload Identity連携の基本的な仕組みは以下の通りです。

  1. GitHub Actionsのワークフローが実行されると、GitHubはOIDCトークンを発行
  2. このOIDCトークンをGoogle Cloudに送信
  3. Google CloudはOIDCトークンを検証し、一時的な認証情報を発行
  4. この一時的な認証情報を使用してGoogle Cloudリソースにアクセス

この仕組みを実現するために、Google Cloud側で「Workload Identityプール」と「プロバイダ」を設定し、GitHub側でワークフローを設定する必要があります。

Workload Identity連携を設定するためのシェル関数#

Workload Identity連携の設定は複数のステップがあり、少し複雑です。そこで、これらの設定を簡単に行えるようにシェル関数化しました。

以下の4つの主要な関数を作成しました。

  1. create_workload_identity_pool - Workload Identityプールを作成する関数
  2. create_oidc_workload_identity_pool_provider - OIDCプロバイダを作成する関数
  3. create_oidc_workload_identity_pool_provider_for_github_actions - GitHub Actions専用のOIDCプロバイダを作成する関数
  4. add_workload_identity_binding_to_service_account_on_gcloud - サービスアカウントにWorkload Identityバインディングを追加する関数

それぞれの関数について詳しく見ていきましょう。

Workload Identityプールを作成する関数#

まず、Workload Identityプールを作成する関数です。これはGoogle Cloud上で外部IDプロバイダからの認証情報を受け付けるための「プール」を作成します。

Terminal window
function create_workload_identity_pool() {
# 関数名を取得
local func_name="${FUNCNAME[0]}"
send_discord_notification "Workload Identity Poolを作成するよ!"
# ヘルプ表示
if [[ "$1" == "--help" ]]; then
echo "[INFO] ${func_name}: 使用方法"
echo " ${func_name} <WORKLOAD_IDENTITY_POOL> <PROJECT_ID> [--location=LOCATION] [--description=DESCRIPTION]"
echo ""
echo "引数:"
echo " WORKLOAD_IDENTITY_POOL 作成するワークロードアイデンティティプールの名前"
echo " PROJECT_ID Google CloudプロジェクトのプロジェクトID"
echo " --location 省略可能: ロケーション (デフォルト: global)"
echo " --description 省略可能: プールの説明"
echo ""
echo "使用例:"
echo " ${func_name} my-pool my-project-id"
echo " ${func_name} my-pool my-project-id --location=global"
echo " ${func_name} my-pool my-project-id --description=\\"My workload identity pool\\""
echo "[INFO] ${func_name}: Detail of gcloud is here: <https://cloud.google.com/sdk/gcloud/reference/iam/workload-identity-pools/create>"
return 0
fi
# パラメータのバリデーション
if [[ -z "$1" ]]; then
echo "[ERROR] ${func_name}: WORKLOAD_IDENTITY_POOL が指定されていません。" >&2
echo "[ERROR] ${func_name}: 使用方法を確認するには --help を使用してください。" >&2
return 1
fi
if [[ -z "$2" ]]; then
echo "[ERROR] ${func_name}: PROJECT_ID が指定されていません。" >&2
echo "[ERROR] ${func_name}: 使用方法を確認するには --help を使用してください。" >&2
return 1
fi
local pool_id="$1"
local project_id="$2"
local location="global"
local description=""
# オプションの解析
shift 2
while [[ $# -gt 0 ]]; do
case "$1" in
--location=*)
location="${1#*=}"
shift
;;
--description=*)
description="--description=${1#*=}"
shift
;;
*)
echo "[ERROR] ${func_name}: 不明なオプション: $1" >&2
echo "[ERROR] ${func_name}: 使用方法を確認するには --help を使用してください。" >&2
return 1
;;
esac
done
# 実行するコマンドを表示
echo "[INFO] ${func_name}: 実行するコマンド: gcloud iam workload-identity-pools create ${pool_id} --project=${project_id} --location=${location} ${description}"
# コマンド実行
echo ""
echo "======= Workload Identity Pools ============================================================================"
if ! gcloud iam workload-identity-pools create "${pool_id}" --project="${project_id}" --location="${location}" ${description}; then
echo "[ERROR] ${func_name}: ワークロードアイデンティティプールの作成に失敗しました。" >&2
send_discord_notification_about_gciam "失敗…" "Workload Identity Poolを作成できなかったよ…" "red"
return 1
fi
echo "============================================================================================================"
echo ""
echo "[INFO] ${func_name}: ワークロードアイデンティティプール '${pool_id}' をプロジェクト '${project_id}' のロケーション '${location}' に正常に作成しました。"
send_discord_notification_about_gciam "作成したよ!" "Workload Identity Poolを作成したよ!" "green"
return 0
}

この関数は以下のような特徴があります。

  • -helpオプションでヘルプを表示
  • 必須パラメータのバリデーション
  • オプションパラメータの解析
  • 実行コマンドの表示
  • エラーハンドリング
  • Discord通知機能(オプション)

使用例としては以下のような感じです。

Terminal window
create_workload_identity_pool github-pool my-project-id --description="Pool for GitHub Actions"

OIDCプロバイダを作成する関数#

次に、OIDCプロバイダを作成する関数です。これは、特定のOIDCプロバイダ(例:GitHub)からの認証情報を受け付けるための設定を行います。

Terminal window
function create_oidc_workload_identity_pool_provider() {
# 関数名を取得
local func_name="${FUNCNAME[0]}"
send_discord_notification "OIDC Workload Identity Pool Providerを作成するよ!"
# ヘルプ表示
if [[ "$1" == "--help" ]]; then
echo "[INFO] ${func_name}: 使用方法"
echo " ${func_name} <PROVIDER> <PROJECT_ID> <WORKLOAD_IDENTITY_POOL> <ISSUER_URI> <ATTRIBUTE_MAPPING> <ATTRIBUTE_CONDITION> [--location=LOCATION]"
echo ""
echo "引数:"
echo " PROVIDER 作成するプロバイダーの名前"
echo " PROJECT_ID Google CloudプロジェクトのプロジェクトID"
echo " WORKLOAD_IDENTITY_POOL プロバイダーを作成するワークロードアイデンティティプールの名前"
echo " ISSUER_URI OIDCプロバイダーの発行者URI"
echo " ATTRIBUTE_MAPPING 属性マッピング (形式: KEY=VALUE,...)"
echo " ATTRIBUTE_CONDITION 属性条件"
echo " --location 省略可能: ロケーション (デフォルト: global)"
echo ""
echo "使用例:"
echo " ${func_name} my-provider my-project-id my-pool <https://accounts.google.com> \\"google.subject=assertion.sub\\" \\"assertion.sub.startsWith('abc')\\""
echo " ${func_name} my-provider my-project-id my-pool <https://accounts.google.com> \\"google.subject=assertion.sub,google.groups=assertion.groups\\" \\"assertion.aud == 'my-audience'\\""
echo "[INFO] ${func_name}: Detail of gcloud is here: <https://cloud.google.com/sdk/gcloud/reference/iam/workload-identity-pools/providers/create-oidc>"
return 0
fi
# パラメータのバリデーション
if [[ -z "$1" ]]; then
echo "[ERROR] ${func_name}: PROVIDER が指定されていません。" >&2
echo "[ERROR] ${func_name}: 使用方法を確認するには --help を使用してください。" >&2
return 1
fi
if [[ -z "$2" ]]; then
echo "[ERROR] ${func_name}: PROJECT_ID が指定されていません。" >&2
echo "[ERROR] ${func_name}: 使用方法を確認するには --help を使用してください。" >&2
return 1
fi
if [[ -z "$3" ]]; then
echo "[ERROR] ${func_name}: WORKLOAD_IDENTITY_POOL が指定されていません。" >&2
echo "[ERROR] ${func_name}: 使用方法を確認するには --help を使用してください。" >&2
return 1
fi
if [[ -z "$4" ]]; then
echo "[ERROR] ${func_name}: ISSUER_URI が指定されていません。" >&2
echo "[ERROR] ${func_name}: 使用方法を確認するには --help を使用してください。" >&2
return 1
fi
if [[ -z "$5" ]]; then
echo "[ERROR] ${func_name}: ATTRIBUTE_MAPPING が指定されていません。" >&2
echo "[ERROR] ${func_name}: 使用方法を確認するには --help を使用してください。" >&2
return 1
fi
if [[ -z "$6" ]]; then
echo "[ERROR] ${func_name}: ATTRIBUTE_CONDITION が指定されていません。" >&2
echo "[ERROR] ${func_name}: 使用方法を確認するには --help を使用してください。" >&2
return 1
fi
local provider="$1"
local project_id="$2"
local pool_id="$3"
local issuer_uri="$4"
local attribute_mapping="$5"
local attribute_condition="$6"
local location="global"
# オプションの解析
shift 6
while [[ $# -gt 0 ]]; do
case "$1" in
--location=*)
location="${1#*=}"
shift
;;
*)
echo "[ERROR] ${func_name}: 不明なオプション: $1" >&2
echo "[ERROR] ${func_name}: 使用方法を確認するには --help を使用してください。" >&2
return 1
;;
esac
done
# 実行するコマンドを表示
echo "[INFO] ${func_name}: 実行するコマンド: gcloud iam workload-identity-pools providers create-oidc ${provider} --project=${project_id} --location=${location} --workload-identity-pool=${pool_id} --issuer-uri=${issuer_uri} --attribute-mapping=\\"${attribute_mapping}\\" --attribute-condition=\\"${attribute_condition}\\""
# コマンド実行
echo ""
echo "======= Workload Identity Pool Providers =================================================================="
if ! gcloud iam workload-identity-pools providers create-oidc "${provider}" \\
--project="${project_id}" \\
--location="${location}" \\
--workload-identity-pool="${pool_id}" \\
--issuer-uri="${issuer_uri}" \\
--attribute-mapping="${attribute_mapping}" \\
--attribute-condition="${attribute_condition}"; then
echo "[ERROR] ${func_name}: OIDCプロバイダー '${provider}' の作成に失敗しました。" >&2
send_discord_notification_about_gciam "失敗…" "OIDC Workload Identity Pool Providerを作成できなかったよ…" "red"
return 1
fi
echo "============================================================================================================"
echo ""
echo "[INFO] ${func_name}: OIDCプロバイダー '${provider}' をワークロードアイデンティティプール '${pool_id}' に正常に作成しました。"
send_discord_notification_about_gciam "作成したよ!" "OIDC Workload Identity Pool Providerを作成したよ!" "green"
return 0
}

この関数は汎用的なOIDCプロバイダを作成するためのものです。GitHub Actions以外のOIDCプロバイダ(例:GitLab、Azure DevOps)を使用する場合にも利用できます。使用例としては以下のような感じです。

Terminal window
create_oidc_workload_identity_pool_provider gitlab-provider my-project-id github-pool <https://gitlab.com> "google.subject=assertion.sub" "assertion.namespace_id=='12345'"

GitHub Actions専用のOIDCプロバイダを作成する関数#

最後に、GitHub Actions専用のOIDCプロバイダを作成する関数です。これは、前述の汎用関数をラップして、GitHub Actions特有の設定を簡単に行えるようにしたものです。

Terminal window
function create_oidc_workload_identity_pool_provider_for_github_actions() {
# 関数名を取得
local func_name="${FUNCNAME[0]}"
send_discord_notification "GitHub Actions用のOIDC Workload Identity Pool Providerを作成するよ!"
# ヘルプ表示
if [[ "$1" == "--help" ]]; then
echo "[INFO] ${func_name}: 使用方法"
echo " ${func_name} <PROVIDER_ID> <PROJECT_ID> <POOL_ID> <REPOSITORY_OWNER> [--location=LOCATION]"
echo ""
echo "引数:"
echo " PROVIDER_ID 作成するプロバイダーのID"
echo " PROJECT_ID Google CloudプロジェクトのプロジェクトID"
echo " POOL_ID プロバイダーを作成するワークロードアイデンティティプールのID"
echo " REPOSITORY_OWNER GitHubリポジトリのオーナー名(組織名またはユーザー名)"
echo " --location 省略可能: ロケーション (デフォルト: global)"
echo ""
echo "使用例:"
echo " ${func_name} github-provider my-project-id my-pool my-org"
echo " ${func_name} github-provider my-project-id my-pool my-org --location=global"
echo "[INFO] ${func_name}: Detail of gcloud is here: <https://cloud.google.com/sdk/gcloud/reference/iam/workload-identity-pools/providers/create-oidc>"
return 0
fi
# パラメータのバリデーション
if [[ -z "$1" ]]; then
echo "[ERROR] ${func_name}: PROVIDER_ID が指定されていません。" >&2
echo "[ERROR] ${func_name}: 使用方法を確認するには --help を使用してください。" >&2
return 1
fi
if [[ -z "$2" ]]; then
echo "[ERROR] ${func_name}: PROJECT_ID が指定されていません。" >&2
echo "[ERROR] ${func_name}: 使用方法を確認するには --help を使用してください。" >&2
return 1
fi
if [[ -z "$3" ]]; then
echo "[ERROR] ${func_name}: POOL_ID が指定されていません。" >&2
echo "[ERROR] ${func_name}: 使用方法を確認するには --help を使用してください。" >&2
return 1
fi
if [[ -z "$4" ]]; then
echo "[ERROR] ${func_name}: REPOSITORY_OWNER が指定されていません。" >&2
echo "[ERROR] ${func_name}: 使用方法を確認するには --help を使用してください。" >&2
return 1
fi
local provider_id="$1"
local project_id="$2"
local pool_id="$3"
local repo_owner="$4"
local location="global"
# オプションの解析
shift 4
while [[ $# -gt 0 ]]; do
case "$1" in
--location=*)
location="${1#*=}"
shift
;;
*)
echo "[ERROR] ${func_name}: 不明なオプション: $1" >&2
echo "[ERROR] ${func_name}: 使用方法を確認するには --help を使用してください。" >&2
return 1
;;
esac
done
# 属性マッピングと条件の設定
local attribute_mapping="google.subject=assertion.sub,attribute.repository=assertion.repository"
local attribute_condition="assertion.repository_owner=='${repo_owner}'"
# 実行するコマンドを表示
echo "[INFO] ${func_name}: 実行するコマンド: gcloud iam workload-identity-pools providers create-oidc ${provider_id} --project=${project_id} --location=${location} --workload-identity-pool=${pool_id} --issuer-uri=https://token.actions.githubusercontent.com/ --attribute-mapping=\\"${attribute_mapping}\\" --attribute-condition=\\"${attribute_condition}\\""
# コマンド実行
echo ""
echo "======= Workload Identity Pool Providers =================================================================="
if ! gcloud iam workload-identity-pools providers create-oidc "${provider_id}" \\
--project="${project_id}" \\
--location="${location}" \\
--workload-identity-pool="${pool_id}" \\
--issuer-uri="<https://token.actions.githubusercontent.com/>" \\
--attribute-mapping="${attribute_mapping}" \\
--attribute-condition="${attribute_condition}"; then
echo "[ERROR] ${func_name}: GitHub Actions用のOIDCプロバイダー '${provider_id}' の作成に失敗しました。" >&2
send_discord_notification_about_gciam "失敗…" "GitHub Actions用のOIDC Workload Identity Pool Providerを作成できなかったよ…" "red"
return 1
fi
echo "============================================================================================================"
echo ""
# プロバイダー名を取得
local provider_name="projects/${project_id}/locations/${location}/workloadIdentityPools/${pool_id}/providers/${provider_id}"
echo "[INFO] ${func_name}: GitHub Actions用のOIDCプロバイダー '${provider_id}' を正常に作成しました。"
send_discord_notification_about_gciam "作成したよ!" "GitHub Actions用のOIDC Workload Identity Pool Providerを作成したよ!" "green"
# GitHub Actions用のYAML情報を表示
echo ""
echo "[INFO] ${func_name}: 以下はGitHub Actions用のYAMLファイルに記述するための設定例です:"
echo "----------------------------------------------------------------"
echo "env:"
echo " GCLOUD_PROJECT_NUMBER: \\${{ secrets.GCLOUD_PROJECT_NUMBER }} # プロジェクト番号を設定してください"
echo " GCLOUD_POOL_ID: ${pool_id}"
echo " GCLOUD_PROVIDER_ID: ${provider_id}"
echo " GCLOUD_SERVICE_ACCOUNT_EMAIL: \\${{ secrets.GCLOUD_SERVICE_ACCOUNT_EMAIL }} # サービスアカウントのメールアドレスを設定してください"
echo "jobs:"
echo " test:"
echo " runs-on: ubuntu-latest"
echo " steps:"
echo " - id: 'gcloud_auth'"
echo " name: 'Authenticate to Google Cloud'"
echo " uses: 'google-github-actions/auth@v2'"
echo " with:"
echo " create_credentials_file: true"
echo " workload_identity_provider: 'projects/\\${{ env.GCLOUD_PROJECT_NUMBER }}/locations/${location}/workloadIdentityPools/${pool_id}/providers/${provider_id}'"
echo " service_account: '\\${{ env.GCLOUD_SERVICE_ACCOUNT_EMAIL }}'"
echo "----------------------------------------------------------------"
echo ""
echo "[INFO] ${func_name}: GitHub Secretsにプロジェクト番号とサービスアカウントのメールアドレスを設定してください。"
echo "[INFO] ${func_name}: 次に、サービスアカウントにリポジトリからのアクセスを許可するためにIAMポリシーバインディングを追加する必要があります。"
return 0
}

この関数は、GitHub Actions専用の設定を簡単に行えるようにしたものです。特に以下の点が便利です。

  • GitHub Actions特有の設定(発行者URI、属性マッピング)が自動的に設定される
  • リポジトリオーナー(組織名またはユーザー名)だけを指定すれば、適切な属性条件が設定される
  • 設定後、GitHub Actionsのワークフロー設定例が表示される

使用例としては以下のような感じです。

Terminal window
create_oidc_workload_identity_pool_provider_for_github_actions github-provider my-project-id github-pool my-organization

サービスアカウントにWorkload Identityバインディングを追加する関数#

GitHub Actionsからサービスアカウントにアクセスできるようにするために、サービスアカウントにroles/iam.workloadIdentityUserロールを付与する必要があります。以下は、この設定を簡単に行うための関数です。

Terminal window
function add_workload_identity_binding_to_service_account_on_gcloud() {
# 関数名を取得
local func_name="${FUNCNAME[0]}"
send_discord_notification "サービスアカウントにWorkload Identityバインディングを追加するよ!"
# ヘルプ表示
if [[ "$1" == "--help" ]]; then
echo "[INFO] ${func_name}: 使用方法"
echo " ${func_name} <SERVICE_ACCOUNT_EMAIL> <PROJECT_NUMBER> <POOL_ID> <REPOSITORY_OWNER> <REPOSITORY_NAME> [--provider-id=PROVIDER_ID] [--condition=KEY=VALUE,...] [--condition-from-file=PATH_TO_FILE]"
echo ""
echo "引数:"
echo " SERVICE_ACCOUNT_EMAIL IAMポリシーバインディングを追加するサービスアカウントのメールアドレス"
echo " PROJECT_NUMBER プロジェクト番号"
echo " POOL_ID ワークロードアイデンティティプールのID"
echo " REPOSITORY_OWNER リポジトリのオーナー"
echo " REPOSITORY_NAME リポジトリの名前"
echo " --provider-id 省略可能: プロバイダーID (GitHub Actions用YAMLの生成に使用)"
echo " --condition 省略可能: IAMの条件 (形式: KEY=VALUE,...)"
echo " --condition-from-file 省略可能: 条件を含むファイルへのパス"
echo ""
echo "使用例:"
echo " ${func_name} my-sa@my-project.iam.gserviceaccount.com 123456789012 my-pool my-org my-repo"
echo " ${func_name} my-sa@my-project.iam.gserviceaccount.com 123456789012 my-pool my-org my-repo --provider-id=github"
echo " ${func_name} my-sa@my-project.iam.gserviceaccount.com 123456789012 my-pool my-org my-repo --condition=\\"title=test,expression=request.time < timestamp('2023-01-01T00:00:00Z')\\""
echo "[INFO] ${func_name}: [INFO] Detail of gcloud is here: <https://cloud.google.com/sdk/gcloud/reference/iam/service-accounts/add-iam-policy-binding>"
return 0
fi
# パラメータのバリデーション
if [[ -z "$1" ]]; then
echo "[ERROR] ${func_name}: SERVICE_ACCOUNT_EMAIL が指定されていません。" >&2
echo "[ERROR] ${func_name}: 使用方法を確認するには --help を使用してください。" >&2
return 1
fi
if [[ -z "$2" ]]; then
echo "[ERROR] ${func_name}: PROJECT_NUMBER が指定されていません。" >&2
echo "[ERROR] ${func_name}: 使用方法を確認するには --help を使用してください。" >&2
return 1
fi
if [[ -z "$3" ]]; then
echo "[ERROR] ${func_name}: POOL_ID が指定されていません。" >&2
echo "[ERROR] ${func_name}: 使用方法を確認するには --help を使用してください。" >&2
return 1
fi
if [[ -z "$4" ]]; then
echo "[ERROR] ${func_name}: REPOSITORY_OWNER が指定されていません。" >&2
echo "[ERROR] ${func_name}: 使用方法を確認するには --help を使用してください。" >&2
return 1
fi
if [[ -z "$5" ]]; then
echo "[ERROR] ${func_name}: REPOSITORY_NAME が指定されていません。" >&2
echo "[ERROR] ${func_name}: 使用方法を確認するには --help を使用してください。" >&2
return 1
fi
local service_account_email="$1"
local project_number="$2"
local pool_id="$3"
local repo_owner="$4"
local repo_name="$5"
local provider_id=""
local condition=""
local condition_from_file=""
# principalSet の生成
local principal_set="principalSet://iam.googleapis.com/projects/${project_number}/locations/global/workloadIdentityPools/${pool_id}/attribute.repository/${repo_owner}/${repo_name}"
# オプションの解析
shift 5
while [[ $# -gt 0 ]]; do
case "$1" in
--provider-id=*)
provider_id="${1#*=}"
shift
;;
--condition=*)
condition="--condition=${1#*=}"
shift
;;
--condition-from-file=*)
condition_from_file="--condition-from-file=${1#*=}"
shift
;;
*)
echo "[ERROR] ${func_name}: 不明なオプション: $1" >&2
echo "[ERROR] ${func_name}: 使用方法を確認するには --help を使用してください。" >&2
return 1
;;
esac
done
# condition と condition-from-file の両方が指定されていないか確認
if [[ -n "${condition}" && -n "${condition_from_file}" ]]; then
echo "[ERROR] ${func_name}: --condition と --condition-from-file は同時に指定できません。" >&2
return 1
fi
# 実行するコマンドを表示
echo "[INFO] ${func_name}: 実行するコマンド: gcloud iam service-accounts add-iam-policy-binding ${service_account_email} --member='${principal_set}' --role=roles/iam.workloadIdentityUser ${condition} ${condition_from_file}"
# コマンド実行
echo ""
echo "======= IAM Policy Binding ================================================================================="
if ! gcloud iam service-accounts add-iam-policy-binding "${service_account_email}" \\
--member="${principal_set}" \\
--role="roles/iam.workloadIdentityUser" \\
${condition} \\
${condition_from_file}; then
echo "[ERROR] ${func_name}: サービスアカウント '${service_account_email}' へのワークロードアイデンティティバインディング追加に失敗しました。" >&2
send_discord_notification_about_gciam "失敗…" "サービスアカウントにWorkload Identityバインディングを追加できなかったよ…" "red"
return 1
fi
echo "============================================================================================================"
echo ""
echo "[INFO] ${func_name}: サービスアカウント '${service_account_email}' に ${repo_owner}/${repo_name} リポジトリからのアクセスを正常に設定しました。"
send_discord_notification_about_gciam "IAMポリシーバインディングを追加したよ!" "サービスアカウントにWorkload Identityバインディングを追加したよ!" "green"
# GitHub Actions用のYAML情報を表示
echo ""
echo "[INFO] ${func_name}: 以下はGitHub Actions用のYAMLファイルに記述するための設定例です:"
echo "----------------------------------------------------------------"
echo "env:"
echo " GCLOUD_PROJECT_NUMBER: \\${{ secrets.GCLOUD_PROJECT_NUMBER }}"
echo " GCLOUD_POOL_ID: \\${{ secrets.GCLOUD_POOL_ID }}"
if [[ -n "${provider_id}" ]]; then
echo " GCLOUD_PROVIDER_ID: \\${{ secrets.GCLOUD_PROVIDER_ID }}"
else
echo " GCLOUD_PROVIDER_ID: \\${{ secrets.GCLOUD_PROVIDER_ID }} # プロバイダーIDを設定してください"
fi
echo " GCLOUD_SERVICE_ACCOUNT_EMAIL: \\${{ secrets.GCLOUD_SERVICE_ACCOUNT_EMAIL }}"
echo "jobs:"
echo " test:"
echo " runs-on: ubuntu-latest"
echo " steps:"
echo " - id: 'gcloud_auth'"
echo " name: 'Authenticate to Google Cloud'"
echo " uses: 'google-github-actions/auth@v2'"
echo " with:"
echo " create_credentials_file: true"
echo " workload_identity_provider: 'projects/\\${{ env.GCLOUD_PROJECT_NUMBER }}/locations/global/workloadIdentityPools/\\${{ env.GCLOUD_POOL_ID }}/providers/\\${{ env.GCLOUD_PROVIDER_ID }}'"
echo " service_account: '\\${{ env.GCLOUD_SERVICE_ACCOUNT_EMAIL }}'"
echo "----------------------------------------------------------------"
echo ""
echo "[INFO] ${func_name}: GitHub SecretsにプロジェクトID、プールID、プロバイダーID、サービスアカウントのメールアドレスを設定してください。"
return 0
}

この関数は、サービスアカウントにWorkload Identityバインディングを追加するための関数です。特に以下の点が便利です。

  • リポジトリオーナーとリポジトリ名を指定するだけで、適切なprincipalSetが自動的に生成される
  • 条件付きのIAMポリシーバインディングも設定可能
  • 設定後、GitHub Actionsのワークフロー設定例が表示される

使用例としては以下のような感じです。

Terminal window
add_workload_identity_binding_to_service_account_on_gcloud github-actions-sa@my-project-id.iam.gserviceaccount.com 123456789012 github-pool my-organization my-repository --provider-id=github-provider

サービスアカウントを作成する関数#

Workload Identity連携を使用するには、サービスアカウントも必要です。以下は、サービスアカウントを作成し、適切なロールを付与する関数です。

Terminal window
function create_gcloud_service_account() {
local func_name="${FUNCNAME[0]}"
send_discord_notification "サービスアカウントを作成するよ!"
# Check for help parameter
if [[ "$1" == "--help" ]]; then
echo "[INFO] ${func_name}: Usage: create_gcloud_service_account <SERVICE_ACCOUNT_ID> <PROJECT_ID> <ROLE>"
echo "[INFO] ${func_name}: Example: create_gcloud_service_account my-service-account my-project-id roles/storage.admin"
echo "[INFO] ${func_name}: [INFO] Detail of gcloud is here: <https://cloud.google.com/sdk/gcloud/reference/iam/service-accounts/create>"
echo "[INFO] ${func_name}: [INFO] Detail of gcloud is here: <https://cloud.google.com/sdk/gcloud/reference/iam/service-accounts/add-iam-policy-binding>"
return 0
fi
# Validate number of parameters
if [[ "$#" -ne 3 ]]; then
echo "[ERROR] ${func_name}: Invalid number of arguments. Use --help for usage."
return 1
fi
local SERVICE_ACCOUNT_ID="$1"
local PROJECT_ID="$2"
local ROLE="$3"
# Create the service account
echo "[INFO] ${func_name}: Creating service account '${SERVICE_ACCOUNT_ID}'..."
gcloud iam service-accounts create "${SERVICE_ACCOUNT_ID}"
if [[ "$?" -ne 0 ]]; then
send_discord_notification_about_gciam "失敗…" "サービスアカウントを作成できなかったよ…" "red"
echo "[ERROR] ${func_name}: Failed to create service account '${SERVICE_ACCOUNT_ID}'."
return 1
fi
# Bind the IAM policy with the provided role
echo "[INFO] ${func_name}: Adding IAM policy binding for project '${PROJECT_ID}' with role '${ROLE}'..."
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \\
--member="serviceAccount:${SERVICE_ACCOUNT_ID}@${PROJECT_ID}.iam.gserviceaccount.com" \\
--role="${ROLE}"
if [[ "$?" -ne 0 ]]; then
send_discord_notification_about_gciam "失敗…" "IAMポリシーをバインドできなかったよ…" "red"
echo "[ERROR] ${func_name}: Failed to add IAM policy binding for project '${PROJECT_ID}'."
return 1
fi
send_discord_notification_about_gciam "バインドしたよ!" "IAMポリシーをバインドしたよ!" "green"
echo "[INFO] ${func_name}: Service account '${SERVICE_ACCOUNT_ID}' created and policy binding added successfully."
}

この関数は、サービスアカウントを作成し、指定したロールをプロジェクトに対して付与します。使用例としては以下のような感じです。

Terminal window
create_gcloud_service_account github-actions-sa my-project-id roles/storage.admin

実際の使用手順#

これらの関数を使って、GitHub ActionsからGoogle Cloudリソースにアクセスするための設定を行う手順を説明します。

1. シェル関数を読み込む#

まず、上記のシェル関数をファイルに保存し、読み込みます。

Terminal window
# 関数を保存したファイルを読み込む
source ./gcloud_workload_identity.sh

2. Workload Identityプールを作成する#

Terminal window
create_workload_identity_pool github-pool my-project-id --description="Pool for GitHub Actions"

3. GitHub Actions用のOIDCプロバイダを作成する#

Terminal window
create_oidc_workload_identity_pool_provider_for_github_actions github-provider my-project-id github-pool my-organization

4. サービスアカウントを作成する#

Terminal window
create_gcloud_service_account github-actions-sa my-project-id roles/storage.admin

5. サービスアカウントにWorkload Identity連携のロールを付与する#

GitHub Actionsからサービスアカウントにアクセスできるようにするために、サービスアカウントにroles/iam.workloadIdentityUserロールを付与します。

Terminal window
# プロジェクト番号を取得
PROJECT_NUMBER=$(gcloud projects describe my-project-id --format="value(projectNumber)")
# サービスアカウントにWorkload Identity Userロールを付与
add_workload_identity_binding_to_service_account_on_gcloud \\
github-actions-sa@my-project-id.iam.gserviceaccount.com \\
${PROJECT_NUMBER} \\
github-pool \\
my-organization \\
my-repository \\
--provider-id=github-provider

この関数を使用することで、複雑なprincipalSetの構築を自動化し、エラーを防ぐことができます。また、GitHub Actions用のYAML設定例も自動的に表示されます。

6. GitHub Actionsのワークフローを設定する#

最後に、GitHub Actionsのワークフローファイル(.github/workflows/deploy.ymlなど)に認証設定を追加します。以下がワークフローのサンプルです。

jobs:
test:
runs-on: ubuntu-latest
if: contains(github.event.head_commit.message, '[skip ci]') == false
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Golang
uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'
- id: 'gcloud_auth'
name: 'Authenticate to Google Cloud'
uses: 'google-github-actions/auth@v2'
with:
create_credentials_file: true
workload_identity_provider: 'projects/${{ env.GCLOUD_PROJECT_NUMBER }}/locations/global/workloadIdentityPools/${{ env.GCLOUD_POOL_ID }}/providers/${{ env.GCLOUD_PROVIDER_ID }}'
service_account: '${{ env.GCLOUD_SERVICE_ACCOUNT_EMAIL }}'
- name: 'Set up Cloud SDK'
uses: 'google-github-actions/setup-gcloud@v2'
- name: 'Use gcloud CLI'
run: 'gcloud info'

この設定により、GitHub Actionsのワークフローが実行されると、以下のような流れで認証が行われます。

  1. GitHub Actionsが実行環境のOIDCトークンを取得
  2. google-github-actions/authアクションがOIDCトークンをGoogle Cloudに送信
  3. Google CloudがOIDCトークンを検証し、一時的な認証情報を発行
  4. 一時的な認証情報を使用してGoogle Cloudリソースにアクセス

実際に認証出来るとログで確認出来る#

実際に認証出来ると、GitHub Actionsの実行ログで確認することが出来ます。

セキュリティ上の注意点#

Workload Identity連携を使用する際には、以下の点に注意します。

  1. 属性条件の設定:必ず適切な属性条件を設定して、特定のリポジトリやブランチからのアクセスのみを許可するようにします。
  2. 最小権限の原則:サービスアカウントには必要最小限の権限のみを付与します。
  3. 監査ログの確認:定期的に監査ログを確認して、不審なアクセスがないか確認します。
  4. 定期的な見直し:定期的に設定を見直し、不要なアクセス権限を削除します。

まとめ#

この記事では、GitHub ActionsからGoogle Cloudリソースにアクセスするための安全な方法として、Workload Identity連携を使用する方法を紹介しました。また、この設定を簡単に行えるようにするためのシェル関数も提供しました。

Workload Identity連携を使用することで、以下のメリットが得られます。

  • サービスアカウントキーを使用しないため、セキュリティリスクが低減
  • キーのローテーションが不要
  • きめ細かいアクセス制御が可能
  • 監査ログによる追跡が容易

これらのシェル関数を使用して、簡単かつ安全にCI/CDパイプラインを構築出来そうです。

おしまい#

リサちゃん avatar
リサちゃん
だいぶ手数が減った気がする
135ml avatar
135ml
作るの大変だった・・・。

以上になります!

記事を共有

この記事が役に立ったなら、ぜひ他の人と共有してください!

【Google Cloud】GitHub Actionsで認証するためのシェル関数を作る
https://endorphinbath.com/posts/gcp-shell-functions-for-github-actions-authentication/
著者
kinkinbeer135ml
公開日
2025-04-25
ライセンス
CC BY-NC-SA 4.0
関連記事 スマート
1
【GCP】GitHub Actionsからキーなしで認証するための設定
Code Google Cloud Platformに認証するときのIAM設定をシェル上から行い、GitHub Actionsで認証を行う作業を掲載します。この手順を踏むことで、IAMを管理しやすくなるかと思います。
2
【Cloud Scheduler】コンテナを動かすために必要なgcloudコマンドをシェル関数化する
Code Google Cloud上でデプロイされたコンテナを操作するためにシェル関数を構築します。その関数には処理が完了した時やエラー発生時に通知を行ったりヘルプ機能も実装します。
3
【Cloud Run】コンテナを稼働させるまでに必要なgcloudコマンドをシェル関数化する
Code Google Cloud上でコンテナをデプロイするためにシェル関数を構築します。その関数には処理が完了した時やエラー発生時に通知を行ったりヘルプ機能も実装します。
4
【GitHub】Pythonでリポジトリの情報を取得するCloud Functionsを作る
Code Pythonを使用してGitHubリポジトリの情報を取得し、Cloud Functionsで処理する方法に関する記事です。PyGithubとThreadingで実装および処理を効率的にしました。
5
【Google Compute Engine】SSH接続できるDebian VMを構築するシェル関数を作る
Code Google Compute Engine上にDebianのVMインスタンスを構築するためのシェル関数を紹介します。それを実行すると、Chromeリモートデスクトップからアクセス出来るVMが使えるようになります。
ランダム記事 ランダム
Profile Image of the Author
kinkinbeer135ml
SIerをやめて、プログラミングを勉強しています。※Amazonアソシエイトに参加しています。
お知らせ
私のブログへようこそ!これはサンプルのお知らせです。
音楽
カバー

音楽

再生中なし

0:00 0:00
歌詞なし
カテゴリ
タグ
サイト統計
記事
287
カテゴリー
8
タグ
93
総文字数
486,174
運用日数
0
最終活動
0 日前

目次