エグゼクティブサマリー
Okta Privileged Access(OPA)Workload Identity for Automationは、プラットフォームで署名されたOIDC JSON Web Token(JWT)を、有効期間が短いエフェメラルSSH証明書と交換することで、Google Cloud Platform(GCP)と統合できます。自動化されたランナーVMは、ローカルのGCPメタデータサーバーにGoogle署名付きのJWTを照会し、認証のためにsft CLIを介してOPAに送信します。そして、ターゲットサーバーにアクセスするために時間ベースのSSH証明書を受信します。これにより、静的SSHキー、APIトークン、サービスアカウントのJSONファイルが不要になります。
自動化を担当するエンジニアなら誰でも、同じような気まずい経験をしたことがあるでしょう。サーバーに接続するためにスクリプトが必要になったため、クレデンシャルを生成し、構成ファイルに貼り付けて、作業を続けるという経験です。数週間後、そのクレデンシャルは3つの構成ファイル、2つのCI/CDパイプライン、そして誰かが「ちょっとしたテスト」のために送信したSlackメッセージに存在しています。どれがまだアクティブなのか、誰にもわかりません。ローテーションによって本番環境を破壊するような事態は、誰もが避けたいと思っています。
このブログ記事では、Okta Privileged Access(OPA)Workload Identity for AutomationとGoogle Cloud Platform(GCP)を使用して、クレデンシャルをディスクに一切保存することなく、自動化スクリプトでターゲットサーバーにSecure Shell(SSH)接続できるようにする、実用的なソリューションについて順を追って説明します。
OPAとGCPのワークロードアイデンティティで静的クレデンシャルを排除する方法
主な目的:プラットフォーム署名付きのアイデンティティ証明を活用して、自動化されたサーバーアクセスから静的クレデンシャル(APIキー、静的SSHキー、サービスアカウントのJSONファイル)を排除します。
認証情報を保存しない:ディスク、構成ファイル、CI/CD変数内にシークレットを保持しません。
有効期間の短いエフェメラル証明書:有効期間15分のSSH証明書を発行し、ローテーションに伴う運用のリスクを排除します。
エンドツーエンドの暗号検証:Okta Privileged Accessは、GCPが発行したJSON Web Token(JWT)を検証するトラストブローカーとして機能します。
監査ログの自動化:Okta System Logで、トークンの交換やSSHセッションのアクティビティ全体にわたる完全なアイデンティティの追跡可能性を実現します。
課題:静的クレデンシャルはインフラストラクチャ機能ではなく、セキュリティ負債である
Ansibleプレイブック、デプロイメントスクリプト、CI/CDランナーなどの自動化されたジョブが特権付きリソースにアクセスする必要がある場合、そのアイデンティティを証明する方法が必要になります。従来のアプローチでは、APIキー、SSH秘密鍵、またはサービスアカウントのJSONファイルといった静的クレデンシャルが渡されます。そのクレデンシャルがどこかに保存されると、その「どこか」が標的になります。
その結果は、予測可能な形で現れます。
クレデンシャルが目的を終えても存続する:1回限りの導入タスクのために作成されたサービスアカウントキーが、何年にもわたって有効なままになります。それを作成したエンジニアが退職しますが、キーはそのまま残ります。誰も監査しません。アクセス権を追加する方が、何を安全に削除できるかを調査するよりも簡単であるため、時間の経過とともに権限が蓄積されていきます。これらは、クレデンシャルを必要としていたワークロードがなくなった後も、環境内に長期間存在し続ける「ゾンビクレデンシャル」です。
ローテーションが危機対応訓練と化す:クレデンシャルが多数のパイプラインや構成ファイルに埋め込まれている場合、ローテーションを行うには、まずすべての参照箇所を見つけ出す必要があります。ローテーション後にシステムが停止するのを見て、チームは参照箇所を発見します。これはローテーション戦略ではなく、操作された停止に過ぎません。
根本的な課題はアーキテクチャにあります。静的クレデンシャルは人間向けに設計されたアイデンティティモデルであり、マシン向けではありません。人間はパスワードを定期的に変更し、新しいパスワードを覚えることができます。マシンが知る必要があるのは、「自分は本当に自分なのか?」ということだけです。そして、クラウドプラットフォームは、保存されたシークレットなしで、その問いに暗号で答えることができます。
ソリューション:有効期間の短いトークンで、永続的なセキュリティ
Okta Privileged Access Workload Identity for Automationは、静的クレデンシャルをプラットフォーム署名付きのアイデンティティ証明に置き換えることで、他の安全なクレデンシャルを取得するために最初のキーを必要とする「シークレットゼロ」の問題を解決します。
このインサイトは単純明快です。GCPの仮想マシン(VM)は、すでに暗号化されたアイデンティティを持っているということです。サービスアカウントをVMにアタッチすると、GCPはGoogleの秘密鍵で署名されたJWTを発行できます。このJWTは、実質的に「私はこのVMであり、このサービスアカウントとして実行されています。このトークンはこの特定の瞬間に発行されました」ということを示します。Googleの秘密鍵がなければ、誰もそのトークンを偽造することはできません。有効期限が自動的に切れ、別のシステムで再利用することはできません。
OPAがトラストブローカーとして機能します。一度構成するだけで、「サービスアカウントXについて、Googleが署名したJWTを信頼する」と指定できます。それ以降は、そのサービスアカウントとして実行されているワークロードは、GCPが発行したJWTを提示することでOPAに対して自身のアイデンティティを証明でき、OPAはそのJWTを有効期間の短いアクセストークンと交換します。そのトークンは、ターゲットサーバーへの接続に使用される、有効期間が数年ではなく数分間のエフェメラルSSH証明書を取得するために使用されます。
これはSSHの仕組みを変更するものではありません。SSHが開始される前にアイデンティティを確立する方法を変更するものです。
システムアーキテクチャとコンポーネントマッピング
この認証ワークフローは、GCPによって暗号で生成されたアイデンティティクレームをOPAが検証する、トラストブローカー設計パターンに基づいています。
| コンポーネント | セキュリティロール | 場所 |
|---|---|---|
GCPメタデータサーバー | リクエストに応じて任意のVMに署名付きJWTを発行する内部GCPエンドポイント | GCPインフラストラクチャ(お使いのVM以外) |
ワークロード接続 | GCPとの信頼を定義するOPA構成オブジェクト。受け入れるJWTと検証するクレームを指定する | OPAダッシュボード |
ワークロードロール | 検証済みのワークロードアイデンティティをターゲットサーバー上のLinuxユーザー名にマッピングするOPA認可エンティティ | OPAダッシュボード |
ポリシーとルール | どのワークロードロールが、どの方法で、どのサーバーにアクセスできるかを定義する | OPAダッシュボード |
sft(OPAクライアント) | ワークロード認証とSSH証明書の発行を処理するコマンドラインインターフェイス(CLI)バイナリ | ランナーVM |
sftd(OPAエージェント) | ターゲットサーバーをOPAに登録し、OPAの認証局(CA)を信頼するようにSSHを構成するデーモン | ターゲットVM |
アーキテクチャと認証フロー
セキュリティ設計の基本
OPAオーディエンスバインディング:GCP JWTは、OPA URLをオーディエンスとしてリクエストされます。傍受されたとしても、他のシステムでリプレイすることはできません。
暗号による検証:OPAは、トークンを発行する前にGoogleの公開鍵を取得し、JWT署名を検証します。偽造または改ざんされたJWTは失敗します。
TTL(有効期限)の厳格な失効:GCP JWTは1時間後に失効します。OPAトークンはセッション中有効で、SSH証明書は定義された期間有効であり、永続するものは何もありません。
GCP向けOkta Privileged Accessのワークロード接続を構成する方法
要件と前提条件
GCPアカウント:請求が有効になっており、プロジェクトのオーナーまたは編集者の権限が必要です。
gcloud CLI:ローカルワークステーションにインストールおよび認証済みであること。
OPAテナント:Okta Privileged Accessのライセンスが付与されており、テナントのURL(例:[https://YOUR-TEAM.pam.okta.com])からアクセスできるテナント。
DevOps管理者ロール:OPAでワークロード接続を作成するために必要です。
セキュリティ管理者ロール:OPAで接続をアクティブ化し、ワークロードロールを作成し、ポリシーを作成するために必要です。
ステップ 1:GCPインフラストラクチャを作成する
ローカルワークステーションでこれらのコマンドを実行してください。
1.1 プロジェクトを作成してAPIを有効にする(GCP)
PROJECT_ID="YOUR_PROJECT_ID"
ZONE="VM_LOCATION"
gcloud projects create "$PROJECT_ID" --name="YOUR_PROJECT_ID"
gcloud config set project "$PROJECT_ID"
gcloud services enable compute.googleapis.com iam.googleapis.com
11.2 ランナーVM用のサービスアカウントを作成する(GCP)
このサービスアカウントは、ランナーのマシンアイデンティティです。キーファイルは生成されません。作成時にVMがこのアカウントにアタッチされていることが、アイデンティティの証明となります。
gcloud iam service-accounts create opa-runner-sa \
--display-name="OPA Runnerサービスアカウント" \
--project="$PROJECT_ID"
生成されたサービスアカウントのメール:opa-runner-sa@<YOUR_PROJECT_ID>.iam.gserviceaccount.com
1.3 ランナーとターゲットのコンピューティングインスタンスを作成する(GCP)
# ランナーVM
gcloud compute instances create runner-vm \
--zone="$ZONE" \
--machine-type=e2-medium \
--image-family=ubuntu-2204-lts \
--image-project=ubuntu-os-cloud \
--service-account=opa-runner-sa@${PROJECT_ID}.iam.gserviceaccount.com \
--scopes=https://www.googleapis.com/auth/cloud-platform \
--tags=opa-runner
# ターゲットVM
gcloud compute instances create target-vm \
--zone="$ZONE" \
--machine-type=e2-medium \
--image-family=ubuntu-2204-lts \
--image-project=ubuntu-os-cloud \
--tags=opa-target
注:上記のサーバーは、「machine-type」:「e2-medium」、「image-family」:「ubuntu-2204-lts」を使用してセットアップされています。独自のマシンタイプとイメージファミリーを選択できます。
1.4 ファイアウォールのルールを構成する(GCP)
# ランナーからターゲットへの内部SSHアクセスを許可します
gcloud compute firewall-rules create allow-runner-to-target \
--allow=tcp:22 \
--source-tags=opa-runner \
--target-tags=opa-target \
--project="$PROJECT_ID"
# OPAエージェント通信のために、ターゲットからのアウトバウンドHTTPSを許可します
gcloud compute firewall-rules create allow-egress-opa \
--direction=EGRESS \
--allow=tcp:443 \
--target-tags=opa-target \
--project="$PROJECT_ID"
ステップ2:ランナーVMをセットアップする(GCP)
ランナーVMに必要なのはsftバイナリのみです。OPAのどのユーザーにも登録されていません。
# Runner VMにSSHで接続
gcloud compute ssh runner-vm --zone="$ZONE"
# 依存関係とsftクライアントバイナリをインストールします
# リポジトリキーをインストールし、Okta PAMリポジトリを追加します
curl -fsSL https://dist.scaleft.com/GPG-KEY-OktaPAM-2023| gpg --dearmor | sudo tee /usr/share/keyrings/oktapam-2023-archive-keyring.gpg > /dev/null
echo "deb [signed-by=/usr/share/keyrings/oktapam-2023-archive-keyring.gpg] https://dist.scaleft.com/repos/deb $(lsb_release -cs) okta" | sudo tee /etc/apt/sources.list.d/oktapam-stable.list
# リポジトリを更新してSFTクライアントツールをインストールします
sudo apt-get update && sudo apt-get install -y scaleft-client-tools
# 添付されたアイデンティティ証明を確認します
curl -sf -H "Metadata-Flavor: Google" "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/email"
# 期待される出力: opa-runner-sa@opa-workload-demo.iam.gserviceaccount.com
終了
ステップ3:ターゲットVMをセットアップする
3.1 OPAダッシュボードをセットアップしてサーバー登録トークンを生成する(Okta)
- 「OPAダッシュボード」 → 「リソース管理」 → 「リソース管理」 → 「リソースグループの作成」 → 「プロジェクトの作成」または「既存のリソースグループ」 → 「保存」に移動します。
- 名前:GCP_Servers_Proj
- 説明:ワークロードデモ用のGCPターゲットサーバー
- 「GCP_Servers_Proj」 → 「プロジェクト」 → 「リソースタイプ-サーバー」 → 「設定」 → 「登録トークン」 → 「表示」 → 「登録トークンを作成する」に移動します。
- OSの選択: Linux
- 生成された登録トークンをコピー
3.2 ターゲットVM(GCPベース)にsftdエージェントをインストールして起動する
# ターゲットVMにSSH接続します
gcloud compute ssh target-vm --zone="$ZONE"
# 依存関係とsftdデーモンをインストールします
# リポジトリキーをインストールし、Okta PAMリポジトリを追加します
curl -fsSL https://dist.scaleft.com/GPG-KEY-OktaPAM-2023| gpg --dearmor | sudo tee /usr/share/keyrings/oktapam-2023-archive-keyring.gpg > /dev/null
echo "deb [signed-by=/usr/share/keyrings/oktapam-2023-archive-keyring.gpg] https://dist.scaleft.com/repos/deb $(lsb_release -cs) okta" | sudo tee /etc/apt/sources.list.d/oktapam-stable.list
# リポジトリを更新してSFTサーバーツールをインストールします
sudo apt-get update && sudo apt-get install -y scaleft-server-tools
# 登録構成トークンを保存
sudo mkdir -p /var/lib/sftd
echo "YOUR_ENROLLMENT_TOKEN_HERE" | sudo tee /var/lib/sftd/enrollment.token > /dev/null
# セキュリティのためファイル権限を制限します
sudo chmod 600 /var/lib/sftd/enrollment.token
# デーモンを有効化してステータスを確認する
sudo systemctl enable sftd && sudo systemctl start sftd
sleep 5
sudo systemctl status sftd --no-pager
終了
3.3 登録を検証する
OPAダッシュボードでステータスが「Enrolled」と表示されていることを確認します:OPAダッシュボード → GCP_Servers_Proj → Servers → target-vm(ステータス:Enrolled)✓
ステップ4:OPAワークロードの接続とロールを構成する(Okta)
4.1 ワークロード接続を作成・アクティブ化する(DevOps管理者およびセキュリティ管理者)
OPAダッシュボードで、[DevOps Administration]→[Workload connections]→[Create Workload Connection]の順に移動します。
Google Cloud Providerを選択します。
アプリのクライアントIDの詳細を入力します。
アプリのクライアントID:アプリのクライアントID(前のステップでGCPプロジェクト内に作成したサービスアカウント)を入力します
「メールにスコープする」(メールは自動生成されます)をオンにします
パラメーターを定義する:
接続名:OKTA-OPA-Demo
トークンのTTL:3600秒
必須のクレーム:aud = [https://YOUR-TEAM.pam.okta.com]および iss = [https://accounts.google.com]
[Create Workload Connection]をクリックします。
- DevOps管理者に切り替えます。「OKTA-OPA-Demo」 → 「Actions」 → 「アクティブ化」の順で開きます。
4.2 ワークロードロールを作成する(セキュリティ管理者)
「セキュリティ管理」 → 「ワークロードロール」 → 「ワークロードロールを作成」に移動します。
属性を構成します。
名前:OKTA-OPA-WR
ワークロード 接続:OKTA-OPA-Demo
[ワークロードロールを保存]をクリックします。OPAは、Linuxのユーザー名(wl_okta_opa_wr)を自動的に割り当てます。
4.3 ポリシーとルールを構成する(セキュリティ管理者)
「セキュリティ管理」 → 「ポリシー」 → 「ポリシーを作成」 → 「デフォルト」に移動します。
名前:NHIサーバーアクセス
リソースグループの選択:すべてのリソースグループ
[Add principals]で、ワークロードロール「OKTA-OPA-WR」を追加します。
「ポリシーにルールを追加」で、「サーバールール」を選択します。
ルール名:ワークロードロールのSSHを許可
セッションタイプ:サーバーSSHセッション
アカウント:「アカウントを名前で選択する」を有効にします → ターゲット:target-vm / root
重要:MFAまたはAccess Requestsを有効にしないでください(ヘッドレスジョブはインタラクティブなプロンプトに応答できません)。
「ポリシーを保存」をクリックし、「Actions」 → 「公開」に移動します。
ステップ5:実行を検証・テストする(GCPベース)
5.1 検証自動化スクリプトを準備する
runner-vmに再度SSH接続し、自動化スクリプトを準備します。
gcloud compute ssh runner-vm --zone="$ZONE"
#!/bin/bash
#
# OPAワークロードアイデンティティデモスクリプト
# 参照元:Okta Privileged Access - ワークロードアイデンティティの紹介
#
# ─── 環境変数を設定 ───────────────────────────────────────────────
# オーディエンス = OPAアドレス(OPAが想定するaudクレームと一致しなければならない)
AUDIENCE="https://opa-gcp.pam.okta.com"
# JWTを取得するためのGCPメタデータURL
METADATA_URL="http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=${AUDIENCE}&format=full"
# OPAチームとアドレス(sftが環境から読み取る)
export SFT_TEAM="opa-gcp"
export OPA_ADDR="https://demo-opa-gcp-demo.pam.okta.com"
# 名前はOPAダッシュボードで作成したものと完全に一致しなければならない
CONNECTION_NAME="okta-opa-demo"
ROLE_NAME="okta_opa_wr"
# ターゲットサーバー名(OPAに登録されているホスト名)
TARGET_SERVER="target-vm"
# ─── ステップ1:GCPアイデンティティJWTを取得 ────────────────────────────────────────────
echo "------------------------------------------------------------"
echo "ステップ1:GCPメタデータサーバーからJWTを取得"
echo "------------------------------------------------------------"
ID_TOKEN=$(curl -s -H "Metadata-Flavor: Google" "$METADATA_URL" | tr -d '\n\r')
if [[ "$ID_TOKEN" == eyJ* ]]; then
GCP_JWT="$ID_TOKEN"
# デコードして有効期間を表示します
PAYLOAD=$(echo "$GCP_JWT" | cut -d. -f2 | base64 --decode 2>/dev/null)
EXP=$(echo "$PAYLOAD" | jq -r '.exp')
ISS=$(echo "$PAYLOAD" | jq -r '.iss')
EMAIL=$(echo "$PAYLOAD" | jq -r '.email')
NOW=$(date +%s)
DIFF=$((EXP - NOW))
echo "発行者 :$ISS"
echo "Eメール : $EMAIL"
echo "オーディエンス : $AUDIENCE"
echo ""
echo "VALUE OF GCP_JWT:"
echo "${GCP_JWT:0:80}... (truncated)"
echo ""
echo "Success: JWT obtained."
echo "トークンはあと$DIFF秒(約$((DIFF / 60))分)有効です。"
その他
echo "エラー:メタデータサーバーからJWTを取得できませんでした。"
echo "このスクリプトは、サービスアカウントがアタッチされたGCP VMで実行してください。"
終了1
fi
# sftで使用するためにエクスポート
export GCP_TOKEN="$GCP_JWT"
echo ""
# ─── STEP 2:GCP JWTをOPAトークンに交換 ──────────────────────────────────
echo "------------------------------------------------------------"
echo "STEP 2:OPAでワークロードを認証してOPA_TOKENを取得"
echo "------------------------------------------------------------"
echo "実行:"
echo "sft wl authenticate --team $SFT_TEAM \\"
echo " --connection $CONNECTION_NAME \\"
echo " --role-hint $ROLE_NAME \\"
echo " --jwt-env GCP_TOKEN"
echo ""
OPA_TOKEN=$(sft wl authenticate \
--team "$SFT_TEAM" \
--connection "$CONNECTION_NAME" \
--role-hint "$ROLE_NAME" \
--jwt-env GCP_TOKEN 2>&1 | tr -d '\n\r')
export OPA_TOKEN
if [[ "$OPA_TOKEN" == *"error"* ]] || [[ -z "$OPA_TOKEN" ]]; then
echo "エラー:OPA_TOKENを取得できませんでした。"
echo "詳細:$OPA_TOKEN"
echo ""
echo "チェックリスト:"
echo " 1. ワークロード接続のステータスが「ACTIVE」(「Draft」ではない)になっていますか?"
echo " 2. 接続名「$CONNECTION_NAME」は完全に一致していますか?"
echo " 3. audクレームは「$AUDIENCE」と等しいですか?"
echo " 4. メールのクレームはWorkload ConnectionのSAと一致していますか?"
終了1
その他
echo "成功:OPA_TOKENを取得しました。"
echo ""
echo "OPA_TOKENの値:"
echo "${OPA_TOKEN:0:80}... (truncated)"
fi
echo ""
# ─── STEP 3:OPAトークンを使用してターゲットサーバーにアクセス ───────────────────────
echo "------------------------------------------------------------"
echo "ステップ3:sftコマンドでOPA_TOKENをテスト"
echo "------------------------------------------------------------"
echo ""
echo "3a. このワークロードがアクセスできるサーバーの一覧:
sft list-servers
echo ""
echo "3b. rootとして$TARGET_SERVERに接続し、コマンドを実行します:
sft ssh --command "hostname && whoami && date && echo 'Workload access SUCCESS'" \
"$TARGET_SERVER"
echo ""
echo "------------------------------------------------------------"
echo "完了:ワークロードアイデンティティのデモが完了しました。"
echo "Okta System Logで2つのイベントを確認してください:"
echo " 1. トークン交換(認証)"
echo " 2. サーバーへのSSHログイン」
echo "------------------------------------------------------------"
5.2 自動化スクリプトを実行する
自動化スクリプトを実行:
$ bash ~/opa-workload-test.sh
5.3 想定される出力と監査ログ
実行すると、ターミナルは以下を返します。
この出力は、クレデンシャルを一切使用しない完全なSSH認証フローを3つのステップで示しています。
GCPアイデンティティの取得:ランナーVMは、プラットフォームで署名されたJWTをGoogle Cloudメタデータ(accounts.google.com)から直接リクエストします。サービスアカウントopa-runner-sa向けに、保存されたシークレットを使用せずにそのアイデンティティを確立します。
トークン交換:スクリプトは、sft wl authenticate を介して GCP JWT を Okta Privileged Access に渡します。OPAはGoogleの暗号署名を検証し、okta_opa_wrロールにマッピングされたOPA_TOKENを発行します。
パスワードレス実行:OPAはtarget-vmを検出し、時間ベースのエフェメラルSSH証明書を使用してリモートサーバーでコマンドを実行します。
ターゲットサーバーの応答には、そのホスト名(target-vm)、システムによって割り当てられたワークロードユーザー(wl_okta_opa_wr)、および実行タイムスタンプが表示されます。これにより、静的なキーではなく、ランタイムプラットフォームの証明情報によって完全に制御される、監査可能な完全なSSHアクセスが確立されます。
監査可能性とシステムログ
認証サイクルごとに、構造化されたイベントがOkta System Log(「Okta管理コンソール」 → 「レポート」 → 「システムログ」)に生成されます。
以下のフィルターを適用すると、必要なシステムログを表示できます。
eventType eq "pam.user_creds.issue" and actor.type eq "WorkloadPrincipal"
自動化インフラストラクチャから静的シークレットを排除する
永続的なSSHキーとサービスアカウントファイルを、プラットフォームで署名された暗号アイデンティティ証明書に置き換えることで、セキュリティチームとエンジニアリングチームは、自動化パイプラインを中断することなく、真のゼロトラストのサーバーアクセスを実現できます。Okta Privileged Accessは、ワークロードの動的なフェデレーション、エフェメラル証明書の発行、包括的な可監査性を単一のコントロールプレーンに統合することで、非人間アイデンティティとアクセス管理を簡素化します。
Okta Privileged Accessが、あらゆるクラウドリソースにわたってマシンと人間のアイデンティティのセキュリティを確保する方法をご覧ください。