Google SecOpsのPlaybooksでアラート対応を自動化する(GitHub編)

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

G-gen の武井です。当記事では、Google SecOps で検知したアラートの是正対応を Playbooks で自動化する方法を解説します。

はじめに

Google SecOps とは

Google Security Operations(以下 Google SecOps、旧称 Chronicle)は、Google Cloud が提供する統合セキュリティ運用プラットフォームです。

SIEM、SOAR、脅威インテリジェンス、Gemini を利用した AI による運用支援を提供します。これらにより、脅威の検知・調査・対応を一元的に行えます。結果として、セキュリティ運用の効率化と高度化を実現できます。

以下の記事も参考にしてください。

blog.g-gen.co.jp

Playbooks(ハンドブック)とは

Playbooks(和名表記はハンドブック)では、SIEM によって検知されたアラートに対してあらかじめ一連の対応手順を定義することで、自動または半自動でアクションを実行します。これにより、対応プロセスを標準化・迅速化できます。

Playbooks は次の要素で構成されます。

要素 概要
トリガー
(Triggers)
Playbooks を起動する条件。特定のアラートやイベントの発生時、またはスケジュールを契機に自動実行される
アクション
(Actions)
実行される処理。例えば「VirusTotal への照会」、「Jira チケット起票」、「ユーザーの無効化」など
フロー
(Flows)
条件分岐や承認を制御する仕組み。自動判断やアナリストの入力を挟みながら次の処理を決定する
ブロック
(Blocks)
再利用可能な処理単位。複数の Playbooks で共通利用できる部品化されたモジュール
ループ
(Loops)
配列(リスト)に対する繰り返し処理。for each として、アラート内のエンティティ群やリスト項目を1件ずつ反復し、各項目に対して同じアクションを実行する
AI エージェント
(AI Agents)
AI エージェントを組み込み、自律的な分析・判断を行わせるステップ。Triage and Investigation Agent(TIN)で、アラートを自律調査して True/False Positive の判定・信頼度スコアを返し、その結果を後続の分岐に利用できる

検証の流れ

当記事では GitHub の Private リポジトリが意図せず Public リポジトリに変更されたというシナリオのもと、以下の段取りで検証を行います。

順序 設定項目 設定箇所
1 カスタムルールの設定 Google SecOps
2 カスタムインテグレーションの設定 Google SecOps
3 Playbooks の設定 Google SecOps
4 動作確認 Google SecOps および GitHub

なお、GitHub の監査ログを Google SecOps に取り込む方法については、以下の記事で解説しています。

blog.g-gen.co.jp

カスタムルールの設定

前述のシナリオに該当するログを取り込んだ際、それをアラートとして検知できるよう、検知ルールを準備します。

Google SecOps には事前定義済みの検知ルールが多数用意されていますが、今回のシナリオ向けに独自のカスタムルールを作成します。事前定義済みの検知ルールを参考にしつつ、Gemini in Google SecOps を使用したルール作成が効果的です。

作成したカスタムルール(今回の例では g_gen_github_repo_visibility_to_public)は以下の通りです。また、作成したルールでアラート検知ができるよう、DetectingAlerting を有効にします。

rule g_gen_github_repo_visibility_to_public {
  meta:
    author = "G-gen"
    description = "Detects a GitHub repository whose visibility is changed to public"
    severity = "HIGH"
    tactic = "TA0010"
    technique = "T1567"
  events:
    $e.metadata.product_name = "GITHUB"
    $e.metadata.product_event_type = "repo.access"
    $e.additional.fields["visibility"] = "public" nocase
  outcome:
    $repo_name = array_distinct($e.target.resource.name)
    $actor_id = array_distinct($e.principal.user.userid)
    $new_visibility = array_distinct($e.additional.fields["visibility"])
    $previous_visibility = array_distinct($e.additional.fields["previous_visibility"])
  condition:
    $e
}

Detecting と Alerting を有効にしないとアラートは検知されない

インテグレーションの設定

インテグレーションとは

Playbooks は、それ単体で GitHub のような外部サービスを操作できません。外部サービスへの接続と操作を担うのがインテグレーションです。

Google SecOps では、VirusTotal や Slack をはじめ数多くの外部サービスに対応したインテグレーションが Content Hub(マーケットプレイスに相当)で提供されています。

カスタムインテグレーションとは

カスタムインテグレーションとは、Google SecOps 組み込みの IDE(統合開発環境)を使って独自に作成するインテグレーションです。

