JSONキー不要!Terraform × Workload Identity Federationで実現する自宅サーバーのキーレス認証

JSONキー不要!Terraform × Workload Identity Federationで実現する自宅サーバーのキーレス認証

AIによるこの記事の要約
AWSメインのエンジニアが3年ぶりにGoogle Cloudを触り、サービスアカウントキー(JSON)が「過去の遺物」になりつつある現状に直面。その解決策である「Workload Identity Federation (WIF)」を、自宅サーバーというIdPのない環境でも導入できる自己署名証明書(X.509)方式で検証しました。Terraformによる構築手順から、現場でハマりやすいプロジェクトIDの指定や権限設定のポイントまでを徹底解説。AWSの「IAM Roles Anywhere」にも通ずる、現代の「キーレス認証」の勘所をまとめた備忘録です。

はじめに

業務でAWSとGoogle Cloudを連携させるにあたり、サービスアカウントを作って、JSONキーを発行して作業を進めていました。
ところが、Google Cloud Console上に表示されたのは「Workload Identity Federation(WIF)を使いませんか?」という、やんわりとしたというか警告みたいな画面が出てました。

Workload Identity Federation を利用しませんか?

Workload Identity Federation を利用しませんか?

そこで思わず手が止まり「あれ今ってサービスアカウントのJSONキーを配り歩く時代じゃないんだな」と。
AWS なら IAM Role を使うのが当たり前なように、Google Cloud もいよいよ「キーレス認証」を勧めるのかと言うのと3年という月日の間に、自分の Google Cloudの知識がすっかり過去の状態になっていたことに気づかされました。

そこで、その興味を試しに触るにあたりまずは自宅のホームラボ(IdPなんて立派なものはない環境)で、どこまで手軽にできるのか実験してみることにしました。(イけてれば業務で本番投入するメモ)

構成の全体像

Workload Identity Federation (WIF) は、外部の ID を GCP のサービスアカウントに「なりすまし(Impersonation)」させる機能です。
今回は、自宅サーバー(オンプレミス)のように外部の ID プロバイダー(IdP)が存在しない環境でも利用できる 「自己署名証明書(X.509)」 を使った構成で実現します。

  1. GCP側 (Terraform): WIFの「プール」と「プロバイダー」を作成。特定の証明書を持つものだけを受け入れるように設定します。
  2. 自宅サーバー側: OpenSSL で証明書を作成し、gcloud コマンドで認証設定ファイルを生成してログインします。

実装ステップ:Terraformとgcloudで構築する

ステップ1:Terraform でインフラ構築(GCP側の受入口)

まずは Terraform で、操作対象となる「サービスアカウント」と、認証の受入口となる「Workload Identity プール・プロバイダー」を作成します。

1. サービスアカウントの作成と権限付与

自宅サーバーから実際に操作を行わせるためのTerraformでサービスアカウントを作成し、必要な権限を付与します。

# サービスアカウントの定義
resource "google_service_account" "test_account" {
  account_id   = "my-home-server-sa" # 任意のID
  display_name = "Home Server Service Account"
  project      = var.project_id
}

# 必要な権限の付与(例: GCS 管理者権限)
resource "google_project_iam_member" "test_account_storage_admin" {
  project = var.project_id
  role    = "roles/storage.admin"
  member  = "serviceAccount:${google_service_account.test_account.email}"
}

2. Workload Identity の設定

WIF のプールとプロバイダーを作成します。プロバイダーの x509 ブロックで証明書を指定するのがポイントです。

# 1. Workload Identity プール
resource "google_iam_workload_identity_pool" "home_pool" {
  workload_identity_pool_id = "home-server-pool"
  display_name              = "Home Server Verification Pool"
  project                   = var.project_id
}

