GitHub Actionsから踏み台経由でプライベートCloud SQLに接続 (OS Login + WIF + SSHトンネル編)
GitHub Actionsから踏み台サーバー経由でプライベートCloud SQLに接続する実践ガイド (OS Login + WIF + SSHトンネル編)
CI/CDパイプライン、特にGitHub Actionsから、VPCのプライベートネットワーク内に配置されたCloud SQLデータベースへ安全かつ自動的に接続したい、というニーズは多いのではないでしょうか?この記事では、Workload Identity Federation (WIF), OS Login そして gcloud compute ssh
(beta) を組み合わせた、管理しやすい接続方法を解説します。
1. はじめに:なぜこの記事を書いたのか
CI/CDパイプラインからプライベートネットワーク内のCloud SQLインスタンスに安全かつ自動で接続するには、いくつかの方法があります。
- Cloud SQL Auth Proxy: 定番ですが、サービスアカウントキーの扱いが少し煩雑になることがあります。※本当はこれでやりたかったけど、すでに踏み台GCEが存在したので不採用です
- 踏み台サーバー + IP承認: 踏み台サーバーに固定IPを割り当て、Cloud SQLの承認済みネットワークに登録する方法は、IPアドレスの管理が必要です。
- 踏み台サーバー + SSHキー配置: サーバーにSSHキーを直接置くのはセキュリティリスクが伴います。
この記事では、これらの課題を解決するため、Workload Identity Federation (WIF)、OS Login、SSH Agent、そして gcloud compute ssh
を組み合わせた方法を紹介します。
この記事で紹介する方法のメリット
- IPアドレス不要: Cloud SQLの承認済みネットワークにCI/CDランナーのIPを登録する必要がありません。
- サービスアカウントキー不要: WIFにより、有効期間の短い一時的な認証情報を利用するため、サービスアカウントキーファイルを管理・漏洩するリスクがありません。
- SSHキーの安全な管理: SSH秘密鍵はGitHub Secretsで管理し、SSH Agent経由で利用するため、サーバー上に鍵を置く必要がありません。OS Loginプロファイルに追加する公開鍵もTTL(有効期間)を設定できます。
- IAMによる一元管理: VMへのSSHアクセス権限も、他のGCPリソースと同じIAMで管理できます。
ターゲット読者
- GitHub Actionsを利用している開発者
- Google Cloud (Compute Engine, Cloud SQL, IAM) を利用している開発者
- プライベートなDBへCI/CDから安全に接続したい方
- WIF, OS Login, SSHトンネリングに興味がある、または利用する必要がある方
2. 前提条件と準備
- 知識: GitHub Actionsの基本、GCPの基本 (IAM, Compute Engine, Cloud SQL, VPC), SSHの基本。Terraformの基本知識があるとスムーズです。
-
ツール:
gcloud
CLI,terraform
CLI (本記事ではTerraformを使用),ssh-keygen
。 -
GCPリソース (準備済み):
- VPCネットワーク
- プライベートIPを持つCloud SQLインスタンス
- 踏み台サーバー (Compute Engine VM):
-
OS Loginが有効化されていること (
enable-oslogin=TRUE
メタデータ) - 外部IPアドレスは不要
-
OS Loginが有効化されていること (
- GitHub: 対象のリポジトリ。
3. TerraformによるGCP設定:認証と権限の基盤を作る
まず、GitHub ActionsがGCPと安全に連携し、必要な操作を行えるように、Terraformを使って認証連携 (WIF) とIAM権限を設定します。
variable.tf
variable "project_id" {
description = "GCPプロジェクトID"
type = string
}
variable "github_repository" {
description = "GitHubリポジトリ名 (例: 'owner/repo')"
type = string
}
variable "workload_identity_pool_id" {
description = "Workload Identity PoolのID"
type = string
default = "github-actions-pool" # 環境ごとに分けることを推奨 (例: pool-dev)
}
variable "workload_identity_provider_id" {
description = "Workload Identity ProviderのID"
type = string
default = "github-actions-provider" # 環境ごとに分けることを推奨 (例: provider-dev)
}
variable "service_account_id" {
description = "GitHub Actionsが使用するサービスアカウントのID"
type = string
default = "github-actions-sql-access" # 環境ごとに分けることを推奨
}
main.tf
# GitHub ActionsのWorkload Identity Federation設定
# Workload Identity Poolとプロバイダーの作成
resource "google_iam_workload_identity_pool" "github_actions" {
project = var.project_id # project属性を追加
workload_identity_pool_id = var.workload_identity_pool_id
display_name = "GitHub Actions Pool"
description = "Identity pool for GitHub Actions"
}
resource "google_iam_workload_identity_pool_provider" "github_actions" {
project = var.project_id # project属性を追加
workload_identity_pool_id = google_iam_workload_identity_pool.github_actions.workload_identity_pool_id
workload_identity_pool_provider_id = var.workload_identity_provider_id
display_name = "GitHub Actions Provider"
attribute_mapping = {
"google.subject" = "assertion.sub"
"attribute.actor" = "assertion.actor"
"attribute.repository" = "assertion.repository"
"attribute.aud" = "assertion.aud"
}
attribute_condition = "assertion.repository == '${var.github_repository}'"
oidc {
issuer_uri = "https://token.actions.githubusercontent.com"
}
}
# Cloud SQLアクセス用のサービスアカウント
resource "google_service_account" "github_actions_cloud_sql" {
project = var.project_id # project属性を追加
account_id = "github-actions-cloud-sql"
display_name = "GitHub Actions Cloud SQL"
description = "Service account for GitHub Actions to access Cloud SQL"
}
# IAM設定 - GitHubリポジトリとサービスアカウントの関連付け
resource "google_service_account_iam_binding" "github_actions_cloud_sql_binding" {
service_account_id = google_service_account.github_actions_cloud_sql.name
role = "roles/iam.workloadIdentityUser"
members = [
"principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.github_actions.name}/attribute.repository/${var.github_repository}"
]
}
# Cloud SQL関連のIAM権限
resource "google_project_iam_member" "github_actions_cloud_sql_client" {
project = var.project_id
role = "roles/cloudsql.client"
member = "serviceAccount:${google_service_account.github_actions_cloud_sql.email}"
}
resource "google_project_iam_member" "github_actions_cloud_sql_instance_user" {
project = var.project_id
role = "roles/cloudsql.instanceUser"
member = "serviceAccount:${google_service_account.github_actions_cloud_sql.email}"
}
# 機密情報アクセス権限
resource "google_project_iam_member" "github_actions_secretmanager_accessor" {
project = var.project_id
role = "roles/secretmanager.secretAccessor"
member = "serviceAccount:${google_service_account.github_actions_cloud_sql.email}"
}
# Compute Engine関連のIAM権限
resource "google_project_iam_member" "github_actions_compute_viewer" {
project = var.project_id
role = "roles/compute.viewer"
member = "serviceAccount:${google_service_account.github_actions_cloud_sql.email}"
}
resource "google_project_iam_member" "github_actions_iap_tunnel_user" {
project = var.project_id
role = "roles/iap.tunnelResourceAccessor"
member = "serviceAccount:${google_service_account.github_actions_cloud_sql.email}"
}
resource "google_project_iam_member" "github_actions_compute_os_login" {
project = var.project_id
role = "roles/compute.osLogin"
member = "serviceAccount:${google_service_account.github_actions_cloud_sql.email}"
}
resource "google_project_iam_member" "github_actions_service_account_user" {
project = var.project_id
role = "roles/iam.serviceAccountUser"
member = "serviceAccount:${google_service_account.github_actions_cloud_sql.email}"
}
output "workload_identity_provider" {
description = "Workload Identity Provider ID for GitHub Actions"
value = google_iam_workload_identity_pool_provider.github_actions.name
}
output "service_account_email" {
description = "Service account email for GitHub Actions to access Cloud SQL"
value = google_service_account.github_actions_cloud_sql.email
}
Terraformコード解説:
上記のTerraformコードでは、主に以下のリソースを作成・設定しています。
- Workload Identity Federation (WIF)設定: GitHub ActionsのOIDCトークンをGCPが信頼し、特定のGitHubリポジトリからの要求のみを受け付けるように設定します。これにより、サービスアカウントキーを使わずにGitHub ActionsからGoogle Cloudへの認証が可能になります。
- サービスアカウント作成: GitHub ActionsがGoogle Cloud内で活動するための「身分」となる専用のサービスアカウントを作成します。
-
IAM権限設定:
-
roles/iam.workloadIdentityUser
: WIF経由で上記サービスアカウントの権限を借用(impersonate)することを許可します。 -
roles/compute.osLogin
: 踏み台サーバーVMにOS Loginを利用してSSH接続するために必要な権限です。 -
roles/iam.serviceAccountUser
: サービスアカウント自身が、自身のOS Loginプロファイル(SSH公開鍵など)を管理するために必要となります。 -
roles/iap.tunnelResourceAccessor
: 外部IPアドレスを持たない踏み台サーバーVMにgcloud compute ssh
を使って接続する場合、内部的にIdentity-Aware Proxy (IAP) を経由したトンネリングが利用されるため、この権限が必要になります。 - その他、必要に応じてCloud SQL ClientロールやSecret Managerアクセスロールなどをサービスアカウントに付与します。
-
Terraformの実行後、outputs
としてWorkload Identity Providerのリソース名とサービスアカウントのメールアドレスが出力されるようにしておくと、後のGitHub Actionsワークフロー設定で参照しやすくなります。
4. GitHub Actions ワークフロー:CI/CDパイプラインの構築
Terraformで設定した認証情報と権限を使って、実際にGitHub ActionsからSSHトンネルを作成し、Cloud SQLに接続するワークフローを構築します。
# .github/workflows/check-prisma-schema-via-ssh.yml
# このワークフローは、Pull Request時にジャンプサーバー経由で
# develop/main 環境のデータベースに接続し、Prismaスキーマの差分をチェックします。
# SSH接続に gcloud compute ssh コマンドを使用し、OS Login と SSH Agent を活用します。
name: Check Prisma Schema Drift via SSH (gcloud ssh)
on:
pull_request:
branches: # PRのターゲットブランチ
- develop
- main
jobs:
# Develop 環境用ジョブ
check_dev_schema:
runs-on: ubuntu-latest
if: github.base_ref == 'develop' # PRのターゲットが develop なら実行
environment: develop # GitHub Environment 名
permissions:
contents: "read" # actions/checkout に必要
id-token: "write" # GCP 認証 (WIF) に必要
timeout-minutes: 15
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 8.15.5 # プロジェクトに合わせてください
run_install: false
- name: Set up Node.js using package.json
uses: actions/setup-node@v4
with:
node-version-file: package.json # プロジェクトに合わせてください
cache: "pnpm"
cache-dependency-path: pnpm-lock.yaml
- name: Install dependencies
run: pnpm install # Prisma CLI も含めてインストール
# GCP 認証 (WIF を使用) - Service Account として認証
# 以降の gcloud コマンドはこの Service Account として実行されます。
# プロジェクトIDは自動で環境変数 GOOGLE_CLOUD_PROJECT に設定されます。
- id: "auth"
name: "Authenticate to Google Cloud"
uses: "google-github-actions/auth@v2"
with:
workload_identity_provider: ${{ vars.WORKLOAD_IDENTITY_PROVIDER }} # Variablesから読み込み
service_account: ${{ vars.SERVICE_ACCOUNT }} # Variablesから読み込み
- name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@v2
# --- SSH 接続設定 ---
# SSH 秘密鍵をエージェントにロード
# gcloud compute ssh がこの鍵を認証に利用できるようにします。
# Secrets.SSH_PRIVATE_KEY にはパスフレーズなしの鍵の内容が必要です。
- name: Setup SSH private key
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Check Authentication and Environment
run: |
echo "--- Checking Environment Variables ---"
env | grep CLOUDSDK_ # 関連する環境変数を確認
env | grep GOOGLE_ # 関連する環境変数を確認
echo "--- Checking gcloud config ---"
gcloud config list # gcloud が認識している設定を表示
- name: Add SSH public key for Service Account OS Login
env:
# SA_EMAIL: ${{ steps.auth.outputs.service_account_email }} # このコマンド自体では直接使わない
PROJECT_ID: ${{ env.GOOGLE_CLOUD_PROJECT }} # 環境変数から取得
run: |
# SSH Agent にロードされた鍵から公開鍵の内容を取得
PUBLIC_KEY=$(ssh-add -L | head -n 1)
if [ -z "$PUBLIC_KEY" ]; then
echo "Error: Could not get public key from SSH agent. Is the SSH_PRIVATE_KEY secret correct and passphrase-less?"
exit 1
fi
# 現在認証されているアカウント(authステップで認証したSAのはず)に対してキーを追加
echo "Adding public key for the authenticated account..."
echo "Public Key: $PUBLIC_KEY" # デバッグ用
# gcloud compute os-login ssh-keys add コマンドを修正
# --service-account と --zone を削除
gcloud compute os-login ssh-keys add \
--project="$PROJECT_ID" \
--key="$PUBLIC_KEY" \
--ttl=1h # 鍵の有効期限を設定
echo "Public key added (or updated)."
# gcloud beta コマンドに必要なコンポーネントをインストール
- name: Install gcloud beta component
run: gcloud components install beta --quiet
# ジャンプサーバー経由でデータベースへのSSHトンネルを作成
# gcloud compute ssh コマンドを使用します。
- name: Create SSH Tunnel to Database (using gcloud ssh)
env:
JUMP_SERVER_NAME: ${{ vars.JUMP_SERVER_NAME }}
JUMP_SERVER_ZONE: ${{ vars.JUMP_SERVER_ZONE }}
PROJECT_ID: ${{ env.GOOGLE_CLOUD_PROJECT }}
DB_INTERNAL_IP: ${{ vars.DB_INTERNAL_IP }}
DB_PORT: ${{ vars.DB_PORT }}
SSH_LOCAL_PORT: ${{ vars.SSH_LOCAL_PORT }}
run: |
echo "Creating tunnel from 127.0.0.1:$SSH_LOCAL_PORT to $DB_INTERNAL_IP:$DB_PORT via ${JUMP_SERVER_NAME}..."
# gcloud compute ssh は自動的に認証済みの Service Account と OS Login を使用します。
# SSH Agent にロードされた鍵が認証に利用されます。
# --ssh-flag="-L ..." でポートフォワーディングを設定
# -N : リモートコマンドを実行しない (トンネルのみ)
# -f : バックグラウンドで実行 (CI環境ではログ管理に注意)
# --verbosity=debug : OS Login や SSH 接続の詳細ログを出力 (デバッグに有用) 一旦削除
gcloud beta compute ssh "$JUMP_SERVER_NAME" \
--project="$PROJECT_ID" \
--zone="$JUMP_SERVER_ZONE" \
--ssh-flag="-L 127.0.0.1:$SSH_LOCAL_PORT:$DB_INTERNAL_IP:$DB_PORT" \
--ssh-flag="-N" \
--ssh-flag="-f" \
--quiet
# gcloud ssh がバックグラウンドで起動するまで少し待つ
# CI環境ではバックグラウンドプロセスの信頼性が課題になることもあります。
sleep 5
# トンネルが確立されるまで待機
# ローカルポートが開くかを nc コマンドで確認します。
- name: Wait for SSH Tunnel
env:
SSH_LOCAL_PORT: ${{ vars.SSH_LOCAL_PORT }}
run: |
echo "Waiting for SSH tunnel on 127.0.0.1:$SSH_LOCAL_PORT (30 seconds)..."
# timeout コマンドで最大待機時間を設定し、nc でポートが開くかチェック
timeout 30 bash -c 'while ! nc -z 127.0.0.1 $SSH_LOCAL_PORT > /dev/null 2>&1; do sleep 1; done'
if [ $? -ne 0 ]; then
echo "Error: SSH tunnel on 127.0.0.1:$SSH_LOCAL_PORT failed to open within 30 seconds."
# デバッグのため、バックグラウンドプロセスの状態確認などをここに追加しても良い
# pgrep -fla "gcloud compute ssh" || true
exit 1
fi
echo "SSH tunnel is established."
# --- SSH 接続設定ここまで ---
# === 接続テストステップ ===
# (SSHトンネル経由でローカルポートに接続)
- name: Install PostgreSQL client
run: |
sudo apt-get update -y
sudo apt-get install -y postgresql-client
echo "psql installed."
# ローカルの転送ポートへのTCP接続をテスト (オプション)
- name: Test TCP connection using nc
env:
SSH_LOCAL_PORT: ${{ vars.SSH_LOCAL_PORT }}
run: |
echo "Attempting basic TCP connection test using netcat..."
nc -zv 127.0.0.1 ${{ env.SSH_LOCAL_PORT }} || true # 失敗しても致命的ではないため続行可能にする場合
# psql でデータベース接続をテスト
- name: Test DB connection using psql
env:
# DATABASE_URL を SSH トンネルのローカルポートを指すように変更
DATABASE_URL: "postgresql://${{ vars.DB_USER }}:${{ secrets.DB_PASSWORD }}@127.0.0.1:${{ vars.SSH_LOCAL_PORT }}/${{ vars.DB_NAME }}?sslmode=disable"
PGCONNECT_TIMEOUT: 30 # psql の接続タイムアウト
run: |
echo "Attempting to connect using psql via SSH tunnel..."
# 接続し、すぐに終了するコマンド。失敗するとここでワークフローが停止。
psql "$DATABASE_URL" -c "\q"
echo "psql connection test finished successfully."
# === 接続テストステップここまで ===
# Prisma でデータベーススキーマを取得
- name: Run prisma db pull
env:
# 上記 psql ステップと同じ DATABASE_URL を使用
DATABASE_URL: "postgresql://${{ vars.DB_USER }}:${{ secrets.DB_PASSWORD }}@127.0.0.1:${{ vars.SSH_LOCAL_PORT }}/${{ vars.DB_NAME }}"
run: |
echo "Running prisma db pull via SSH tunnel..."
# package.json に 'prisma:pull': 'prisma db pull' が定義されている想定
pnpm run prisma:pull
# schema.prisma の変更をチェック
- name: Check for schema changes
run: |
echo "Checking for differences in prisma/schema.prisma..."
# git diff --exit-code は差分があれば非ゼロ終了コードを返す
git diff --exit-code prisma/schema.prisma
if [ $? -ne 0 ]; then
echo "Error: Schema drift detected! prisma/schema.prisma differs from the database schema."
echo "Please run 'pnpm run prisma:pull' locally to update your schema.prisma and commit the changes."
exit 1 # 差分があればワークフローを失敗させる
fi
echo "No schema drift detected."
ワークフロー解説:
上記YAMLコードは、以下の主要なステップで構成されています。
-
GCP認証 (WIF):
- ワークフローの
permissions
でid-token: write
を設定し、OIDCトークンの発行を許可します。 -
google-github-actions/auth
アクションを使用し、Terraformで作成したWorkload Identity Providerとサービスアカウントの情報を指定してGCPに認証します。これらの情報はGitHubのVariablesやSecretsに格納しておくのが一般的です。
- ワークフローの
-
SSH秘密鍵のエージェントへのロード:
-
ssh-keygen
コマンドで事前にパスフレーズなしのSSHキーペアを作成し、その秘密鍵をGitHubのSecrets (SSH_PRIVATE_KEY
など) に登録しておきます。 -
webfactory/ssh-agent
アクションを使い、この秘密鍵をSSHエージェントにロードします。これにより、後続のSSHコマンドがこの鍵を自動的に利用できるようになります。
-
-
OS Login 公開鍵の動的追加:
- SSHエージェントにロードされた鍵に対応する公開鍵を
ssh-add -L
コマンドで取得します。 -
gcloud compute os-login ssh-keys add
コマンドを使い、認証中のサービスアカウントのOS Loginプロファイルに、取得した公開鍵を一時的に追加します。--ttl=1h
のように有効期限を設定することで、一定時間後に自動的に鍵が無効になるため、セキュリティが向上します。このステップが、踏み台サーバーにOS Login経由でSSH接続するための鍵登録処理となります。
- SSHエージェントにロードされた鍵に対応する公開鍵を
-
gcloud beta
コンポーネントのインストール:- Workload Identity Federation経由で
gcloud compute ssh
を利用する場合、現状ではベータ版のコマンド (gcloud beta compute ssh
) を使う必要があるため、事前にgcloud components install beta --quiet
コマンドでbeta
コンポーネントをインストールしておきます。
- Workload Identity Federation経由で
-
SSHトンネルの作成 (バックグラウンド実行):
-
gcloud beta compute ssh
コマンドを使用し、踏み台サーバーへのSSH接続を確立します。 -
--ssh-flag="-L <ローカルポート>:<Cloud SQLプライベートIP>:<Cloud SQLポート>"
オプションで、ローカルマシンの指定ポートへのアクセスを、踏み台サーバー経由でCloud SQLのIPとポートに転送するように設定します。 -
--ssh-flag="-N"
オプションで、リモートコマンドを実行せずにポートフォワーディングのみを行うようにします。 -
--ssh-flag="-f"
オプションで、SSH接続プロセスをバックグラウンドで実行します。これにより、ワークフローの次のステップに進むことができます。 -
--quiet
オプションで、SSH接続時のホストキー確認などのインタラクティブなプロンプトを抑制します。
-
-
トンネル確立待機:
- バックグラウンドで起動したSSHトンネルが実際に通信可能になるまで、
nc -z localhost <ローカルポート>
のようなコマンドとループ処理、timeout
コマンドを組み合わせて一定時間待ち合わせます。
- バックグラウンドで起動したSSHトンネルが実際に通信可能になるまで、
-
DB操作実行:
- SSHトンネルが確立されたら、GitHub Actions Runner上の
localhost
と指定したローカルポートに対して、psql
やアプリケーション(例: Prisma ORM)からCloud SQLデータベースに接続します。データベース接続文字列のホスト名を127.0.0.1
またはlocalhost
に、ポートをフォワーディングで指定したローカルポートに変更するのがポイントです。
- SSHトンネルが確立されたら、GitHub Actions Runner上の
5. トラブルシューティング:ハマりどころと解決策
この構成は複数の要素が絡むため、問題が発生することもあります。主な原因と対処法をまとめます。
-
認証エラー (
google-github-actions/auth
で失敗):- ワークフローの
permissions
ブロックにid-token: write
が正しく設定されているか確認してください。 -
google-github-actions/auth
アクションに渡しているworkload_identity_provider
とservice_account
の値が、Terraformで作成したものと完全に一致しているか確認してください(GitHub Variables/Secretsの設定ミスに注意)。 - Workload Identity Federation Providerの
attribute_condition
(リポジトリ名など) が、ワークフローを実行しているリポジトリと一致しているか確認してください。
- ワークフローの
-
gcloud
コマンド失敗 (認証後だがgcloud auth list
でアカウントが表示されないなど):-
google-github-actions/auth
の後にgoogle-github-actions/setup-gcloud
を明示的に使用していない場合、gcloud
の設定が期待通りに行われないことがあります。setup-gcloud
を追加するか、auth
アクションのログで環境変数が正しくエクスポートされているか確認してください。
-
-
OS Loginキー追加失敗:
- 認証に使用しているサービスアカウントに
roles/compute.osLogin
およびroles/iam.serviceAccountUser
のIAMロールが正しく付与されているか確認してください。 - 踏み台サーバーとなるCompute EngineインスタンスでOS Loginが有効化されているか(メタデータ
enable-oslogin
がTRUE
になっているか)確認してください。
- 認証に使用しているサービスアカウントに
-
SSHトンネル作成失敗 (
gcloud beta compute ssh
でエラー):-
gcloud components install beta --quiet
ステップが正常に完了し、beta
コンポーネントがインストールされているか確認してください。 - 外部IPアドレスを持たない踏み台サーバーに接続する場合、サービスアカウントに
roles/iap.tunnelResourceAccessor
のIAMロールが付与されているか確認してください。 - サービスアカウントに
roles/compute.osLogin
が付与されているか、OS Loginキーが正しく追加されているか再確認してください。 - 踏み台サーバーの名前、ゾーンが正しいか確認してください。
-
-
トンネル確立後の接続失敗:
-
Wait for SSH Tunnel
ステップが成功しているか、sleep
の時間が短すぎないか確認してください。 - データベース接続文字列のホスト名が
127.0.0.1
またはlocalhost
に、ポートがSSHトンネル作成時に指定したローカルポート (SSH_LOCAL_PORT
) に正しく設定されているか確認してください。 - 踏み台サーバーからCloud SQLインスタンスのプライベートIPとポートへのVPC内ファイアウォールルールが適切に設定されているか確認してください(通常、同一VPC内またはVPCピアリングが正しければ接続可能です)。
- データベースのユーザー名、パスワード、データベース名が正しいか確認してください。
-
デバッグTips:
-
gcloud beta compute ssh
コマンドに一時的に-v
や--verbosity=debug
フラグを追加すると、SSH接続の試行に関する詳細なログが出力されます(ただし、非常に多くのログが出力されるため注意が必要です)。 -
ローカル環境での再現: 複雑な問題を切り分けるには、GitHub Actionsワークフローで使うサービスアカウントのキーファイルとSSH秘密鍵をローカル環境に用意し、各
gcloud
コマンドを手動で実行してみるのが最も効果的です。(詳細は[ローカルでの動作確認手順 - (ここに別記事へのリンクを挿入)]を参照してください。)
6. まとめと考察
本記事では、GitHub ActionsからWorkload Identity Federation, OS Login, SSH Agent, そして gcloud beta compute ssh
を活用し、踏み台サーバー経由でプライベートネットワーク内のCloud SQLに安全に接続する方法を解説しました。
この構成により、従来の方法で課題となりやすかったサービスアカウントキーの管理や固定IPアドレスの管理から解放され、IAMによる一元的な権限管理と、よりセキュアなCI/CDパイプラインを実現できます。
設定項目は多岐にわたりますが、一度この仕組みを構築すれば、セキュリティを維持しつつ、効率的にプライベートなデータベースリソースへCI/CDパイプラインからアクセスできるようになります。
あと、ローカルで実際に借用されたservice accountで認証して同じような実行を行う方法を別記事で備忘として残しておこうと思います。🤔
7. 参考資料
- Workload Identity Federation - Google Cloud IAM ドキュメント
- OS Login の構成 - Google Compute Engine ドキュメント
gcloud compute os-login ssh-keys add
コマンドリファレンスgcloud beta compute ssh
コマンドリファレンス- GitHub Action: Authenticate to Google Cloud (
google-github-actions/auth
) - GitHub Action:
webfactory/ssh-agent
- github actions と Workload Identityを使っている記事
Discussion