2026年7月現在、GitHub に関するインテグレーションは存在しないため、「GitHub への接続」と「リポジトリの可視性(公開範囲)変更」の2つのアクションを含むカスタムインテグレーションを作成し、これらを後段の Playbooks から呼び出します。

カスタムインテグレーションの作成

SecOps の管理コンソールから Response > IDE > +と遷移し、インテグレーション(今回の例では GitHubCustom)を作成します。

次に、インテグレーションの歯車アイコンをクリックします。

画面が遷移したら、以下2つのパラメータを追加します。API Token を必須(Mandatory)にすると既定値の入力を求められ、秘匿値が残ってしまうため、ここでは必須を Off にします。

パラメータ タイプ 既定値 必須
API Root String https://api.github.com On
API Token Password (空) Off

カスタムアクションの作成

インテグレーション(土台)の次に、その上で動くアクションを作成します。アクションには即座に結果が返る Sync と、長時間処理向けの Async がありますが、今回はいずれも即応答のため Sync を選択します。

先程同様、Response > IDE > +と遷移し、以下2つのアクションを作成します。

  • 接続確認用アクションPing): GitHub に正しく接続できるかを確認します。Google SecOps では、すべてのインテグレーションがこの接続テスト用アクションを1つ持つ必要があります。
  • 可視性変更用アクションSet Repository Visibility): GitHub REST API の PATCH /repos/{owner}/{repo} を呼び出し、リポジトリの可視性を変更します。

接続確認用アクション (Ping)では GitHub の GET /user を呼び出し、トークンが有効であることを確認します。

from SiemplifyAction import SiemplifyAction
from SiemplifyUtils import output_handler
from ScriptResult import EXECUTION_STATE_COMPLETED, EXECUTION_STATE_FAILED
import requests

INTEGRATION_NAME = "GitHubCustom"

@output_handler
def main():
    siemplify = SiemplifyAction()
    siemplify.script_name = "Ping"

    api_root = siemplify.extract_configuration_param(INTEGRATION_NAME, "API Root",
                                                     default_value="https://api.github.com")
    token = siemplify.extract_configuration_param(INTEGRATION_NAME, "API Token")

    status = EXECUTION_STATE_COMPLETED
    result_value = "true"
    try:
        resp = requests.get(
            f"{api_root}/user",
            headers={
                "Authorization": f"Bearer {token}",
                "Accept": "application/vnd.github+json",
                "X-GitHub-Api-Version": "2022-11-28",
            },
            timeout=30,
        )
        resp.raise_for_status()
        output_message = f"Successfully connected to GitHub as {resp.json().get('login')}."
    except Exception as e:
        status = EXECUTION_STATE_FAILED
        result_value = "false"
        output_message = f"Failed to connect to GitHub: {e}"

    siemplify.end(output_message, result_value, status)


if __name__ == "__main__":
    main()

可視性変更用アクション(Set Repository Visibility) では実行のたびに外から渡す入力パラメータを2つ定義します。

設定パラメータがインテグレーション全体で共通の接続情報であるのに対し、入力パラメータは実行ごとに変わる値(対象リポジトリなど)を受け取ります。

パラメータ タイプ 既定値 必須
Repository Full Name String (空) Off
Target Visibility String private On

Repository Full Name は、後段の Playbooks でアラートから動的に渡すため、ここでの必須は Off で問題ありません。

from SiemplifyAction import SiemplifyAction
from SiemplifyUtils import output_handler
from ScriptResult import EXECUTION_STATE_COMPLETED, EXECUTION_STATE_FAILED
import requests

INTEGRATION_NAME = "GitHubCustom"

@output_handler
def main():
    siemplify = SiemplifyAction()
    siemplify.script_name = "Set Repository Visibility"

    api_root = siemplify.extract_configuration_param(INTEGRATION_NAME, "API Root",
                                                     default_value="https://api.github.com")
    token = siemplify.extract_configuration_param(INTEGRATION_NAME, "API Token")

    full_name = siemplify.extract_action_param("Repository Full Name", print_value=True)
    target = siemplify.extract_action_param("Target Visibility", default_value="private", print_value=True)

    status = EXECUTION_STATE_COMPLETED
    result_value = "true"
    try:
        owner, repo = full_name.split("/", 1)
        url = f"{api_root}/repos/{owner}/{repo}"
        resp = requests.patch(
            url,
            headers={
                "Authorization": f"Bearer {token}",
                "Accept": "application/vnd.github+json",
                "X-GitHub-Api-Version": "2022-11-28",
            },
            json={"visibility": target},
            timeout=30,
        )
        if resp.status_code == 200:
            siemplify.result.add_result_json(resp.json())
            output_message = f"Reverted {full_name} to {target}."
        else:
            status = EXECUTION_STATE_FAILED
            result_value = "false"
            output_message = f"Failed ({resp.status_code}): {resp.text}"
    except Exception as e:
        status = EXECUTION_STATE_FAILED
        result_value = "false"
        output_message = f"Error: {e}"

    siemplify.end(output_message, result_value, status)