# 2. Workload Identity プロバイダー (X.509証明書方式)
resource "google_iam_workload_identity_pool_provider" "home_provider" {
  workload_identity_pool_id          = google_iam_workload_identity_pool.home_pool.workload_identity_pool_id
  workload_identity_pool_provider_id = "home-server-cert-provider"
  project                            = var.project_id
  display_name                       = "Home Server Certificate Provider"

  attribute_mapping = {
    "google.subject" = "assertion.subject.dn.cn"
  }

  x509 {
    trust_store {
      trust_anchors {
        pem_certificate = chomp(file("cert.pem")) # 余計な改行を除去
      }
    }
  }
}

# 3. サービスアカウントへのなりすまし権限付与
resource "google_service_account_iam_member" "home_wif_sa_user" {
  service_account_id = google_service_account.test_account.name
  role               = "roles/iam.workloadIdentityUser"
  # このプールで認証された全員を許可(検証用)
  member             = "principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.home_pool.name}/*"
}

ステップ2:自宅サーバーで証明書作成

次に、自宅サーバー側で自己署名証明書を作ります。

# 証明書 (cert.pem) と秘密鍵 (key.pem) を生成
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes -subj "/CN=home-server-01"

作成した cert.pem を Terraform の実行ディレクトリに配置して terraform apply します。

作成されたWorkload Identity プール

作成されたWorkload Identity プール

ステップ3:認証設定ファイルの生成とログイン

自宅サーバーで gcloud コマンドを使い、WIF 用の設定ファイルを生成してログインします。

# 認証設定ファイルの生成(絶対パスが重要!)
gcloud iam workload-identity-pools create-cred-config \
    projects/[PROJECT_NUMBER]/locations/global/workloadIdentityPools/[POOL_ID]/providers/[PROVIDER_ID] \
    --service-account="[SA_EMAIL]" \
    --credential-cert-path="$(pwd)/cert.pem" \
    --credential-cert-private-key-path="$(pwd)/key.pem" \
    --output-file="gcp-wif-config.json"

# 環境変数の設定とログイン実行
export GOOGLE_APPLICATION_CREDENTIALS="$(pwd)/gcp-wif-config.json"
gcloud auth login --cred-file="$(pwd)/gcp-wif-config.json"

これで、JSONキーなしでの認証が完了です!

ハマったポイント

① JSONキーとWIFの決定的な違い(プロジェクトIDの指定)

JSON キーにはプロジェクト情報が含まれていますが、WIF の設定ファイルには「トークンの取得手順」しか書かれていません。 そのまま gcloud コマンドを実行すると The required property [project] is not currently set. と怒られます。

解決策: 環境変数でプロジェクトを明示的に指定する必要がありました。

export CLOUDSDK_CORE_PROJECT="your-project-id"

② PEMフォーマットのエラー(Error 400)

Terraform で cert.pem を読み込む際、改行コードが正しくないとエラーになります。

解決策: chomp(file("cert.pem")) で末尾の空行を削除すれば回避できます。

③ 設定ファイル内の「パス」問題

設定ファイル内の証明書パスが相対パスだと、実行ディレクトリが変わると認証に失敗します。

解決策: 設定ファイル生成時に必ず 絶対パス ($(pwd)/...) を使いましょう。

まとめ

JSON キーを廃止し、X.509 証明書による Workload Identity 連携を導入することで、キー漏洩のリスクを極小化し、JSONキーの作成手順と管理そのものをなくすことができました。

今回は Google Cloud で検証しましたが、AWS でも「IAM Roles Anywhere」を使えば、全く同じノリ(証明書によるキーレス認証)で自宅サーバーからアクセスが可能です。
主要なクラウドベンダーが揃って「静的なキーは持たない」という方向に舵を切っている今、この仕組みを理解しておくことは、どのクラウドを扱う上でも必須のスキルになっていくと感じました。

「プロジェクトIDを都度指定する」など、JSON キーのときとは勝手が違う部分もありますが、一度構築して覚えてしまえば安心感が違います。
自宅サーバーのような環境でも手軽に導入できるので、ぜひ「脱・JSONキー」に挑戦してみてください!

@urchin_hat
Written by
@urchin_hat

とある領域のSaaSサービスでSREとして活動中。現在はインフラの正常化とAIを活用した運用効率化(AIOps)に注力しています。

Back to Memo