if __name__ == "__main__":
    main()

パラメータ(オレンジ枠)の入力画面

インスタンス設定

作成したカスタムインテグレーションは、インスタンスとして有効化することで使用可能になります。

SecOps の管理コンソールから Response > Integrations Setup > 環境区分(今回は Default Environment)> +と遷移し、先程作成したカスタムインテグレーションを選択してインスタンスを作成します。

インスタンスが作成できたら、歯車アイコンからパラメーターを入力し、Test > Save の順で保存します。

なお、今回は検証のため、個人アカウントで発行した Personal Access Token を使用していますが、本番運用では Fine-grained PAT や GitHub App による認証が望ましいです。

Test は成功して✔がつくこと

Playbooks の設定

Playbooks の構成

ここまでで、アラートを検知するカスタムルールと、是正対応を実行するカスタムインテグレーションが揃いました。最後に、これらを束ねて「検知から是正までを自動化する」ワークフローを Playbooks として組み立てます。

今回作成する Playbooks は、以下の流れで構成します。SecOps の管理コンソールから Response > Playbooks > + と遷移して新規 Playbooks(今回の例ではGitHub_Public_to_Private_Demo)を作成します。

順序 要素 設定内容
1 トリガー カスタムルールでアラートを検知した場合に起動
2 コンディション 特定の GitHub Organization 配下のリポジトリかを判定
3 アクション① #2 が True の場合、カスタムインテグレーションで可視性を変更
4 アクション② ケースにコメントを記入
5 アクション③ ケースのクローズ

トリガー

トリガーは Playbooks の起動条件です。今回は、カスタムルールが検知したアラートにのみ反応させるため、Alert Type が g_gen_github_repo_visibility_to_public である場合に設定します。これにより、このアラート以外では Playbooks が起動しません。

コンディション

コンディションは Playbooks 内の条件分岐です。ある条件を満たす場合のみ後続の処理へ進み、満たさない場合は別ルート(ELSE)へ分岐させられます。

コンディションを挟んだ理由は、是正の対象を特定の Organization のリポジトリに限定するためで、今回の例では g-gen-secops-test/ で始まる場合のみ、後続のアクションへ進むよう設定します。

アクションの設定

アクションは Playbooks で実行する実際の処理です。今回はコンディションの条件を満たした場合、3 つの処理を実行します。

1つ目は、Public に変更されたリポジトリの可視性を Private に戻す処理(Set Repository Visibility)です。カスタムインテグレーションで作成したインスタンスを選択し、入力パラメータを以下のように設定します。

対象のリポジトリはプレースホルダ(Event.event_target_resource_name)とすることで、発火したアラートから動的に判断します。

2つ目は、ケースにコメントを記入する Case Comment です。これは Google SecOps 標準の Siemplify インテグレーションに含まれるアクションで、ケースに任意のコメントを記入するために使用します。Comment に自動対応の記録を残します。

3つ目は、対応が完了したケースをクローズする Close Case です。先程同様 Siemplify インテグレーションに含まれるアクションで、自動対応の済んだケースを未対応のまま残さずクローズするために使用します。

動作確認

動作確認を行うため、カスタムルールの検知対象となる操作(リポジトリの可視性を Public に変更)を実行します。

しばらくすると、Google SecOps のケース画面にてアラートを検知していたことがわかりますが、その時点で既にケースがクローズされています。

Playbooks の起動条件を満たすアラートが検知されたため、可視性変更からケースのクローズまでの一連処理が自動的に実行され、かつ、正常終了していることがわかります。

ケースの詳細を確認すると、Case Comment で定義したコメントが入力済みです。

肝心の GitHub リポジトリの可視性についても Public -> Private に変更されていることを確認できました。

武井 祐介 (記事一覧)

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

Google Cloud Partner Top Engineer 2026 選出。