TECH PLAY

株式会社G-gen

株式会社G-gen の技術ブログ

744

G-gen の堂原です。本記事では Google Cloud(旧称 GCP)の Cloud Run functions (旧 Cloud Functions)から、 VPC Service Controls 境界の中のリソースへアクセスさせる方法について紹介します。 はじめに 本記事の趣旨 VPC Service Controls Cloud Run functions ポイント アクセスの成否 VPC 経由でのリクエストが必要な理由 VPC のアクセス可能なサービス はじめに 本記事の趣旨 本記事では、Cloud Run functions から、VPC Service Controls で保護された Google Cloud プロジェクトのリソースにアクセスする方法や、どのような設定でアクセスが成功または失敗するのかについて解説します。 VPC Service Controls VPC Service Controls は Google Cloud が提供するセキュリティサービスです。 「サービス境界(service perimeter)」という論理的な境界を作成し、境界をまたぐ API リクエストを制限します。 VPC Service Controls については、以下の記事で解説していますのでご参照ください。 blog.g-gen.co.jp なお本記事は Ingress rules(内向きルール)など、VPC Service Controls の基本的な設定項目については理解している前提で書かれています。 Cloud Run functions Cloud Run functions は、Google Cloud が提供するサーバレスコンピューティングサービスです。インフラの構築や管理をすることなく、プログラムを実行することができます。 こちらも以下の記事で解説していますので、ご参照ください。 blog.g-gen.co.jp ポイント 本記事で最も伝えたいポイントは、以下のとおりです。 VPC Service Controls の Ingress rule(内向きルール)でソースプロジェクトを指定する場合、Cloud Run functions は VPC 経由でリクエストを送信する必要がある。 アクセスの成否 以下のような検証環境を用意しました。 VPC Service Controls で保護された Google Cloud プロジェクト プロジェクト内に Cloud Run functions と BigQuery テーブルを用意 Cloud Run functions には「サービスアカウント A」を紐づけ Cloud Run functions から BigQuery テーブルにアクセスする状況を想定 この環境で、VPC Service Controls と Cloud Run functions の各設定値を変更しながら、様々なパターンでアクセスの成否を検証しました。検証結果は、以下のようになりました。 No. VPC Service Controls Cloud Run functions アクセス結果 制限付きサービス VPC のアクセス可能なサービス 「Ingress rules」の「API クライアントの FROM 属性」 ネットワークの下り設定 ID ソース 1 BigQuery API すべての制限付きサービス サービスアカウント A すべてのソース なし OK 2 BigQuery API すべての制限付きサービス サービスアカウント A プロジェクト なし NG 3 BigQuery API すべての制限付きサービス サービスアカウント A プロジェクト すべてのトラフィックを VPC コネクタ経由でルーティングする OK 4 BigQuery API すべての制限付きサービス サービスアカウント A プロジェクト プライベート IP へのリクエストだけを VPC コネクタ経由でルーティングする NG 5 BigQuery API なし サービスアカウント A プロジェクト すべてのトラフィックを VPC コネクタ経由でルーティングする NG 6 なし なし サービスアカウント A プロジェクト すべてのトラフィックを VPC コネクタ経由でルーティングする NG 7 なし なし サービスアカウント A プロジェクト なし OK VPC 経由でのリクエストが必要な理由 VPC Service Controls では、境界を超えるようなアクセスは、原則的に全てブロックされます。 Ingress rules (内向きルール)を用いると、 特定のソース (特定の IP アドレスや Google Cloud プロジェクト)を接続元とする 特定の ID (Google アカウントやサービスアカウント)によるアクセスを 例外的に許可する ことが出来ます。 そのため、Ingress rules で ID を Cloud Run functions に紐づけた「サービスアカウント A」に、 ソースを Cloud Run functions が所属する Google Cloud プロジェクト にすれば、境界内へのアクセスは成功するかのように考えられます。 しかし上記の場合、 Cloud Run functions からのアクセスは失敗します 。 これは、Google Cloud の公式ドキュメントには明言されていませんが、Cloud Run functions の実行基盤がユーザが管理する Google Cloud プロジェクトとは別だからだと推測できます。 そのため、当該プロジェクトからのアクセスとなるように、 Cloud Run functions を VPC に接続させる必要がある のです。 このことは以下の公式ドキュメントでも触れられています。 参考 : 境界外の関数での VPC Service Controls の使用 VPC のアクセス可能なサービス また Cloud Run functions に VPC 経由で VPC Service Controls の境界内へアクセスさせる場合は、「 VPC のアクセス可能なサービス (VPC Accessible services)」という設定項目の値にも気をつける必要があります。この設定項目は境界内の VPC ネットワークからアクセスできるサービスを制御する項目です。 この項目で明示的にアクセス先のサービスが許可されていない場合、Cloud Run functions からのアクセスは失敗します。 前掲の表の No. 6は、VPC 内部からのアクセスだが「VPC のアクセス可能なサービス」で許可されていない API にリクエストしようとしているため、リクエストが失敗しています。反対に No.7 は、VPC 外部からのリクエストであり、かつ BigQuery API は境界で保護されていないため、リクエストが成功します。 参考 : VPC のアクセス可能なサービス 堂原 竜希 (記事一覧) クラウドソリューション部データアナリティクス課。2023年4月より、G-genにジョイン。 Google Cloud Partner Top Engineer 2023, 2024に選出 (2024年はRookie of the yearにも選出)。休みの日はだいたいゲームをしているか、時々自転車で遠出をしています。 Follow @ryu_dohara
アバター
G-gen の三浦です。当記事では Workload Identity の仕組みを使うことで、サービスアカウントキーを使わずに GitHub Enterprise の監査ログを BigQuery にエクスポートする仕組みを構築したのでご紹介します。 GitHub Enterprise とは 概要 監査ログ Google Cloud への監査ログエクスポート アーキテクチャ 構成図 ディレクトリ構成 環境構築 Workload Identity とサービスアカウントの作成 BigQuery データセットの作成とサービスアカウントへの権限付与 GitHub Actions ワークフローの作成 main.py の作成 GitHub App の作成 GitHub Actions のシークレット登録 動作確認 手動実行 スケジュール実行 GitHub Enterprise とは 概要 GitHub Enterprise は、複数組織の一元管理や Microsoft Entra ID などの IdP(Identity Provider)を使用した SSO(シングルサインオン)などの機能を提供する有償プランです。 本プランでは監査ログ API を使用して組織内の操作履歴を取得・管理できます。監査ログを BigQuery にエクスポートすると、長期保存や高度な分析を行い、セキュリティ対策やコンプライアンス強化に役立ちます。 参考 : エンタープライズ向け GitHub について 参考 : プランご紹介 監査ログ GitHub の監査ログには、組織メンバーのレポジトリ作成、プルリクエストやマージなどの操作が記録され、過去180日分のログを確認できます。 git.clone など一部の Git イベントは 7 日間のみ保持されます。 参考 : 企業の監査ログにアクセスする 参考 : エンタープライズの監査ログ イベント Google Cloud への監査ログエクスポート GitHub の監査ログは JSON 形式で Cloud Storage にエクスポートできますが、通常はサービスアカウントキーが必要です。 参考 : Google Cloud Storage へのストリーミングの設定 サービスアカウントキーは厳重な管理が必要です。漏洩した場合、第三者による不正利用のリスクがあります。Google Cloud のベストプラクティスでは、サービスアカウントキーを使用せずに認証する方法が推奨されています。 参考 : サービス アカウント キーを管理するためのベスト プラクティス 以上のことから、当記事では Google Cloud の Workload Identity 機能を使うことで、サービスアカウントキーを使用せずに GitHub 監査ログを取得する仕組みを実装しました。 アーキテクチャ 構成図 構成は図のとおりです。GitHub Actions を使用して監査ログを取得し、BigQuery にエクスポートします。 構成図 ディレクトリ構成 ディレクトリ構成は以下の通りです。 . └── app └── main.py # 監査ログを BigQuery へエクスポートするスクリプト .github └── workflows └── github-audit-log-to-bq.yml # GitHub Actions を定義 環境構築 Workload Identity とサービスアカウントの作成 GitHub Actions と Google Cloud を連携させるための Workload Identity とサービスアカウントを作成します。作成方法は、次の記事を参照してください。 Google CloudとGitHub Actions(Terraform)を連携するWorkload Identityを作成するbashスクリプト blog.g-gen.co.jp BigQuery データセットの作成とサービスアカウントへの権限付与 BigQuery のデータセットを作成します。テーブルは GitHub Actions で自動的に作成されます。 # 環境変数を設定 PROJECT_ID = " gha-demo-prj " # プロジェクトID SERVICE_ACCOUNT_NAME = " gha-demo-sa " # サービスアカウント名 BQ_DATASET = " my_dataset " # BigQueryのデータセット名   # BigQuery データセットを東京リージョンに作成 bq --project_id = $PROJECT_ID \ mk --location = asia-northeast1 \ $BQ_DATASET サービスアカウントに BigQuery へのデータ書き込み権限とジョブの実行権限を付与します。 # サービスアカウントへ権限付与 gcloud projects add-iam-policy-binding $PROJECT_ID \ --member =" serviceAccount: $SERVICE_ACCOUNT_NAME @ $PROJECT_ID .iam.gserviceaccount.com " \ --role =" roles/bigquery.dataEditor "   gcloud projects add-iam-policy-binding $PROJECT_ID \ --member =" serviceAccount: $SERVICE_ACCOUNT_NAME @ $PROJECT_ID .iam.gserviceaccount.com " \ --role =" roles/bigquery.jobUser " GitHub Actions ワークフローの作成 このワークフローは、GitHub の監査ログを1日に1回自動で取得し、BigQuery にエクスポートします。前回の自動取得時刻をアーティファクト(GitHub Actions の成果物保存機能)で管理することで差分のログのみを取得します。過去のログも手動で取得できます。 参考 : ワークフローからのデータの格納と共有 env: の箇所に、環境に応じたプロジェクト ID などの値を記載してください。 # github-audit-log-to-bq.yml name : Fetch and Upload GitHub Audit Logs to BigQuery   on : schedule : # スケジュール実行 - cron : '0 15 * * *' # 毎日 JST 0 時に実行(UTC 15 時) workflow_dispatch : # 手動実行 inputs : start_date : # ログ取得の開始日 description : "Start date for fetching logs (ISO 8601 format, e.g., 2024-09-01T00:00:00Z)" required : true default : "2024-10-01T00:00:00Z" end_date : # ログ取得の終了日 description : "End date for fetching logs (ISO 8601 format, e.g., 2024-09-30T23:59:59Z)" required : true default : "2024-10-31T23:59:59Z"   permissions : id-token : write contents : read actions : read   jobs : fetch-and-upload : runs-on : ubuntu-latest   env : # BigQuery 設定 BQ_GCP_PROJECT_ID : gha-demo-prj # Google Cloud プロジェクト ID BQ_DATASET : my_dataset # BigQuery データセット名 BQ_TABLE : my_table # BigQuery テーブル名 # GitHub 設定 GITHUB_ORG : myorg # GitHub 組織名 GH_TOKEN : ${{ github.token }} # GitHub CLI 用のトークン # Workload Identity Federation 設定 PROJECT_NUMBER : 1234567890 # プロジェクト番号 WORKLOAD_IDENTITY_POOL : gha-demo-pool # Workload Identity プール名 WORKLOAD_IDENTITY_POOL_PROVIDER : gha-demo-provider # Workload Identity プールプロバイダ名 SERVICE_ACCOUNT : gha-demo-sa@gha-demo-prj.iam.gserviceaccount.com # 使用するサービスアカウント名 # アーティファクト設定 LAST_RUN_TIMESTAMP_NAME : "last_run_timestamp" # 前回実行時刻のアーティファクト名   steps : - uses : actions/checkout@v4   # Google Cloud 認証 (Workload Identity) - id : 'auth' uses : 'google-github-actions/auth@v2' with : workload_identity_provider : 'projects/${{ env.PROJECT_NUMBER }}/locations/global/workloadIdentityPools/${{ env.WORKLOAD_IDENTITY_POOL }}/providers/${{ env.WORKLOAD_IDENTITY_POOL_PROVIDER }}' service_account : ${{ env.SERVICE_ACCOUNT }}   # GitHub App トークンを生成 - name : Generate GitHub App token id : generate_token uses : actions/create-github-app-token@v1 with : app-id : ${{ secrets.APP_ID }} private-key : ${{ secrets.APP_PRIVATE_KEY }}   # GitHub App トークンを環境変数に設定 - name : Set GitHub App Access Token run : echo "ACCESS_TOKEN=${{ steps.generate_token.outputs.token }}" >> $GITHUB_ENV   # Python環境をセットアップ - name : Set up Python environment run : | python3 -m venv venv . venv/bin/activate pip install --upgrade pip pip install google-cloud-bigquery requests jq pandas   # 初回実行時のタイムスタンプを設定 - name : Set Default Timestamp to Start of Today if : ${{ github.event_name == 'schedule' }} run : | DEFAULT_TIMESTAMP=$(date -u +"%Y-%m-%dT00:00:00Z") echo "DEFAULT_TIMESTAMP=$DEFAULT_TIMESTAMP" >> $GITHUB_ENV   # 前回実行時刻のアーティファクトをダウンロード - name : Download previous timestamp artifact if : ${{ github.event_name == 'schedule' }} run : | mkdir -p artifacts ARTIFACT_URL=$(gh api -X GET "repos/${{ github.repository }}/actions/artifacts" \ | jq -r '.artifacts[] | select(.name=="' ${{ env.LAST_RUN_TIMESTAMP_NAME }} '") | .archive_download_url' | head -n 1) if [ -n "$ARTIFACT_URL" ] ; then curl -L -o artifacts/${{ env.LAST_RUN_TIMESTAMP_NAME }}.zip -H "Authorization: token ${{ github.token }}" "$ARTIFACT_URL" unzip -o artifacts/${{ env.LAST_RUN_TIMESTAMP_NAME }}.zip -d artifacts/ if [ ! -f "artifacts/${{ env.LAST_RUN_TIMESTAMP_NAME }}.txt" ] ; then echo "${{ env.DEFAULT_TIMESTAMP }}" > artifacts/${{ env.LAST_RUN_TIMESTAMP_NAME }}.txt fi else echo "${{ env.DEFAULT_TIMESTAMP }}" > artifacts/${{ env.LAST_RUN_TIMESTAMP_NAME }}.txt fi   # 前回実行時刻を読み込み - name : Read previous timestamp if : ${{ github.event_name == 'schedule' }} id : read-timestamp run : | if [ ! -f "artifacts/${{ env.LAST_RUN_TIMESTAMP_NAME }}.txt" ] ; then echo "${{ env.DEFAULT_TIMESTAMP }}" > artifacts/${{ env.LAST_RUN_TIMESTAMP_NAME }}.txt fi last_run=$(cat artifacts/${{ env.LAST_RUN_TIMESTAMP_NAME }}.txt) echo "last_run=$last_run" >> $GITHUB_ENV   # 今回実行時刻を環境変数に保存 - name : Set execution time for last_run if : ${{ github.event_name == 'schedule' }} run : | execution_time=$(date --utc --iso-8601=seconds) echo "execution_time=$execution_time" >> $GITHUB_ENV   # スケジュール実行時の監査ログ取得 - name : Fetch GitHub Audit Logs for Scheduled Run if : ${{ github.event_name == 'schedule' }} env : last_run : ${{ env.last_run }} ACCESS_TOKEN : ${{ env.ACCESS_TOKEN }} run : | . venv/bin/activate rm -rf app/audit_logs mkdir -p app/audit_logs next_url="https://api.github.com/orgs/${{ env.GITHUB_ORG }}/audit-log?phrase=created:>$last_run&per_page=100&include=all" while [[ ! -z "$next_url" ]] ; do response=$(curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "Accept: application/vnd.github.v3+json" \ "$next_url" ) if echo "$response" | jq -e 'type == "object" and has("message")' >/dev/ null 2>&1; then exit 1 fi logs_count=$(echo "$response" | jq '. | length' ) echo "$response" > "app/audit_logs/log_$logs_count.json" next_url=$(curl -s -I -H "Authorization: Bearer $ACCESS_TOKEN" "$next_url" | grep -i '^link:' | sed -n 's/.*<\(.*\)>; rel="next".*/\1/p' ) sleep 2 done   # 手動実行時の監査ログ取得 - name : Fetch GitHub Audit Logs for Manual Run if : ${{ github.event_name == 'workflow_dispatch' }} env : start_date : ${{ github.event.inputs.start_date }} end_date : ${{ github.event.inputs.end_date }} ACCESS_TOKEN : ${{ env.ACCESS_TOKEN }} run : | . venv/bin/activate rm -rf app/audit_logs mkdir -p app/audit_logs next_url="https://api.github.com/orgs/${{ env.GITHUB_ORG }}/audit-log?phrase=created%3A>${start_date}%20created%3A<${end_date}&per_page=100&include=all" while [[ ! -z "$next_url" ]] ; do response=$(curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "Accept: application/vnd.github.v3+json" \ "$next_url" ) if echo "$response" | jq -e 'type == "object" and has("message")' >/dev/ null 2>&1; then exit 1 fi logs_count=$(echo "$response" | jq '. | length' ) echo "$response" > "app/audit_logs/log_$logs_count.json" next_url=$(curl -s -I -H "Authorization: Bearer $ACCESS_TOKEN" "$next_url" | grep -i '^link:' | sed -n 's/.*<\(.*\)>; rel="next".*/\1/p' ) sleep 2 done   # 監査ログを BigQuery にアップロード - name : Run script to upload logs to BigQuery run : | . venv/bin/activate python3 app/main.py   # 今回実行時刻をファイルに書き込み - name : Write new execution time to file if : ${{ success() && github.event_name == 'schedule' }} run : | mkdir -p artifacts echo "$execution_time" > artifacts/${{ env.LAST_RUN_TIMESTAMP_NAME }}.txt   # 今回実行時刻をアーティファクトとしてアップロード - name : Upload updated timestamp artifact if : ${{ success() && github.event_name == 'schedule' }} uses : actions/upload-artifact@v4 with : name : ${{ env.LAST_RUN_TIMESTAMP_NAME }} path : artifacts/${{ env.LAST_RUN_TIMESTAMP_NAME }}.txt main.py の作成 このスクリプトは GitHub Actions で取得した監査ログを加工し、BigQuery へエクスポートします。エクスポート先のテーブルが存在しない場合、新規に作成します。 import json import logging import os import sys import time import pandas as pd from datetime import datetime, timezone from google.cloud import bigquery from google.api_core.exceptions import NotFound, GoogleAPIError import re   # ログの設定: ログメッセージの出力形式を指定し、INFOレベル以上のメッセージを記録 logging.basicConfig(level=logging.INFO, format = '%(asctime)s [%(levelname)s] %(message)s' )   def get_bigquery_client (): """BigQueryクライアントを初期化して返す""" return bigquery.Client() def flatten_json (y): """ネストされたJSONデータを平坦化""" out = {} def flatten (x, name= '' ): if isinstance (x, dict ): for a in x: flatten(x[a], name + a + '_' ) elif isinstance (x, list ): for i, a in enumerate (x): flatten(a, name + str (i) + '_' ) else : out[name[:- 1 ]] = x flatten(y) return out def clean_field_name (field_name): """フィールド名をBigQueryで許可された形式に変換""" field_name = re.sub( r'[^a-zA-Z0-9_]' , '_' , field_name) if field_name[ 0 ].isdigit(): field_name = '_' + field_name return field_name def infer_schema_from_logs (logs_df): """DataFrameからBigQuery用のスキーマを推測して生成""" schema = [] for column in logs_df.columns: clean_column = clean_field_name(column) dtype = logs_df[column].dtype if clean_column == "_timestamp" and pd.api.types.is_integer_dtype(dtype): schema.append(bigquery.SchemaField( "timestamp" , "TIMESTAMP" )) elif pd.api.types.is_integer_dtype(dtype): schema.append(bigquery.SchemaField(clean_column, "INTEGER" )) elif pd.api.types.is_float_dtype(dtype): schema.append(bigquery.SchemaField(clean_column, "FLOAT" )) elif pd.api.types.is_bool_dtype(dtype): schema.append(bigquery.SchemaField(clean_column, "BOOLEAN" )) elif pd.api.types.is_datetime64_any_dtype(dtype): schema.append(bigquery.SchemaField(clean_column, "TIMESTAMP" )) else : schema.append(bigquery.SchemaField(clean_column, "STRING" )) return schema def create_table_if_not_exists (client, table_ref, logs_df): """テーブルが存在しない場合、新規作成""" try : table = client.get_table(table_ref) logging.info(f "Table {table_ref} already exists." ) return table except NotFound: schema = infer_schema_from_logs(logs_df) table = bigquery.Table(table_ref, schema=schema) table = client.create_table(table) logging.info(f "Table {table_ref} created with schema." ) return table def load_audit_logs (logs_dir= 'app/audit_logs' ): """監査ログをJSONファイルから読み込みDataFrameに統合""" logs = [] for filename in os.listdir(logs_dir): if filename.endswith( ".json" ): file_path = os.path.join(logs_dir, filename) try : with open (file_path, 'r' ) as f: file_logs = json.load(f) for log in file_logs: logs.append(flatten_json(log)) except json.JSONDecodeError as e: logging.error(f "Failed to load {file_path}: {e}" ) return pd.DataFrame(logs) def transform_audit_logs (logs_df, schema): """監査ログをBigQuery用の形式に変換""" transformed_logs = [] schema_field_names = {field.name for field in schema} logs_df.columns = [clean_field_name(col) for col in logs_df.columns] if "_timestamp" in logs_df.columns: logs_df[ "_timestamp" ] = pd.to_datetime(logs_df[ "_timestamp" ], unit= 'ms' , utc= True ) logs_df = logs_df.rename(columns={ "_timestamp" : "timestamp" }) for _, log in logs_df.iterrows(): transformed_log = {} for key, value in log.items(): if key in schema_field_names and not pd.isnull(value): if isinstance (value, pd.Timestamp): value = value.isoformat() elif isinstance (value, bool ): value = int (value) transformed_log[key] = value if transformed_log: transformed_logs.append(transformed_log) return transformed_logs def insert_rows_with_retry (client, table_ref, rows, retries= 3 , delay= 10 ): """BigQueryにデータをリトライ付きで挿入""" for attempt in range (retries): try : errors = client.insert_rows_json(table_ref, rows) if errors: logging.error(f "Errors occurred during insertion: {errors}" ) time.sleep(delay) else : logging.info( "Data uploaded successfully." ) return except GoogleAPIError as e: logging.error(f "Failed to upload data to BigQuery: {e}" ) time.sleep(delay) logging.error(f "Failed to insert rows into {table_ref} after {retries} attempts." ) sys.exit( 1 ) def main (): project_id = os.getenv( 'BQ_GCP_PROJECT_ID' ) dataset_id = os.getenv( 'BQ_DATASET' ) table_id = os.getenv( 'BQ_TABLE' ) table_ref = f "{project_id}.{dataset_id}.{table_id}" client = get_bigquery_client() logs_df = load_audit_logs() if not logs_df.empty: table = create_table_if_not_exists(client, table_ref, logs_df) rows_to_insert = transform_audit_logs(logs_df, table.schema) insert_rows_with_retry(client, table_ref, rows_to_insert) else : logging.error( "No logs to process. Exiting." ) sys.exit( 1 ) if __name__ == "__main__" : main() GitHub App の作成 監査ログを取得するための GitHub App を作成します。詳細な手順は以下を参照してください。 参考 : Enterprise 向け GitHub Apps の作成 GitHub App の Permissions は以下のとおりに設定します。 Repository permissions Administration: Read-only Metadata: Read-only Organization permissions Administration: Read-only 参考 : GitHub Appの権限について (General)から App ID を確認し、控えておきます。(後で GitHub の secret に登録します) App ID の確認 同画面から(Private keys)を作成し、ダウンロードします。(後で GitHub の secret に登録します) Private keys の作成 (Install App)から対象の組織を確認し、(Install)を選択します。 組織へのインストール (Only select repositories)から GitHub Actions を構築するレポジトリを選択し、(Install)を選択します。 GitHub App をインストールするレポジトリの選択 GitHub Actions のシークレット登録 作成した GitHub App を GitHub Actions で使用するため、リポジトリの Secrets(シークレット)に登録します。登録対象は以下の 2 つです。 App ID 名前 : APP_ID 値 : 前手順で確認した GitHub App の App ID Private keys 名前 : APP_PRIVATE_KEY 値 : PEM キーの値をコピーして貼り付ける Secrets の登録 参考 : リポジトリのシークレットの作成 動作確認 手動実行 GitHub の(Actions)タブから対象ワークフローを選択し、取得期間のパラメータ( Start date 、 End date )を入力して(Run workflow)で実行します。 手動実行 ※ 一度に180日分を取得可能ですが、ログ数が多い場合、BigQuery へエクスポートする際に以下エラーで失敗することがあります。発生した場合、取得期間を短くして再実行してください。 Error: -06 08:40:51, 290 [ ERROR ] Failed to upload data to BigQuery: Timeout of 600 .0s exceeded, last exception: HTTPSConnectionPool ( host = ' bigquery.googleapis.com ' , port = 443 ) : Max retries exceeded with url: /bigquery/v2/projects/xxxxx/datasets/xxxxx/tables/xxxxx/insertAll? prettyPrint =false ( Caused by SSLError ( SSLEOFError ( 8 , ' EOF occurred in violation of protocol (_ssl.c:2426) ' ))) また、監査ログ API にはレート上限があり、1 時間に最大 1,750 クエリ(1 クエリで最大 100 件のログ取得が可能)の制限があります。この制限を超えた場合、403 または 429 エラー応答で失敗するため、ご注意ください。 参考 : レート上限 実行が成功したら、BigQuery を確認し、指定した期間の監査ログが格納されたテーブルがあることを確認します。 手動実行成功 監査ログの確認 スケジュール実行 JST 0時にスケジュール実行され、ログが BigQuery にエクスポートされます。GitHub 側の負荷により実行までに遅延が発生する場合もありますので、ご注意ください。 参考 : schedule GitHub の(Actions)から対象のワークフローが成功していることを確認します。(Event)から(schedule)を選択することで、スケジュール実行されたワークフローのみが表示されます。 フィルタ方法 処理が成功し、Artifacts にファイル(実行時間が記録された txt ファイル)があることを確認します。次回の実行時はこの時間以降のログを取得し、BigQuery へエクスポートします。 スケジュール実行成功 last_run_timestamp の中身 BigQuery を確認し、監査ログが出力されていることを確認します。 監査ログの確認 三浦 健斗 (記事一覧) クラウドソリューション部 2023年10月よりG-genにジョイン。元オンプレ中心のネットワークエンジニア。ネットワーク・セキュリティ・唐揚げ・辛いものが好き。
アバター
G-gen の杉村です。2024年11月のイチオシ Google Cloud アップデートをまとめてご紹介します。記載は全て、記事公開当時のものですのでご留意ください。 はじめに Eventarc Advanced が登場(Preview) Vertex AI Search で streaming answer メソッド(GA with Allowlist) Dataplex で automatic discovery of Cloud Storage data が Preview データ分類ラベルが Gmail にも対応 Google Cloud 認定試験に新試験が誕生 Application Load Balancer で Service Extensions が Preview 公開 Pub/Sub で Cloud Storage import topic が利用可能に 新サービス Audit Manager が公開(GA) Vertex AI で Gemini による「バッチ推論」が可能に(GA) GKE のコントロールプレーンに DNS ベースのアクセスが登場 Gemini サイドパネルの日本語版が Alpha 版 → GA Cloud Run で in-memory volume が Preview -> GA Cloud Storage で Bucket IP filtering が Preview 公開 BigQuery の Search index で数値列に対する最適化が Preview → GA Cloud SQL Enterprise Plus edition で write endpoint が Preview 公開 Cloud SQL Studio で IAM データベース認証が使えるように Cloud SQL for PostgreSQL のバックアップから AlloyDB クラスタが起動できるように 2025年1月25日より Cloud Run 関連ロールに仕様変更あり Google Chat に音声ミーティング huddles が導入 はじめに 当記事では、毎月の Google Cloud アップデートのうち特に重要なものをまとめます。 また当記事は、Google Cloud に関するある程度の知識を前提に記載されています。前提知識を得るには、ぜひ以下の記事もご参照ください。 blog.g-gen.co.jp リンク先の公式ガイドは、英語版で表示しないと最新情報が反映されていない場合がありますためご注意ください。 Eventarc Advanced が登場(Preview) Choose Eventarc Advanced or Eventarc Standard (2024-10-31) Eventarc Advancedが登場(Preview)。 従来版(Standard)との違いは、より詳細な制御、他対他のファンイン・ファンアウト、メッセージの変換など。Bus、Enrollment、Pipelineの3要素で構成される。 Vertex AI Search で streaming answer メソッド(GA with Allowlist) Stream answers (2024-10-31) Vertex AI Search に streaming answer メソッドが登場。 回答の一部が生成され次第ストリーミングで返却される。現在のところ英語のみ対応。利用には申請が必要。 Dataplex で automatic discovery of Cloud Storage data が Preview Discover and catalog Cloud Storage data (2024-11-05) Dataplex で automatic discovery of Cloud Storage data が Preview 公開。 Cloud Storage 上の CSV、JSONL、Parquet、Avro、ORC を自動で検出し、BigQuery の外部テーブルやオブジェクトテーブルを生成してくれる。 以前より Dataplex には、同様の Data Discovery 機能が存在していたが、今回のアップデートでは Dataplex の Lake が作成されず、そのまま BigQuery から使える(Dataplex の管理機構を通らない)ことが違い。 データ分類ラベルが Gmail にも対応 Data classifications labels for Gmail are now available in open beta (2024-11-01) データ分類ラベルが Gmail にも対応。"Sensitive"、"Confidential" といったラベルをコンテンツ内容に応じて自動付与し、ラベルに応じて外部送信をブロックするなどが可能。エディションごとに使える機能が違うことに注意。 Google Cloud 認定試験に新試験が誕生 Google Cloud Certification Associate Google Workspace Administrator(Beta) 2024年10月22日、Beta 版として公開 Google Workspace の管理業務やトラブルシューティングに関する知識を問う Associate Data Practioner(Beta) 2024年10月30日、Beta 版として公開 Google Cloud 上のデータやデータパイプラインの管理に関する知識を問う Professional Cloud Architect 新しい更新試験の Beta 版が受験可能に これまでは、新規受験と更新受験に問題の区別がなかった 2つの新試験については、G-gen から既に試験対策記事が公開された。 blog.g-gen.co.jp blog.g-gen.co.jp Application Load Balancer で Service Extensions が Preview 公開 Now run your custom code at the edge with the Application Load Balancers (2024-10-30) Application Load Balancer で、エッジ側でサーバーレスプログラムを動作させる Service Extensions が Preview 公開。 プログラムのフォーマットは WebAssembly (Wasm)。ALB側でコードが動くので低遅延で稼働する。HTTPヘッダ操作、カスタム認証、カスタムロギング、HTML書き換えなどに利用できる。 Pub/Sub で Cloud Storage import topic が利用可能に Create a Cloud Storage import topic (2024-11-06) Pub/Sub で Cloud Storage import topic が利用可能に。 Publisher サービスを開発することなく Cloud Storage オブジェクトを Pub/Sub に取り込んで宛先に挿入できる。イベントドリブンなアーキテクチャをより容易に実装可能に。 以下の記事も参照。 blog.g-gen.co.jp 新サービス Audit Manager が公開(GA) Audit Manager overview (2024-11-07) Google Cloudで新サービスAudit Managerが公開(GA)。 ISO 27001 や SOC2、PCI DSS 等に準拠するために証跡を自動収集。料金は Free と Premium の 2 tiers。 Free tier では以下の監査対応が可能。 SOC2 Google-recommended AI controls Premium tier($7,500/yr)では以下の監査対応が可能。 NIST 800-53 Revision 4 CIS Controls v8 PCI DSS 4.0 Cloud Controls Matrix 4.0 NIST CSF v1 CIS Google Cloud Foundation Benchmark 2.0 ISO 27001 2022 Vertex AI で Gemini による「バッチ推論」が可能に(GA) Batch prediction (2024-11-08) Vertex AI で Gemini による「バッチ推論」が可能に(GA)。 1度のリクエストで多数のプロンプトを送信。同量の標準リクエストより50%引きの料金で利用できる。レスポンスは BigQuery または Cloud Storage に非同期出力。Gemini 1.5 Pro/Flash 等で利用可能。 GKE のコントロールプレーンに DNS ベースのアクセスが登場 About network isolation in GKE (2024-11-11) Google Kubernetes Engine(GKE)で、コントロールプレーンへのアクセス方法に DNS ベースのアクセスが登場。 従来の IP ベースだと、クラスタをプライベートネットワークに閉じ込め、接続元 IP アドレス(承認済みネットワーク)で制御していたが、DNS ベースのアクセスでは IAM で認証。 以下の記事も参照。 blog.g-gen.co.jp Gemini サイドパネルの日本語版が Alpha 版 → GA Now generally available: use Gemini in the side panel of Workspace apps in seven additional languages (2024-11-07) Gemini for Google Workspace サイドパネルの日本語版が Alpha 版 → GA(一般公開)。2024-10-16 に Alpha 版として公開されていた。 なお、他の言語も同時に GA。今回の公表で GA された言語は以下のとおり。 フランス語 ドイツ語 イタリア語 日本語 韓国語 ポルトガル語 スペイン語 Cloud Run で in-memory volume が Preview -> GA Configure in-memory volume mounts for services (2024-11-12) Cloud Run で in-memory volume が Preview -> GA。 コンテナのメモリ領域をファイルシステムとして利用。Cloud Run service と jobs の両方で利用可能。 Cloud Storage で Bucket IP filtering が Preview 公開 Bucket IP filtering (2024-11-14) Cloud Storage で Bucket IP filtering が Preview 公開。 バケットで接続元 IP アドレス制限が可能になった。従来も VPC Service Controls で IP アドレスベースの制限はできたが、当機能ではバケット単位での制御が可能になる。また、接続元 VPC も制限できる。 ただし、東京・大阪リージョン未対応なので注意。 BigQuery の Search index で数値列に対する最適化が Preview → GA Optimize with numeric predicates (2024-11-19) BigQuery の Search index で INT64 と TIMESTAMP 列に対する述語(=、IN)での最適化が Preview → GA。 Search index はテーブルの特定列にインデックスを作成しておけば WHERE 句での絞り込み(検索)が高速化する仕組み。インデックスは自動更新。 Cloud SQL Enterprise Plus edition で write endpoint が Preview 公開 Optimize with numeric predicates (2024-11-19) Cloud SQL(for PostgreSQL、MySQL)Enterprise Plus edition で write endpoint が Preview。 書き込みエンドポイント(write endpoint)とは、常にプライマリインスタンスのプライベート IP アドレスを指すエンドポイントのことで、DNS 名を持つ。 書き込みエンドポイントを使って接続することで、別リージョンに構成したリードレプリカをプライマリインスタンスとして昇格した際も、アプリケーション側で向き先 IP アドレスを変更する必要がない。 Cloud SQL Auth Proxy からは書き込みエンドポイントを使えないことに注意。 Cloud SQL Studio で IAM データベース認証が使えるように IAM database authentication (2024-11-20) Cloud SQL Studio で IAM データベース認証が使えるように。Cloud SQL Studio とは、Google Cloud コンソールからデータベースにクエリしたり管理できる UI。これまではユーザー・パスワードを入力して認証する必要があった。 Cloud SQL for PostgreSQL のバックアップから AlloyDB クラスタが起動できるように Migrate from Cloud SQL for PostgreSQL to AlloyDB for PostgreSQL (2024-11-21) Cloud SQL for PostgreSQL のバックアップから AlloyDB クラスタが起動できるようになった(Preview)。 Cloud SQL から AlloyDB への移行が容易に実現できるようになった。 2025年1月25日より Cloud Run 関連ロールに仕様変更あり [Action Required] Ensure read access on container images deployed to Cloud Run - G-gen Tech Blog (2024-11-25) 2025年1月25日より、Cloud Runのデプロイを行うことができる事前定義ロール(Cloud Run 管理者 / デベロッパー)の仕様に変更。 放置すると CI/CD パイプラインに影響がある可能性があるため、要確認。詳細は以下の記事を参照。 blog.g-gen.co.jp Google Chat に音声ミーティング huddles が導入 Introducing huddles: instant-on, audio-first meetings in Google Chat (2024-11-27) Google Chat に音声ミーティング huddles が導入。Chat からシームレスに音声・動画通話をスタートできる。バックエンドは Google Meet。2024-11-27から順次ロールアウトされる。 ほとんどのエディションで利用可能。 杉村 勇馬 (記事一覧) 執行役員 CTO / クラウドソリューション部 部長 元警察官という経歴を持つ現 IT エンジニア。クラウド管理・運用やネットワークに知見。AWS 12資格、Google Cloud認定資格11資格。X (旧 Twitter) では Google Cloud や AWS のアップデート情報をつぶやいています。 Follow @y_sugi_it
アバター
G-gen の武井です。当記事では IAM Deny policies(拒否ポリシー)を使った予防的統制について解説します。 はじめに 当記事について 予防的統制 拒否ポリシー 拒否ポリシーの使い所 拒否ポリシーと組織のポリシーの違い 検証の概要 目的 前提 環境 必要な IAM ロール 拒否ポリシーでサポートされる権限 環境構築 ソースコード 実行結果 動作確認 拒否ポリシー設定前 拒否ポリシー設定後 関連記事 はじめに 当記事について 当記事では、 IAM Deny policies (以下、拒否ポリシー)で特定の操作を制限し、Google Cloud 環境に予防的統制を効かせる方法を解説します。 予防的統制 予防的統制とは、 リスク (意図しない操作、不正な操作) を未然に防ぐための統制 を意味します。 以下は Google Cloud における予防的統制の一例です。 使用するプロダクト 効果 拒否ポリシー (Cloud IAM) リソースに対する特定の操作を IAM パーミッション (権限) に基づき制限する 組織のポリシー (Resource Manager) リソースに対する特定の操作を 制約 (定義済みのアクション) に基づき制限する VPC Service Controls API へのアクセスをコンテキストベースのルールに基づき制限する 拒否ポリシー 拒否ポリシーは、 通常の IAM Policy よりも強い強制力で Google Cloud リソースへの操作を制限 します。 IAM ポリシーの評価フローでは、拒否ポリシー(明示的な Deny)が通常の IAM Policy(明示的な Allow)より先に評価され、優先的に適用されます。 そのため、拒否ポリシーが設定されている場合、IAM Policy を上回る強制力で当該操作を拒否します。 IAM におけるポリシーの評価フロー 拒否ポリシーの詳細は以下の記事で解説しています。 blog.g-gen.co.jp 拒否ポリシーの使い所 ポリシーの評価順は前述の通り、拒否ポリシー(明示的な Deny)が最も強い強制力を持ちます。 そのため、IAM による権限設計では、まずは拒否ポリシーを使わずに IAM Policy(明示的な Allow)で管理することを原則とし、 どうしても強い権限で拒否したい(権限にフタをしたい)場合に拒否ポリシーを使う という方針が望ましいと言えます。 拒否ポリシーは統制の度合いとしては強力なため、安易に使ってしまうと後から修正が難しくなる場合があるのでご注意ください。 拒否ポリシーと組織のポリシーの違い Google Cloud の予防的統制には、拒否ポリシーに似た仕組みとして 組織のポリシー (Resource Manager の1機能)があります。 前者は IAM パーミッション(権限) 、後者は 制約 と呼ばれる定義済みのアクションにもとづいて操作を制限するという点に違いがあります。 参考 : ロールのコンポーネント (権限) 参考 : 組織のポリシーの制約 検証の概要 目的 以下の要件にもとづき、組織リソースに対して拒否ポリシーを適用し、実際の動作を確認します。 組織のポリシー(制約)の作成・削除・更新 についてはすべてのプリンシパルで禁止にしつつ、Terraform が使用するサービスアカウント、ならびに管理者グループだけは例外(操作可能)としています。 # 拒否したい操作 拒否対象のプリンシパル 例外のプリンシパル 1 組織のポリシーの作成 すべて ・Terraform 用 サービスアカウント ・管理者グループ 2 組織のポリシーの削除 すべて ・Terraform 用 サービスアカウント ・管理者グループ 3 組織のポリシーの更新 すべて ・Terraform 用 サービスアカウント ・管理者グループ 前提 デモを実施するにあたり、以下の IAM Policy を設定しています。 # プリンシパル 付与した IAM ロール 付与したリソース (場所) 1 Terraform 用 サービスアカウント ・オーナー ・組織管理者 ・組織ポリシー管理者 ・拒否管理者 組織リソース 2 管理者グループ ・オーナー ・組織管理者 ・組織ポリシー管理者 ・拒否管理者 組織リソース 3 非管理者グループ ・組織ポリシー管理者 組織リソース 環境 拒否ポリシーの設定は Terraform で行います。 また、拒否ポリシー設定後は以下の条件で動作確認を行います。 # プリンシパル 操作 期待する動作 1 管理者グループ 組織のポリシーを作成 成功 2 非管理者グループ 組織のポリシーを削除 失敗 必要な IAM ロール 拒否ポリシーを管理する場合、組織レベルで 拒否管理者ロール(roles/iam.denyAdmin) が必要です。 今回のデモでは Terraform が使用するサービスアカウントに対し、組織レベルで上記ロールを付与しています。 参考 : 必要なロール 拒否ポリシーでサポートされる権限 拒否ポリシーでは一部の権限を指定することはできません。 拒否ポリシーにてサポートされる権限については以下をご確認ください。 参考 : Permissions supported in deny policies 環境構築 ソースコード 今回の検証では、Terraform で環境構築を実施します。使用した Terraform のソースコードは以下のとおりです。 $ tree . ├── env │ └── organization │ ├── backend.tf │ ├── locals.tf │ ├── main.tf │ └── versions.tf └── modules └── preventive_controls └── organization_deny_policies ├── main.tf ├── outputs.tf └── variables.tf # main.tf (modules) resource "google_iam_deny_policy" "default" { parent = urlencode ( "cloudresourcemanager.googleapis.com/organizations/$ { var.organization_id } " ) name = "dev-ggen-deny-policy-organization" display_name = "Dev G-gen Deny Policy Organization" # https://cloud.google.com/iam/docs/deny-permissions-support # 組織のポリシーの編集禁止 rules { description = "First rule" deny_rule { denied_principals = [ "principalSet://goog/public:all" ] denied_permissions = [ "orgpolicy.googleapis.com/policies.create" , "orgpolicy.googleapis.com/policies.delete" , "orgpolicy.googleapis.com/policies.update" , ] exception_principals = var.permitted_principals } } } # variables.tf variable "permitted_principals" { description = "List of principals that are exempt from the deny policy" type = list ( string ) } variable "organization_id" { description = "The ID of the organization to create resources in" type = string } # main.tf (env) module "organization_deny_policies" { source = "../../modules/preventive_controls/organization_deny_policies" organization_id = local.organization_id permitted_principals = local.permitted_principals } # locals.tf locals { organization_id = "1234567890" # https://cloud.google.com/iam/docs/principal-identifiers#v2 permitted_principals = [ "principal://iam.googleapis.com/projects/-/serviceAccounts/terraform-gha-sa@iam-demo-prj.iam.gserviceaccount.com" , "principalSet://goog/group/ggen-administrator-test@dev.g-gen.co.jp" , ] } 参考 : google_iam_deny_policy 参考 : プリンシパルID (IAM v2 API) 実行結果 terraform apply の実行結果は以下のとおりです。 Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # module.organization_deny_policies.google_iam_deny_policy.default will be created + resource "google_iam_deny_policy" "default" { + display_name = "Dev G-gen Deny Policy Organization" + etag = (known after apply) + id = (known after apply) + name = "dev-ggen-deny-policy-organization" + parent = "cloudresourcemanager.googleapis.com%2Forganizations%2F1234567890" + rules { + description = "First rule" + deny_rule { + denied_permissions = [ + "orgpolicy.googleapis.com/policies.create" , + "orgpolicy.googleapis.com/policies.delete" , + "orgpolicy.googleapis.com/policies.update" , ] + denied_principals = [ + "principalSet://goog/public:all" , ] + exception_principals = [ + "principal://iam.googleapis.com/projects/-/serviceAccounts/terraform-gha-sa@iam-demo-prj.iam.gserviceaccount.com" , + "principalSet://goog/group/ggen-administrator-test@dev.g-gen.co.jp" , ] } } } Plan: 1 to add, 0 to change, 0 to destroy. module.organization_deny_policies.google_iam_deny_policy.default: Creating... module.organization_deny_policies.google_iam_deny_policy.default: Still creating... [ 10s elapsed ] module.organization_deny_policies.google_iam_deny_policy.default: Creation complete after 11s [ id=cloudresourcemanager.googleapis.com%2Forganizations%2F1234567890/dev-ggen-deny-policy-organization ] Apply complete! Resources: 1 added, 0 changed, 0 destroyed. Cloud コンソール上で表示される拒否ポリシーの詳細 動作確認 拒否ポリシー設定前 両グループとも IAM Policy によって組織のポリシーの編集が許可されているため、当該操作が実行できました。 #1、組織のポリシーが編集(作成)できた #2、組織のポリシーが編集(削除)できた 拒否ポリシー設定後 非管理者グループにおいては、拒否ポリシー設定前には実行できた操作が、設定後には制限されました。 # プリンシパル 操作 期待する動作 実際の結果 1 管理者グループ 組織のポリシーを作成 成功 成功 2 非管理者グループ 組織のポリシーを削除 失敗 失敗 #1、拒否ポリシー設定後も組織のポリシーが編集(作成)できた #2、拒否ポリシーによって組織のポリシーの編集(削除)が制限された 関連記事 今回ご紹介した他にも、G-gen Tech Blog では予防的統制に関する記事を多数公開しています。これらもあわせてご確認ください。 blog.g-gen.co.jp blog.g-gen.co.jp blog.g-gen.co.jp 武井 祐介 (記事一覧) クラウドソリューション部所属。G-gen唯一の山梨県在住エンジニア Google Cloud Partner Top Engineer 2025 選出。IaC や CI/CD 周りのサービスやプロダクトが興味分野です。 趣味はロードバイク、ロードレースやサッカー観戦です。 Follow @ggenyutakei
アバター
2024年11月25日、Google Cloud から管理者宛てに「 [Action Required] Ensure read access on container images deployed to Cloud Run 」というタイトルのメール通知がありました。当記事では、通知の内容とユーザー側で必要なアクション、影響範囲の確認方法などを解説します。 通知の内容 変更の適用前(2025年1月15日以前) 変更の適用後(2025年1月15日以降) ユーザー側で必要なアクション 想定される影響範囲 影響範囲の確認方法 通知メール Cloud Asset Inventory Cloud Logging Cloud Run functions への影響 対処していない場合に発生するエラーの例 通知の内容 Cloud Run のデプロイに使用することができる事前定義の IAM ロール「 Cloud Run 管理者 ( roles/run.admin )」および「 Cloud Run デベロッパー ( roles/run.developer )」には、 暗黙的に Artifact Registory の読み取り権限がついています。 Cloud Run 管理者や Cloud Run デベロッパーには Artifact Registry の読み取り権限が「明示的には」付与されていない 2025年1月15日(米国時間)以降 、この暗黙的な読み取り権限がなくなり、 Cloud Run 管理者 ロールと Cloud Run デベロッパー ロールでは Artifact Registry にあるコンテナイメージの読み取りができなくなります。したがって、このロールだけでは Cloud Run の作成、更新ができなくなります。 今後、Cloud Run の作成、更新を行うプリンシパル(ユーザー、サービスアカウント)は、コンテナイメージに対する明示的な読み取り権限が必要となります。具体的には、コンテナイメージが存在する Artifact Registry リポジトリ、もしくはプロジェクトに対する Artifact Registry 読み取り ( roles/artifactregistry.reader )ロールが必要となります。 以下に、変更の適用前・適用後の状況を要約します。 変更の適用前(2025年1月15日以前) 暗黙的な権限により、 Cloud Run 管理者 または Cloud Run デベロッパー ロールを紐づけられたプリンシパルは Artifact Registry にあるコンテナイメージを読み取ることができる。 変更の適用後(2025年1月15日以降) Cloud Run 管理者 ロールおよび Cloud Run デベロッパー ロールでは Artifact Registry にあるコンテナイメージを読み取ることはできない。そのため Cloud Run の作成、更新操作ができない。 今まで Cloud Run のデプロイに Cloud Run 管理者 または Cloud Run デベロッパー ロールを使用していたプリンシパルには、 Artifact Registry 読み取り ロールも紐づける必要がある。 オーナー ( roles/owner )ロール、または 編集者 ( roles/editor )ロールが紐づいているプリンシパルについては、この変更による影響はない。 ユーザー側で必要なアクション 2025年1月15日 までに、 Cloud Run 管理者 または Cloud Run デベロッパー ロールが紐づけられたプリンシパルを洗い出し、必要に応じて Artifact Registry 読み取り ロールを付与する必要があります。 想定される影響範囲 Cloud Build や GitHub Actions 等の CI/CD パイプラインから Cloud Run のデプロイを行っているようなケースでは、パイプラインが使用するサービスアカウントに Cloud Run 管理者 もしくは Cloud Run デベロッパー ロールが付与されている可能性があります。 今回の変更への対処が漏れてしまった場合、パイプラインが停止してしまう恐れがあるため、現在サービスアカウントに紐づけられているロールを確認し、権限が不足している場合は Artifact Registry 読み取り ロール等を付与する必要があります。 影響範囲の確認方法 通知メール 変更の影響を受ける可能性がある組織やプロジェクトのオーナーや、エッセンシャルコンタクトに登録された連絡先には、2024年11月25日に Google Cloud から [Action Required] Ensure read access on container images deployed to Cloud Run というタイトルのメールが配信されています。 変更の影響があるプロジェクトは、同メール最下部の「 Your affected projects are listed below: 」以下に記載されています。 変更の影響があるプロジェクトはメールに記載されている エッセンシャルコンタクトについては以下の記事を参照してください。 参考 : Google Cloudの組織(Organization)を徹底解説 - エッセンシャルコンタクト Cloud Asset Inventory また、Cloud Asset Inventory を使用することで、特定のロールが紐づいたプリンシパルの一覧を確認できます。 Google Cloud コンソールから確認する場合、たとえば Cloud Run デベロッパー ロールであれば、Cloud Asset Inventory の画面の IAM ポリシー タブにて roles: run.developer でフィルタリングします。プロジェクトに対してロールが紐づけられているプリンシパルと、特定の Cloud Run リソースにロールが紐づけられているプリンシパルの両方を検索することができます。 Cloud Run 管理者 ロールについては roles: run.admin でフィルタリングすることができます。 Asset Inventory を使用して、対処が必要なプリンシパルを確認する gcloud CLI では gcloud asset search-all-iam-policies コマンドで確認できます。 # Cloud Run デベロッパーロールが付与されたプリンシパルの一覧を表示する $ gcloud asset search-all-iam-policies --query =' roles:run.developer ' # 出力例 $ gcloud asset search-all-iam-policies --query =' roles:run.developer ' --- assetType: run.googleapis.com/Service # ロールが特定の Cloud Run に紐付いている場合 folders: - folders/xxxxxxxxxxxx - folders/xxxxxxxxxxxx organization: organizations/xxxxxxxxxxxx policy: bindings: - members: - serviceAccount:my-sa@myproject.iam.gserviceaccount.com role: roles/run.developer project: projects/xxxxxxxxxxxx resource: //run.googleapis.com/projects/myproject/locations/asia-northeast1/services/hello --- assetType: cloudresourcemanager.googleapis.com/Project # ロールがプロジェクトに紐付いている場合 folders: - folders/xxxxxxxxxxxx - folders/xxxxxxxxxxxx organization: organizations/xxxxxxxxxxxx policy: bindings: - members: - serviceAccount:xxxxxxxxxxxx-compute@developer.gserviceaccount.com role: roles/run.developer project: projects/xxxxxxxxxxxx resource: //cloudresourcemanager.googleapis.com/projects/myproject Cloud Asset Inventory については、以下の記事も参考にしてください。 参考 : Cloud Asset Inventoryを徹底解説! Cloud Logging 2025年1月15日の変更が適用されるまでは、該当のロールを使用して Cloud Run のデプロイが可能ですが、Cloud Logging に以下のエラーログが記録されるようになっています。 Cloud Run API check failed. Requests will be rejected after January 2025 hard enforcement deadline. User does not have access to image {Artifact Registry 内のコンテナイメージの URL} Cloud Logging にて以下のクエリを実行することで、当該ログを検索することができます。 resource . type = " cloud_run_revision " severity=ERROR " User does not have access to image " 変更の適用前もデプロイは可能だが、エラーログが記録される ログが出ている場合、対処が必要なプリンシパルを使用してデプロイが行われているので、 Artifact Registry 読み取り ロール等の付与を行います。 上記のクエリを使用してログベースのアラートを設定しておくことで、対象のログの確認漏れを防ぐことができます。 ログベースのアラートについては、以下の記事を参考にしてください。 参考 : Cloud Loggingの概念と仕組みをしっかり解説 - ログベースのアラート Cloud Run functions への影響 Cloud Run functions(第2世代)は、実行基盤として Cloud Run がベースになっています。Cloud Run functions に、今回の変更は影響があるのでしょうか。 今回の変更について、Cloud Run functions への影響はありません。Cloud Run functions のデプロイ時は、サービスエージェントと呼ばれる特殊なサービスアカウントが、ビルドや Artifact Registry からのイメージ取得を行います。これらのアカウントにデフォルトで付与されているロールを変更しなければ、今回の変更では影響がないようになっています。 Cloud Run functions のデプロイの仕組みに関する詳細は、以下のドキュメントに記載されています。 参考 : 管理者サービス アカウント 対処していない場合に発生するエラーの例 たとえば、Cloud Run のデプロイを行っているサービスアカウントが、別プロジェクトにある Artifact Registry リポジトリの読み取り権限を持たない場合、監査ログに以下のようなエラーが記録されます。 "User must have permission to read the image, asia-northeast1-docker.pkg.dev/<プロジェクトID>/<リポジトリ名>/<イメージ名>:latest. Ensure that the provided container image URL is correct and that the above account has permission to access the image. If you just enabled the Cloud Run API, the permissions might take a few minutes to propagate. Note that the image is from project [<プロジェクトID>], which is not the same as this project [<サービスアカウントがあるプロジェクトのID>]. Permission must be granted to the User from this project. See https://cloud.google.com/run/docs/deploying#other-projects \n Cause: 403 Forbidden\nGET https://asia-northeast1-docker.pkg.dev/v2/ プロジェクトID>/<リポジトリ名>/<イメージ名>/manifests/latest\n{\"errors\":[{\"code\":\"DENIED\",\"message\":\"Permission \\"artifactregistry.repositories.downloadArtifacts\\" denied on resource \\"projects/<プロジェクトID>/locations/asia-northeast1/repositories/<リポジトリ名>\\" (or it may not exist)\"}]}\n" 佐々木 駿太 (記事一覧) G-gen最北端、北海道在住のクラウドソリューション部エンジニア 2022年6月にG-genにジョイン。Google Cloud Partner Top Engineer 2025 Fellowに選出。好きなGoogle CloudプロダクトはCloud Run。 趣味はコーヒー、小説(SF、ミステリ)、カラオケなど。 Follow @sasashun0805
アバター
G-gen の又吉です。当記事では、生成 AI の出力を迅速かつ効率的に評価できる Vertex AI 上の API である、 Gen AI evaluation service を紹介します。 概要 ユースケース 評価指標について 評価タイプ 計算ベース モデルベース 料金 使ってみる 概要 準備 実行と結果 その他 クォータの制限について 評価データセットの件数 概要 Gen AI evaluation service は、生成 AI アプリケーションの出力を効率的に評価するための機能です。Vertex AI の1機能として、API で提供されます。この機能を使うと、事前定義された評価指標や、ユーザーが独自に定義したカスタム評価指標を用いて、生成 AI アプリケーションのパフォーマンスを 定量的に評価 できます。 同様の LLM 評価ツールとしては、オープンソースのフレームワークである Ragas などがありますが、Gen AI evaluation service は Vertex AI とシームレスに統合されている 点と、 マネージドサービスでありインフラの管理が不要な点 がメリットです。一方で、Ragas に比べ評価指標テンプレートが少ない点や、少額ではありますが API 利用料金が発生するといったデメリットがあります。 参考 : Gen AI evaluation service overview ユースケース Gen AI Evaluation Service は、以下のようなユースケースで役立ちます。 生成 AI モデルの選定 最適なモデルパラメータを探索 プロンプトエンジニアリングの調整 ファインチューニングの評価 RAG(Retrieval Augmented Generation)の評価 Function calling の評価 以下の公式ドキュメントでは、ユースケース別のサンプル Notebook が公開されており、参考にすることができます。 参考 : Notebooks for evaluation use cases 評価指標について 評価タイプ Gen AI evaluation service には、 計算ベース (Computation-based)と モデルベース (Model-based)の 2 種類の評価タイプがあります。 計算ベースの評価は、正解データとの比較に基づいてスコアを算出します。処理速度が速いため、リアルタイム評価にも適しています。代表的な指標として、自然言語処理で広く使われる BLEU や ROUGE などがあります。 しかし、LLM の出力評価では、そもそも「正解データ」を準備することが難しい場合があります。これは、LLM の出力に対して単一の正解を定めにくいためです。このため、多くの場合、人間の判断による評価が行われますが、スケールするにつれて手間が増加するという課題もあります。こうした背景から、現在ではモデルベースの評価が注目されています。 モデルベースの評価は、LLM 自体を判定モデルとして用い、人間による評価に近い形で評価します。正解データを必須とせず、「流暢さ」や「一貫性」といった複雑な基準での評価が可能で、プロンプトの調整により柔軟な評価基準を設定できます。 評価タイプ 評価アプローチ 正解データ(Ground truth) レイテンシ 計算ベース 数式を用いて評価する 必須 早い モデルベース 判定モデル (LLM) に評価させる 任意 遅い 計算ベース 計算ベースの評価指標は、候補モデル(評価対象の LLM)の出力が正解データにどれだけ一致しているかを数値化します。以下はテキスト生成向けの評価指標です。 評価指標 説明 適するユースケース Exact match 候補モデルの出力が正解データと完全一致する場合は「1」、しない場合は「0」を出力 QA や分類タスク BLEU 候補モデルの出力と正解データの n-gram の一致度を算出。出力は [0 ~ 1] の範囲で、スコアが高いほど生成テキストが正解に近いことを示す。 翻訳タスク ROUGE 候補モデルの出力と正解データの n-gram の F1-score を算出。出力は [0 ~ 1] の範囲で、スコアが高いほど内容が類似していることを示す。 要約タスク その他、Function Calling 向けの評価指標などもあります。詳細は以下の公式ドキュメントをご参照ください。 参考 : Computation-based metrics モデルベース モデルベースの評価指標では、LLM が判定モデルとして機能し、候補モデルの出力を評価します。この手法は一般的に、 LLM-as-a-Judge とも呼ばれます。 評価方式には、単一の出力に対する Pointwise と、複数の出力の比較を行う Pairwise があります。 方式 説明 ユースケース Pointwise 単一の候補モデルの出力にスコアを付与 運用段階での継続的なモニタリング Pairwise 2 つの候補モデルの出力を比較し、より適切な方を選択 モデル選定やプロンプト比較 また、Gen AI evaluation service には、様々なタスクに合わせた事前定義済みのプロンプトテンプレートが用意されています。 テキスト生成 マルチターン会話形式 要約 QA 品質 Pointwise ・ Fluency ・ Groundedness など ・ Multi-turn Chat Quality ・ Multi-turn Safety ・ Summarization Quality ・ Question Answering Quality Pairwise ・ Fluency ・ Groundedness など ・ Multi-turn Chat Quality ・ Multi-turn Safety ・ Summarization Quality ・ Question Answering Quality これらのテンプレートは更新される可能性があるため、最新情報は以下の公式ドキュメントをご参照ください。 参考 : Metric prompt templates for model-based evaluation 料金 Gen AI Evaluation Serviceの料金は、入出力の文字数と評価タイプに基づいて計算されます。 評価タイプ 価格 モデルベース (Pointwise, Pairwise) 入力: $0.005 per 1k characters 出力: $0.015 per 1k characters 計算ベース 入力: $0.00003 per 1k characters 出力: $0.00009 per 1k characters 参考 : Vertex AI Pricing - Gen AI Evaluation Service 使ってみる 概要 ここでは、RAG システムで生成された回答の精度を評価する例を紹介します。 構成図 また、筆者の実行環境としては Colab Enterprise を使用します。Colab Enterprise の利用方法は以下の公式ドキュメントのクイックスタートをご参考下さい。 参考 : Create a notebook by using the Google Cloud console 準備 1. ライブラリのインストール !pip install google-cloud-aiplatform[evaluation]== 1.71 . 0 2. Vertex AI インスタンスの初期化 import vertexai from vertexai.evaluation import EvalTask, MetricPromptTemplateExamples, PointwiseMetric import pandas as pd PROJECT_ID = "" # @param {type:"string"} LOCATION = "" # @param {type:"string"} EXPERIMENT = "" # @param {type:"string"} vertexai.init( project=PROJECT_ID, location=LOCATION ) 3. 事前定義済み評価指標テンプレートの確認 MetricPromptTemplateExamples.list_example_metric_names() 出力は以下の通りです。 ['coherence', 'fluency', 'safety', 'groundedness', 'instruction_following', 'verbosity', 'text_quality', 'summarization_quality', 'question_answering_quality', 'multi_turn_chat_quality', 'multi_turn_safety', 'pairwise_coherence', 'pairwise_fluency', 'pairwise_safety', 'pairwise_groundedness', 'pairwise_instruction_following', 'pairwise_verbosity', 'pairwise_text_quality', 'pairwise_summarization_quality', 'pairwise_question_answering_quality', 'pairwise_multi_turn_chat_quality', 'pairwise_multi_turn_safety'] 4. question_answering_quality テンプレートの内容を確認 # プロンプトテンプレートの中身を表示 print (MetricPromptTemplateExamples.get_prompt_template( "question_answering_quality" )) 出力は以下の通りです。 question_answering_quality テンプレートの評価基準は、RAG アーキテクチャを使ったアプリケーションの評価にも使えそうであるため、今回はこのテンプレートをそのまま利用します。 # Instruction You are an expert evaluator. Your task is to evaluate the quality of the responses generated by AI models. We will provide you with the user input and an AI-generated response. You should first read the user input carefully for analyzing the task, and then evaluate the quality of the responses based on the Criteria provided in the Evaluation section below. You will assign the response a rating following the Rating Rubric and Evaluation Steps. Give step-by-step explanations for your rating, and only choose ratings from the Rating Rubric. # Evaluation ## Metric Definition You will be assessing question answering quality, which measures the overall quality of the answer to the question in user input. The instruction for performing a question-answering task is provided in the user prompt. ## Criteria Instruction following: The response demonstrates a clear understanding of the question answering task instructions, satisfying all of the instruction's requirements. Groundedness: The response contains information included only in the context if the context is present in user prompt. The response does not reference any outside information. Completeness: The response completely answers the question with sufficient detail. Fluent: The response is well-organized and easy to read. ## Rating Rubric 5: (Very good). The answer follows instructions, is grounded, complete, and fluent. 4: (Good). The answer follows instructions, is grounded, complete, but is not very fluent. 3: (Ok). The answer mostly follows instructions, is grounded, answers the question partially and is not very fluent. 2: (Bad). The answer does not follow the instructions very well, is incomplete or not fully grounded. 1: (Very bad). The answer does not follow the instructions, is wrong and not grounded. ## Evaluation Steps STEP 1: Assess the response in aspects of instruction following, groundedness, completeness and fluency according to the criteria. STEP 2: Score based on the rubric. # User Inputs and AI-generated Response ## User Inputs ### Prompt {prompt} ## AI-generated Response {response} 5. カスタム評価指標 helpfulness の定義 # カスタムテンプレートを作成 helpfulness_prompt_template = """ You are a professional writing evaluator. Your job is to score writing responses according to pre-defined evaluation criteria. You will be assessing helpfulness, which measures the ability to provide important details when answering a prompt. You will assign the writing response a score from 5, 4, 3, 2, 1, following the rating rubric and evaluation steps. ## Criteria Helpfulness: The response is comprehensive with well-defined key details. The user would feel very satisfied with the content in a good response. ## Rating Rubric 5 (completely helpful): Response is useful and very comprehensive with well-defined key details to address the needs in the instruction and usually beyond what explicitly asked. The user would feel very satisfied with the content in the response. 4 (mostly helpful): Response is very relevant to the instruction, providing clearly defined information that addresses the instruction's core needs. It may include additional insights that go slightly beyond the immediate instruction. The user would feel quite satisfied with the content in the response. 3 (somewhat helpful): Response is relevant to the instruction and provides some useful content, but could be more relevant, well-defined, comprehensive, and/or detailed. The user would feel somewhat satisfied with the content in the response. 2 (somewhat unhelpful): Response is minimally relevant to the instruction and may provide some vaguely useful information, but it lacks clarity and detail. It might contain minor inaccuracies. The user would feel only slightly satisfied with the content in the response. 1 (unhelpful): Response is useless/irrelevant, contains inaccurate/deceptive/misleading information, and/or contains harmful/offensive content. The user would feel not at all satisfied with the content in the response. ## Evaluation Steps STEP 1: Assess comprehensiveness: does the response provide specific, comprehensive, and clearly defined information for the user needs expressed in the instruction? STEP 2: Assess relevance: When appropriate for the instruction, does the response exceed the instruction by providing relevant details and related information to contextualize content and help the user better understand the response. STEP 3: Assess accuracy: Is the response free of inaccurate, deceptive, or misleading information? STEP 4: Assess safety: Is the response free of harmful or offensive content? Give step by step explanations for your scoring, and only choose scores from 5, 4, 3, 2, 1. # User Inputs and AI-generated Response ## User Inputs ### Prompt {prompt} ## AI-generated Response {response} """ # カスタム評価指標を定義 helpfulness = PointwiseMetric( metric= "helpfulness" , metric_prompt_template=helpfulness_prompt_template, ) 6. サンプルデータの定義 今回利用する以下のサンプルデータは以下のとおりです。 questions :ユーザーの質問 retrieved_contexts :コンテキストとなる検索結果 generated_answers :LLM の出力 golden_answers :正解データ questions = [ "富士山はどこの県に位置していますか?" , "東京タワーはどの区に位置していますか?" , "沖縄の主要な伝統料理は何ですか?" , "沖縄の伝統舞踊で有名なものは何ですか?" ] retrieved_contexts = [ "富士山は、静岡県と山梨県にまたがって位置しています。標高3,776メートルのこの山は、日本の最高峰であり、象徴的な自然のシンボルとして親しまれています。" , "東京タワーは、東京都港区に位置しており、1958年に建てられた高さ333メートルの電波塔です。東京のシンボルとして、観光名所となっています。" , "日本の主要な伝統料理には、寿司や天ぷらがあります。また、天ぷらは沖縄でもソウルフードとなっています" , "沖縄の伝統舞踊には、エイサーがあり、太鼓のリズムに合わせて踊られるもので、祭りなどで広く披露されています。" ] generated_answers = [ "静岡県" , "港区" , "天ぷら" , "エイサー" ] golden_answers = [ "静岡県と山梨県" , "港区" , "ゴーヤーチャンプルー、ソーキそば" , "エイサー" , ] 7. 評価データセットの作成 各評価指標の入力に必要なカラム名は以下の通りです。 評価指標 評価タイプ 必要なカラム名 question_answering_quality モデルベース(Pontwise) ・prompt ・response helpfulness モデルベース(Pontwise) ・prompt ・response exact_match 計算ベース ・response ・reference 必要なカラム名に沿って評価データセットを作成します。 # 評価データセットを作成 eval_dataset = pd.DataFrame( { "prompt" : [ "Answer the question: " + question + " Context: " + item for question, item in zip (questions, retrieved_contexts) ], "response" : generated_answers, # 候補モデルの出力 "reference" : golden_answers, # 正解データ } ) 実行と結果 8. 評価を実行 # 評価タスクを定義 eval_task = EvalTask( dataset=eval_dataset, metrics=[ "question_answering_quality" , # モデルベース(事前定義の評価指標) helpfulness, # モデルベース(ユーザー独自の評価指標) "exact_match" # 計算ベース ], experiment=EXPERIMENT, ) # 評価リクエストを実行 result = eval_task.evaluate() evaluate メソッドの戻り値は EvalResult クラスであり以下の属性を持っています。 属性名 説明 summary_metrics 各指標の平均値や標準偏差などのサマリ情報 metrics_table 評価結果の詳細情報 metadata 評価時の実験名などのメタデータ情報 9. 評価結果のサマリを出力 result.summary_metrics 出力は以下の通りです。 {'row_count': 4, 'question_answering_quality/mean': 4.0, 'question_answering_quality/std': 1.1547005383792515, 'helpfulness/mean': 3.0, 'helpfulness/std': 0.816496580927726, 'exact_match/mean': 0.5, 'exact_match/std': 0.5773502691896257} 10. 評価結果の詳細を出力 result.metrics_table 出力は以下の通りです。 文字が見えづらいため、 question_answering_quality 評価指標の最初のレコードのみを以下に記載します。 [ prompt ] Answer the question: 富士山はどこの県に位置していますか? Context: 富士山は、静岡県と山梨県にまたがって位置しています。標高3,776メートルのこの山は、日本の最高峰であり、象徴的な自然のシンボルとして親しまれています。 [ response ] 静岡県 [ reference ] 静岡県と山梨県 [ question_answering_quality/explanation ] The response is incomplete. Although grounded in the given context and fluent, it only mentioned one of the two prefectures where Mt. Fuji is located. The prompt asked "In which prefecture is Mt. Fuji located?" The context clearly stated it's located in both Shizuoka and Yamanashi prefectures. Therefore, the instruction following is weak. ~日本語に翻訳~ 回答は不完全です。与えられた文脈に基づいており流暢ではありますが、富士山がある 2 つの県のうちの 1 つしか言及されていません。プロンプトは「富士山はどの県にありますか?」と尋ねており、文脈から静岡県と山梨県の両方にあることは明らかです。したがって、指示に従うことが不十分です。 [ question_answering_quality/score ] 3.0 定量的なスコアが取得できていることが確認できました。 なお、モデルベースの評価指標の出力には explanation 列が含まれており、判定モデルがスコアを算出するために行った思考の過程が記録されています。つまり、explanation 列の内容が 判定モデルが出力したスコアの根拠 となります。 参考 : View and interpret evaluation results その他 クォータの制限について モデルベースの評価タイプでは、判定モデルに Vertex AI Gemini API が使用されるためクォータには注意が必要です。特に、1 度に大量の評価データセットを含める場合や、評価リクエストの同時実行数が高くなる場合は、 gemini-1.5-pro のクォータの制限緩和をご検討ください。 制限緩和の申請については、公式ドキュメントをご参照ください。 参考 : Run model-based evaluation with increased rate limits and quota 評価データセットの件数 高品質な評価結果を得るためには、評価データセットを 100〜400 件にすることが推奨されています。この範囲であれば、外れ値の影響を最小限に抑えつつ、さまざまなシナリオでのパフォーマンスが期待できます。また、400 件を超えると前述の改善効果が薄れる傾向があるため、一般的な目安として 400 件を上限とすることが推奨されます。 参考 : Best practices 又吉 佑樹 (記事一覧) クラウドソリューション部 はいさい、沖縄出身のクラウドエンジニア! セールスからエンジニアへ転身。Google Cloud 全 11 資格保有。Google Cloud Champion Innovator (AI/ML)。Google Cloud Partner Top Engineer 2024。Google Cloud 公式ユーザー会 Jagu'e'r でエバンジェリスト。好きな分野は生成 AI。 Follow @matayuuuu
アバター
G-gen の杉村です。Google Cloud(旧称 GCP)で、サービスアカウントから認証キーを作成しようとした際に サービス アカウント キーの作成が無効になっています 組織ポリシーの制約「iam.disableServiceAccountKeyCreation」が組織に適用されています。 と表示されてキーが作成できない場合の、対処法を紹介します。 事象とメッセージ 原因 対処する前に 対処方法 対処手順 IAM 権限の確認 組織、フォルダまたはプロジェクトを選択 組織のポリシー画面へ遷移 制約の編集画面へ遷移 制約を編集 結果の確認 事象とメッセージ Google Cloud(旧称 GCP)で、サービスアカウントから認証キーを作成しようとした際に、以下のメッセージが表示され、サービスアカウントキーが作成できませんでした。 サービス アカウント キーの作成が無効になっています サービス アカウント キーの作成が無効になっています 組織ポリシーの制約「iam.disableServiceAccountKeyCreation」が組織に適用されています。 考えられる原因: 組織ポリシー管理者が、サービス アカウント キーに関連するセキュリティ インシデントを防ぐために、この組織ポリシーを適用しました。また、 「デフォルトで保護」の適用 により、組織にポリシーが自動的に適用された可能性もあります。 推奨される次のステップ: サービス アカウント キーは、適切に管理しなかった場合、セキュリティ リスクとなります。可能であれば、 より安全な代替手段 を選択してください。サービス アカウント キーで認証する必要がある場合は、 組織の「組織ポリシー管理者」(roles/orgpolicy.policyAdmin)のロールを持つ管理者が 「iam.disableServiceAccountKeyCreation」の制約を 無効にする 必要があります。 追跡番号: (英数字) コンソールが英語版の場合、以下のようなメッセージです。 Service account key creation is disabled Service account key creation is disabled The organization policy constraint 'iam.disableServiceAccountKeyCreation' is enforced on your organization. Possible Causes: Your Organization Policy Administrator enforced the Organization Policy to prevent security incidents related to Service Account keys. Alternatively, your organization may have been automatically enforced with the policy as part of Secure by Default enforcements. Recommended Next Steps: Service account keys are a security risk if not managed correctly. You should choose a more secure alternative whenever possible. If you must authenticate with a service account key, an administrator with the "Organization Policy Administrator" (roles/orgpolicy.policyAdmin) role on the organization needs to disable the "iam.disableServiceAccountKeyCreation" constraint. Tracking number: (alphanumeric characters) 原因 この事象は、組織ポリシーの制約 iam.disableServiceAccountKeyCreation が組織レベル、フォルダレベルまたはプロジェクトレベルで有効化されているときに発生します。 組織のポリシー は、セキュリティや統制の向上のために、所定のルールを Google Cloud 環境全体に適用する仕組みのことです。組織のポリシーの詳細は、以下の記事を参照してください。 blog.g-gen.co.jp iam.disableServiceAccountKeyCreation は、サービスアカウントキーの作成を禁止する制約です。この制約は、2024年初頭以降に作成された Google Cloud 組織では デフォルトで有効化 されています。それ以前に作成された組織でも、管理者が明示的にこの制約を有効化している場合は、この事象が発生します。 参考 : サービス アカウント キー作成の無効化 対処する前に サービスアカウントキーは JSON フォーマットのテキストファイル(もしくは P12 形式のファイル)であり、流出の危険があります。そのため一般的には サービスアカウントキーの使用は非推奨 であり、代わりにプログラム動作基盤(Compute Engine VM や Cloud Run Service)にサービスアカウントをアタッチしたり、動作基盤が Google Cloud 以外なのであれば Workload Identity や Workforce Identity の使用が推奨されます。 2024年初頭以降に作成された Google Cloud 組織で iam.disableServiceAccountKeyCreation がデフォルトで有効化されているのは、リスクの高い手法であるサービスアカウントキーの使用を抑止するためです。 このエラーを解消する最も簡単な方法は、 iam.disableServiceAccountKeyCreation 制約を無効化することですが、無効化を行う前に、 本当にサービスアカウントキーを生成する必要があるのか 、代わりにサービスアカウントのアタッチや Workload Identity で 代用できないか を、十分ご検討ください。 なお Workload Identity とは、OIDC や SAML 2.0 を利用して、Amazon Web Services(AWS)や Microsoft Azure、Active Directory Federation Service 等の ID を使って Google Cloud に認証する仕組みです。 参考 : サービス アカウント キーから移行する 参考 : Workload Identity 連携 参考 : Workforce Identity の連携 対処方法 組織ポリシーの制約 iam.disableServiceAccountKeyCreation を無効化することで、サービスアカウントキーが作成できるようになります。 組織ポリシーの制約は、組織レベル、フォルダレベル、プロジェクトレベルで適用することができ、親リソースのポリシーは子リソースに 継承 されます。ただし、明示的に設定することで、子リソース側で親リソースの制約をオーバーライド(上書き)することも可能です。 よって、取り得る選択肢としては、以下のいずれかになります。 iam.disableServiceAccountKeyCreation を組織レベルで無効化する iam.disableServiceAccountKeyCreation をフォルダレベルでオーバーライドして無効化する iam.disableServiceAccountKeyCreation をプロジェクトレベルでオーバーライドして無効化する 上記のうち 1. 、 2. の場合、組織全体もしくはフォルダ全体で制約が無効になり、影響は他のプロジェクトにも及びます。 3. の影響範囲は当該プロジェクトのみです。 これ以降、当記事では当該制約を無効化する手順を解説しますが、前掲の「対処する前に」をお読みいただき、 リスクを理解したうえで実施 してください。 対処手順 IAM 権限の確認 当手順を実施するには、操作する Google アカウント、もしくはアカウントが所属するグループが、 組織レベル で 組織ポリシー管理者 ( roles/orgpolicy.policyAdmin )ロールを持っている必要があります。 組織ポリシー管理者を付与できる最も下位レベルのリソースは「組織」です。よって、フォルダやプロジェクトレベルで制約をオーバーライドする場合でも、組織レベルで組織ポリシー管理者ロールを持っている必要があります。 作業者の Google アカウントが必要な権限を持っていない場合は、組織レベルで IAM ロール「組織ポリシー管理者」を付与してください。 参考 : IAM を使用した組織リソースのアクセス制御 組織、フォルダまたはプロジェクトを選択 Google Cloud コンソールにログインし、プロジェクトセレクターをクリックして、制約を無効化を適用する組織、フォルダ、またはプロジェクトを選択します。 当記事の「対処する前に」「対処方法」をよくお読みになり、制約の編集位置を決めたうえで選択してください。 組織のポリシー画面へ遷移 コンソール上部の検索ボックスに「組織のポリシー」を入力し、サジェストされた「組織のポリシー」を選択します。 または、「IAM と管理」画面から直接遷移しても構いません。 制約の編集画面へ遷移 制約一覧の上部のフィルタに constraints/iam.disableServiceAccountKeyCreation を入力します。 フィルタ結果の中から、Disable service account key creation をクリックして、編集画面へ遷移します。 制約を編集 ボタン「ポリシーを管理」を押下します。 「ポリシーのソース」ブロックで、「親のポリシーをオーバーライドする」を選択します。「ルール」ブロックが表示されるので、「ルールの追加」を押下し、「適用」を「オフ」にします。最後に、ボタン「ポリシーを設定」を押下します。 結果の確認 設定が完了すると、以下のような表示になります。 杉村 勇馬 (記事一覧) 執行役員 CTO / クラウドソリューション部 部長 元警察官という経歴を持つ現 IT エンジニア。クラウド管理・運用やネットワークに知見。AWS 12資格、Google Cloud認定資格11資格。X (旧 Twitter) では Google Cloud や AWS のアップデート情報をつぶやいています。 Follow @y_sugi_it
アバター
Google Cloud の組織ポリシー機能で、プロジェクトにタグを適用することで例外設定を行う方法を検証しました。 はじめに 当記事について 前提知識 検証 タグキーと値の作成 フォルダとプロジェクトの作成 ポリシーの適用 補足情報 条件の指定について Terraform はじめに 当記事について Google Cloud(旧称 GCP)では 組織のポリシー を使って、組織内のプロジェクトに一律でセキュリティや統制強化のための設定を適用できます。このとき、特定のプロジェクトにのみ 例外 を設けたい場合もあります。 例えば、組織全体に「公開アクセスの防止を適用する( constraints/storage.publicAccessPrevention )」という組織のポリシーの制約を適用しているとします。しかし、あるプロジェクトでは Cloud Storage の公開バケットに静的コンテンツをホスティングしているとします。このときは、当該プロジェクトのみを制約の適用外にする必要があります。 当記事ではそのような場合を想定して、タグを使って特定のプロジェクトは制約の対象外としつつ、その他全ての組織内プロジェクトに制約を適用する検証を行いました。 参考 : タグを使用した組織のポリシーの設定 前提知識 当記事では Resource Manager の タグ 機能を利用します。タグの詳細や、類似機能であるラベルとの差異については、以下の記事を参照してください。 blog.g-gen.co.jp 組織のポリシー機能については、以下の記事を参照してください。特に、継承と呼ばれる性質については理解が必要です。 blog.g-gen.co.jp 検証 タグキーと値の作成 まず、組織のリソースとして、「IAM と管理」画面から タグキー を作成します。今回は apply-policy という名称で作成します。 タグキー作成 次に、タグキーの値として、 true と false を作成します。今回の検証ではこの値を使っていますが、必ずしもブール値である必要はなく、運用上都合の良い文字列を指定して構いません。 タグの値作成 フォルダとプロジェクトの作成 以下のようにフォルダとプロジェクトを作成します。 フォルダに属さないプロジェクト test-20241028-true test-20241028-false test-20241028-none フォルダ my_folder 同フォルダ配下の、以下のプロジェクト test-20241028-true-in-folder test-20241028-false-in-folder test-20241028-none-in-folder タグ apply-policy: true を、プロジェクト test-20241028-true と test-20241028-true-in-folder に付与します。 タグ apply-policy: false を、プロジェクト test-20241028-false と test-20241028-false-in-folder に付与します。 さらに、タグ apply-policy: false を、フォルダ my_folder に付与します。 プロジェクトの作成・タグの付与 フォルダにタグを付与した場合、そのフォルダに属するプロジェクトには タグが継承 されます。ただし、プロジェクトにタグが直接付与されている場合、そちらが 優先 されます。上記のスクリーンショットでは、プロジェクト test-20241028-none-in-folder の Tags 列に継承を表すアイコンが表示されており、フォルダから継承されたタグが適用されていることがわかります。 ポリシーの適用 この組織に対して、組織レベルで制約を適用します。今回適用する制約は「公開アクセスの防止を適用する( constraints/storage.publicAccessPrevention )」です。組織レベルにこの制約を適用しつつ、タグ apply-policy: false が付与されたプロジェクトではこの制約の効果が発揮されない状態を目指します。 組織のポリシーの Google Cloud コンソール画面で上記の制約を検索し、編集します。この時、設定値として、「親のポリシーをオーバーライドする」を選択します。編集画面では、2つのルールを追加します。 1つ目は、特定のタグキーと値を持っていることを条件に、「適用」を「オフ」とするものです。設定値「値のパス」は、 [organization_name]/apply-policy/false とします。タグを作成済みの場合、プルダウンメニューから選択できます。 ポリシーの編集 値のパス 2つ目は、1つ目のルールの条件に合致しない場合に適用される、デフォルトのルールです。「ルールの追加」を押下し、「適用」のラジオボタンで「オン」を選択します。これを設定しない場合、 A boolean policy must always include one unconditional rule. というメッセージが表示され、ポリシーの設定が完了しません。 組織レベルでポリシーが適用された場合、コンソール画面の表記は以下のようになります。 適用された組織ポリシー ポリシーの適用後、各プロジェクトのポリシー適用状態は以下のようになります。 プロジェクト ○:適用済み、×:未適用 test-20241028-true ○ test-20241028-false × test-20241028-none ○ test-20241028-true-in-folder ○ test-20241028-false-in-folder × test-20241028-none-in-folder × 以下は、各プロジェクトレベルでポリシーの適用状態を確認した際のキャプチャです。想定したとおりに、ポリシーが適用されていることがわかります。 test-20241028-true test-20241028-false test-20241028-none test-20241028-true-in-folder test-20241028-false-in-folder test-20241028-none-in-folder 以上の検証結果から、以下のことが確かめられました。 明示的にタグを付与したプロジェクトには、ポリシーが適用されない 親フォルダのタグを継承しているプロジェクトには、ポリシーが適用されない タグが付与されていないプロジェクトには、デフォルトルールに基づきポリシーが適用される 補足情報 条件の指定について 今回の検証では、ポリシーの除外対象とするプロジェクトをタグで指定しました。反対に、適用対象をタグで指定することも可能です。 また、今回の検証ではタグ名を使って指定する方法を紹介しましたが、他にタグの永続 ID(permanent ID。タグキーや値が持つリソース ID)で指定することもできます。 参考 : 永続 ID を使用する条件 Terraform 当検証で使用した組織レベルのリソースは、以下のように Terraform で記述することができます。なお以下のサンプルコード内の変数 organization_number_id は10~13桁の数字で表される組織 ID です。 resource "google_tags_tag_key" "apply_policy" { short_name = "apply-policy" parent = "organizations/$ { var.organization_number_id } " description = "The flag indicating whether to apply the policy or not." } resource "google_tags_tag_value" "apply_policy_true" { parent = "tagKeys/$ { google_tags_tag_key.apply_policy.name } " short_name = "true" description = "Apply organization policy to the project." } resource "google_tags_tag_value" "apply_policy_false" { parent = "tagKeys/$ { google_tags_tag_key.apply_policy.name } " short_name = "false" description = "Do NOT apply organization policy to the project." } resource "google_org_policy_policy" "storage_public_access_prevention" { name = "organizations/$ { var.organization_number_id } /storage.publicAccessPrevention" parent = "organizations/$ { var.organization_number_id } " spec { rules { enforce = "FALSE" condition { title = "Do NOT apply with the tag" description = "Do NOT apply storage.publicAccessPrevention on the projects tagged with apply-policy: false" expression = "resource.matchTag('$ { var.organization_number_id } /apply-policy', 'false')" } } rules { enforce = "TRUE" } } } G-genメンバー (記事一覧) クラウドソリューション部
アバター
G-gen の杉村です。Pub/Sub の Cloud Storage インポートトピック (Cloud Storage import topic)を使うと、事前に指定した Cloud Storage バケットに Put されたテキストオブジェクトを、ノーコードで Pub/Sub トピックにパブリッシュし、簡単に Pub/Sub サブスクリプションに配信できます。 前提知識 Cloud Storage インポートトピックとは 設定値 検証の概要 環境構築 サービスエージェントへ IAM 権限の付与(パブリッシュ) バケットの作成 トピックの作成 サービスエージェントへ IAM 権限の付与(バケット読み取り) BigQuery テーブルと BigQuery サブスクリプションの作成 トピックの状態を確認 動作確認 オブジェクトの Put テーブルの確認 追加検証(区切り文字の追加) 追加検証(メッセージ本文の確認) 前提知識 Cloud Storage インポートトピックとは Pub/Sub は、Google Cloud(旧称 GCP)のフルマネージドなメッセージングサービスです。Pub/Sub の意義や、実現できるアーキテクチャは以下の記事もご参照ください。 blog.g-gen.co.jp Pub/Sub の Cloud Storage インポートトピック (Cloud Storage import topic)を使うと、事前に指定した Cloud Storage バケットに Put されたテキストオブジェクトを、ノーコードで Pub/Sub トピックにパブリッシュし、簡単に Pub/Sub サブスクリプションに配信できます。 参考 : Create a Cloud Storage import topic この Cloud Storage インポートトピックを 使わない場合 は、Cloud Storage にオブジェクトが Put されたことを Eventarc で検知し、Cloud Run functions 等を起動、記述したプログラムで配信先に書き込むという処理の開発が必要になります。 一方で、当記事で紹介する Cloud Storage インポートトピックを使えば、Cloud Storage バケットに書き込まれたオブジェクトを読み取る プログラムを開発することなく 、自動的に Pub/Sub トピックにパブリッシュすることができます。 そのようにして Pub/Sub トピックにパブリッシュされたメッセージは、サブスクリプションを経由して、BigQuery に書き込んだり、他の API エンドポイントに Push することなどが可能です。 通常のトピックと Cloud Storage インポートトピックの違い 設定値 Cloud Storage インポートトピックには、以下のような設定値があります。 設定名 説明 取り込み元バケット データを取り込む Cloud Storage バケットを指定 オブジェクトの形式 Text、Avro、Pub/Sub Avro から選択 区切り文字 Text の場合のみ指定。この区切り文字に基づいてメッセージが分割される。1文字まで。省略すると \n (改行) 最短のオブジェクト作成時間 取り込み開始時刻。この時刻より前に作成されたオブジェクトは取り込まれない glob パターン ここで指定したパスパターンに一致するオブジェクトのみが取り込まれる。 ** で全オブジェクト。 **.txt で拡張子指定等 以下は、Google Cloud コンソールにおける設定画面のスクリーンショットです。 トピック作成画面 検証の概要 当記事では、以下の構成で検証を行います。 検証 1 上記の構成では、Cloud Storage インポートトピックによる自動的なメッセージ取り込みを行います。取り込んだメッセージは、BigQuery サブスクリプション経由で BigQuery テーブルに書き込みます。これによりソースコードを一切書くことなく、Cloud Storage に到着したテキストデータを順次、BigQuery に書き込むことが可能です。 Pub/Sub の BigQuery サブスクリプションの詳細は、以下の記事を参照してください。 blog.g-gen.co.jp さらに、追加検証として、メッセージ本文の構成を確かめるため、Pull サブスクリプションを作成して直接メッセージの内容を確認する検証も行います。 検証 2 環境構築 サービスエージェントへ IAM 権限の付与(パブリッシュ) Pub/Sub が利用するサービスエージェント(Google Cloud サービスが利用するサービスアカウントのこと)に、必要な IAM 権限を付与します。 サービスエージェント名は service-{PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com です。 {PROJECT_NUMBER} にはプロジェクト番号が入ります。このサービスエージェントに、プロジェクトレベルで Pub/Sub パブリッシャー( roles/pubsub.publisher )ロールを付与します。このロールは、サービスエージェントが Cloud Storage インポートトピックにデータをパブリッシュするのに必要になります。 参考 : Add the Pub/Sub publisher role to the Pub/Sub service account 参考 : サービスエージェントとは何か ‐ G-gen Tech Blog プロジェクトレベルの IAM バインディング一覧画面では、サービスエージェントに付与された IAM ロールは非表示になっています。以下のスクリーンショットのように「Google 提供のロール付与を含める」チェックボックスをオンにすると、IAM ロールが表示されます。 なお以下のスクリーンショットでは、デフォルトで付与されている「Cloud Pub/Sub サービス エージェント」、今回付与した「Pub/Sub パブリッシャー」に加えて「BigQuery データ編集者」が付与されていますが、これは今回の検証で BigQuery サブスクリプションを利用するためです。 プロジェクトの IAM 画面 バケットの作成 Cloud Storage バケットを作成します。今回は、以下のようなバケットを作成しました。 Cloud Storage バケットの作成 トピックの作成 Cloud Storage インポートトピックを作成します。 オブジェクトの形式は Text とし、区切り文字は空白とします。区切り文字を明示しない場合、 \n (改行)が区切り文字として認識されます。つまり、あるテキストファイルをバケットに Put した場合、 1行が1メッセージ として Pub/Sub トピックに取り込まれます。 Cloud Storage インポートトピックの作成 サービスエージェントへ IAM 権限の付与(バケット読み取り) このとき、Pub/Sub のサービスエージェント( service-{PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com )が対象バケットへの読み取り権限を持っていない場合、以下のようなメッセージが表示されます。 権限の確認と付与 「権限の設定」を押下すると、以下のような画面が表示され、「ロールの付与」をクリックすることで必要な IAM 権限を付与できます。 IAM 権限の付与 これを行うと、対象バケットのレベルで「Storage オブジェクト閲覧者」「Storage レガシー バケット読み取り」ロールが付与されます。以下のように、バケットの「権限」タブで付与された IAM ロールを確認できます。 バケットレベルの権限の確認 BigQuery テーブルと BigQuery サブスクリプションの作成 データ格納先の BigQuery テーブルを作成します。id 列と data 列を持つシンプルなテーブルを作成します。 BigQuery テーブル その後、Cloud Storage インポートトピックに紐づくサブスクリプションを「BigQuery サブスクリプション」タイプで作成します。 BigQuery サブスクリプションの作成 BigQuery サブスクリプションは、トピックが受け取ったメッセージを自動的に BigQuery に書き込んでくれます。今回は「スキーマを使用しない」に設定したので、メッセージは data という名称を持つ列に文字列として書き込まれます。 トピックの状態を確認 ここで、トピックの状態を確認します。作成した Cloud Storage インポートトピックの詳細画面で、トピックのステータスが以下のように緑色で表示されていれば、正しく設定が完了しています。 トピックが正しく設定されている状態 もし以下のように表示されていた場合、Pub/Sub のサービスエージェントがトピックへのパブリッシュ権限を持っていないことが考えられます。当記事の サービスエージェントへ IAM 権限の付与(パブリッシュ) に戻り、プロジェクトレベルで Pub/Sub パブリッシャー( roles/pubsub.publisher )ロールを付与してください。あるいは、トピックレベルでロールを付与することも可能です。 取り込みのリソースエラー: 権限の公開が拒否されました 取り込みのリソースエラー: 権限の公開が拒否されました 動作確認 オブジェクトの Put 動作確認のため、Cloud Storage バケットにオブジェクトを Put します。 今回は、以下のようなファイルを Put しました。改行で区切られた、2行のテキスト情報です。 test-file-01.txt This is the first message. This is the second message. オブジェクトの Put テーブルの確認 Put されたテキストファイル内のテキスト情報は、Cloud Storage インポートトピックに自動的に取り込まれ、BigQuery サブスクリプションによって、対象テーブルの data 列に書き込まれるはずです。 対象テーブルに SELECT 文を実行すると、想定どおり、2行のテキスト情報が書き込まれていました。オブジェクトの Put からテーブルに情報が書き込まれるまで、およそ1分程度のラグがありました。 BigQuery にテキストデータが格納された 追加検証(区切り文字の追加) 追加検証として、先程は省略したトピックの「区切り文字」の設定を追加してみます。 以下のように、区切り文字を , (カンマ)として設定します。 区切り文字をカンマに設定 その後、Cloud Storage バケットに次のファイルを Put します。半角スペースの扱いを確かめるため、3列目の文字列 3rd field の手前には、あえて半角スペースを入れています。 test-csv-02.csv 1st field,2nd field, 3rd field 結果は、以下のように想定どおり格納されました。カンマのあとの半角スペースも反映されており、 3rd field の手前には半角スペースが入っています。 カンマ区切りのデータが格納された 追加検証(メッセージ本文の確認) さらに追加検証として、Pull サブスクリプションを作成して、Cloud Storage インポートトピックから発行されるメッセージの本文を確認します。 以下のように、Pull サブスクリプションを作成します。 Pull サブスクリプションを作成 以下のファイルを Put します。 another 1st field,another 2nd field, another 3rd field その後、 gcloud pubsub subscriptions pull コマンドでサブスクリプションからメッセージを Pull します。 --limit オプションをつけずに実行すると、1個のメッセージのみが Pull されます。今回は --limit=10 を指定し、3つのメッセージが取得できることを確認します。 3つのメッセージが Pull できた 想定どおり、3つのメッセージが Pull できました。データ本文( data )は Base64 でエンコードされているため、 echo "${data}" | base64 --decode のようにしてデコードすると、内容が確認できます。 メッセージ本文は、以下のような形式であることがわかりました。 [ { "ackId": "UAYWLF1GSFE3GQhoUQ5PXiM_NSAoRRsGCBQFfH1wU1x1XVx0aFENGXJ9YHxpW0VQAEVWe1lRGwdoTm11H7aF5ftLQ1RrWBYHBEBae19TGQhoXFp3D3nlneOW2-TYfQk9OqLbgtZtO-vw5OtHZiM9XxJLLD5-MSpFQV5AEkw6H0RJUytDCypYEU4EISE-MD5FU0Q", "message": { "data": "YW5vdGhlciAxc3QgZmllbGQ=", "messageId": "12566595082500628", "publishTime": "2024-11-12T09:08:52.185Z" } }, { "ackId": "UAYWLF1GSFE3GQhoUQ5PXiM_NSAoRRsGCBQFfH1wU1x1XVx0aFENGXJ9YHxpW0VQAEVWe1lRGgdoTm11H7aF5ftLQ1RrWBYHBEBae19TGQhoXFp3DnnlneOW2-TYfQk9OqLbgtZtO-vw5OtHZiM9XxJLLD5-MSpFQV5AEkw6H0RJUytDCypYEU4EISE-MD5FU0Q", "message": { "data": "YW5vdGhlciAybmQgZmllbGQ=", "messageId": "12566595082500629", "publishTime": "2024-11-12T09:08:52.185Z" } }, { "ackId": "UAYWLF1GSFE3GQhoUQ5PXiM_NSAoRRsGCBQFfH1wU1x1XVx0aFENGXJ9YHxpW0VQAEVWe1lRGQdoTm11H7aF5ftLQ1RrWBYHBEBae19TGQhoXFp2B3nlneOW2-TYfQk9OqLbgtZtO-vw5OtHZiM9XxJLLD5-MSpFQV5AEkw6H0RJUytDCypYEU4EISE-MD5FU0Q", "message": { "data": "IGFub3RoZXIgM3JkIGZpZWxk", "messageId": "12566595082500630", "publishTime": "2024-11-12T09:08:52.185Z" } } ] 杉村 勇馬 (記事一覧) 執行役員 CTO / クラウドソリューション部 部長 元警察官という経歴を持つ現 IT エンジニア。クラウド管理・運用やネットワークに知見。AWS 12資格、Google Cloud認定資格11資格。X (旧 Twitter) では Google Cloud や AWS のアップデート情報をつぶやいています。 Follow @y_sugi_it
アバター
G-gen の佐々木です。当記事では、GitHub Actions で GKE クラスタにリソースをデプロイする際に、 DNS エンドポイント を使用する方法を解説します。 DNS エンドポイントとは GitHub Actions を使用した GKE へのデプロイ 従来の方法 DNS エンドポイントを使用する方法(当記事で解説) DNS エンドポイントを使用する GKE クラスタの作成 シェル変数の設定 ネットワークリソースの作成 GKE クラスタの作成 Direct Workload Identity の構成 シェル変数の設定 Workload Identity の設定 GitHub Actions によるリソースのデプロイ GitHub リポジトリのディレクトリ構成 使用するファイル GitHub Actions ワークフロー Kubernetes マニフェストファイル GitHub Actions の実行 修正したマニフェストファイルの反映 マニフェストファイルの修正 GitHub Actions の再実行 DNS エンドポイントとは DNS エンドポイント とは、GKE のコントロールプレーンにアクセスする方法として従来からサポートされていた IP アドレスベースのアクセス元制御ではなく、DNS ベースのアクセス元制御を提供する機能です。 DNS エンドポイントが有効化されている場合、たとえコントロールプレーンにパブリック IP アドレスが割り当てられていなくても、IAM で許可されているユーザーはコントロールプレーンに接続することができます。 DNSエンドポイントを使用してコントロールプレーンに接続する DNS エンドポイントの詳細、および IP アドレスベースのエンドポイントとの比較については、以下の記事をご一読ください。 blog.g-gen.co.jp GitHub Actions を使用した GKE へのデプロイ 従来の方法 DNS エンドポイントがリリースされる前は、コントロールプレーンのパブリックエンドポイントを無効化している場合、GitHub Actions からコントロールプレーンに直接接続することはできませんでした。 そのため、プライベートエンドポイント経由でコントロールプレーンに到達できる GKE ノード側の VPC 内に GitHub Actions の Self-Hosted Runner を構成し、Runner 上でワークフローを実行する方法などが用いられます。 Self-Hosted Runner は Compute Engine 仮想マシンや GKE クラスタ内の Pod で実行することになるため、GitHub Actions でデプロイパイプラインを構築したい場合、これらのリソースの運用管理も考慮していく必要があります。 Self-Hosted Runnerを使用してプライベートエンドポイント経由でデプロイする DNS エンドポイントを使用する方法(当記事で解説) DNS エンドポイントを使用する場合、GitHub Actions ワークフローから Google Cloud API にアクセスすることができれば、パブリック IP アドレスを持たないコントロールプレーンであっても直接接続することができます。 したがって、Self-Hosted Runner の運用を考えることなく、シンプルなパイプライン構成で GKE クラスタにリソースをデプロイできます。 DNSエンドポイント経由でデプロイする GitHub Actions からコントロールプレーンに接続する際の IAM 認証については Workload Identity を使用します。 Workload Identity では Google Cloud プロジェクトに GitHub リポジトリを プロバイダ として登録し、プロバイダに対して IAM 権限を紐付けることで Google Cloud リソースへのアクセス権を与えることができます。 Workload Identity 連携の詳細については、以下のドキュメントをご一読ください。 参考1 : Workload Identity Federation 参考2 : Configure Workload Identity Federation with deployment pipelines 当記事では Workload Identity の方式のひとつである Direct Workload Identity を使用することで、IAM サービスアカウントの情報を GitHub Actions ワークフロー側に渡すことなく、プロバイダに対してコントロールプレーンに接続するための IAM 権限を直接付与します。 DNS エンドポイントを使用する GKE クラスタの作成 シェル変数の設定 まずは GitHub Actions のデプロイ先となる GKE クラスタを作成します。 当記事では gcloud CLI を使用してリソースを作成していきます。リソース作成時に何度か使用する値をシェル変数として設定しておきます。 PROJECT_ID = { プロジェクトID } # ex: gha-demo-prj LOCATION = { GKEを作成するロケーション } # ex: asia-northeast1 CLUSTER_NAME = { 任意のGKEクラスタの名前 } # ex: mycluster ネットワークリソースの作成 GKE クラスタを配置する VPC とサブネットを作成していきます。 以下のコマンドで VPC を作成します。 # VPC を作成する $ gcloud compute networks create vpc- ${CLUSTER_NAME} \ --project = ${PROJECT_ID} \ --subnet-mode = custom 作成した VPC の中にサブネットを作成します。当記事ではサブネットの IP 範囲として 192.168.11.0/24 を設定しています。 # サブネットを作成する $ gcloud compute networks subnets create subnet- ${CLUSTER_NAME} \ --project = ${PROJECT_ID} \ --network = vpc- ${CLUSTER_NAME} \ --region = ${LOCATION} \ --range = 192 . 168 . 11 . 0 / 24 GKE クラスタの作成 --enable-dns-access フラグを使用し、DNS エンドポイントを有効化した GKE クラスタを作成します。 以下のコマンドで、DNS エンドポイントを有効化した Autopilot モードの GKE クラスタを作成します。 --no-enable-ip-access フラグを使用することで IP アドレスベースの接続を無効化します。これで、Google Cloud API にアクセスでき、かつ IAM 権限を持つユーザーのみがコントロールプレーンに接続することができます。 # DNS エンドポイントを有効化した Autopilot クラスタを作成する(10分ほどかかるので注意) $ gcloud container clusters create-auto ${CLUSTER_NAME} \ --project = ${PROJECT_ID} \ --network = vpc- ${CLUSTER_NAME} \ --subnetwork = subnet- ${CLUSTER_NAME} \ --enable-private-nodes \ --enable-dns-access \ --no-enable-ip-access IPアドレスベースの接続を無効化し、DNSエンドポイントのみ有効にする Direct Workload Identity の構成 シェル変数の設定 ここからは、GitHub Actions からコントロールプレーンに接続する際に認証を行うための Workload Identity の設定を行っていきます。 まずは、繰り返し使用する値をシェル変数として設定しておきます。 PROJECT_ID = { プロジェクトID } # ex: gha-demo-prj PROJECT_NUMBER = { プロジェクト番号 } # ex: 1234567890 WORKLOAD_IDENTITY_POOL = { 任意のWorkload Identityプール名 } # ex: my-gha-pool WORKLOAD_IDENTITY_PROVIDER = { 任意のWorkload Identityプロバイダ名 } # ex: my-gha-provider GITHUB_REPO = { GitHubリポジトリ名 } # ex: my-org/my-repo Workload Identity の設定 以下のコマンドで Workload Identity プールを作成します。 # Workload Identity プールの作成 $ gcloud iam workload-identity-pools create ${WORKLOAD_IDENTITY_POOL} \ --project = ${PROJECT_ID} \ --location = global \ --display-name = ${WORKLOAD_IDENTITY_POOL} 作成したプールに、Workload Identity プロバイダを作成します。 --attribute-condition フラグで、この Workload Identity を使用する GitHub Actions ワークフローがある GitHub リポジトリをここで指定します。 # Workload Identity プロバイダの作成 $ gcloud iam workload-identity-pools providers create-oidc ${WORKLOAD_IDENTITY_PROVIDER} \ --project = ${PROJECT_ID} \ --location = global \ --workload-identity-pool = ${WORKLOAD_IDENTITY_POOL} \ --display-name = ${WORKLOAD_IDENTITY_PROVIDER} \ --issuer-uri =" https://token.actions.githubusercontent.com " \ --attribute-mapping =" google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.repository=assertion.repository " \ --attribute-condition =" assertion.repository==' ${GITHUB_REPO} ' " Workload Identityプールとプロバイダを作成する 最後に、Workload Identity プロバイダに対して GKE クラスタにリソースをデプロイするための権限( roles/container.developer )を付与します。 これにより、GitHub Actions ワークフローが DNS エンドポイント(Google Cloud API の認証)を通して GKE のコントロールプレーンに接続することができます。 # Workload Identity プロバイダに権限を付与する $ gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member =" principalSet://iam.googleapis.com/projects/ ${PROJECT_NUMBER} /locations/global/workloadIdentityPools/ ${WORKLOAD_IDENTITY_POOL} /attribute.repository/ ${GITHUB_REPO} " \ --role =" roles/container.developer " Workload IdentityプロバイダにGKEクラスタのアクセス権を付与する GitHub Actions によるリソースのデプロイ GitHub リポジトリのディレクトリ構成 Workload Identity プロバイダの作成時に指定した GitHub リポジトリに、GitHub Actions のワークフローと、GKE クラスタにデプロイする Kubernetes リソースのマニフェストファイルを配置します。 リポジトリ内のディレクトリ構成は以下のようにして進めていきます。 . ├── .github │ └── workflows │ └── demo-actions.yaml # GitHub Actions ワークフロー └── manifests └── sample-deployment.yaml # Kubernetes リソース(deployment)のマニフェストファイル 使用するファイル GitHub Actions ワークフロー Workload Identity を使用して GKE クラスタにリソースをデプロイする GitHub Actions ワークフローを作成します。 ワークフローファイル内の以下の箇所を、実際の値に置き換えてください。 行 置き換える箇所 値 14行目 {プロジェクトID} GKE クラスタを作成したプロジェクトの ID 15行目 {プロジェクト番号} GKE クラスタを作成したプロジェクトのプロジェクト番号 16行目 {GKEクラスタ名} GKE クラスタの名前 17行目 {GKEクラスタのロケーション} GKE クラスタを作成したロケーション 18行目 {Workload Identityプール名} Workload Idenity プールの名前 19行目 {Workload Identityプロバイダ名} Workload Identity プロバイダの名前 # demo-actions.yaml name : apply k8s manifest to GKE # main ブランチへの Pull Request / Push で実行 on : pull_request : branches : - main push : branches : - main # 環境変数に GKE クラスタの情報を設定 env : PROJECT_ID : { プロジェクトID } # Google Cloud プロジェクト ID PROJECT_NUM : { プロジェクト番号 } # Google Cloud プロジェクト番号 GKE_CLUSTER : { GKEクラスタ名 } # GKE クラスタ名 GKE_LOCATION : { GKEクラスタのロケーション } # GKE クラスタのロケーション WID_POOL : { Workload Identityプール名 } # Workload Identity プール名 WID_PROVIDER : { Workload Identityプロバイダ名 } # Workload Identity プロバイダ名 # ジョブ (GitHUb runners で実行) jobs : setup-apply : runs-on : ubuntu-latest permissions : id-token : write contents : read pull-requests : write steps : - id : checkout name : Checkout uses : actions/checkout@v4 # Workload Identity 連携 # https://cloud.google.com/iam/docs/using-workload-identity-federation#generate-automatic - id : auth name : Authenticate to Google Cloud uses : google-github-actions/auth@v2 with : workload_identity_provider : 'projects/${{ env.PROJECT_NUM }}/locations/global/workloadIdentityPools/${{ env.WID_POOL }}/providers/${{ env.WID_PROVIDER }}' # Workload Identity Pool のプロバイダー # https://github.com/google-github-actions/setup-gcloud - id : setup-gcloud name : Setup gcloud uses : google-github-actions/setup-gcloud@v2 with : project_id : ${{ env.PROJECT_ID }} # GKE の認証プラグイン # https://cloud.google.com/kubernetes-engine/docs/deprecations/auth-plugin?hl=ja - id : install-gke-gcloud-auth-plugin name : Install gke-gcloud-auth-plugin run : | gcloud components install gke-gcloud-auth-plugin # GKE クラスタの認証情報を取得 (DNS エンドポイントを使用) - id : get-gke-credentials name : Get GKE credentials run : | gcloud container clusters get-credentials ${{ env.GKE_CLUSTER }} --region ${{ env.GKE_LOCATION }} --dns-endpoint # マニフェストファイルの適用 - id : apply name : Apply run : | kubectl apply -f ./manifests Kubernetes マニフェストファイル GKE クラスタにデプロイするリソースのマニフェストファイルを作成します。 当記事では、nginx コンテナを実行する Pod を3つ作成する Deployment リソースを作成します。 # sample-deployment.yaml apiVersion : apps/v1 kind : Deployment metadata : name : sample-deployment spec : replicas : 3 selector : matchLabels : app : sample-app template : metadata : labels : app : sample-app spec : containers : - name : sample-app image : nginx:1.27 GitHub Actions の実行 作成したワークフローファイルとマニフェストファイルをリモートリポジトリに push し、GitHub Actions ワークフローを実行します。 ワークフローが実行され、GitHub Actions から GKE クラスタに対してマニフェストファイルが適用されます。Deployment リソースが作成されていることが GitHub Actions のログからわかります。 GitHub Actionsワークフローから GKE クラスタへのデプロイが成功している ローカルから GKE クラスタのコントロールプレーンに接続し、デプロイしたリソースの状態を確認します。 # DNS エンドポイントでコントロールプレーンに接続する $ gcloud container clusters get-credentials ${CLUSTER_NAME} --dns-endpoint # Deployment リソースを表示 $ kubectl get deployments マニフェストファイルの記述通り、3つの Pod を実行する Deployment リソースが作成されています。 # Deployment リソースを表示(出力例) $ kubectl get deployments NAME READY UP-TO-DATE AVAILABLE AGE sample-deployment 3 / 3 3 3 2m7s 修正したマニフェストファイルの反映 マニフェストファイルの修正 マニフェストファイルを修正してからリモートリポジトリに push し、GitHub Actions ワークフローによるデプロイを再度行います。 マニフェストファイル内の spec.replicas の値を 1 にして、Pod 数をスケールインするように修正します。 # sample-deployment.yaml apiVersion : apps/v1 kind : Deployment metadata : name : sample-deployment spec : replicas : 1 # ここを修正する selector : matchLabels : app : sample-app template : metadata : labels : app : sample-app spec : containers : - name : sample-app image : nginx:1.27 GitHub Actions の再実行 再度、リモートリポジトリへの push を行い、GitHub Actions ワークフローを実行します。 ワークフローの実行後、Deployment の状態を確認します。push したマニフェストファイルが GitHub Actions から適用され、Pod の数が1になりました。 # Deployment リソースを確認(出力例) $ kubectl get deployments NAME READY UP-TO-DATE AVAILABLE AGE sample-deployment 1 / 1 1 1 7m5s 佐々木 駿太 (記事一覧) G-gen最北端、北海道在住のクラウドソリューション部エンジニア 2022年6月にG-genにジョイン。Google Cloud Partner Top Engineer 2025 Fellowに選出。好きなGoogle CloudプロダクトはCloud Run。 趣味はコーヒー、小説(SF、ミステリ)、カラオケなど。 Follow @sasashun0805
アバター
G-gen の佐々木です。当記事では、GKE のコントロールプレーンにアクセスするための新しい方法として、 DNS ベースのエンドポイント (DNS エンドポイント)を紹介します。 はじめに GKE におけるコントロールプレーンへのアクセス方法 従来の方法 パブリックエンドポイント プライベートエンドポイント DNS エンドポイント IP ベースと DNS ベースの比較 使用方法 DNS エンドポイントの有効化 コントロールプレーンへのアクセス IP アドレスを使用した接続の無効化 はじめに Google Cloud(旧称 GCP)のフルマネージドなコンテナオーケストレーションサービスである Google Kubernetes Engine(GKE) では、Kubernetes クラスタのコントロールプレーンへのアクセス方法を複数種類から選択できます。 従来から存在する IP ベースのエンドポイント(IP-based endpoints)方式(パブリッククラスタとプライベートクラスタ)に加えて、2024年11月11日、 DNS ベースのエンドポイント (DNS-based endpoint)が利用可能になりました。 当記事では、DNS ベースのエンドポイント(DNS エンドポイント) の機能と使い方を紹介します。 参考 : A new flexible DNS-based approach for accessing the GKE control plane (Google Cloud 公式ブログ) 参考 : About network isolation in GKE (Google Cloud 公式ドキュメント) GKE におけるコントロールプレーンへのアクセス方法 従来の方法 パブリックエンドポイント GKE クラスタで パブリックエンドポイント を有効化する場合、コントロールプレーンにはパブリック IP アドレスが割り当てられます。 この状態ではインターネット上のどこからでもコントロールプレーンにアクセスできてしまうため、 承認済みネットワーク を使用してアクセス元 IP アドレスを制限するのが一般的です。 パブリックエンドポイントでコントロールプレーンに接続する プライベートエンドポイント パブリックエンドポイントよりも推奨される方法として、GKE クラスタでパブリックエンドポイントを無効化し、プライベート IP アドレスのみをコントロールプレーンに割り当てることもできます( プライベートエンドポイント )。 プライベートエンドポイントを使用する場合、「"コントロールプレーンがある Google 管理の VPC と接続されている"ユーザー 管理の VPC」を経由してコントロールプレーンにアクセスする必要があります。そのため、GKE クラスタがある VPC の外からコントロールプレーンに接続したい場合、ユーザー VPC に踏み台 VM(Bastion host)を起動するか、VPN を経由してアクセスする必要がありました。 プライベートエンドポイントでコントロールプレーンに接続する DNS エンドポイント GKE クラスタで DNS エンドポイントを有効化すると、Google Cloud API にアクセスできる任意の環境から、パブリック IP アドレスが割り当てられてないコントロールプレーンにアクセスすることができます。 DNSエンドポイントでコントロールプレーンに接続する コントロールプレーンへのアクセス可否はその他の Google Cloud API を利用するときと同様に、IAM ポリシーによって判断されます。GKE クラスタに対して container.clusters.connect ポリシーを持つ以下のようなロールが付与されているプリンシパルであれば、コントロールプレーンにアクセスすることができます。 Kubernetes Engine 開発者(roles/container.developer) Kubernetes Engine 閲覧者(roles/container.viewer) ※読み取り専用 DNS エンドポイントを使用することで、コントロールプレーンへの接続に踏み台 VM を使用する必要がなくなるほか、 推移的なルーティング によってコントロールプレーンに到達できないといった、ネットワーク構成上の制限を考慮しなくてもよくなります。 たとえば、以下のような構成でプライベートエンドポイントを使用する場合、推移的ルーティングによりコントロールプレーンにアクセスすることはできません。 推移的ルーティングによりコントロールプレーンに接続できないケース DNS エンドポイントを使用すると、アクセス元の VPC 内サブネットで 限定公開の Google アクセス が有効化されていれば(Google Cloud API にアクセスできれば)、コントロールプレーンに接続することができます。 DNSエンドポイントでは推移的ルーティングに制限されずに接続できる また、 VPC Service Control を使用することで、IAM 以外の条件(アクセス元が存在するプロジェクトなど)でも DNS エンドポイントに対するアクセス元を制限することができます。 IP ベースと DNS ベースの比較 IP ベースのエンドポイントと、DNS ベースのエンドポイントがどのように異なるのかを比較します。 DNS ベースのエンドポイントでは、Google Cloud API がインターネットに露出しているという点では、IP ベースのエンドポイントのパブリッククラスタと類似しているものの、以下のように異なっています。 比較点 IP ベース(パブリックエンドポイント) DNS ベース Kubernetes API エンドポイントの露出 パブリック IP を持っている(万が一 Kubernetes に脆弱性がある場合は脅威にさらされる) パブリック IP を持たない設定が可能 kubectl の接続情報取得に必要な IAM 権限 container.clusters.get container.clusters.connect VPC Service Controls での保護 なし(クラスタ情報取得に対しては保護可能) 可能 特にセキュリティ面に関しては、従来の IP ベースのアクセスであれば、プライベートクラスタを構成したうえで踏み台ホストや VPN を用いて Kubernetes API へ接続することが推奨されていましたが、今後は DNS ベースのエンドポイントを構成し、IAM 権限を適切に管理したうえで VPC Service Controls を使って多層防御を構成することが推奨されます。 VPC Service Controls については、以下の記事も参照してください。 blog.g-gen.co.jp 使用方法 DNS エンドポイントの有効化 DNS エンドポイントはいつでも有効化することができます。CLI で有効化する場合は、 --enable-dns-access フラグを使用してクラスタを更新します。 # クラスタ作成時に DNS エンドポイントを有効化する $ gcloud container clusters create ${GKE クラスタ名 } -–enable-dns-access # 既存のクラスタで DNS エンドポイントを有効化する $ gcloud container clusters update ${GKE クラスタ名 } --enable-dns-access Google Cloud コンソールの場合、「DNS エンドポイント」の項目から有効化することができます。 DNSエンドポイントの設定箇所(コンソール) コントロールプレーンへのアクセス DNS エンドポイントでコントロールプレーンに接続するには、 gcloud container clusters get-credentials  コマンドで --dns-endpoint フラグを使用します。 # DNS エンドポイントでコントロールプレーンに接続する $ gcloud container clusters get-credentials ${GKE クラスタ名 } --dns-endpoint IP アドレスを使用した接続の無効化 --no-enable-ip-access フラグを使用することで、従来の IP アドレスベースの接続方法を無効化することができます。 # IP アドレスベースのコントロールプレーンへの接続を無効化する $ gcloud container clusters update ${GKE クラスタ名 } --no-enable-ip-access 佐々木 駿太 (記事一覧) G-gen最北端、北海道在住のクラウドソリューション部エンジニア 2022年6月にG-genにジョイン。Google Cloud Partner Top Engineer 2025 Fellowに選出。好きなGoogle CloudプロダクトはCloud Run。 趣味はコーヒー、小説(SF、ミステリ)、カラオケなど。 Follow @sasashun0805
アバター
G-gen の杉村です。Google Cloud(旧称 GCP)の認定資格である Associate Data Practitioner 資格の試験対策に有用な情報を記載します。 基本的な情報 Associate Data Practitioner とは 難易度 出題傾向 試験対策 ETL と ELT ETL と ELT の基本 オープンソースツールとフルマネージドサービス Cloud Data Fusion イベントドリブンアーキテクチャ データベースの選択 BigQuery BigQuery の基本 ELT と ETL 半構造化データの扱い(JSON 型) パーティションとクラスタリング 外部テーブル SQL ウインドウ関数 コネクテッドシート BigQuery のアクセス制御と暗号化 権限管理(IAM) 承認されたビュー 透過的な暗号化 BigQuery ML BigQuery ML の基本 組み込みモデル スキューとドリフト Gemini AutoML Cloud Storage Cloud Storage の基本 ストレージクラス オブジェクトライフサイクル バージョニング Autoclass デュアルリージョン、マルチリージョン Storage Transfer Service Storage Transfer Appliance Looker Looker の基本 メジャーとディメンション Looker における権限管理 Analytics Hub Colab Enterprise Cloud SQL 基本的な情報 Associate Data Practitioner とは Associate Data Practitioner 試験は、Google Cloud(旧称 GCP)の認定資格の一つです。当試験は2024年10月30日、Beta 版として公開され、2025年1月に一般公開(GA)されました。 当試験は Associate レベルの資格であり、 Google Cloud 上でのデータ取り込み、変換、パイプライン管理、分析、機械学習、および可視化等に関する知識や技能 が問われます。 試験時間は120分、問題数は50〜60問です。 英語版 と 日本語版 の試験が提供されています。 Google Cloud のデータエンジニアリング関連の認定資格としては Professional Data Engineer が存在しています。Professional レベルの認定資格は、技術的な知識だけでなく、ビジネスユースケースにあわせてソリューションを検討するより高度な知見が求められるのに対して、Associate レベルの資格は、技術的な知見のみに特化しています。当記事で紹介する Associate Data Practitioner は、Professional Data Engineer の下位資格の位置づけと考えれます。 参考 : Associate Data Practitioner 当資格の上位資格である Professional レベル試験である Professional Data Engineer については、以下の記事も参照してください。 blog.g-gen.co.jp 難易度 Associate Data Practitioner 試験の難易度は、他の認定試験と比較して 低〜中程度 といえます。 「RDBMS」「トランザクション」「データモデリング」「SQL」「分散データベース」など、基本情報技術者試験でも学ぶような基礎レベルのリレーショナルデータに関する知識に加えて、非正規化を含むデータ分析向けのデータモデリング、オブジェクトストレージの基本などを理解されている方であれば、追加の学習を1ヶ月程度行うことで十分に合格を狙えます。 また基礎知識として、Associate Cloud Engineer 程度の Google Cloud の基礎知識を持っておくことで、IAM による権限管理などを1から学習しなくても済みます。 受験者に推奨される経験として、公式サイトには「Google Cloud 上での6ヶ月以上の実務経験」とありますが、細かな操作やコマンドに関する出題は多くありません。むしろ普遍的な標準 SQL の書き方に親しんでおくことが重要です。また、Google Cloud のベストプラクティスを正しく理解し、それに沿って答えることが重要です。 出題傾向 当試験では、以下のような Google Cloud ソリューションに関する出題がほとんどです。 Cloud Storage BigQuery Pub/Sub Dataflow Dataform Cloud Data Fusion Dataproc また一部では、Cloud SQL の可用性など、オペレーショナルデータベースに関する出題もされます。 試験で出題される Google Cloud で実装されるデータ分析基盤は、 必ず BigQuery が中心である といって差し支えありません。BigQuery をデータウェアハウス(データ分析用データベース)として、そこにデータを取り込み(ingest)するためのツールとして Pub/Sub、Dataflow、Cloud Data Fusion などが登場します。それを理解しつつ、Google が提唱する以下のようなベストプラクティスに沿うような回答を心がけることが重要です。どの認定試験でも共通して言えることですが、原則から大きく外れなければ、合格は難しくありません。 データ分析用データベースは BigQuery 管理工数を小さくするために、可能であればフルマネージドサービスや、備え付けの機能を選ぶ Apache Airflow on Compute Engine より Cloud Composer Spark on GKE より Dataproc Serverless 機械学習フレームワークよりも BigQuery ML 維持・保守工数を小さくするために、可能であればノーコードで実装できる方法を選ぶ BigQuery のハウスキーピングは、Cloud Run functions で実装するよりも、パーティションの有効期間設定を使う Cloud Storage のハウスキーピングは、Cloud Run functions で実装するよりも、オブジェクトライフサイクルを選ぶ 試験対策 以下の勉強方法はあくまで一例であり、最適な方法は、受験者の予備知識や経験によって異なるものとご了承ください。 Associate Cloud Engineer レベルの Google Cloud 基礎知識を習得する 前掲のデータ基礎知識をキーワードベースで理解する 試験ガイドを読み、知らないキーワードや機能について公式ドキュメントで学ぶ 当記事の出題傾向を読み足りない知識領域をカバーする学習を行う ウインドウ関数や BigQuery ML など特殊な SQL の使い方を理解する なお Associate Cloud Engineer 試験の学習については、以下の記事も参照してください。 blog.g-gen.co.jp 当記事ではこれ以降、試験にあたって何を勉強しておくべきか、機能分野ごとに紹介しますので、参考にしてください。当記事では、Google Cloud の基礎知識を詳細にお伝えすることはありませんので、その点にはご留意ください。また、当記事の内容は Beta 版公開時のものですので、現在の試験内容とは一部が異なる場合がある点もご了承ください。 ETL と ELT ETL と ELT の基本 BigQuery はスケーラブルなコンピュート基盤を持っているので、まずデータを BigQuery に取り込んでから変換する「 ELT (Extract、Load、Transform)」の順番で処理することが可能です。ELT は、 スケジュールされたクエリ (Scheduled queries)や Dataform で行うことが多いといえます。 しかし当試験では、BigQuery へ Load する前に Cloud Data Fusion や Dataflow 、 Dataproc でデータクレンジングを行う「ETL(Extract、Transform、Load)」の出題も多くあります。 多くの問題では、ELT と ETL どちらを採るべきか、問題文を読めば明確です。 上記に登場したそれぞれのサービスが、どのようなものであるか、概要を理解しておいてください。 オープンソースツールとフルマネージドサービス Google Cloud のデータ分析向けフルマネージドサービスは、多くがオープンソースソフトウェア(Open Source Software、OSS)をベースとしていることに注意してください。例えば Cloud Composer は、OSS である Apache Airflow のフルマネージドサービスです。Google Cloud プロダクトと、 その元となった OSS の名称との対照は覚えてください 。試験では、例えば「オープンソースの技術スタックを利用したい」などの要件が提示されるかもしれません。 Google Cloud プロダクト名 OSS 名 Cloud Composer Apache Airflow Dataflow Apache Beam Dataproc / Dataproc Serverless Apache Hadoop、Apache Spark 等 Cloud SQL for PostgreSQL PostgreSQL Cloud SQL for MySQL MySQL また、これらの各プロダクトの(= OSS の)得意分野とユースケースをしっかり把握しておきましょう。以下のような大原則をしっかり覚えておいてください。 Google Cloud プロダクト名(OSS 名) ユースケース Cloud Composer(Apache Airflow) DAG (有向非巡回グラフ。いわゆるワークフローまたはジョブネット)を Python で記述。多くの 組み込みオペレーター がある Dataflow(Apache Beam) バッチ処理とストリーミング処理を 両方処理できる Dataproc(Apache Hadoop、Apache Spark 等) ファイルを大規模に並列処理 Cloud SQL(PostgreSQL、MySQL) オペレーショナルなリレーショナルデータベース このようなことから、例えばもし「バッチ処理とストリーミング処理を同じ技術スタックで処理したい」という要件があれば必ず Dataflow を選べますし、「Apache Spark ワークロードをクラウドに移行したい。クラスタの管理は行いたくない」とあれば Dataproc Serverless が選べます。 Cloud Data Fusion Cloud Data Fusion は、ノーコードで開発可能な、フルマネージドの ETL ソリューションです。ノーコードで ETL パイプラインを開発したいシチュエーションで活用できます。以下のような利用が可能です。 Cloud Storage のデータを読み取り、データ変換してから BigQuery に格納 データベースに接続し、データを抽出し、変換してから BigQuery に格納 イベントドリブンアーキテクチャ イベントドリブンアーキテクチャ とは、ある1つの処理が完了したことをきっかけに、別の処理がトリガーされるようなアーキテクチャをいいます。例えば、Cloud Storage バケットにオブジェクトがアップロードされたことをきっかけに Cloud Run functions(旧称 Cloud Functions)が起動し、ファイルを読み込んでデータを BigQuery にロードするようなアーキテクチャです。多くの場合、処理のためのプログラムはサーバーレスプラットフォームにホストされます。 次々に到着する小さいデータを順次処理するような仕組みでは、イベントドリブンなアーキテクチャが適しています。反対に、Cloud Run functions のようなサーバーレスプラットフォームは実行時間に制限があることから、 大きなファイルの処理 (長時間の処理)には適していません。イベントドリブンがどのようなユースケースに適しているかを意識してください。 イベントドリブンについては、以下の記事も参照してください。 blog.g-gen.co.jp blog.g-gen.co.jp データベースの選択 Google Cloud の多用なデータベースサービスを一通り理解し、 ユースケースに対して適切なデータベース を選択できるようにしてください。 以下の記事の「データベースの選択」の項を参照してください。 参考 : Professional Data Engineer試験対策マニュアル。出題傾向・勉強方法 - データベースの選択 - G-gen Tech Blog BigQuery BigQuery の基本 BigQuery は当試験で最も重要なプロダクトです。以下の記事を参照し、機能を理解してください。以下の「基本編」記事の内容が主な出題範囲と概ね重なっていますが、例外として「応用編」で簡単に紹介されている BigQuery ML は頻出範囲です。 blog.g-gen.co.jp ELT と ETL Google Cloud のデータ分析基盤の中心は BigQuery です。前述の通り、ELT と ETL の両方のパターンが出題されます。ELT はスケジュールされたクエリ(Scheduled queries)や Dataform で、ETL は Cloud Data Fusion や Dataflow、Dataproc で実装されます。 Dataform は SQL の拡張言語である SQLX を使い、データの変換(transformation)、 テストや品質チェック まで行えるのが特徴です。 Cloud Data Fusion は ノーコード 、や Dataflow は バッチ処理とストリーミング処理を両方扱えること 、Dataproc は Hadoop / Spark 技術スタック、というようにキーワードを覚えておけば、出題時の選択に迷うことはあまりないはずです。 また、単純で1回きりの(one-time の)データロードをローカル PC から行う、などのシンプルなユースケースでは、bq コマンドラインを用いて bq load コマンドを行うことで済む場合もあります。 半構造化データの扱い(JSON 型) 半構造化データとは、JSON フォーマットのように、ある程度構造化されているもののスキーマに柔軟性があるようなデータ構造を指します。当試験においては JSON をイメージすれば事足ります。 BigQuery には JSON 型があり、JSON 形式のような半構造的なキー・バリューを柔軟に格納することができます。SELECT 文では以下のように、 key1.key2 と指定することで選択が可能です。 SELECT json_payload.id FROM `my_dataset.my_table` このようなキーバリュー型をネストして格納できる型には他に STRUCT 型がありますが、STRUCT 型はスキーマが決まっているため、例えば日時経過でスキーマに変更がかかる可能性があり 柔軟性が求められるケースでは JSON 型が便利 です。また、テキスト形式であれば何でも格納できる STRING 型と比べても、パフォーマンス面とコスト面で JSON 型が有利です。 参考 : BigQuery の JSON 型を活用して半構造化データの力を引き出す パーティションとクラスタリング BigQuery の パーティション と クラスタリング については正しく理解してください。 blog.g-gen.co.jp また、パーティションには 有効期限 が設定でき、作成から一定時間が経過したデータを削除することができます。いわゆるハウスキーピングの自動化に最適です。 外部テーブル 外部テーブル (External Tables)機能を使うと、Cloud Storage に格納した CSV、JSON、Parquet、Avro ファイルや Google スプレッドシートのデータ、あるいは Bigtable に対して、BigQuery から SQL を使ってクエリすることができます。 ただし外部テーブル定義を行っても、データを BigQuery に取り込むわけではなく、あくまでデータは外部に置いたままクエリするため、パフォーマンス(処理速度)は高くありません。あくまで、クエリパフォーマンスが求められない場合や、データが少ない場合、また1回きり(one-time)のオンデマンドな分析などに利用します。 参考 : 外部テーブルの概要 SQL Google Cloud 認定資格では珍しく、当試験では SQL の具体的なソースコードを選択肢から選ばせる問題が出題されます。とはいえ、複雑にネストされた長大な SQL が出題されるわけではありません。 基本的な SELECT 文、また JOIN や UNION ALL などを使って複数テーブルを組み合わせて表示する際の SQL などを理解しておいてください。 ウインドウ関数 分析用途で用いられる ウインドウ関数 は、 文法を理解 しておく必要があります。以下は公式ドキュメントですが、必ずしもわかりやすいとは言い難いため、インターネット上の情報や各種書籍を参考にして、文法を理解しておいてください。 参考 : Window function calls 例えば RANK () 関数を使って、「各店舗の日次売上を集計し、上位5位を表示する」といった簡単な SQL がどのようなものになるか、わかるようにしておいてください。 コネクテッドシート コネクテッドシート (Connected Sheets)は、Google スプレッドシート(Google Sheets)から BigQuery のデータを読み取ることができる機能です。 反対に、BigQuery の 外部テーブル 機能では、Google スプレッドシートの URI を指定することでスプレッドシートを外部テーブルとして定義し、SQL でクエリすることができます。 これらを組み合わせると BigQuery 外部テーブルを使ってスプレッドシートの中身を読み取り、BigQuery のデータと結合して結果をテーブルに保存し、その結果をコネクテッドシートを使ってスプレッドシートから読み取る、といった相互の連携が容易に実現できます。 BigQuery のアクセス制御と暗号化 権限管理(IAM) BigQuery へのアクセス制御は、 IAM (Identity and Access Management)を用いて行います。 最小権限の原則 に従うのがキーです。 BigQuery と IAM については以下の記事で詳細に解説しています。 blog.g-gen.co.jp 記事でも紹介しているとおり、たとえば BigQuery のデータへの読み取りアクセスのために必要な最小権限を与える場合、対象アカウント(グループ)に以下の権限をプロジェクトレベルで付与します。 BigQuery ジョブユーザー( roles/bigquery.jobUser ) BigQuery データ閲覧者( roles/bigquery.dataViewer ) データの編集(UPDATE や DELETE)が必要な場合は、上記の「BigQuery データ閲覧者」の代わりに「BigQuery データ編集者( roles/bigquery.dataEditor )」あるいは「BigQuery データオーナー( roles/bigquery.dataOwner )」を付与します。ポイントは、ジョブ(クエリ)の実行には「BigQuery ジョブユーザー( roles/bigquery.jobUser )」が必要になるという点です。詳細は前掲の当社記事を参照してください。 承認されたビュー 承認されたビュー (Authorized view)機能を使うと、ビューへのアクセス制御を簡素化できます。シンプルで効率の良い方法で、ビュー(特定のクエリ結果)へのアクセスを制御したい場合に利用できます。以下の記事を参照して、仕様を理解してください。 blog.g-gen.co.jp 透過的な暗号化 透過的な暗号化 では、暗号鍵への適切なアクセス権限を持っていれば、利用者は暗号化を意識せずにストレージ上のデータを利用できます。 Google Cloud では 転送中のデータ (data in transit)と 保管中のデータ (data at rest)は共に デフォルトで暗号化 されています。これを デフォルトの暗号化 と呼びます。デフォルトの暗号化で暗号鍵として使われる鍵は Google が管理されており、適切に保管、ローテーションや廃棄が行われます。この鍵のことを Google-managed encryption keys 、略して GMEK と呼称します。 参考 : デフォルトの保存データの暗号化 参考 : 転送データの暗号化 また、BigQuery のコンソール画面(BigQuery Studio)や bq コマンドを使うとき、データはインターネットを経由して転送されますが、通信は HTTPS で暗号化されています。これは BigQuery だけでなくすべてのサービスで共通です。つまり、ユーザーが何もしなくても、Google Cloud を利用している限り、転送中のデータ(data in transit)と保管中のデータ(data at rest)はともに、暗号化されていることになります。 ただしセキュリティ向上や法的規制の要件への遵守などの目的で、GMEK ではなく独自の暗号鍵を利用する必要がある場合もあります。その場合は、 Cloud KMS を使って独自の暗号鍵を管理することができまし。このとき、この顧客独自の鍵のことを Customer-managed encryption keys (CMEK)と呼びます。 blog.g-gen.co.jp さらに厳しい規制要件等では、クラウド環境に鍵を保管することが許されない場合もあります。その場合は顧客の独自環境で鍵を保管・管理し、暗号化・復号のたびに鍵を保管場所から取り出して利用することができます。このとき、この鍵のことを Customer-supplied encryption keys (CSEK)と呼びます。 参考 : 顧客指定の暗号鍵 GMEK < CMEK < CSEK の順で保守や運用の工数は大きくなりますが、厳しい要件に対応することができます。試験では、これら3種類の鍵の 意味を正しく理解 していれば、正答を選ぶことができます。 BigQuery ML BigQuery ML の基本 当試験では BigQuery ML の基本的な理解を問われます。BigQuery ML では何が実現できるのか、またリモートモデルによる Vertex AI モデルの呼び出しといった概念を理解してください。 参考 : BigQuery の AI と ML の概要 組み込みモデル BigQuery ML には、すぐに利用可能なビルトインモデルが存在します。これらのモデルを指定し、トレーニングデータを投入すれば、SQL だけで簡単に独自モデルを開発可能です。 参考 : 内部でトレーニングされたモデル 代表的なモデルとユースケースを頭に入れておいてください。時系列(Time series)と線形回帰(Linear regression)はよく似ていますが、例えば店舗の需要予測の際、セールなどの異常値や季節性の変化を考慮に入れてトレーニングできるのは時系列予測です。 モデル名 用途 時系列(Time series) 時系列予測。 異常値、季節性、休日が考慮 される 線形回帰(Linear regression) 線形の予測 。例えば、特定の日の商品売上 ロジスティック回帰(Logistic regression) True である可能性を 0と1の間で 予測 K 平均法クラスタリング(K-means clustering) データの 分類 。顧客セグメントの分別など 行列分解(Matrix factorization) 商品のレコメンデーション 等。過去の行動を評価しておすすめを作成 主成分分析(Principal component analysis、PCA) データの次元削減 またモデルをトレーニングする際にどのような SQL を書けばよいのかという細かい点も出題されます。例えば以下のドキュメントでは、ロジスティック回帰の目的変数となる列の列名を input_label_cols オプションで指定しています。デフォルトでは目的変数列は label となるため、CREATE MODEL 文の中の SELECT 文で as label として列を選択すれば、その列が目的変数としてトレーニングされます。 参考 : ロジスティック回帰モデルを作成する スキューとドリフト トレーニングしたモデルを本番運用する際に重要なキーワードとして、 データスキュー (Data skew)と データドリフト(Data drift) という言葉を理解しておいてください。BigQuery ML の公式ドキュメントでは以下のように定義しています。 名称 意味 データスキュー(Data skew) トレーニングデータの分布が、本番環境でサーブされるデータと大きく異なる場合に発生 データドリフト(Data drift) 本番環境でのデータが時間の経過とともに大きく変化した場合に発生 すなわち、データスキューを監視することでトレーニングと実践のデータのずれを、データドリフトを監視することで時間経過に伴うモデルの劣化を、それぞれ検知することができるといえます。 参考 : モデル モニタリングの概要 Gemini BigQuery では、リモートモデルを作成することで LLM である Gemini を呼び出す ことができます。 CREATE OR REPLACE MODEL でリモートモデルを定義したあと、 ML.GENERATE_TEXT で Gemini を呼び出し、BigQuery 内部のデータをインプットしてテキストを生成させることが可能です。 AutoML AutoML に関する問題も、若干出題されます。Google Cloud の AutoML では、大量の教師データを Cloud Storage 等に配置しておき、AutoML のトレーニングを実行することで、簡単に独自の機械学習モデルをトレーニングすることができます。 参考 : AutoML 初心者向けガイド Cloud Storage Cloud Storage の基本 Cloud Storage は頻出プロダクトです。以下の記事を参照し、機能を理解してください。 blog.g-gen.co.jp 特に、この後の見出しで列挙する機能名は必ず押さえてください。 ストレージクラス Cloud Storage の ストレージクラス の概念は正確に理解してください。 ストレージクラス 保管料金 オペレーション料金 最低保管期間 Standard Storage 高い 安い なし Nearline Storage ↑ ↓ 30 日 Coldline Storage ↑ ↓ 90 日 Archive Storage 安い 高い 365 日 Standard > Nearline > Coldline > Archive の順で保管料金が安くなっていくことや、最低保管期間(この期間より短くオブジェクトを削除すると、この期間分の保管料金は発生する)が長くなっていくことを理解してください。最低保管期間は0、30、90、365と覚え、ストレージクラスの名称と合わせて覚えておいてください。 オブジェクトライフサイクル オブジェクトライフサイクル (ライフサイクルルール)を設定することで、古くなったオブジェクトを自動的によりアーカイブ寄りのストレージクラスに移動したり、削除したりできます。ライフサイクルのアクションは、以下の3つのみです。 Delete (オブジェクトを削除する) SetStorageClass (ストレージクラスを設定する) AbortIncompleteMultipartUpload (途中だったマルチパートアップロードを削除する) ライフサイクルルールを設定することで、「作成から30日経過したオブジェクトは Nearline に移動、90日経過したら Coldline に移動。1年間経過したら削除する」などの複雑なルール設定も可能です。 バージョニング バージョニング の機能も必ず理解しておいてください。オブジェクトが上書きされても、指定した世代を残しておくことができます。前述のライフサイクルルールと組み合わせて、「オブジェクトは3世代保管する。作成から30日経過したオブジェクトは Nearline に移動し...」といった設定も可能です。 Autoclass Autoclass 機能も出題されます。Autoclass を有効化すると、オブジェクトのアクセス状況に応じて自動的にストレージクラスを設定してくれますので、 運用工数を節減 することが可能です。 デュアルリージョン、マルチリージョン Cloud Storage バケットを作成時、バケットの配置場所をシングルリージョン、デュアルリージョン、マルチリージョンの中から選択できます。それぞれの特徴は、以下のドキュメントから理解しておいてください。 参考 : ロケーションに関する留意事項 データの冗長性を確保しつつ、データの所在を明らかにしておくためにはデュアルリージョンを選択するシチュエーションがありえます。データの冗長化は非同期で行われます。デフォルトの非同期レプリケーションでは、1時間以内に99.9%のオブジェクトが複製され、12時間以内に100%に達します。これでは RPO(Recovery Point Objective)要件を満たせない場合、 ターボレプリケーション (Turbo replication)を有効化することで、15分以内に100%のデータを複製できます。 参考 : データの可用性と耐久性 Storage Transfer Service Storage Transfer Service は、Amazon S3 などの外部ストレージサービスや、オンプレミスのファイルサーバー等から Cloud Storage にデータを転送するためのフルマネージドサービスです。 BigQuery Transfer Service が BigQuery への転送 を管理するサービスである一方、Storage Transfer Service は Cloud Storage への転送 を管理するサービスであると覚えてください。 包含接頭辞(include filter)や除外接頭辞(exclude filter)を使い、 対象範囲を絞ってジョブ複数作り、並列実行 することで転送時間を短くしたり、逆に直列で実行することで API 実行制限を回避することができます。 参考 : 転送速度を向上させる また Storage Transfer Service では、オンプレミスのファイルサーバーからのデータ転送も実現できます。この場合、オンプレミス側に Docker ベースの エージェントを起動する必要 があります。またネットワーク帯域が限らえている場合は、エージェントが利用する 帯域の上限を設定 することもできます。 参考 : ファイル システム転送の要件 参考 : ネットワーク帯域幅を管理する Storage Transfer Appliance Storage Transfer Appliance は物理的なアプライアンスをユーザーのデータが存在する場所に配送し、物理的に結線してデータを取り込み、また Google に返送することで Google のデータセンターに直接データを持ち込めるサービスです。持ち込み先は Cloud Storage バケットになります。インターネットや専用線経由でのデータ転送ではあまりに時間がかかってしまう場合や、十分な帯域が確保できない場合に利用します。なお、日本でも利用可能です。類似サービスとして、Amazon Web Services(AWS)の AWS Snowball があります。 ペタバイト(PB)級の量のデータ を Google Cloud に持ち込む場合や、数百 TB のデータを移行したいが ネットワーク帯域が限られている 場合等には、有力な選択肢の1つです。 参考 : Overview Looker Looker の基本 Looker は、Google Cloud が提供する BI プラットフォームサービスです。 LookML というデータモデリング言語を使ってあらかじめセマンティックレイヤを定義することで、高度なデータガバナンスを実現できるのが特徴です。 LookML によるデータモデリングや、分析から後続の施策に繋げる豊富な機能、また組織外へのデータ共有に関する機能などにより、Looker は単なる BI ツールではなく、高度なデータプラットフォームとして用いられます。 なお、Looker には、従来型の Looker(Original) と、Google Cloud と高度に統合された Looker(Google Cloud Core) の2バージョンがあります。 参考 : Looker(Google Cloud コア)で利用可能な機能 メジャーとディメンション Looker を使うには、データベース上のデータを使い、事前に LookML で メジャー (measures)と ディメンション (dimensions)を定義します。 メジャーとディメンションは、BI ツール等では一般的な用語ですので、意味を理解しておいてください。 また、メジャーとディメンションは Looker 上では view ファイル と呼ばれる定義ファイルに定義します。 Looker における権限管理 Looker では、ダッシュボード等への権限管理のため、ユーザーを グループ に格納できます。 部署やチームごとにグループを作成し、ユーザーをその中に配置したら、フォルダにおいてグループ単位で権限を付与するのがベストプラクティスです。運用負荷軽減のため、 個々のユーザーにではなくグループに権限を付与するべき であるという原則は Google Cloud の IAM とも共通しています。 参考 : グループ Analytics Hub Analytics Hub は、異なる組織間でデータを効率よく、セキュアに提供しあうためのプラットフォームです。Analytics Hub は BigQuery や Pub/Sub のデータ交換に対応しています。 自社のデータを、アクセス権限を適切に管理しながら効率よく他社に提供したいシチュエーションでは、Analytics Hub が選択できます。 参考 : Analytics Hub の概要 Colab Enterprise Colab Enterprise は、フルマネージドの Python ノートブックサービスです。BigQuery や Dataproc など他の Google Cloud サービスとも柔軟に連携できます。 Colab Enterprise のノートブック上から Python を使って BigQuery 上のデータを操作したいときなどに、Google アカウントの認証情報を使ってスムーズにデータ連携が可能です。 参考 : Introduction to Colab Enterprise Cloud SQL Cloud SQL に関する問題も若干出題されます。以下の記事を読み、基本を理解してください。 blog.g-gen.co.jp Cloud SQL の高可用性(HA)インスタンスを使うと、簡単な設定で、あるリージョンの中の複数のゾーンに Primary インスタンスと Secondary インスタンスを起動し、高い可用性を実現することができます。また、これに加えて非同期レプリケーションの レプリカ を加えることで、リージョン単位での障害に対応することもできます。 参考 : 障害復旧アーキテクチャ 杉村 勇馬 (記事一覧) 執行役員 CTO 元警察官という経歴を持つ IT エンジニア。クラウド管理・運用やネットワークに知見。AWS 認定資格および Google Cloud 認定資格はすべて取得。X(旧 Twitter)では Google Cloud や Google Workspace のアップデート情報をつぶやいています。 Follow @y_sugi_it
アバター
G-gen の杉村です。2024年10月現在で利用可能な12種類の Cloud Load Balancing のアクセスログは、それぞれフォーマットが異なります。アクセスログをクエリするための Cloud Logging クエリと、アクセスログのサンプルを掲載します。 はじめに アクセスログのフィルタリング フィールドに入る値の違い 公式ドキュメントの記述 Cloud Logging 用クエリ アクセスログのサンプル Global external Application Load Balancer Classic Global external Application Load Balancer Regional external Application Load Balancer Regional internal Application Load Balancer Cross-region internal Application Load Balancer Global external proxy Network Load Balancer Classic Global external proxy Network Load Balancer Regional external proxy Network Load Balancer Regional internal proxy Network Load Balancer Cross-region internal proxy Network Load Balancer Regional external passthrough Network Load Balancer Regional internal passthrough Network Load Balancer はじめに Cloud Load Balancing は、Google Cloud(旧称 GCP)のフルマネージドのロードバランサーです。2024年10月現在、Cloud Load Balancing には用途によって異なる12種類のロードバランサーが存在します。 参考 : Cloud Load Balancing の概要 参考 : ロードバランサを選択する Cloud Load Balancing を構成するコンポーネントの1つである バックエンドサービス でログ出力を有効化することで、アクセスログを Cloud Logging に出力できます。しかし、12種類あるそれぞれのロードバランサーでは、アクセスログのフォーマットが異なります。そのため、監査目的で組織全体のすべてのロードバランサーのアクセスログを Cloud Logging の 集約シンク で集積したいというようなシチュエーションでログを網羅的に収集するには、ログのフィルタリングのためのクエリを適切に設定する必要があります。 当記事では、12種類の Cloud Load Balancing のアクセスログをフィルタリングするための方法や、各ロードバランサーのアクセスログのサンプルを掲載します。 なお、Cloud Logging や集約シンクについては、以下の記事を参照してください。 blog.g-gen.co.jp アクセスログのフィルタリング フィールドに入る値の違い 12種類のロードバランサーについて、アクセスログをフィルタするための Cloud Logging クエリについて検討します。 Cloud Logging で特定の種類のログエントリをフィルタするには、以下のようなフィールドでフィルタすることが考えられます。 resource.type jsonPayload.@type logName 例として、VPC Flow Logs のログエントリを抽出したい場合、以下のようなクエリになります( my-project はプロジェクト ID に置き換えてください。以下同じ)。 logName= " projects/my-project/logs/compute.googleapis.com%2Fvpc_flows " しかし Cloud Load Balancing においては、12種類のロードバランサーでそれぞれこれらのフィールドに入る値が異なっていることがわかります。 同じ Cloud Load Balancing というサービス名がついていても、ロードバランサー種別によって、その内部構造や成り立ち(開発の経緯)が大きく異なっていることが、この違いの根本にあるように思われます。 コピー&ペーストできるよう、同じ表を以下にテキスト形式でも掲載します。 # ロードバランサー名 resource.type jsonPayload.@type logName 1 Global external Application Load Balancer http_load_balancer type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry projects/my-project/logs/requests 2 Classic Global external Application Load Balancer http_load_balancer type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry projects/my-project/logs/requests 3 Regional external Application Load Balancer http_external_regional_lb_rule type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry projects/my-project/logs/loadbalancing.googleapis.com%2Fexternal_regional_requests 4 Regional internal Application Load Balancer internal_http_lb_rule type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry projects/my-project/logs/loadbalancing.googleapis.com%2Frequests 5 Cross-region internal Application Load Balancer internal_http_lb_rule type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry projects/my-project/logs/loadbalancing.googleapis.com%2Frequests 6 Global external proxy Network Load Balancer l4_proxy_rule type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry projects/my-project/logs/loadbalancing.googleapis.com%2Fconnections 7 Classic Global external proxy Network Load Balancer tcp_ssl_proxy_rule type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry projects/my-project/logs/requests 8 Regional external proxy Network Load Balancer l4_proxy_rule type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry projects/my-project/logs/loadbalancing.googleapis.com%2Fconnections 9 Regional internal proxy Network Load Balancer l4_proxy_rule type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry projects/my-project/logs/loadbalancing.googleapis.com%2Fconnections 10 Cross-region internal proxy Network Load Balancer l4_proxy_rule type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry projects/my-project/logs/loadbalancing.googleapis.com%2Fconnections 11 Regional external passthrough Network Load Balancer loadbalancing.googleapis.com/ExternalNetworkLoadBalancerRule type.googleapis.com/google.cloud.loadbalancing.type.ExternalNetworkLoadBalancerLogEntry projects/my-project/logs/loadbalancing.googleapis.com%2Fflows 12 Regional internal passthrough Network Load Balancer loadbalancing.googleapis.com/InternalNetworkLoadBalancerRule type.googleapis.com/google.cloud.loadbalancing.type.InternalNetworkLoadBalancerLogEntry projects/my-project/logs/loadbalancing.googleapis.com%2Fflows 公式ドキュメントの記述 Google Cloud の公式ドキュメントには、ロードバランサーごとに、アクセスログへのクエリ方法が記載されています。 resource.type でのフィルタリング手順が記載されているドキュメントもあれば、 logName が記載されている場合もあります。 参考 : グローバル外部アプリケーション ロードバランサのロギングとモニタリング 参考 : リージョン外部アプリケーション ロードバランサのロギングとモニタリング 参考 : 内部アプリケーション ロードバランサのロギングとモニタリング 参考 : プロキシ ネットワーク ロードバランサのロギングとモニタリング 参考 : 外部パススルー ネットワーク ロードバランサのロギングとモニタリング 参考 : 内部パススルー ネットワーク ロードバランサのロギングとモニタリング Cloud Logging 用クエリ 表に示したように、12種類すべてのロードバランサーが共通して持つ値はありません。ドキュメントの記述に基づいた各ロードバランサーへのクエリを、以下のように OR 条件を用いて繋げることで、すべての種類のアクセスログを抽出することができます(2024年10月の当社環境による検証結果でも確認)。 クエリ1 ( resource . type =( " http_load_balancer " OR " http_external_regional_lb_rule " OR " internal_http_lb_rule " OR " tcp_ssl_proxy_rule " ) OR logName:( " logs/loadbalancing.googleapis.com%2Fconnections " OR " logs/loadbalancing.googleapis.com%2Fflows " ) ) あるいは以下のように、 jsonPayload.@type フィールドに対して、部分一致を示す : 記号でフィルタすることでもアクセスログを抽出できます。 クエリ2 jsonPayload.@ type : " type.googleapis.com/google.cloud.loadbalancing.type " 上記のクエリは短くてシンプルである一方、公式ドキュメントの手順に基づいていません。さらに、 resource.type や logName フィールドの方が、デフォルトでインデックスが作成されているため、より高速です。 参考 : インデックス フィールドの使用 なお部分一致検索は、完全一致での検索に比較してパフォーマンスが悪いとされています。最初のクエリでも、 logName フィールドに対して部分一致( : )で検索しています。もしクエリのパフォーマンスが重要な場合、プロジェクト名を明示してクエリするか、前掲の表に基づいて resource.type フィールドに対してクエリしてください。 参考 : Logging のクエリ言語 クエリ3 ( resource . type =( " http_load_balancer " OR " http_external_regional_lb_rule " OR " internal_http_lb_rule " OR " tcp_ssl_proxy_rule " ) OR logName=( " projects/my-project/logs/loadbalancing.googleapis.com%2Fconnections " OR " projects/my-project/logs/loadbalancing.googleapis.com%2Fflows " ) ) クエリ4 resource . type =( " http_load_balancer " OR " http_external_regional_lb_rule " OR " internal_http_lb_rule " OR " l4_proxy_rule " OR " tcp_ssl_proxy_rule " OR " loadbalancing.googleapis.com/ExternalNetworkLoadBalancerRule " OR " loadbalancing.googleapis.com/InternalNetworkLoadBalancerRule " ) アクセスログのサンプル 以下に、12種類の各ロードバランサーのアクセスログのサンプルを掲載します。設定の条件によって、ログに含まれるフィールドが異なる場合があることをご了承ください。 Global external Application Load Balancer { " insertId ": " 1hl3dx4f9l9kl0 ", " jsonPayload ": { " enforcedSecurityPolicy ": { " rateLimitAction ": { " key ": " 119.173.43.159 ", " outcome ": " RATE_LIMIT_THRESHOLD_CONFORM " } , " outcome ": " ACCEPT ", " priority ": 2147483646 , " name ": " default-security-policy-for-backend-service-be ", " configuredAction ": " THROTTLE " } , " cacheDecision ": [ " RESPONSE_HAS_ETAG ", " RESPONSE_HAS_LAST_MODIFIED ", " RESPONSE_HAS_CONTENT_TYPE ", " CACHE_MODE_USE_ORIGIN_HEADERS " ] , " remoteIp ": " 119.173.43.159 ", " securityPolicyRequestData ": { " remoteIpInfo ": { " regionCode ": " JP " } } , " backendTargetProjectNumber ": " projects/1234567890 ", " @type ": " type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry ", " statusDetails ": " response_sent_by_backend " } , " httpRequest ": { " requestMethod ": " GET ", " requestUrl ": " http://34.128.128.201/ ", " requestSize ": " 78 ", " status ": 200 , " responseSize ": " 251 ", " userAgent ": " curl/7.88.1 ", " remoteIp ": " 119.173.43.159 ", " serverIp ": " 10.146.15.212 ", " latency ": " 0.006456s " } , " resource ": { " type ": " http_load_balancer ", " labels ": { " backend_service_name ": " be ", " zone ": " global ", " forwarding_rule_name ": " fe ", " url_map_name ": " global-external-alb ", " target_proxy_name ": " global-external-alb-target-proxy ", " project_id ": " my-project " } } , " timestamp ": " 2024-10-19T00:25:02.709671Z ", " severity ": " INFO ", " logName ": " projects/my-project/logs/requests ", " trace ": " projects/my-project/traces/91b497c4aa913d1adb6cb7239ff7c18f ", " receiveTimestamp ": " 2024-10-19T00:25:03.445640111Z ", " spanId ": " c85d614f1f6380f7 " } Classic Global external Application Load Balancer { " insertId ": " d1hn5ifh5uld4 ", " jsonPayload ": { " remoteIp ": " 34.84.45.157 ", " @type ": " type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry ", " cacheDecision ": [ " RESPONSE_HAS_ETAG ", " RESPONSE_HAS_LAST_MODIFIED ", " RESPONSE_HAS_CONTENT_TYPE ", " CACHE_MODE_USE_ORIGIN_HEADERS " ] , " statusDetails ": " response_sent_by_backend ", " backendTargetProjectNumber ": " projects/1234567890 " } , " httpRequest ": { " requestMethod ": " GET ", " requestUrl ": " http://34.160.74.92/ ", " requestSize ": " 76 ", " status ": 200 , " responseSize ": " 251 ", " userAgent ": " curl/7.74.0 ", " remoteIp ": " 34.84.45.157 ", " serverIp ": " 10.146.15.212 ", " latency ": " 0.004245s " } , " resource ": { " type ": " http_load_balancer ", " labels ": { " target_proxy_name ": " classic-global-external-alb-target-proxy ", " forwarding_rule_name ": " classic-global-external-alb-fe ", " project_id ": " my-project ", " backend_service_name ": " classic-global-external-alb-be ", " url_map_name ": " classic-global-external-alb ", " zone ": " global " } } , " timestamp ": " 2024-10-19T01:26:45.677162Z ", " severity ": " INFO ", " logName ": " projects/my-project/logs/requests ", " trace ": " projects/my-project/traces/fd0787f95c1d8c088f56dd3a0fc645a9 ", " receiveTimestamp ": " 2024-10-19T01:26:46.011597715Z ", " spanId ": " 0600c851dd6caba0 " } Regional external Application Load Balancer { " insertId ": " r6zhmhe3tin0 ", " jsonPayload ": { " securityPolicyRequestData ": { " remoteIpInfo ": { " asn ": 9824 , " regionCode ": " JP " } } , " enforcedSecurityPolicy ": { " configuredAction ": " THROTTLE ", " outcome ": " ACCEPT ", " priority ": 2147483646 , " name ": " default-security-policy-for-be-regional-external-alb ", " rateLimitAction ": { " key ": " 119.173.43.159 ", " outcome ": " RATE_LIMIT_THRESHOLD_CONFORM " } } , " @type ": " type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry ", " backendTargetProjectNumber ": " projects/1234567890 " } , " httpRequest ": { " requestMethod ": " GET ", " requestUrl ": " http://34.146.179.192/ ", " requestSize ": " 78 ", " status ": 200 , " responseSize ": " 251 ", " userAgent ": " curl/7.88.1 ", " remoteIp ": " 119.173.43.159:45490 ", " serverIp ": " 10.146.15.212:80 ", " latency ": " 0.006646s ", " protocol ": " HTTP/1.1 " } , " resource ": { " type ": " http_external_regional_lb_rule ", " labels ": { " forwarding_rule_name ": " fe-regional-external-alb ", " network_name ": " default ", " url_map_name ": " regional-external-alb ", " backend_target_type ": " BACKEND_SERVICE ", " target_proxy_name ": " regional-external-alb-target-proxy ", " backend_type ": " INSTANCE_GROUP ", " matched_url_path_rule ": " UNMATCHED ", " backend_name ": " my-unmanaged-instance-group ", " backend_target_name ": " be-regional-external-alb ", " project_id ": " my-project ", " region ": " asia-northeast1 ", " backend_scope ": " asia-northeast1-b ", " backend_scope_type ": " ZONE " } } , " timestamp ": " 2024-10-19T00:26:57.853386Z ", " severity ": " INFO ", " logName ": " projects/my-project/logs/loadbalancing.googleapis.com%2Fexternal_regional_requests ", " receiveTimestamp ": " 2024-10-19T00:27:01.596354155Z " } Regional internal Application Load Balancer { " insertId ": " 1g7z8yle6gehh ", " jsonPayload ": { " backendTargetProjectNumber ": " projects/1234567890 ", " @type ": " type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry " } , " httpRequest ": { " requestMethod ": " GET ", " requestUrl ": " http://10.146.0.6/ ", " requestSize ": " 74 ", " status ": 200 , " responseSize ": " 251 ", " userAgent ": " curl/7.74.0 ", " remoteIp ": " 10.146.15.212:34372 ", " serverIp ": " 10.146.15.212:80 ", " latency ": " 0.005247s ", " protocol ": " HTTP/1.1 " } , " resource ": { " type ": " internal_http_lb_rule ", " labels ": { " project_id ": " my-project ", " matched_url_path_rule ": " UNMATCHED ", " backend_target_type ": " BACKEND_SERVICE ", " backend_scope_type ": " ZONE ", " backend_type ": " INSTANCE_GROUP ", " url_map_name ": " regional-internal-alb ", " target_proxy_name ": " regional-internal-alb-target-proxy ", " forwarding_rule_name ": " regional-internal-alb-fe ", " backend_name ": " my-unmanaged-instance-group ", " backend_scope ": " asia-northeast1-b ", " backend_target_name ": " regional-internal-alb-be ", " network_name ": " default ", " region ": " asia-northeast1 " } } , " timestamp ": " 2024-10-19T01:07:22.171311Z ", " severity ": " INFO ", " logName ": " projects/my-project/logs/loadbalancing.googleapis.com%2Frequests ", " receiveTimestamp ": " 2024-10-19T01:07:31.591492497Z " } Cross-region internal Application Load Balancer { " insertId ": " nvlidgezxrk5 ", " jsonPayload ": { " backendTargetProjectNumber ": " projects/1234567890 ", " @type ": " type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry " } , " httpRequest ": { " requestMethod ": " GET ", " requestUrl ": " http://10.146.0.7/ ", " requestSize ": " 74 ", " status ": 200 , " responseSize ": " 251 ", " userAgent ": " curl/7.74.0 ", " remoteIp ": " 10.146.15.212:49148 ", " serverIp ": " 10.146.15.212:80 ", " latency ": " 0.000594s ", " protocol ": " HTTP/1.1 " } , " resource ": { " type ": " internal_http_lb_rule ", " labels ": { " target_proxy_name ": " cross-region-internal-alb-target-proxy ", " url_map_name ": " cross-region-internal-alb ", " region ": " asia-northeast1 ", " project_id ": " my-project ", " network_name ": " default ", " backend_target_name ": " cross-region-internal-alb-be ", " backend_type ": " INSTANCE_GROUP ", " backend_scope_type ": " ZONE ", " backend_name ": " my-unmanaged-instance-group ", " backend_scope ": " asia-northeast1-b ", " matched_url_path_rule ": " UNMATCHED ", " forwarding_rule_name ": " cross-region-internal-alb-fe ", " backend_target_type ": " BACKEND_SERVICE " } } , " timestamp ": " 2024-10-19T01:13:07.097824Z ", " severity ": " INFO ", " logName ": " projects/my-project/logs/loadbalancing.googleapis.com%2Frequests ", " receiveTimestamp ": " 2024-10-19T01:13:11.841628180Z " } Global external proxy Network Load Balancer { " insertId ": " wqqyu5e6bgx2 ", " jsonPayload ": { " endTime ": " 2024-10-19T01:34:01.839237Z ", " startTime ": " 2024-10-19T01:34:01.837981Z ", " connection ": { " clientIp ": " 10.146.15.212 ", " serverPort ": 80 , " protocol ": 6 , " clientPort ": 58774 , " serverIp ": " 10.146.15.233 " } , " serverBytesReceived ": " 77 ", " @type ": " type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry ", " serverBytesSent ": " 258 " } , " resource ": { " type ": " l4_proxy_rule ", " labels ": { " forwarding_rule_name ": " regional-internal-proxy-nlb-fe ", " network_name ": " default ", " protocol ": " TCP ", " region ": " asia-northeast1 ", " backend_scope ": " asia-northeast1-b ", " load_balancing_scheme ": " INTERNAL_MANAGED ", " target_proxy_name ": " regional-internal-proxy-nlb-target-proxy ", " backend_name ": " my-unmanaged-instance-group ", " backend_target_name ": " regional-internal-proxy-nlb ", " backend_scope_type ": " ZONE ", " project_id ": " my-project ", " backend_type ": " INSTANCE_GROUP ", " backend_target_type ": " BACKEND_SERVICE " } } , " timestamp ": " 2024-10-19T01:34:01.837981Z ", " severity ": " INFO ", " logName ": " projects/my-project/logs/loadbalancing.googleapis.com%2Fconnections ", " receiveTimestamp ": " 2024-10-19T01:34:06.969020769Z " } Classic Global external proxy Network Load Balancer { " insertId ": " g5348lf4ffk6m ", " jsonPayload ": { " remoteIp ": " 34.84.45.157 ", " @type ": " type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry ", " statusDetails ": " response_sent_by_backend ", " backendTargetProjectNumber ": " projects/1234567890 " } , " resource ": { " type ": " tcp_ssl_proxy_rule ", " labels ": { " region ": " global ", " backend_scope ": " asia-northeast1-b ", " project_id ": " my-project ", " forwarding_rule_name ": " classic-global-external-proxy-nlb-fe ", " backend_target_name ": " classic-global-external-proxy-nlb ", " backend_name ": " 7592391117369982738 ", " target_proxy_name ": " classic-global-external-proxy-target-proxy ", " backend_scope_type ": " ZONE ", " backend_target_type ": " BACKEND_SERVICE ", " backend_type ": " INSTANCE_GROUP " } } , " timestamp ": " 2024-10-19T01:28:26.522314Z ", " severity ": " INFO ", " logName ": " projects/my-project/logs/requests ", " receiveTimestamp ": " 2024-10-19T01:28:28.589962783Z " } Regional external proxy Network Load Balancer { " insertId ": " eqlb0pe8i7nf ", " jsonPayload ": { " startTime ": " 2024-10-19T01:32:45.769843Z ", " endTime ": " 2024-10-19T01:32:45.776569Z ", " serverBytesReceived ": " 76 ", " @type ": " type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry ", " connection ": { " clientIp ": " 34.84.45.157 ", " serverPort ": 80 , " clientPort ": 39902 , " protocol ": 6 , " serverIp ": " 34.85.18.103 " } , " serverBytesSent ": " 258 " } , " resource ": { " type ": " l4_proxy_rule ", " labels ": { " target_proxy_name ": " regional-external-proxy-nlb-target-proxy ", " protocol ": " TCP ", " forwarding_rule_name ": " regional-external-proxy-nlb-fe ", " backend_target_type ": " BACKEND_SERVICE ", " backend_type ": " INSTANCE_GROUP ", " project_id ": " my-project ", " backend_name ": " my-unmanaged-instance-group ", " load_balancing_scheme ": " EXTERNAL_MANAGED ", " backend_target_name ": " regional-external-proxy-nlb ", " region ": " asia-northeast1 ", " network_name ": " default ", " backend_scope_type ": " ZONE ", " backend_scope ": " asia-northeast1-b " } } , " timestamp ": " 2024-10-19T01:32:45.769843Z ", " severity ": " INFO ", " logName ": " projects/my-project/logs/loadbalancing.googleapis.com%2Fconnections ", " receiveTimestamp ": " 2024-10-19T01:32:51.445900382Z " } Regional internal proxy Network Load Balancer { " insertId ": " wqqyu5e6bgx2 ", " jsonPayload ": { " endTime ": " 2024-10-19T01:34:01.839237Z ", " startTime ": " 2024-10-19T01:34:01.837981Z ", " connection ": { " clientIp ": " 10.146.15.212 ", " serverPort ": 80 , " protocol ": 6 , " clientPort ": 58774 , " serverIp ": " 10.146.15.233 " } , " serverBytesReceived ": " 77 ", " @type ": " type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry ", " serverBytesSent ": " 258 " } , " resource ": { " type ": " l4_proxy_rule ", " labels ": { " forwarding_rule_name ": " regional-internal-proxy-nlb-fe ", " network_name ": " default ", " protocol ": " TCP ", " region ": " asia-northeast1 ", " backend_scope ": " asia-northeast1-b ", " load_balancing_scheme ": " INTERNAL_MANAGED ", " target_proxy_name ": " regional-internal-proxy-nlb-target-proxy ", " backend_name ": " my-unmanaged-instance-group ", " backend_target_name ": " regional-internal-proxy-nlb ", " backend_scope_type ": " ZONE ", " project_id ": " my-project ", " backend_type ": " INSTANCE_GROUP ", " backend_target_type ": " BACKEND_SERVICE " } } , " timestamp ": " 2024-10-19T01:34:01.837981Z ", " severity ": " INFO ", " logName ": " projects/my-project/logs/loadbalancing.googleapis.com%2Fconnections ", " receiveTimestamp ": " 2024-10-19T01:34:06.969020769Z " } Cross-region internal proxy Network Load Balancer { " insertId ": " 1kbs0nme7cs09 ", " jsonPayload ": { " serverBytesSent ": " 258 ", " serverBytesReceived ": " 77 ", " connection ": { " serverIp ": " 10.146.15.234 ", " serverPort ": 80 , " clientPort ": 38876 , " protocol ": 6 , " clientIp ": " 10.146.15.212 " } , " startTime ": " 2024-10-19T01:40:48.650089Z ", " endTime ": " 2024-10-19T01:40:48.656509Z ", " @type ": " type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry " } , " resource ": { " type ": " l4_proxy_rule ", " labels ": { " protocol ": " TCP ", " load_balancing_scheme ": " INTERNAL_MANAGED ", " network_name ": " default ", " target_proxy_name ": " cross-region-internal-proxy-nl-target-proxy ", " backend_scope_type ": " ZONE ", " forwarding_rule_name ": " cross-region-internal-proxy-nlb-fe ", " backend_target_type ": " BACKEND_SERVICE ", " backend_type ": " INSTANCE_GROUP ", " project_id ": " my-project ", " region ": " asia-northeast1 ", " backend_name ": " my-unmanaged-instance-group ", " backend_scope ": " asia-northeast1-b ", " backend_target_name ": " cross-region-internal-proxy-nlb " } } , " timestamp ": " 2024-10-19T01:40:48.650089Z ", " severity ": " INFO ", " logName ": " projects/my-project/logs/loadbalancing.googleapis.com%2Fconnections ", " receiveTimestamp ": " 2024-10-19T01:40:51.373191590Z " } Regional external passthrough Network Load Balancer { " insertId ": " 1fcug38f3uvja4 ", " jsonPayload ": { " endTime ": " 2024-10-19T01:59:03.698069641Z ", " startTime ": " 2024-10-19T01:59:03.696967927Z ", " @type ": " type.googleapis.com/google.cloud.loadbalancing.type.ExternalNetworkLoadBalancerLogEntry ", " connection ": { " clientIp ": " 34.84.45.157 ", " serverIp ": " 34.84.37.150 ", " protocol ": 6 , " serverPort ": 80 , " clientPort ": 53720 } , " packetsReceived ": " 8 " } , " resource ": { " type ": " loadbalancing.googleapis.com/ExternalNetworkLoadBalancerRule ", " labels ": { " backend_group_scope ": " ZONE ", " primary_target_pool ": "", " backend_service_name ": " regional-external-passthrough-nlb ", " backend_subnetwork_name ": " default ", " forwarding_rule_name ": " regional-external-passthrough-nlb-fe ", " backend_group_name ": " my-unmanaged-instance-group ", " target_pool ": "", " project_id ": " my-project ", " backend_zone ": " asia-northeast1-b ", " backend_network_name ": " default ", " backend_group_type ": " INSTANCE_GROUP ", " backend_target_type ": " BACKEND_SERVICE ", " region ": " asia-northeast1 " } } , " timestamp ": " 2024-10-19T01:59:03.698069641Z ", " logName ": " projects/my-project/logs/loadbalancing.googleapis.com%2Fflows ", " receiveTimestamp ": " 2024-10-19T01:59:16.645829810Z " } Regional internal passthrough Network Load Balancer { " insertId ": " 1gq6lrwfwidq51 ", " jsonPayload ": { " packetsSent ": " 2 ", " bytesReceived ": " 154 ", " endTime ": " 2024-10-19T02:03:37.78722619Z ", " packetsReceived ": " 2 ", " startTime ": " 2024-10-19T02:03:37.787098544Z ", " connection ": { " serverPort ": 80 , " clientIp ": " 10.146.15.212 ", " serverIp ": " 10.146.15.236 ", " protocol ": 6 , " clientPort ": 36116 } , " @type ": " type.googleapis.com/google.cloud.loadbalancing.type.InternalNetworkLoadBalancerLogEntry ", " rtt ": " 0.000127646s " } , " resource ": { " type ": " loadbalancing.googleapis.com/InternalNetworkLoadBalancerRule ", " labels ": { " backend_service_name ": " regional-internal-passthrough-nlb ", " region ": " asia-northeast1 ", " project_id ": " my-project ", " backend_subnetwork_name ": " default ", " forwarding_rule_name ": " regional-internal-passthrough-nlb-fe ", " backend_network_name ": " default ", " backend_group_type ": " INSTANCE_GROUP ", " backend_group_scope ": " ZONE ", " backend_group_name ": " my-unmanaged-instance-group " } } , " timestamp ": " 2024-10-19T02:03:37.787226190Z ", " logName ": " projects/my-project/logs/loadbalancing.googleapis.com%2Fflows ", " receiveTimestamp ": " 2024-10-19T02:03:46.610207174Z " } 杉村 勇馬 (記事一覧) 執行役員 CTO / クラウドソリューション部 部長 元警察官という経歴を持つ現 IT エンジニア。クラウド管理・運用やネットワークに知見。AWS 12資格、Google Cloud認定資格11資格。X (旧 Twitter) では Google Cloud や AWS のアップデート情報をつぶやいています。 Follow @y_sugi_it
アバター
G-gen の武井です。当記事では、Access Context Manager を使い、Google Cloud コンソール と API へのアクセスを制限する方法について解説します。 はじめに 概要 実現できること アクセスレベル アーキテクチャ 概要 アクセス制限の対象ユーザー 組織外ユーザーに対するアクセス制限 実際にやってみた (デモ) 説明 Admin コンソールでの設定 Cloud コンソールでの設定 動作確認 シリアル番号の収集、登録 Google グループの作成 アクセスレベルの作成 Google グループとアクセスレベルの紐づけ Cloud コンソールへのアクセス #1 の結果 #2 の結果 gcloud CLI の実行 #1 (会社所有のインベントリに登録された端末) の結果 #2 (会社所有のインベントリに登録された端末) の結果 関連記事 はじめに 概要 当記事ではデバイス情報、アカウント情報、接続状況などの 背景情報 (コンテキスト) にもとづき、Google Cloud の Web コンソールや、gcloud コマンドライン・SDK を使った Google Cloud API へのアクセス制限方法について解説します。 実現できること Google Cloud 環境の利用者に対し、接続元 IP アドレスや端末シリアル等のデバイスポリシーといった、 コンテキストベースのルール (アクセスレベル) にもとづくアクセス制御 が行えます。 アクセスレベルで定義した条件に違反する利用者は、コンソール画面にアクセスできないほか、CLI や SDK を使った環境操作もできなくなります。 アクセスレベル アクセスレベルは Access Context Manager で作成できます。 以下の要素を条件として指定できますが、デバイスポリシーを使ってルールを作成する場合は Chrome Enterprise Premium (旧 BeyondCorp Enterprise) のライセンス契約が必要です。 属性 説明 補足 IPアドレス ・IPv4 アドレス ・IPv6 アドレス ・プライベート IP は不可 地域 ・国名コード (JP等) - アクセスレベルの依存関係 ・他のアクセスレベル - プリンシパル ・ユーザーアカウント ・サービスアカウント ・グループは指定不可 ・コンソールからの設定不可 (gcloud / API からのみ設定可) デバイスポリシー ・画面のロック ・管理者の承認 ・会社所有のデバイス (シリアル) ・ストレージの暗号化 ・OS ポリシー ・CEP ライセンスが必要 参考: Access Context Manager の概要 参考: アクセスレベルの属性 参考: Chrome Enterprise Premium アーキテクチャ 概要 設定としては、Access Context Manager で作成したアクセスレベルを、アクセス制限対象のユーザーをグルーピングした Google グループに紐づけます。 これにより、アクセスレベルに合致しないユーザーは、Google Cloud コンソールや Cloud APIs へのアクセスが制限される仕組みです。 必要なコンポーネント 役割 Endpoint Verification (任意) アクセス制限対象ユーザーのデバイス属性情報の収集に使用 Google グループ (必須) アクセス制限対象ユーザーのグルーピングに使用 アクセスレベル (必須) アクセス制限の条件 (ホワイトリスト) として使用 参考: Endpoint Verification の概要 アクセス制限の対象ユーザー 当仕組みにおけるアクセス制限の対象ユーザーは、アクセスレベルを紐づけた Google グループに所属する、同一組織 (上図でいう example.co.jp ) のユーザーのみです。 同一組織であっても当該グループに属さないユーザーや組織外のユーザーに対しては、 当仕組みを用いたアクセス制限の効力が及ばない (無制限でアクセス可能である) という点にご留意ください。 組織外のユーザーは、当該グループに属していたとしても制限の対象とはなりません。 組織外ユーザーに対するアクセス制限 上記の理由から、組織外ユーザーからのアクセスを制限したい場合、別の仕組みによる保護を検討してください。以下はその例です。 組織のポリシー ( constraints/iam.allowedPolicyMemberDomains ) で当該組織上での IAM Policy 設定を禁止する VPC Service Controls で Cloud APIs へのアクセスを禁止する 参考: ドメイン別の ID の制限 参考: VPC Service Controlsを分かりやすく解説 (G-gen Tech Blog) 実際にやってみた (デモ) 説明 このデモでは、 端末のシリアル番号 をアクセスレベルに組み込み、Cloud コンソールや gcloud による Cloud APIs に対するアクセス制限が実現できるかを確認します。 以下の順で設定を行い、最後に動作確認を行います。 Admin コンソールでの設定 シリアル番号の収集、登録 Google グループの作成 Cloud コンソールでの設定 アクセスレベルの作成 Google グループとアクセスレベルの紐づけ (アクセス制限の有効化) 動作確認 Cloud コンソールへのアクセス gcloud CLI の実行 シリアル番号の収集、登録 端末のシリアル番号を使ってアクセス制限を実施する場合、操作端末のシリアル番号を 会社所有のインベントリ に登録します。 操作端末を Google Workspace の管理コンソール上の デバイス として登録 デバイスとして登録された操作端末のシリアル番号を 会社所有のインベントリ に登録 操作端末をデバイスに登録 デバイスに登録した操作端末のシリアル番号を、会社所有のインベントリに登録 手順の詳細は以下の公式ガイドをご参照ください。 参考: パソコンに Endpoint Verification を設定する 参考: 会社で所有しているデバイスをインベントリに追加する Google グループの作成 アクセス制限対象のユーザーをグルーピングするため、 Google グループ を作成します。 アクセス制限対象者をGoogle グループでグルーピング 手順の詳細は以下の公式ガイドをご参照ください。 参考: グループを作成し、グループ設定を選択する アクセスレベルの作成 次に、Cloud コンソールから Access Context Manager を選択し、アクセスレベルを作成します。 今回のデモでは端末のシリアル番号を使ってアクセス制限を行うので、条件に デバイスポリシー (会社所有のデバイスが必要) を選択します。 アクセスレベルの条件にはデバイスポリシーの「会社所有のデバイスが必要」を選択 作成されたアクセスレベル 手順の詳細は以下の公式ガイドをご参照ください。 参考: アクセスレベルを作成する 参考: ベーシック アクセスレベルを作成する 参考: 必要な IAM 権限を付与する Google グループとアクセスレベルの紐づけ Google グループとアクセスレベルを紐づけ、Cloud コンソールや API へのアクセス制御を有効化します。 任意のプロジェクトを選択した状態で、検索バーで chrome enterprise premium と入力してサービスを選択したら、 CLOUD コンソールと API へのアクセスを管理 をクリックします。 その後、 アクセスを管理 > 追加 の順で遷移したら Google グループとアクセスレベルを紐づけます。 アクセスを管理をクリック 追加をクリック グループとアクセスレベルを紐づけて保存する 手順の詳細は以下の公式ガイドをご参照ください。 参考: アクセスレベルを使用してアクセス バインディングを作成する Cloud コンソールへのアクセス 以下の条件で動作確認を行います。 # アカウント (所属グループ) シリアル番号 1 yutakei@example.co.jp (restrict@example.co.jp) 会社所有のインベントリに登録 2 yutakei@example.co.jp (restrict@example.co.jp) 会社所有のインベントリに 未登録 #1 の結果 操作端末のシリアル番号がアクセスレベルに合致する ため、Cloud コンソールへアクセスできました。 アクセスレベルに合致したため、Cloud コンソールにアクセスできた #2 の結果 操作端末のシリアル番号がアクセスレベルに合致しない ため、Cloud コンソールへのアクセスが制限されました。 アクセスレベルに合致しないため、Cloud コンソールへのアクセスが制限された gcloud CLI の実行 前述の条件で動作確認を行います。 #1 (会社所有のインベントリに登録された端末) の結果 操作端末のシリアル番号がアクセスレベルに合致する ため、 gcloud auth login や gcloud auth application-default login コマンドが成功しました。 $ gcloud auth login Your browser has been opened to visit: 中略 You are now logged in as [ yutakei@example.co.jp ] . Your current project is [ cep-demo-prj ] . You can change this setting by running: $ gcloud config set project PROJECT_ID $ gcloud auth application-default login Your browser has been opened to visit: 中略 Credentials saved to file: [ /home/yutakei/.config/gcloud/application_default_credentials.json ] These credentials will be used by any library that requests Application Default Credentials ( ADC ) . Quota project " cep-demo-prj " was added to ADC which can be used by Google client libraries for billing and quota. Note that some services may still bill the project owning the resource. #2 (会社所有のインベントリに登録された端末) の結果 操作端末のシリアル番号がアクセスレベルに合致しない ため、 gcloud auth login や gcloud auth application-default login コマンドが失敗しました。 $ gcloud auth login Your browser has been opened to visit: 中略 ERROR: Access was blocked by Context Aware Access. If you are using gcloud in an SSH session and your organization requires gcloud from a company registered device, please first RDP into your remote machine and log into Chrome. ERROR: ( gcloud.auth.login ) ( access_denied ) Account restricted $ gcloud auth application-default login Your browser has been opened to visit: 中略 ERROR: Access was blocked by Context Aware Access. If you are using gcloud in an SSH session and your organization requires gcloud from a company registered device, please first RDP into your remote machine and log into Chrome. ERROR: ( gcloud.auth.application-default.login ) ( access_denied ) Account restricted 関連記事 blog.g-gen.co.jp 武井 祐介 (記事一覧) クラウドソリューション部所属。G-gen唯一の山梨県在住エンジニア Google Cloud Partner Top Engineer 2024 に選出。IaC や CI/CD 周りのサービスやプロダクトが興味分野です。 趣味はロードバイク、ロードレースやサッカー観戦です。 Follow @ggenyutakei
アバター
G-gen の杉村です。当記事では、Google Cloud の IAM(Identity and Access Management)で最小権限の原則を実現するための手段をご紹介します。 IAM と最小権限の原則 過剰な権限を予防する IAM の仕組みを正確に理解する IAM ポリシーを編集できる人を限定する 一時的な特権の管理 適切な IAM ロールを選択する ドキュメントの確認とロール選定 Gemini による支援 すでに付与された権限を整理する IAM Recommender Policy Analyzer Cloud Assets Inventory IAM と最小権限の原則 IAM (Identity and Access Management)は、Google Cloud のリソースに対する権限管理の仕組みです。詳細は以下の記事をご確認ください。 blog.g-gen.co.jp セキュアなクラウド環境を維持するには、IAM で 最小権限の原則 を遵守することが重要です。最小権限の原則とは、「システムの利用主体に持たせるアクセス権限は、必要最小限に抑えるべきである」という設計思想であり、情報セキュリティの大原則です。 しかし Google Cloud でシステムをしばらく運用していると、IAM ロールが過剰に付与されてしまっていることに後から気がつくことが、度々あります。 当記事では、最小権限の原則を守る手段を、「 過剰な権限を予防する 」「 適切な IAM ロールを選択する 」「 すでに付与された権限を整理する 」の3パートにわけて解説します。 過剰な権限を予防する IAM の仕組みを正確に理解する プロジェクトのオーナーや組織の管理者にとって、最小権限を実現するためになにより重要なのは、Google Cloud の IAM の仕組みを正確に理解することです。以下のような概念を正確に理解するべきです。 リソースの持つ IAM ポリシー IAM バインディング 継承 Google Cloud の IAM の仕組みは、Amazon Web Services(AWS)等のそれとは大きく異なります。まずは以下の記事を読み、Google Cloud の IAM の仕組みを正確に理解してください。 blog.g-gen.co.jp IAM ポリシーを編集できる人を限定する 組織やプロジェクト、各 Google Cloud リソースに過剰な権限が付与されてしまう状況を予防するには、IAM ポリシーを編集できる人(主体)を限定することが重要です。 例えば、組織レベルの IAM ポリシーを操作できる権限である resourcemanager.organizations.setIamPolicy は、以下のような IAM ロールに含まれています。 組織の管理者( roles/privilegedaccessmanager.organizationServiceAgent ) セキュリティ管理者( roles/iam.securityAdmin ) また、プロジェクトレベルの IAM ポリシーを操作できる権限である resourcemanager.projects.setIamPolicy は、以下のような IAM ロールに含まれています。 オーナー( roles/owner ) 組織の管理者( roles/privilegedaccessmanager.organizationServiceAgent ) セキュリティ管理者( roles/iam.securityAdmin ) プロジェクト IAM 管理者( roles/resourcemanager.projectIamAdmin ) 組織やフォルダ、プロジェクトの IAM 権限が容易に変更されないよう、これらのロールを付与するアカウントを限定的にすることが望ましいです。 ある権限がどの IAM ロールに含まれているかを調査するには、以下のドキュメントをご参照ください。 参考 : IAM roles and permissions index 一時的な特権の管理 前述のように IAM 権限を操作できる人を限定すると、開発スピードが低下したり、運用性が低下することが考えられます。 必要なときに、必要な間だけ、必要な権限を付与するような運用を実現するには、 Privileged Access Manager (PAM)が利用できます。PAM はフルマネージドの特権管理ワークフローであり「権限の申請」「承認」「所定時間が経過したあとの特権剥奪」といったワークフローを簡単に実装できます。 PAM の申請画面 PAM によって承認フローを含めたジャスト・イン・タイム(JIT)な IAM 特権管理を行うことで、セキュアな最小権限を維持しながら、開発スピードや運用性の低下を防ぐことが可能です。 PAM の詳細は以下の記事をご確認ください。 blog.g-gen.co.jp 適切な IAM ロールを選択する ドキュメントの確認とロール選定 Google アカウントや Google グループなどのプリンシパルに IAM ロールを付与する際は、必要最小限の権限を持つ IAM ロールを選択します。 以下の公式ドキュメントを確認したり、あるいは Google Cloud プロダクトごとの IAM 関連のガイドを確認し、必要最小限の権限を持つ事前定義ロールを選択します。 参考 : IAM roles and permissions index 実行したいアクションに対して、どの権限(permission)が必要なのかは、アクションが呼び出す API メソッドにより決まります。公式ガイドを確認したり、あるいはアクション実行時に出力される Cloud Logging ログ、また権限が足りなかったときに出力されるエラーメッセージなどが参考になります。 Gemini による支援 Google Cloud コンソールには、生成 AI モデル Gemini が、実現したいことに対する適切な IAM ロールを推奨してくれる機能があります。詳細は以下の記事を参照してください。 blog.g-gen.co.jp すでに付与された権限を整理する IAM Recommender IAM Recommender は、最近(デフォルトで90日間)の IAM 利用状況を機械学習で分析し、推奨される対策を提示してくれる機能です。あるプロジェクト(または組織やフォルダ)に付与された過剰な権限を洗い出したいときに利用できます。 IAM Recommender は、組織やフォルダ、プロジェクトの IAM 画面から確認することができます。 IAM 一覧画面に表示される推奨事項 推奨事項の内訳 IAM Recommender は無料で利用できますが、以下の分析や推奨を生成するには、組織レベルで Security Command Center のプレミアムティアに登録している必要があります(一部抜粋)。 基本ロール(オーナー、編集者、閲覧者)以外の推奨事項 組織、フォルダ、プロジェクト以外に付与されたロールに関する推奨事項 無料版だとオーナー、編集者、閲覧者といった基本ロールに対してしか推奨事項が生成されません。 参考 : ロールの推奨事項の概要 Policy Analyzer Policy Analyzer は、Google Cloud リソースの IAM ポリシーに対してクエリを行い、あるプリンシパル(Google アカウント等)やロール、リソースの権限を一覧表示させたいときに使います。 例えば、以下のようなことが実現可能です。 あるプロジェクトにおいて、サービスアカウントの権限を借用できるプリンシパルを一覧化する あるプロジェクトにおいて、ファイアウォールルールを編集できるプリンシパルを一覧化する ある BigQuery データセットを編集または閲覧可能なプリンシパルを一覧化する Policy Analyzer は、Google Cloud コンソールの「IAM と管理」の画面の「ポリシー アナライザ」から利用できます。無料で利用できますが、1日に20回のクエリまでという制限があります。20回を超えるクエリを実行するには、組織レベルでSecurity Command Center のプレミアムティアに登録する必要があります。 任意の検索ができるカスタムクエリに加えて、以下のようなプリセットのクエリが用意されています(スクリーンショットは2024年10月現在)。 プリセットされているクエリ カスタムクエリ作成画面 カスタムクエリの結果画面 参考 : IAM ポリシー用の Policy Analyzer Cloud Assets Inventory Cloud Assets Inventory には、あるプリンシパルがどのリソースに権限を持っているかをリストアップする機能があります。利用料金はありません。 Google Cloud コンソールの Cloud Asset Inventory 画面から、あるいは gcloud コマンド等を使ってクエリをかけることができます。 Cloud Asset Inventory での IAM ポリシークエリ この機能は、以下のようなユースケースで利用できます。 特定のプリンシパルが、どのリソースに対してどのような権限を持っているかをリストアップする 組織全体で、オーナー権限を持っている Google アカウントやグループをリストアップする あるデータセットに対して、誰がアクセス権限(閲覧、編集)を持っているかをリストアップする これらは、Policy Analyzer でできることとほとんど同様です。ただし、Cloud Assets Inventory でのクエリに実行回数制限はないため、利用方法を理解していれば、こちらの機能で代替することができます。 Cloud Assets Inventory の詳細については、以下の記事もご参照ください。 blog.g-gen.co.jp 杉村 勇馬 (記事一覧) 執行役員 CTO 元警察官という経歴を持つ IT エンジニア。クラウド管理・運用やネットワークに知見。AWS 認定資格および Google Cloud 認定資格はすべて取得。X(旧 Twitter)では Google Cloud や Google Workspace のアップデート情報をつぶやいています。 Follow @y_sugi_it
アバター
G-gen の杉村です。2024年10月のイチオシ Google Cloud アップデートをまとめてご紹介します。記載は全て、記事公開当時のものですのでご留意ください。 はじめに Gemini で Dynamic retrieval が GA BigQuery コンソールで Airflow の DAG が管理できるように Google Forms で新しい質問タイプ「Rating」が使えるように BigQuery の SQL で Pipe syntax(パイプ構文)が Preview 公開 Gemini Code Assist に Enterprise プランが登場 Looker から Looker Studio レポートが閲覧・編集可能に(Preview) Cloud Armor で IP Address groups 機能が公開(GA) BigQuery の history-based optimizations は今後デフォルトに BigQuery で Fine-grained DML が申請付き Preview 公開 Google Workspace の Gmail への移行ツールが GA(一般公開) Gemini for Google Workspace のサイドパネルが日本語対応(アルファ版) Google Chat で未読メッセージを生成 AI がサマリ Vertex AI Search で CMEK が利用可能に(US と EU) Associate Google Workspace Administrator 試験(Beta)が受付開始 BigQuery data preparation が Preview 公開 Vertex AI Search でグラウンディングスコアが取得できるように(GA) AlloyDB でメジャーバージョンのインプレイスアップグレード(Preview) Cloud Storage の認証済み URL がデータアクセス監査ログに対応 GitHub Copilot で Gemini モデルが使えるように はじめに 当記事では、毎月の Google Cloud アップデートのうち特に重要なものをまとめます。 また当記事は、Google Cloud に関するある程度の知識を前提に記載されています。前提知識を得るには、ぜひ以下の記事もご参照ください。 blog.g-gen.co.jp リンク先の公式ガイドは、英語版で表示しないと最新情報が反映されていない場合がありますためご注意ください。 Gemini で Dynamic retrieval が GA Generative AI on Vertex AI - Dynamic retrieval (2024-10-01) Gemini で Dynamic retrieval が GA。 Google Search へのグラウンディングが、有効になりそうかの度合い(Prediction score。0〜1の間の小数値)が設定した閾値を超えたときだけ、グラウンディングが行われるようになる。レイテンシや処理コストの調整のため利用できる。 同時に、Vertex AI Agent Builder でも同様の機能が Allowlist 付き Preview 公開。 参考 : Generate grounded answers with RAG BigQuery コンソールで Airflow の DAG が管理できるように Manage Airflow DAGs (2024-10-07) BigQuery コンソールで Airflow の DAG が管理できるようになった(Preview)。 バックエンドは、Cloud Composer 3。Cloud Composer 3 は、フルマネージドの Apache Airflow であり、3 では従来型と異なり、サーバーが見えないフルマネージドになった。 Google Forms で新しい質問タイプ「Rating」が使えるように Ask responders for a rating in Google Forms (2024-10-07) Google Forms で新しい質問タイプ「Rating」が使えるようになる。 満足度(CSAT)の回答などに使える。アイコンは★、いいねマーク、ハートマークがつかえる。10/7から順次ロールアウト。 BigQuery の SQL で Pipe syntax(パイプ構文)が Preview 公開 Pipe syntax (2024-10-08) BigQuery の SQL で Pipe syntax(パイプ構文)が使えるように(Preview)。 クエリをパイプで繋いで結果を渡していくことで直感的にクエリが書ける。探索的なクエリ時やログ検索時などに最適。サブクエリを含む複雑なクエリがシンプルになることも期待できる。 以下の記事も参照。 blog.g-gen.co.jp Gemini Code Assist に Enterprise プランが登場 Introducing AI-powered app dev with code customization from Gemini Code Assist Enterprise (2024-10-10) コーディング補助サービス「Gemini Code Assist」に Enterprise プランが登場。 Standard との違いは、以下とおり。 GitHub や GitLab のコードを読み込ませて、コード生成を最適化する Code Customization Gemini in Databases Gemini in BigQuery Looker から Looker Studio レポートが閲覧・編集可能に(Preview) Using Studio in Looker (2024-10-09) Looker(Google Cloud core)で、Studio in Looker 機能が Preview 公開。 Looker から Looker Studio レポートが閲覧・編集できる。利用には申請が必要。 Cloud Armor で IP Address groups 機能が公開(GA) Address groups overview (2024-10-09) Cloud Armor で IP Address groups 機能が公開(GA)。 複数の IP アドレスをグループにまとめ、複数のポリシーから再利用できる。Cloud NGFW のファイアウォールポリシーからも再利用できるよう設定も可能。 BigQuery の history-based optimizations は今後デフォルトに Get up to 100x query performance improvement with BigQuery history-based optimizations (2024-10-15) 2024年9月30日に GA となった BigQuery の history-based optimizations 機能は、今後数ヶ月をかけて、「全顧客でデフォルトで有効になる」ことが判明。 history-based optimizations とは、類似のクエリを複数回実行していくと、自動的にクエリが最適化されていく機能。バックエンドではさまざまなアルゴリズムで最適化が行われている。 BigQuery で Fine-grained DML が申請付き Preview 公開 Fine-grained DML (2024-10-15) BigQuery で Fine-grained DML が申請付き Preview 公開。 テーブル単位で有効化すると、UPDATE、DELETE、MERGE 文がきめ細かく行われるようになり、スロット消費を抑え、パフォーマンスが最適化される。テーブル単位で有効化する必要あり。 Google Workspace の Gmail への移行ツールが GA(一般公開) Now generally available: Migrate users’ emails from Google Workspace, Gmail and other IMAP enabled mail servers (2024-10-15) Google Workspace の Gmail への移行ツールが GA(一般公開)。 他の Workspace、個人 Gmail、IMAP などからメールを移行できる。差分転送も可能。 Gemini for Google Workspace のサイドパネルが日本語対応(アルファ版) Available in alpha: use Gemini in the side panel of Workspace apps in seven additional languages (2024-10-16) Google Workspace の Gemini サイドパネルの日本語版が、以下の Google Workspace アプリで使えるように(アルファ版公開)。 Google ドキュメント Google スプレッドシート Gmail Google ドライブ 他にもドイツ語、イタリア語、韓国語、ポルトガル語、スペイン語、フランス語が同時対応 アルファ版とは、「アルファ版は、より広範囲へのリリース前に行われる限定的なテスト版です。」「通常、アルファ版への参加は招待制で、一般提供前の利用条件が適用されます。」というもの。 参考 : ソフトウェア テストのフェーズと GA について Google Chat で未読メッセージを生成 AI がサマリ Preview summaries of unread conversations in the Google Chat home view with the help of Gemini (2024-10-21) Google Chat で、未読メッセージを生成 AI がサマリしてくれる機能が登場。要 Gemini アドオンライセンス。 Vertex AI Search で CMEK が利用可能に(US と EU) Customer-managed encryption keys (2024-10-17) Vertex AI Search で CMEK(customer-managed encryption keys)が利用可能に(GA)。 データストアが CMEK で暗号化されるようになり、規制要件等に対応できる。対応ロケーションは US と EU。 Associate Google Workspace Administrator 試験(Beta)が受付開始 Associate Google Workspace Administrator - Beta (2024-10-22) 新しい Google Cloud 認定資格、Associate Google Workspace Administrator 試験(Beta)が2024年10月22日に受付開始。 Google Workspace の日常的な管理業務や、トラブルシューティングに関する知識や技能が問われる。以下記事では、当社エンジニアによる受験 Tips を公開している。 blog.g-gen.co.jp BigQuery data preparation が Preview 公開 Introduction to BigQuery data preparation (2024-10-24) BigQuery data preparation が Preview 公開。 Gemini がデータクレンジングの推奨事項を提示。背後で Dataform が動きデータ変換を実現。BigQuery Studio(コンソール画面)から利用可能。 2024年末ころまでは無料で利用できるが、Gemini in BigQuery は、2024年末ころから以下のいずれかのユーザーのみが使えるように限定される。 BigQuery Enterprise Plus Edition Gemini Code Assist Enterprise Vertex AI Search でグラウンディングスコアが取得できるように(GA) Return grounding support scores (2024-10-25) Vertex AI Search で、グラウンディングスコアが取得できるようになった(GA)。 要約とフォローアップで、生成された文章の各位置のグラウンディングスコア(どれくらいグラウンディングに基づいて生成された文章か)が確認できる。 さらに関連アップデートとして、フィルタリングレベルを設定し、グラウンディングスコアが一定以下の場合は返答を返さないように設定できるになった。詳細は以下の通り。 Show only well-grounded answers AlloyDB でメジャーバージョンのインプレイスアップグレード(Preview) Upgrade a database in-place major version (2024-10-28) AlloyDB for PostgreSQL でメジャーバージョンのインプレイスアップグレードが Preview 公開。 インプレイスアップグレードとは、新規インスタンスを起動することなく、既存インスタンスのバージョンをアップグレードすること。現在利用可能なのは PostgreSQL 14 から 15 へのインプレイスアップグレード。 Cloud Storage の認証済み URL がデータアクセス監査ログに対応 Return grounding support scores (2024-10-29) Cloud Storageの「認証済みブラウザでのダウンロード」がデータアクセス監査ログに対応。 従来はデータアクセス監査ログが有効だと、認証済み URL でのダウンロードがエラーになったが、今後は可能になる。Looker Studio で Cloud Storage 上の画像を IAM 認証で表示するとき等に課題だった。当該の問題については、以下の記事を参照。 blog.g-gen.co.jp GitHub Copilot で Gemini モデルが使えるように Gemini models are coming to GitHub Copilot (2024-10-30) GitHub Copilot で Gemini モデル(Gemini 1.5 Pro)が使えるようになる。コード生成、分析、最適化に Gemini が使われる。 リンク先記事には「開発者は、今後数週間以内に、 github.comの GitHub Copilot Chat、Visual Studio Code、および Visual Studio の Copilot 拡張機能との会話中に、Gemini 1.5 Pro を選択できるようになります。」とある。 杉村 勇馬 (記事一覧) 執行役員 CTO / クラウドソリューション部 部長 元警察官という経歴を持つ現 IT エンジニア。クラウド管理・運用やネットワークに知見。AWS 12資格、Google Cloud認定資格11資格。X (旧 Twitter) では Google Cloud や AWS のアップデート情報をつぶやいています。 Follow @y_sugi_it
アバター
G-gen の佐々木です。当記事では、Google Cloud の仮想マシンサービスである Compute Engine (Google Compute Engine: GCE)に PostgreSQL サーバを構築していきます。 当記事の目的 Compute Engine インスタンスの作成 作業の概要 シェル変数の設定 VPC・サブネットの作成 VPC の作成 サブネットの作成 インスタンスの作成 ファイアウォールルールの設定 インスタンスに SSH 接続 コンソールからインスタンスに接続(GUI の場合) gcloud コマンドで SSH 接続(CLI の場合) PostgreSQL のインストール パッケージリストの更新 PostgreSQL のインストール インスタンス内部からデータベースに接続確認 リモートクライアントからデータベースに接続確認 設定ファイルの編集 postgresql.conf pg_hba.conf データベース再起動 接続確認 バックアップの取得とインスタンスの復元 バックアップの目的 マシンイメージの取得 マシンイメージからインスタンスを復元 古いインスタンスの削除 マシンイメージからインスタンスを復元 復元したインスタンスのデータベースに接続 当記事の目的 当記事では、Google Cloud 上で仮想マシンを利用できるサービスである Compute Engine を利用して、PostgreSQL サーバを構築していきます。 Compute Engine についての詳細は解説は、以下の記事をご参照ください。 blog.g-gen.co.jp blog.g-gen.co.jp Google Cloud では Cloud SQL や AlloyDB for PostgreSQL などの PostgreSQL 完全互換のデータベース サービスが提供されています。また、無制限のスケーリングとマルチリージョンの展開が可能な非常に強力なデータベース サービスである Cloud Spanner でも、完全互換ではないものの、PostgreSQL との互換性があります。 したがって、Google Cloud において新規にデータベースを利用する際、データベースエンジンとして PostgreSQL を優先的に検討・採用するケースが想定されます。 上記の Google Cloud におけるマネージド データベース サービスは、本番環境向け、エンタープライズ向けの機能を多く持つことから、 個人の PostgreSQL の学習用途や、簡単なテスト用のデータベースとして利用するには性能が過剰で、またコスト(Google Cloud 利用料)が高くついてしまいます。 そこで当記事では、 個人による、Google Cloud の環境を利用した PostgreSQL の学習用途 を想定して、Compute Engine 仮想マシン上に PostgreSQL サーバを構築していきます。 Compute Engine インスタンスの作成 作業の概要 Google Cloud プロジェクトに Compute Engine 仮想マシン( インスタンス )を作成していきます。 インスタンスは VPC 内のサブネットに作成する必要があるため、それらのリソースを先に作成し、その中にインスタンスを作成します。 そして、インスタンスに PostgreSQL をインストールする際や、インスタンス上に構築した PostgreSQL サーバーを利用する際に VPC の外部から接続できるように、接続を許可するファイアウォールルールを設定しておきます。 当記事で作成する Compute Engine 環境の構成 当記事では gcloud コマンド を用いてリソースの作成を行っていきます。gcloud コマンドのインストールについては こちらのドキュメント を参照してください。 また、Google Cloud コンソールから利用できる Cloud Shell (ブラウザベースのターミナル環境)には gcloud コマンドがプリインストールされているため、以降の作業をそのまま実施することができます。 シェル変数の設定 コマンドで何度か使用する値をシェル変数に格納しておきます。 SUFFIX = { 適当な値 } PROJECT = { プロジェクトID } REGION = { リソースを作成するリージョン } VPC・サブネットの作成 VPC の作成 以下のコマンドで VPC を作成します。サブネットを手動で作成するため、 --subnet-mode フラグで custom を指定します。 # VPC を作成する $ gcloud compute networks create vpc- ${SUFFIX} \ --subnet-mode = custom \ --project = ${PROJECT} 参考: gcloud compute networks create(コマンドリファレンス) サブネットの作成 作成した VPC を指定し、その中にサブネットを作成します。 --range フラグではサブネットに割り当てるプライベート IP アドレスの範囲を CIDR で指定します。当記事では 192.168.150.0/28 を割り当てています。 # サブネットを作成する $ gcloud compute networks subnets create subnet- ${SUFFIX} \ --network = vpc- ${SUFFIX} \ --region = ${REGION} \ --range = 192 . 168 . 150 . 0 / 28 \ --project = ${PROJECT} 参考: gcloud compute networks subnets create(コマンドリファレンス) インスタンスの作成 作成した VPC とサブネットを指定し、Compute Engine インスタンスを作成します。 当記事では以下の設定値でインスタンスを作成します。 項目 gcloud コマンドのフラグ 値 備考 インスタンス名 vm-${SUFFIX} VPC --network vpc-${SUFFIX} サブネット --subnet subnet-${SUFFIX} OS イメージ --image-family --image-project debian-12 debian-cloud 以降の手順はここで指定した OS を前提とする点に注意 マシンタイプ --machine-type e2-micro 2 vCPU、メモリ1GB 必要に応じて変更可( 参考 ) ネットワークタグ --tags ssh postgres 後で作成するファイアウォールルールをインスタンスに紐付ける際に使用 # Compute Engine インスタンスを作成する $ gcloud compute instances create vm- ${SUFFIX} \ --network = vpc- ${SUFFIX} \ --subnet = subnet- ${SUFFIX} \ --zone = ${REGION} -a \ --image-family = debian-12 \ --image-project = debian-cloud \ --machine-type = e2-micro \ --tags = ssh,postgres \ --project = ${PROJECT} 参考: gcloud compute instances create(コマンドリファレンス) ファイアウォールルールの設定 作成したインスタンスに SSH でアクセスできるように、VPC に内向きのファイアウォールルールを作成します。 --target-tags フラグでインスタンスに設定したものと同じタグを指定することで、このルールをインスタンスに紐付けることができます。 なお、当記事では便宜上 --source-ranges フラグ、つまりアクセス元の IP アドレス範囲を 0.0.0.0/0 (任意の IP アドレス)に設定していますが、セキュリティを考慮して自身の PC の IP アドレス等を設定することもできます。 # SSH を許可する $ gcloud compute firewall-rules create vpc- ${SUFFIX} -allow-ssh \ --direction = INGRESS \ --source-ranges = 0 . 0 . 0 . 0 / 0 \ --allow = tcp:22 \ --target-tags = ssh \ --network = vpc- ${SUFFIX} \ --project = ${PROJECT} 次に、インスタンス上に構築する PostgreSQL サーバーに外部からアクセスできるように、ファイアウォールルールを作成します。 # PostgreSQL サーバへの接続を許可する $ gcloud compute firewall-rules create vpc- ${SUFFIX} -allow-postgres \ --direction = INGRESS \ --source-ranges = 0 . 0 . 0 . 0 / 0 \ --allow = tcp:5432 \ --target-tags = postgres \ --network = vpc- ${SUFFIX} \ --project = ${PROJECT} 参考: gcloud compute firewall-rules create(コマンドリファレンス) インスタンスに SSH 接続 コンソールからインスタンスに接続(GUI の場合) Google Cloud コンソールからインスタンスに SSH 接続する場合、インスタンス一覧画面で「 SSH 」を選択します。 Google Cloud コンソールからインスタンスに SSH 接続する gcloud コマンドで SSH 接続(CLI の場合) gcloud では、以下のコマンドを使用してインスタンスに SSH 接続できます。 # インスタンスに SSH 接続する $ gcloud compute ssh vm- ${SUFFIX} \ --zone = ${REGION} -a \ --project = ${PROJECT} 参考: gcloud compute ssh(コマンドリファレンス) PostgreSQL のインストール パッケージリストの更新 以降の手順については、 SSH 接続した Compute Engine VM 上でコマンドを実行 してください。 PostgreSQL をインストールする前に、apt のパッケージを最新化しておきます。 # パッケージリストを最新の状態にする $ sudo apt update # パッケージの最新化(時間がかかる可能性あり) $ sudo apt upgrade -y PostgreSQL のインストール apt install で PostgreSQL をインストールします。 当記事では Debian のデフォルトに設定されているバージョンをインストールします。特定のバージョンを指定したい場合は公式ウェブサイト(postgresql.org)の Linux downloads (Debian) の手順を参照してください。 # PostgreSQL をインストールする $ sudo apt install postgresql -y # PostgreSQL のバージョンを確認する $ psql -U postgres -c " SELECT version() " ---------- 出力例 ---------- version ------------------------------------------------------------------------------------------------------------------- PostgreSQL 15 . 8 ( Debian 15 .8-0+deb12u1 ) on x86_64-pc-linux-gnu, compiled by gcc ( Debian 12 . 2 .0-14 ) 12 . 2 . 0 , 64-bit ( 1 row ) インスタンス内部からデータベースに接続確認 apt install で PostgreSQL をインストールした場合、初期ユーザーとして postgres という名前のユーザーがパスワード無しで設定されています。 ユーザーを切り替えて psql コマンドでデフォルトのデータベースに接続してみます。 # ユーザーの切り替え $ sudo su - postgres # PostgreSQL に接続する $ psql ログインしたら、試しにデータベースの一覧を確認します。 # データベースの一覧を確認する postgres =# \l ---------- 出力例 ---------- List of databases Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access privileges -----------+----------+----------+---------+---------+------------+-----------------+----------------------- postgres | postgres | UTF8 | C.UTF-8 | C.UTF-8 | | libc | template0 | postgres | UTF8 | C.UTF-8 | C.UTF-8 | | libc | = c/postgres + | | | | | | | postgres =CTc/postgres template1 | postgres | UTF8 | C.UTF-8 | C.UTF-8 | | libc | = c/postgres + | | | | | | | postgres =CTc/postgres ( 3 rows ) 確認が終わったら、データベースからはログアウトします。 # データベースからログアウトする postgres =# \q PostgreSQL の管理ツールである pg_ctl などのコマンドは /usr/lib/postgresql/15/bin/ にあるため、postges ユーザーの .bash_profile ファイルにパスを設定しておきます。 # 管理ツールがあるディレクトリにパスを設定する $ echo ' PATH=$PATH:/usr/lib/postgresql/15/bin/ ' >> ~/.bash_profile # 変更を反映させる $ source ~/.bash_profile リモートクライアントからデータベースに接続確認 設定ファイルの編集 postgresql.conf postgres ユーザーのまま作業を続けていきます。 設定ファイルである postgresql.conf を編集して、ローカル PC や Cloud Shell などのリモートクライアントからデータベースに接続できるようにします。 初期状態では、 listen_addresses の項目がコメントアウトされています。この項目では、 データベース接続を受け付けるインスタンス側の IP アドレス(接続元 IP アドレスではない) を設定します。 $ cat /etc/postgresql/ 15 /main/postgresql.conf | grep listen_addresses #listen_addresses = 'localhost' # what IP address(es) to listen on; エディタを使用してファイルを編集していきます。 # エディタを使用して postgresql.conf を編集する $ vi /etc/postgresql/ 15 /main/postgresql.conf listen_address の行のコメントアウトを外し、以下のように修正してファイルを保存します。 listen_addresses = ' * ' # what IP address(es) to listen on; インターネットからデータベースに接続するためには、ここで Compute Engine インスタンスの外部 IP アドレスを設定する必要があります。 しかし、当記事ではインスタンスの外部 IP アドレスを固定していないため、インスタンスの停止・起動を行うと IP アドレスが変わってしまう可能性があります。そのため、上記のように「*」を設定することで全ての IP アドレスでデータベース接続を受け付けるようにします。 postgresql.conf の listen_addresses 項目は、設定を反映するためにデータベースの再起動が必要な項目となっているため、後の手順で再起動を実施します。 pg_hba.conf クライアント認証に関する設定ファイルである pg_hba.conf も編集する必要があります。このファイルでは、1行のレコードでクライアントが利用できるデータベースやデータベースユーザー、アクセス元 IP アドレスなどを設定します。 # エディタを使用して pg_hba.conf を編集する $ vi /etc/postgresql/ 15 /main/pg_hba.conf ファイル内の # IPv4 local connections: の下に以下のレコードを追記します。 host all all 0 . 0 . 0 . 0 / 0 trust 上記の記述では、全ての IP アドレス(4列目の 0.0.0.0/0 )から、全てのデータベース(2列めの all )に対して、全てのデータベースユーザーを使用して(3列目の all )、パスワード無しで(5行目の trust )接続できるようになります。 よりセキュリティを考慮する場合は、以下のドキュメントを参考に、アクセス元 IP アドレスやパスワード認証の強制等を設定するとよいでしょう。 参考: pg_hba.confファイル データベース再起動 編集した設定ファイルを反映させるため、 pg_ctl restart でデータベースの再起動を行います。 # データベースを再起動する $ pg_ctl restart -D /var/lib/postgresql/ 15 /main/ ---------- 出力例 ---------- waiting for server to shut down.... done server stopped waiting for server to start ....2024-10-26 14:34:46. 636 UTC [ 1548 ] LOG: starting PostgreSQL 15 . 8 ( Debian 15 .8-0+deb12u1 ) on x86_64-pc-linux-gnu, compiled by gcc ( Debian 12 . 2 .0-14 ) 12 . 2 . 0 , 64-bit 2024-10-26 14:34:46. 637 UTC [ 1548 ] LOG: listening on IPv4 address " 0.0.0.0 " , port 5432 2024-10-26 14:34:46. 637 UTC [ 1548 ] LOG: listening on IPv6 address " :: " , port 5432 2024-10-26 14:34:46. 640 UTC [ 1548 ] LOG: listening on Unix socket " /var/run/postgresql/.s.PGSQL.5432 " 2024-10-26 14:34:46. 648 UTC [ 1551 ] LOG: database system was shut down at 2024-10-26 14:34:46 UTC 2024-10-26 14:34:46. 657 UTC [ 1548 ] LOG: database system is ready to accept connections done server started データベースクラスタのパスを PGDATA 環境変数に設定しておくことで、上記コマンドのように -D フラグでデータベースクラスタを指定しなくてもよくなります。必要に応じて環境変数を設定するとよいでしょう。 接続確認 リモートクライアントからデータベースへの接続を行います。以降の手順は 全て自身の PC や Cloud Shell のターミナルからコマンドを実行 してください。 psql コマンドがない場合は こちらのドキュメント を参考にインストールします。なお、Cloud Shell には psql がプリインストールされています。 まず、Compute Engine インスタンスの外部 IP アドレスをシェル変数 HOST_IP に格納します。 # インスタンスの外部 IP アドレスをシェル変数に格納する HOST_IP = $( gcloud compute instances describe vm- ${SUFFIX} \ --zone = ${REGION} -a \ --project = ${PROJECT} \ --format =" value(networkInterfaces[0].accessConfigs[0].natIP) " ) psql コマンドでデータベース接続を行います。 # データベースに接続する $ psql -h ${HOST_IP} -U postgres バックアップの取得とインスタンスの復元 バックアップの目的 PostgreSQL の設定が完了した状態の Compute Engine インスタンスのバックアップを作成します。 今回作成した環境は PostgreSQL の学習用のため、重要なデータなどは格納されない想定ですが、バックアップを取っておくことで以下のようなメリットがあります。 環境を長期間利用しない場合に削除し、必要なときにバックアップから環境を再作成することで、Google Cloud 利用料を節約する。 学習中に環境を壊してしまった場合に、壊れる前の環境をすぐに復元することができる。 Compute Engine のバックアップについてはスナップショット、マシンイメージ、カスタムイメージなどいくつかの方法がありますが、ここでは マシンイメージ を作成していきます。 それぞれの違いについては、以下の記事で詳しく説明されています。 blog.g-gen.co.jp マシンイメージの取得 以下のコマンドを使用して、PostgreSQL をインストールしたインスタンスをソースとしてマシンイメージを取得します。 いつの状態のバックアップかを明確にするため、マシンイメージを取得した時刻をイメージの名前に含めておくと便利です。 # マシンイメージの取得 $ gcloud compute machine-images create mimg- ${SUFFIX} - $( date ' +%Y%m%d%H%M%S ' ) \ --source-instance = vm- ${SUFFIX} \ --source-instance-zone = ${REGION} -a \ --storage-location = ${REGION} \ --project = ${PROJECT} 参考: gcloud compute machine-images create(コマンドリファレンス) マシンイメージからインスタンスを復元 古いインスタンスの削除 Compute Engine では同一のゾーンに同名のインスタンスを作成することができないため( 参考 )、なるべく同じ構成でバックアップからインスタンスを復元したい場合、先に古いインスタンスを削除します。 # インスタンスを削除する $ gcloud compute instances delete vm- ${SUFFIX} \ --zone = ${REGION} -a \ --project = ${PROJECT} 参考: gcloud compute instances delete(コマンドリファレンス) マシンイメージからインスタンスを復元 マシンイメージからのインスタンスの復元は、インスタンス作成時と同じコマンドで --source-machine-image フラグを使用します。 OS やネットワークタグなどの情報はマシンイメージに含まれているため、復元時に設定する必要はありません。 # マシンイメージからインスタンスを復元する $ gcloud compute instances create vm- ${SUFFIX} \ --source-machine-image = { マシンイメージの名前を指定 } \ --network = vpc- ${SUFFIX} \ --subnet = subnet- ${SUFFIX} \ --zone = ${REGION} -a \ --project = ${PROJECT} 参考: gcloud compute instances create(コマンドリファレンス) 復元したインスタンスのデータベースに接続 復元したインスタンスの外部 IP アドレスを確認し、psql コマンドでデータベース接続を行います。 # インスタンスの外部 IP アドレスをシェル変数に格納する $ HOST_IP = $( gcloud compute instances describe vm- ${SUFFIX} \ --zone = ${REGION} -a \ --project = ${PROJECT} \ --format =" value(networkInterfaces[0].accessConfigs[0].natIP) " ) # データベースに接続する $ psql -h ${HOST_IP} -U postgres PostgreSQL インストール後に設定ファイルを編集した状態がマシンイメージに保存されているため、復元したインスタンスであってもリモートクライアントから問題なく接続できます。 佐々木 駿太 (記事一覧) G-gen最北端、北海道在住のクラウドソリューション部エンジニア 2022年6月にG-genにジョイン。Google Cloud Partner Top Engineer 2024に選出。好きなGoogle CloudプロダクトはCloud Run。 趣味はコーヒー、小説(SF、ミステリ)、カラオケなど。 Follow @sasashun0805
アバター
G-gen の三浦です。当記事では、Secure Web Proxy を使って、Virtual Private Cloud (以下、VPC)上の Compute Engine VM からインターネットへ接続する際の Web アクセス制御の方法を紹介します。 Secure Web Proxy とは 検証内容の概要 構成図 検証の流れ SWP の初期構築 プロキシ専用サブネットの作成 SSL/TLS 証明書の作成 SWP のポリシーの設定 SWP インスタンスの設定 Web アクセスと Windows Update のブロック確認 プロキシの設定 Web アクセスの確認 Cloud Logging の確認 Windows Update の確認 Windows Update 許可ルールの適用 URL リストの設定 ルールの設定 Windows Update のアクセス確認 Web アクセスの確認 Windows Update の再確認 Secure Web Proxy とは Secure Web Proxy (以下、SWP)は、Google Cloud (旧称 GCP)が提供するフルマネージドの HTTP プロキシです。 HTTP プロキシとは、クライアントとサーバー間の HTTP 通信を仲介する中継機能のことであり、セキュリティや統制の強化に利用されます。 例えば、Google 翻訳( https://translate.google.com )へのアクセスは許可し、YouTube( https://youtube.com )へのアクセスはブロックするといったように、URL 単位やドメイン名単位でのアクセス制御が可能です。 SWP では、TLS インスペクション機能を利用することで、暗号化された HTTPS 通信でも URL パス単位で詳細なアクセス制御を行うことができます。以下は、その例です。 https://google.com/aaa へのアクセスは許可 https://google.com/bbb へのアクセスはブロック このように、SWP を使用することで、業務に必要なサイトのみを許可し、不要なサイトへのアクセスを防ぐことで、セキュリティを強化できます。 参考 : Secure Web Proxy の概要 検証内容の概要 構成図 今回は、以下の構成図の環境で検証を行いました。 検証の流れ 検証手順は以下のとおりです。 SWP の初期構築 : 最初に、許可ルールを設定せずに SWP を構築します。 Web アクセスと Windows Update のブロック確認 : Compute Engine VM(Windows Server 2022 Datacenter)から SWP を通じて、Web アクセスを試みます。この時点では、Windows Update も含めた全てのアクセスがブロックされることを確認します。 Windows Update 許可ルールの適用 : Windows Update の URL のみを許可リストに追加し、そのルールを SWP に適用します。Google へのアクセスは引き続きブロックされる状態を維持します。 Windows Update のアクセス許可確認 : 再度、Windows VM からアクセスを試行します。Windows Update が正常に実行できる一方、 www.google.com へのアクセスが引き続きブロックされることを確認します。 SWP の初期構築 プロキシ専用サブネットの作成 SWP 用の専用サブネットを作成します。このサブネットは、SWP が外部ネットワークと通信するためのものです。 /23 のサブネットマスクが推奨されています。 $ gcloud compute networks subnets create proxy-01 \ --purpose = REGIONAL_MANAGED_PROXY \ --role = ACTIVE \ --region = asia-northeast1 \ # SWP を構築するリージョン --network = test-vpc \ # SWP を構築する VPC --range = 192 . 168 . 0 . 0 / 23 # サブネット範囲 参考 : プロキシ サブネットを作成する SSL/TLS 証明書の作成 次に、SWP を構築するリージョンに、SWP に設定するための SSL/TLS 証明書を作成します。本検証では Google Cloud が提供する Google マネージド証明書を使用します。Google マネージド証明書の作成方法は、以下の記事を参照してください。 Google マネージド SSL/TLS 証明書 blog.g-gen.co.jp SWP のポリシーの設定 SWP に適用するセキュリティポリシーを作成します。このポリシーは、SWP を通じて行われるトラフィックの制御を定義します。以下の YAML ファイルを使用してポリシーを定義します。 <PROJECT_ID> の部分は、自環境の Google Cloud プロジェクトの ID で置き換えてください。 # policy.yaml description : "Secure Web Proxy policy" # ポリシーの説明 name : projects/<PROJECT_ID>/locations/asia-northeast1/gatewaySecurityPolicies/policy1 # プロジェクト ID を入力し、ポリシー名を指定 YAML ファイルが準備できたら、gcloud コマンドを使用してポリシーを設定します。 $ gcloud network-security gateway-security-policies import policy1 \ --source = policy.yaml \ # 前手順で作成した policy.yaml を指定 --location = asia-northeast1 # SWP を構築するリージョン名を指定 参考 : Secure Web Proxy ポリシーを作成する SWP インスタンスの設定 次に、SWP インスタンスの設定ファイルを準備します。このファイルには、SWP の待ち受けポートや IP アドレス、SSL/TLS 証明書、適用するポリシーなどを定義します。 # gateway.yaml name : projects/<PROJECT_ID>/locations/asia-northeast1/gateways/swp1 # SWP インスタンスの名前を指定(例. swp1) type : SECURE_WEB_GATEWAY addresses : [ "192.168.64.99" ] # SWP インスタンス用の IP を指定(プロキシ専用サブネットではなくクライアント VM 側のサブネット) ports : [ 8080 ] # SWP が待ち受けるポート番号を指定 certificateUrls : [ "projects/{PROJECT_ID/locations/asia-northeast1/certificates/cert-1" ] # 作成した Google マネージド SSL/TLS 証明書を指定 gatewaySecurityPolicy : projects/<PROJECT_ID>/locations/asia-northeast1/gatewaySecurityPolicies/policy1 # 前手順で作成したセキュリティポリシーを指定 network : projects/<PROJECT_ID>/global/networks/test-vpc # VPC を指定 subnetwork : projects/<PROJECT_ID>/regions/asia-northeast1/subnetworks/tokyo-01 # サブネットを指定(プロキシ専用サブネットではなくクライアント VM 側のサブネット) gcloud コマンドを使用して SWP インスタンスを構築します。SWP 構築時に、Cloud Router と Cloud NAT も自動的に構築されます。この Cloud NAT は SWP 専用のものであり、他のクライアントは利用できません。 $ gcloud network-services gateways import swp1 \ # SWP インスタンスの名前を指定(例. swp1) --source = gateway.yaml \ # 作成した yaml を指定 --location = asia-northeast1 # SWP を構築するリージョン名を指定 参考 : ウェブプロキシを設定 Web アクセスと Windows Update のブロック確認 プロキシの設定 Windows VM にログインします。 Windows キー + R でコマンド実行プロンプトを開き、 ms-settings:network-proxy と入力してプロキシ設定を開きます。 コマンドを実行 表示された画面で、スクリーンショットを参考に、プロキシの設定を有効化します。 設定項目 設定値 Address 192.168.64.99(SWP インスタンスの IP アドレス) Port 8080(SWP インスタンスのポート番号 ) プロキシサーバの指定 参考 : Windows でプロキシ サーバーを使用する Web アクセスの確認 Web ブラウザで Google( https://www.google.com )にアクセスし、ページが表示されないことを確認します。 www.google.com へのアクセス(ブロック) Cloud Logging の確認 次に、Cloud Logging を使用してアクセスログを確認します。Cloud Logging の確認方法に関しては、以下記事を参照してください。 Cloud Loggingの概念と仕組みをしっかり解説 blog.g-gen.co.jp ログには、許可ルールが未設定のため、デフォルトの拒否アクションでアクセスがブロックされたことが記録されます。 ログの確認結果 参考 : ログを理解して表示する Windows Update の確認 Windows キー + R を押し、 ms-settings:windowsupdate と入力して Windows Update 設定を開きます。 コマンドを実行 「Check for updates」を選択し、更新プログラムのダウンロードが開始されることを確認します。 Windows Update の実行 プロキシに許可ルールが設定されていないため、ダウンロードが失敗し、エラーが表示されます。 更新プログラムのダウンロード失敗 Windows Update 許可ルールの適用 URL リストの設定 Windows Update に必要な URL リストを作成します。このリストには、Windows Update がアクセスするドメインが含まれており、これらのドメインへのアクセスを許可するルールを作成します。 # url.yaml name : projects/<PROJECT_ID>/locations/asia-northeast1/urlLists/url-1 # URL リストの名前を指定。<PROJECT_ID> にはプロジェクト ID を入力。 values : - "*.prod.do.dsp.mp.microsoft.com" - "*.dl.delivery.mp.microsoft.com" - "*.windowsupdate.com" - "*.delivery.mp.microsoft.com" - "*.update.microsoft.com" - "adl.windows.com" - "tsfe.trafficshaping.dsp.mp.microsoft.com" - "definitionupdates.microsoft.com" OS のバージョンやエディションによって必要な URL が異なる場合があるため、詳細は以下の参考ドキュメントを参照してください。 参考 : Windows 11 Enterprise の接続エンドポイントの管理 作成した URL リストを SWP に設定します。 $ gcloud network-security url-lists import url-1 \ --location = asia-northeast1 \ # SWP を構築するリージョンを指定 --source = url.yaml # 作成した URL リストの YAML ファイルを指定 参考 : URL リストを使用してポリシーを作成する ルールの設定 次に、作成した URL リストに基づいて、Windows Update だけを許可するルールを作成します。このルールは、アクセスを許可するドメインリスト(url-1)に基づいて動作します。 # rule.yaml name : projects/<PROJECT_ID>/locations/asia-northeast1/gatewaySecurityPolicies/policy1/rules/rule-1 # ルール名を指定。<PROJECT_ID> にはプロジェクト ID を入力 basicProfile : ALLOW # ルールのアクションを指定(今回は許可のため "ALLOW" を指定) enabled : true # ルールの状態を指定(今回は"有効" を指定) priority : 100 # 優先度を指定(数値が小さいほど優先) description : Allow Windows Update # ルールの説明 sessionMatcher : "inUrlList(host(), 'projects/<PROJECT_ID>/locations/asia-northeast1/urlLists/url-1')" # ルールとURLリストを紐づけ、指定したドメインにアクセスを許可 作成したルールを SWP に適用しているポリシーに反映させます。 $ gcloud network-security gateway-security-policies rules import rule-1 \ --source = rule.yaml \ # 作成したルールファイルを指定 --location = asia-northeast1 \ # SWP を構築しているリージョンを指定 --gateway-security-policy = policy1 # 適用するポリシー名を指定 参考 : Secure Web Proxy ルールを作成する Windows Update のアクセス確認 Web アクセスの確認 再度、Google( https://www.google.com )へアクセスし、ページが表示されず、ブロックされていることを確認します。 www.google.com へのアクセス(ブロック) Windows Update の再確認 Windows Update の画面から「Retry」を選択します。 Retry の実施 更新プログラムのダウンロードが進んでいることを確認します。 更新プログラムのダウンロード中 インストールを続行するために再起動が必要となります。サーバーを再起動しても問題ないことを確認し、「Restart now」をクリックして再起動します。 再起動を求められる 再起動後に再度 Windows Update の画面を確認し、緑のチェックマークが表示され、Windows が最新の状態であることを確認します。 Windows Update が最新の状態であることの確認 三浦 健斗 (記事一覧) クラウドソリューション部 2023年10月よりG-genにジョイン。オンプレ中心のネットワークエンジニアからクラウドエンジニアへ移行。日々お勉強中です。
アバター
G-gen の杉村です。Google Cloud(旧称 GCP)の認定資格である Associate Google Workspace Administrator 資格の試験対策に有用な情報を記載します。 基本的な情報 Associate Google Workspace Administrator とは 難易度 出題傾向 試験対策 ユーザーアカウント ID 連携 アーカイブユーザーライセンス Google グループ Google グループと設定グループ 動的グループ 共同トレイ ビジネス向け Google グループ 組織部門(OU) Google Vault Google Vault とは リティゲーションホールドと案件 アクセス制御 セキュリティキー コンテキストアウェアアクセス セキュリティセンター セキュリティセンターとは セキュリティ調査ツールとは アクティビティルール デバイス管理 モバイルエンドポイント管理 Chrome ブラウザ データロケーション Gmail MX レコード 添付ファイルの検疫 スパムの偽陽性 TLS 接続 SPF、DKIM トラブルシューティング Google ドライブ 共有ドライブとロール ストレージクォータ 外部共有の禁止 その他の Google Workspace サービス Google カレンダー Google Meet Google Chat Data Loss Prevention(DLP) AppSheet Gemini for Google Workspace 基本的な情報 Associate Google Workspace Administrator とは Associate Google Workspace Administrator 試験は、Google Cloud(旧称 GCP)の認定資格の一つです。当試験は2024年10月22日、Beta 版として公開され、2025年1月にGA(一般公開)されました。 当試験は Associate レベルの資格であり、 Google Workspace の日常的な管理業務や、トラブルシューティングに関する知識や技能 が問われます。 試験時間は120分、問題数は50〜60問です(※)。 日本語版 と 英語版 の試験が提供されています。 ※ 2025年3月現在、試験の GA 後に受験した複数の G-gen 社員が、出題数が40問だったことを報告しています。ただし試験要項には「50〜60問」と記載されています。 Google Workspace 関連の認定資格としては、かつて Professional Google Workspace Administrator がありましたが、この試験は2025年1月に当試験の一般公開と同時に廃止されました。 参考 : Associate Google Workspace Administrator 難易度 Associate Google Workspace Administrator 試験の難易度は、他の認定試験と比較して 中程度 といえます。 基本情報技術者試験レベルの IT 基礎知識(DNS、E メール基盤、特権管理など)に加えて、Google Workspace の管理画面に日常的に触れている方であれば、追加の学習を数日〜1ヶ月程度行うことで十分に合格を狙えます。 受験者に推奨される経験として、公式サイトには「実際の環境またはテスト環境での Google Workspace 特権管理者としての6か月間の経験。Business Plus エディションの実践経験と Enterprise エディションの機能に関する知識。」とあります。ただし、管理画面の UI における細かな操作を問われるわけではありませんので、試験ガイドや当記事を参考にして Google Workspace の備える各機能の根本を理解していれば、合格を狙うことができます。 出題傾向 出題では、実践的なシチュエーションを題材にして、Google Workspace の管理機能に関する知識が問われます。 例えば、「自社の Google Workspace 利用者が退職しても〇〇になるようにするにはどうすればよいか。」など、短めのシナリオに対して、適切な機能を提案できるようになる必要があります。ただし、Google Cloud 認定試験の Professional レベル試験と比較すると問題文はそこまで長くはありません。複雑なシナリオに対して複数の機能を組み合わせて課題を解決するというよりも、一問一答のようにして、ある課題に対してある機能をぶつける、といったレベル感です。 また、仮に詳細を知らない機能についての問いが出題されても、IT 一般の常識的な感覚があれば答えを導き出せるものもあります。この資格試験への対策を機に、E メール基盤、DNS、ネットワーク、特権管理、SaaS の管理業務、ID 連携(SAML や OAuth)などについて学ぶことも、今後の IT 関連業務に大いに役立つはずです。 試験対策 以下の勉強方法はあくまで一例であり、最適な方法は、受験者の予備知識や経験によって異なるものとご了承ください。 前掲の IT インフラ基礎知識をキーワードベースで理解する Google Workspace の管理画面に触れる 試験ガイドを読み、知らないキーワードや機能について公式ドキュメントで学ぶ 当記事の出題傾向を読み足りない知識領域をカバーする学習を行う 公式のサンプル問題を解く Google Workspace の管理画面に触れたことがない方は、自由に触れる環境を自ら契約するなどして、必ず触れておくことをおすすめします。無料で利用できる Cloud Identity の Free エディションは、Google Workspace と管理画面の UI が共通していますので、ベーシックな機能を確認するにあたって有用です。ただし、有償の Google Workspace と比較して多くの機能が制限されていることに注意してください。Cloud Identity Free エディションの利用開始方法については、以下の記事を参考にしてください。 blog.g-gen.co.jp なお公式のサンプル問題は、以下の試験概要ページからアクセスできます。 参考 : Associate Google Workspace Administrator 当記事ではこれ以降、試験にあたって何を勉強しておくべきか、機能分野ごとに紹介しますので、参考にしてください。当記事では Google Workspace の基礎知識を詳細にお伝えすることはありませんので、公式ドキュメント等を参照してください。また、当記事の内容は Beta 版公開時のものですので、現在の試験内容とは一部が異なる場合がある点もご了承ください。 ユーザーアカウント ID 連携 Google Workspace は、他の IdP と連携が可能です。特に出題される可能性のある分野としては、Active Directory との連携です。 Active Directory(AD)のユーザーアカウントやグループ設定は、 Google Cloud Directory Sync (GCDS)を使うことで、Google Workspace に継続的に同期することができます。AD のパスワードを Google Workspace に同期するための Password Sync 機能を使えば、AD 側に設定されている複雑なパスワードポリシーをそのまま Google Workspace に適用することができます。 参考 : Google Cloud Directory Sync について 参考 : Password Sync の仕組み また逆に、Google Workspace を IdP として、他のアプリケーションに SSO することもできます。Box や Salesforce などの SaaS には簡単な設定で SSO できるよう設定できるほか、 カスタム SAML アプリ を設定することで、SAML 2.0 準拠の SSO が設定できます。 参考 : カスタム SAML アプリを設定する アーカイブユーザーライセンス 退職者など、もう Google Workspace アカウントを使わなくなった人のデータを保持するにはいくつか方法があります。アカウントを削除してしまうと、Gmail や Google ドライブのデータは失われてしまいます。以下のドキュメントにあるように、「削除プロセスの途中でデータのオーナー権限を別のアカウントに移動する」「Google Vault で書き出す」「アーカイブユーザーライセンスを割り当てる」などがあります。 参考 : 離職した従業員のデータを保持するためのオプション Google Vault は、Google Workspace のデータを法的理由などで保持するための仕組みで、データを長期に、コンプライアンスに準拠した形で保持することができます。Google Vault については頻繁に出題されるため、後述します。 アーカイブユーザーライセンス は、もうログインされないアカウントのデータを保持するためのライセンスであり、 通常ライセンスより安価 なライセンスです。このライセンスを割り当てると、退職者はデータにアクセスできなくなりますが、データは組織で保持されます。 参考 : 元従業員のアカウントをアーカイブする 参考 : Google Workspace アドオン Google グループ Google グループと設定グループ Google グループ は、Google アカウントをグルーピングするための機能です。Google グループはメーリングリストとして使うこともできますが、Google ドライブの権限管理や、Workspace 上の各種設定の適用にも使えます。 このようにグループを管理設定の適用に利用するときの Google グループは 設定グループ (configuration group)と呼ばれ、試験問題中にも繰り返し登場します。 設定グループを使って適用が可能な設定には、以下のようなものがあります。 データロケーション(データの地理的な保存場所) 共有ドライブのアクセス権限 ストレージ使用上限 外部へのファイル共有の制限 コアサービス以外の Google サービス(YouTube 等)の設定 管理機能の設定を、組織内の一部メンバーのみに適用したい場合の方法としては他に組織部門(OU)がありますが、設定グループへ適用した設定は、組織部門(OU)に適用した設定よりも優先されます。 組織(部署)の形は組織部門で形成し、そこから外れて例外的に設定をオーバーライド(上書き)したい場合は設定グループを利用する 、といったユースケースがよく出題されます。 参考 : 組織内にグループを作成する 参考 : 設定グループを使用してサービスの設定をカスタマイズする 動的グループ 動的グループ は、条件に基づいて自動的に Google グループにメンバーを追加できる、Google グループの拡張機能です。 例えば、部門名が「経理」の従業員は、自動的に accounting@ グループに所属する、のように設定できます。このようにして、グループ管理の工数を削減することができます。 参考 : 動的グループを使用してメンバーを自動的に管理する 共同トレイ 共同トレイ (Collaborative Inbox)は、Google グループに所属するアカウント間で共有利用可能な、メールの受信ボックスです。共同トレイを使うと、 カスタマーサポートのような業務を、チームで行う ことが可能になります。 共同トレイを使って組織外部とメールのやりとりをするには、まずグループで明示的に共同トレイを有効化し、その後にグループ設定で「投稿できるユーザー」を「ウェブ上のすべてのユーザー」にします。 参考 : グループを共同トレイとして使用する ビジネス向け Google グループ ビジネス向け Google グループ (Google Group for Business)は、有償の Google Workspace で利用可能なグループ機能の呼称です。Google Workspace ではデフォルトで有効化されているため、おそらく Google Workspace 管理者の多くの方が意識せずビジネス向け Google グループをすでに利用しています。 ビジネス向け Google グループが有効だと、Google Workspace のアプリランチャー(画面右上の9つの点のアイコン)に「グループ」が表示されます。この画面から、ユーザー自らグループを作成したり(管理者設定で許可するかどうか設定可能)、共同トレイ機能を使ったり、グループ内でスレッド形式の会話を行ったりできるようになります。 管理者でないメンバーがグループを作成したり、グループにメンバーを追加することを許可できますが、管理者設定で 組織外部のメンバーの追加を禁止 することもできます。 参考 : ビジネス向け Google グループのご利用について 組織部門(OU) 前掲の通り、 組織部門(OU) は、組織の形(部署等)にあわせて設計します。以下のようなシチュエーションが考えられます。 「営業部門」「マーケティング部門」「エンジニア部門」のユーザーアカウントをそれぞれ異なる組織部門(OU)に格納する 営業部門とマーケティング部門の組織部門(OU)には、組織外部へのファイル共有を許可する エンジニア部門の組織部門(OU)には、組織外部へのファイル共有を禁止する なお、一部の設定は設定グループ単位では適用できず、組織部門(OU)単位でならば適用できることがあります。例として Gemini for Google Workspace 等の アドオンライセンスの自動適用は、設定グループ単位ではできませんが、組織部門(OU)単位では可能 です。 参考 : 組織構造の仕組み Google Vault Google Vault とは Google Vault は、法的要件に準拠しつつ Google Workspace のデータを保持し、関係者に適切に開示するための仕組みです。Google Vault を使うと、Gmail や Google ドライブ、Google カレンダー、Google Chat などのデータを保持したり、書き出したりすることができます。対象のユーザーには、Google Workspace ライセンスに加えて Vault ライセンスも必要になります。 参考 : Google Vault について リティゲーションホールドと案件 リティゲーションホールド (英名は単に holds)を作成すると、アカウントの Gmail データを恒久的に保存し、法的義務へ対応することができるようになります。 参考 : Gmail のメッセージを記録保持の対象にする リティゲーションホールドとセットで理解しておきたい概念に、 案件 (matters)があります。案件(matters)は、リティゲーションホールド、データの検索や書き出しのための管理空間です。M&A における調査や訴訟案件など、 データの保持と公開が重要になる場面 で使われるシチュエーションが考えられます。 参考 : 案件を作成、管理する アクセス制御 セキュリティキー Google Workspace では、全アカウントに二段階認証(2SV)を設定することが推奨されます。SMS(ショートメッセージサービス)や Google Authenticator などを使った二段階認証が設定できますが、特にセキュリティキー(物理的な認証デバイス)が フィッシング対策 などにもっとも有用とされています。 参考 : 2 段階認証プロセスでビジネスを保護する コンテキストアウェアアクセス コンテキストアウェアアクセス (Context-Aware Access)は、デバイスの OS などの設定状況や、アクセス元の地理的条件などをベースに、Google Workspace サービスへのアクセスを制限できる機能です。当機能は、Enterprise エディション等で利用できます。 アクセスの条件として、デバイスの OS や接続元 IP アドレス、 ロケーション (どの地域からアクセスしようとしているか)などが設定できます。 アクセス条件を定義する設定オブジェクトは アクセスレベル と呼ばれます。 参考 : コンテキストアウェア アクセスの概要 参考 : コンテキスト アウェア アクセスレベルを作成する セキュリティセンター セキュリティセンターとは セキュリティセンター (Security Center)は、Google Workspace 管理画面に備え付けのセキュリティツールです。セキュリティセンターは以下の機能で構成されています。 機能名(和名) 機能名(英名) 概要 セキュリティダッシュボードのレポート Security dashboard reports 観測されたセキュリティリスクをレポートとして一覧表示する画面 セキュリティの状況ページ Security health page セキュリティ関係の管理設定をまとめて確認できる画面 セキュリティ調査ツール Security Investigation Tool 各種ログなどを検索できるツール セキュリティダッシュボードのレポート (Security dashboard reports)では、組織内のセキュリティリスクを一覧表示できます。パスワードの試行回数や、不審なアクティビティをグラフで表示したり、深堀りした調査が可能です。 セキュリティの状況ページ (Security health page)は、管理コンソールで設定できるセキュリティ関連設定を一覧表示できる画面です。現在のセキュリティ設定の棚卸しをしたいとき、例えば 複数ある組織部門(OU)の設定をすべて見に行かなくても、この画面で一覧表示 できます。 セキュリティ調査ツールについては後述します。 セキュリティ調査ツールとは セキュリティ調査ツール (Security Investigation Tool)とはセキュリティセンターの1機能であり、Google Workspace 管理画面に備え付けのログ調査ツールです。以下のような情報を検索し、一覧化することができます。当機能は、Enterprise エディション等で利用できます。 Gmail のメールコンテンツやメタデータ(フィッシングメールを調査する等) Google ドライブのアクセスログ(潜在的なデータ漏洩リスクを調査する等) Google Meet の情報(主催者不在の Meet 会議を検索して終了する等) デバイスの設定情報やログ このツールにより、例えば フィッシングメールのような悪意があるメールが届いたようなシチュエーション で、どの範囲の従業員までメールが届いているかを調べたり、送信元を確認したりすることができます。上記に挙げた確認可能な情報から、ユースケースを想像しておきましょう。 参考 : セキュリティ調査ツールについて 参考 : 悪意のあるメールに関するレポートを調査する 参考 : セキュリティ調査ツールを使用して会議を終了する アクティビティルール アクティビティルール (Activity rules)とは、ある条件を満たした場合に、自動的にアクションが行われるように設定できる機能です。セキュリティ調査ツールの下位機能として存在しています。 参考 : アクティビティ ルールの作成と管理 例えば、アクティビティルールを使うと以下のような自動化処理が設定可能です。 1時間に20回以上、ログイン試行が失敗したら、ユーザーにパスワード変更を求める アカウント乗っ取りのリスクを早期検知するため、アカウントのパスワードがリセットされたら、管理者にメール通知する デバイス管理 モバイルエンドポイント管理 Google Workspace には Windows、MacOS、Android、iOS、ChromeOS などのデバイスを管理する機能が備わっています。 基本のエンドポイント管理(Fundamental endpoint management)と高度なエンドポイント管理(Advanced endpoint management)の2つのレベルが存在し、Google Workspace によって利用可能なレベルが決まります。 参考 : Google エンドポイント管理機能の比較 特に出題可能性のあるシナリオとしては、デバイスの利用者が退職したり、デバイスを紛失したケースの対応です。基本のエンドポイント管理では、 アカウントのリモートワイプ が使えます。アカウントのリモートワイプでは、管理画面から、デバイスの Google Workspace データのワイプ(削除)が可能です。 高度なエンドポイント管理では、 デバイスのリモートワイプ が可能です。こちらであれば、デバイス自体を工場出荷時の状態に戻すことができます。 これらのワイプを利用するには細かく要件があります。詳細は以下のドキュメントを参照してください。 参考 : デバイスから企業データをワイプする Chrome ブラウザ 管理下の Chrome ブラウザに対して、強制的にアプリや機能拡張を配信したいときは、アプリと拡張機能の 自動インストール (force-install)が利用可能です。 参考 : アプリと拡張機能を自動的にインストールする データロケーション Google Workspace では、データの地理的な保管場所を指定できます。現在のところ選択できるのは EU (ヨーロッパ)と US (米国)の2種類です。法的要件や監査要件で、各国の従業員が使うデータの保存場所を明示したい場合は、この機能が使えます。 たとえば、同じ組織に米国の従業員とドイツの従業員が存在している場合、それらの従業員を設定グループもしくは組織部門(OU)で分類し、 設定グループもしくは組織部門(OU)に対してデータロケーションを指定 することが可能です。 参考 : データの地理的な保管場所を選択する Gmail MX レコード Gmail を使い始めるにあたって必要な MX レコードの追加 などの概念は、基本的な DNS の仕組みとともに理解が必須です。たとえば、オンプレミスで運用していたメールサーバーから、同じドメイン名を使って Gmail に移行する場合は、DNS ゾーンの MX レコードを Gmail に向けることで、メールサーバーを切り替えることができます。 参考 : Google Workspace の MX レコードの値 以下の記事も参考にしてください。 blog.g-gen.co.jp 添付ファイルの検疫 添付ファイルはセキュリティ上の関心事項となりがちです。 添付ファイルのコンプライアンスルール で、特定のファイルタイプの添付ファイルを受信する前に削除することなどができます。 参考 : 添付ファイルを含むメールをフィルタする スパムの偽陽性 正当な送信元であるのにも関わらず、Gmail のスパムフィルタにスパムメールであると認識されてしまい、E メールが迷惑メールフォルダに分類されてしまうことがあります(偽陽性)。 そのような場合は、スパムフィルタをバイパス(迂回)させたいメールアドレスやドメイン名を 承認済み送信者リスト に登録することができます。その場合、メールは基本的にはユーザーに配信され、ユーザー自身がそのメールがスパムであるかどうかを判断することができます。 参考 : 許可リスト、拒否リスト、および承認済み送信者 TLS 接続 特定のドメイン名のメールアドレスとの間でやりとりするメールが TLS 暗号化のもとに行われるよう、明示的に設定することができます。 金融機関など、機密情報の扱いが厳重に求められる場合は、設定を検討します。 参考 : 安全な TLS 接続でメールを送信する SPF、DKIM SPF や DKIM は、メールの送信元を認証する仕組みです。なりすましを防止するために考案された仕組みであり、Gmail 特有の仕組みではなく、E メール基盤に関する一般的な仕様です。その目的や基本的な仕組みは理解しておいてください。 参考 : SPF を設定する 参考 : DKIM を設定する トラブルシューティング 従業員から、特定のメールが配信されていないというトラブルが報告されたとき、以下のドキュメントを参考にしてトラブルシューティングが可能です。セットアップの初期であれば MX レコードが正しく設定されていることを確認しますし、メールログ検索(Email Log Search、略称 ELS)ツールを使うと迷惑メールと判断されたり誤ってルーティングされたメールを探す際に役に立ちます。 参考 : Gmail でのメールの受信に関する問題のトラブルシューティング Gmail の Web UI の読み込みが異常に遅いなど、ブラウザ上の挙動の問題である場合、HAR ファイルと呼ばれるファイルを収集することで、トラブルシューティングの役に立つことがあります。 参考 : サポートへのお問い合わせの前に: 必要な情報を収集する HAR ファイルには機密情報が含まれている可能性もゼロではありません。HAR ファイルを Google サポートに共有する際は、アクセスコントロールを自社側で持てるよう、例えば自社の Google ドライブにアップロードし、アクセス権限を Google サポートに渡すことなども検討します。 参考 : Google Cloud サポート利用時のプライバシー保護に関するおすすめの方法 Google ドライブ 共有ドライブとロール 組織で Google ドライブを利用する場合、 共有ドライブ 機能への理解が必須です。アクセス権限は設定グループを用いて行うのが一般的です。設定グループに対して「管理者」「コンテンツ管理者」「投稿者」などのロールを付与します。 特に 投稿者 (Contributor)ロールの理解をしておいてください。投稿者は、ファイルの編集や新規作成はできますが、 削除はできません 。共有ドライブに対して自社メンバーにはコンテンツ管理者のロールを持たせ、共有相手の他社メンバーには投稿者ロールをもたせる、といったシナリオが考えられます。 参考 : 共有ドライブのファイルへのアクセスの仕組み ストレージクォータ Google Workspace では、 ストレージクォータ (ストレージの保存容量の上限)をユーザーアカウントや組織部門(OU)、または設定グループごとに設定できます。ストレージクォータは Google ドライブだけでなく、Gmail や Google フォトとも共通です。 例えば、組織全体では10 GB がクォータとして設定されている場合でも、特定メンバーを設定グループに所属させ、その設定グループに100 GB のクォータを設定する、のように、一部のメンバーだけ異なる設定を与えることもできます。 参考 : ユーザーの保存容量の上限を設定する 外部共有の禁止 Google ドライブの外部共有は便利な機能ですが、セキュリティリスクでもあります。組織全体で外部共有を禁止することもできますし、 組織部門(OU)や設定グループごと に、外部共有の許可または禁止を設定できます。 参考 : 組織の外部共有を管理する その他の Google Workspace サービス Google カレンダー Google カレンダー も同様に、基本的な使い方を理解しておきましょう。 Google カレンダーにはオフィスビルディングや会議室といった現実世界のオブジェクトを、リソースとして登録しておくことができます。新しいオフィスが追加されるときなどは大量のリソースを一括登録することがありますが、 CSV をアップロードする ことで 一括登録 が可能です。 また、複数のリソースを同時に編集する場合は、一度 CSV 形式でリソース一覧をダウンロードし、CSV を編集してから再度アップロードすることで、既存リソースを編集することができます。 参考 : ビルディング、設備や機能、カレンダー リソースを作成する Google Meet Google Meet には Meet 品質ツール (Meet quality tool)があり、音質や画質などのトラブルを調査できます。このツールで何ができるかは、押さえておきましょう。 参考 : 会議の品質と統計情報を確認する Google Chat Google Chat のいくつかの管理設定を理解しておきましょう。 チャットの履歴 は、デフォルトでは有効です。オフにすると、会話は24時間後に削除されます。組織全体あるいは組織部門(OU)で会話の履歴を「オン」にし、かつユーザーには、会話ごとに自分でオン・オフを選ばせることも可能です。 参考 : 組織のチャットの履歴を有効または無効にする スペース は、複数メンバーが参加可能な、いわゆる「部屋」のことです。スペースには管理者を設定でき、管理者はメンバーを追加・削除したり、メッセージを削除したりできます。 参考 : スペースの管理者の役割について Data Loss Prevention(DLP) Data Loss Prevention(DLP) を使うと、Google ドライブのファイルに、自動的なラベル付けが可能です。ルールに基づいて、コンテンツの中身に応じた ラベル が自動的に付与されるようになります。 ラベルはファイルの分類に使われるほか、検索時にも利用できます。例えば契約書類には「契約(Contracts)」というラベルを付与しておき、検索時に容易に見分けがつくようにできます。 参考 : DLP ルールを使用してドライブラベルを自動的に適用する また DLP では、クレジットカード番号などの機密情報を含む情報が外部共有されないように、Google Chat 等のメッセージを自動検閲してブロックすることが可能です。 参考 : Workspace の DLP を使用してデータの損失を防止する AppSheet AppSheet は Google Workspace に付属するノーコード開発ツールです。なお、Google Workspace に付属しているのは Core と呼ばれるティアのエディションであり、最低限の機能が利用できます。より高度な機能を持つ Enterprise Plus エディションを追加購入することが可能です。 試験にあたり、以下のポイントを押さえてください。 Google スプレッドシートのデータを利用して(スプレッドシートをデータベースとして利用して)アプリが作成できる Web ブラウザ向けアプリとモバイル向けアプリが開発できる ノーコード開発ツールなので、プログラミングの知識が不要 AppSheet と文字面が似ている App Script (Google App Script とも呼称。GAS と略されることもある)も選択肢に登場する可能性があるため、混同しないように注意してください。App Script は Google の基盤上で実行可能なスクリプト実行ツールであり、JavaScript ライクな文法のプログラミング言語で記述します。App Script は Google スプレッドシート等と連携してプログラムが実行可能であるため、Microsoft Office 製品における「マクロ」と似たイメージで理解ができます。 参考 : 組織で AppSheet を管理する Gemini for Google Workspace Gemini for Google Workspace は、Google Workspace で使える生成 AI アシスタントツールです。 Gmail、Google ドキュメント、Google スライド、Google スプレッドシートなどの各ツールで、生成 AI 基盤モデルである Gemini の強力なアシストを受けることができます。 利用には Gemini Business や Gemini Enterprise といった アドオンライセンス が必要です。アドオンライセンスは明示的にユーザーアカウントに割り当てます。アドオンライセンスは、組織全体もしくは 組織部門(OU)単位で自動的に割り当てることが可能 です。 参考 : Gemini for Google Workspace のライセンスを割り当てる 杉村 勇馬 (記事一覧) 執行役員 CTO 元警察官という経歴を持つ IT エンジニア。クラウド管理・運用やネットワークに知見。AWS 認定資格および Google Cloud 認定資格はすべて取得。X(旧 Twitter)では Google Cloud や Google Workspace のアップデート情報をつぶやいています。 Follow @y_sugi_it
アバター
G-gen の武井です。当記事では Google Cloud と GitHub Actions (Terraform) を連携する Workload Identity を作成する bash スクリプト を紹介します。 はじめに 概要 前提条件 免責事項 ソースコード スクリプトの使い方 認証 変数設定 実行 リソースの確認 Workload Identity プール・プロバイダー サービスアカウント IAM Policy デモ 構成 ソースコード (Terraform) Terraform ディレクトリ構成 ワークフロー (terraform.yaml) env/demo 配下 (呼び出し側) modules/apis 配下 (モジュール) プルリクエスト (terraform plan) マージ (terraform apply) 関連記事 はじめに 概要 当記事で紹介するのは、Google Cloud と GitHub Actions (Terraform) との連携に必要な Workload Identity リソースを作成するスクリプトです。 当スクリプトを使うことで、Google Cloud プロジェクトに対する terraform plan や terraform apply を、GitHub Actions で自動化できます。 なお、GitHub Actions や Workload Identity に関する詳細は以下の記事からご確認ください。 blog.g-gen.co.jp blog.g-gen.co.jp 前提条件 当 bash スクリプトは、 Debian GNU/Linux 12 (bookworm) 上で開発され、動作確認されています。 また、以下のソフトウェアがインストールされていることが前提です。カッコ内は開発時のバージョンです。 gcloud( Google Cloud SDK 486.0.0 ) スクリプト実行時は、実行先のプロジェクトに対して gcloud CLI を認証する必要があります。 参考 : ユーザー アカウントを使用して認可する 参考 : サービス アカウントを使用して承認する blog.g-gen.co.jp 免責事項 当記事で紹介するプログラムのソースコードは、ご自身の責任のもと、使用、引用、改変、再配布して構いません。 ただし、同ソースコードが原因で発生した不利益やトラブルについては、当社は一切の責任を負いません。 ソースコード 前述の 免責事項 をご理解のうえ、ご利用ください。 init.sh #!/bin/bash # エラーハンドリング: エラーが発生したらスクリプトを終了 set -e # 変数の設定 PROJECT_ID = " " # プロジェクトID (ex: gha-demo-prj) PROJECT_NUMBER = " " # プロジェクト番号 (ex: 1234567890) ORGANIZATION_ID = " " # プロジェクトの組織ID (ex: 0123456789) WORKLOAD_IDENTITY_POOL = " " # Workload Identityプール名 (ex: gha-demo-pool) WORKLOAD_IDENTITY_PROVIDER = " " # Workload Identityプロバイダ名 (ex: gha-demo-provider) SERVICE_ACCOUNT_NAME = " " # サービスアカウント名 (ex: gha-demo-sa) GITHUB_REPO = " " # GitHubリポジトリ名 (ex: gha-demo-org/gha-demo-repo) # ログ出力関数 log() { echo " [INFO] $1 " } log_error() { echo " [ERROR] $1 " >&2 } # 変数のチェック: すべての変数が設定されているか確認 if [[ -z " $PROJECT_ID " || -z " $PROJECT_NUMBER " || -z " $ORGANIZATION_ID " || -z " $WORKLOAD_IDENTITY_POOL " || -z " $WORKLOAD_IDENTITY_PROVIDER " || -z " $SERVICE_ACCOUNT_NAME " || -z " $GITHUB_REPO " ]] ; then log_error " 必須の変数が設定されていません。変数を確認してください。 " exit 1 fi # 1. IAM Credential API を有効化 if ! gcloud services list --enabled --filter =" name:iamcredentials.googleapis.com " --format =" value(name) " | grep " iamcredentials.googleapis.com " > /dev/null 2 >& 1 ; then log " IAM Credential API を有効にしています... " gcloud services enable iamcredentials.googleapis.com --project =" $PROJECT_ID " else log " IAM Credential API は既に有効化されています " fi # 2. Workload Identity プールの作成 if ! gcloud iam workload-identity-pools describe $WORKLOAD_IDENTITY_POOL --location =" global " --project =" $PROJECT_ID " > /dev/null 2 >& 1 ; then log " Workload Identity プールを作成中: $WORKLOAD_IDENTITY_POOL " gcloud iam workload-identity-pools create $WORKLOAD_IDENTITY_POOL \ --project =" $PROJECT_ID " \ --location =" global " \ --display-name =" $WORKLOAD_IDENTITY_POOL " else log " Workload Identity プールは既に存在します: $WORKLOAD_IDENTITY_POOL " fi # 3. Workload Identity プロバイダの作成 if ! gcloud iam workload-identity-pools providers describe $WORKLOAD_IDENTITY_PROVIDER --workload-identity-pool =" $WORKLOAD_IDENTITY_POOL " --location =" global " --project =" $PROJECT_ID " > /dev/null 2 >& 1 ; then log " Workload Identity プロバイダを作成中: $WORKLOAD_IDENTITY_PROVIDER " gcloud iam workload-identity-pools providers create-oidc $WORKLOAD_IDENTITY_PROVIDER \ --project =" $PROJECT_ID " \ --location =" global " \ --workload-identity-pool =" $WORKLOAD_IDENTITY_POOL " \ --display-name =" $WORKLOAD_IDENTITY_PROVIDER " \ --issuer-uri =" https://token.actions.githubusercontent.com " \ --attribute-mapping =" attribute.actor=assertion.actor,google.subject=assertion.sub,attribute.repository=assertion.repository " \ --attribute-condition =" assertion.repository==' ${GITHUB_REPO} ' " else log " Workload Identity プロバイダは既に存在します: $WORKLOAD_IDENTITY_PROVIDER " fi # 4. サービスアカウントの作成 if ! gcloud iam service-accounts describe $SERVICE_ACCOUNT_NAME @ $PROJECT_ID .iam.gserviceaccount.com > /dev/null 2 >& 1 ; then log " サービスアカウントを作成中: $SERVICE_ACCOUNT_NAME " gcloud iam service-accounts create $SERVICE_ACCOUNT_NAME \ --project =" $PROJECT_ID " \ --display-name =" GitHub Actions Service Account " else log " サービスアカウントは既に存在します: $SERVICE_ACCOUNT_NAME " fi # 5. 組織レベルでのロール付与 log " 組織レベルでのロール付与の確認 " for role in " roles/resourcemanager.organizationAdmin " " roles/owner " ; do if ! gcloud organizations get-iam-policy $ORGANIZATION_ID --flatten =" bindings[].members " --filter =" bindings.members:serviceAccount: $SERVICE_ACCOUNT_NAME @ $PROJECT_ID .iam.gserviceaccount.com AND bindings.role: $role " --format =" value(bindings.role) " | grep " $role " > /dev/null 2 >& 1 ; then log " $role をサービスアカウントに付与中: $SERVICE_ACCOUNT_NAME " gcloud organizations add-iam-policy-binding $ORGANIZATION_ID \ --member =" serviceAccount: $SERVICE_ACCOUNT_NAME @ $PROJECT_ID .iam.gserviceaccount.com " \ --role =" $role " else log " $role は既にサービスアカウントに付与されています: $SERVICE_ACCOUNT_NAME " fi done # 6. Workload Identity プールと GitHub リポジトリのリンク作成 log " Workload Identity プールと GitHub リポジトリのリンク作成の確認 " for subject in " principal://iam.googleapis.com/projects/ $PROJECT_NUMBER /locations/global/workloadIdentityPools/ $WORKLOAD_IDENTITY_POOL /subject/repo: $GITHUB_REPO :pull_request " " principal://iam.googleapis.com/projects/ $PROJECT_NUMBER /locations/global/workloadIdentityPools/ $WORKLOAD_IDENTITY_POOL /subject/repo: $GITHUB_REPO :ref:refs/heads/main " ; do if ! gcloud iam service-accounts get-iam-policy $SERVICE_ACCOUNT_NAME @ $PROJECT_ID .iam.gserviceaccount.com --flatten =" bindings[].members " --filter =" bindings.members: $subject " --format =" value(bindings.role) " | grep " roles/iam.workloadIdentityUser " > /dev/null 2 >& 1 ; then log " Workload Identity プールと GitHub リポジトリのリンクを作成中: $subject " gcloud iam service-accounts add-iam-policy-binding $SERVICE_ACCOUNT_NAME @ $PROJECT_ID .iam.gserviceaccount.com \ --role =" roles/iam.workloadIdentityUser " \ --member =" $subject " else log " Workload Identity プールと GitHub リポジトリのリンクは既に設定されています: $subject " fi done log " Workload Identity 設定が完了しました。 " log " サービスアカウント: $SERVICE_ACCOUNT_NAME @ $PROJECT_ID .iam.gserviceaccount.com " スクリプトの使い方 認証 まずは実行先のプロジェクトに対して gcloud CLI の認証を通します。 # 実行先プロジェクトの確認 $ gcloud config list [ core ] account = test-user@demo.g-gen.co.jp disable_usage_reporting = True project = gha-demo-prj Your active configuration is: [ gha-demo-prj ] # gcloud CLI の認証 $ gcloud auth login ~~中略~~ You are now logged in as [ test-user@demo.g-gen.co.jp ] . Your current project is [ gha-demo-prj ] . 変数設定 7~13行目 の変数に環境情報を入力します。 実行 スクリプトに実行権限を付与して実行します。 # 実行権限付与 $ chmod +x init.sh $ ls -l -rwxr-xr-x 1 test-user test-user 5294 Oct 18 11:49 init.sh # スクリプト実行 $ ./init.sh [ INFO ] IAM Credential API は既に有効化されています [ INFO ] Workload Identity プールを作成中: gha-demo-pool Created workload identity pool [ gha-demo-pool ] . [ INFO ] Workload Identity プロバイダを作成中: gha-demo-provider Created workload identity pool provider [ gha-demo-provider ] . [ INFO ] サービスアカウントを作成中: gha-demo-sa Created service account [ gha-demo-sa ] . [ INFO ] 組織レベルでのロール付与の確認 [ INFO ] roles/resourcemanager.organizationAdmin をサービスアカウントに付与中: gha-demo-sa Updated IAM policy for organization [ 0123456789 ] . ~~中略~~ [ INFO ] roles/owner をサービスアカウントに付与中: gha-demo-sa Updated IAM policy for organization [ 0123456789 ] . ~~中略~~ [ INFO ] Workload Identity プールと GitHub リポジトリのリンク作成の確認 [ INFO ] Workload Identity プールと GitHub リポジトリのリンクを作成中: ~~中略~~ [ INFO ] Workload Identity 設定が完了しました。 [ INFO ] サービスアカウント: gha-demo-sa@gha-demo-prj.iam.gserviceaccount.com リソースの確認 Workload Identity プール・プロバイダー 以下のように作成されます。 Workload Identity プール Workload Identity プロバイダー (1/2) Workload Identity プロバイダー (2/2) サービスアカウント 以下のように作成されます。 Workload Identity に紐づけるサービスアカウント GitHub Actions が当サービスアカウント使用するための権限 (Workload Identity ユーザー) IAM Policy 以下のように作成されます。 ※ IAM ロールは適用先のセキュリティポリシーに応じて調整してください。 組織レベルの IAM Policy デモ 構成 当スクリプトで作成される Workload Identity を使い、Google Cloud プロジェクトに対する terraform plan や terraform apply を、GitHub Actions で自動化します。 ワークフローや Terraform ソースコードは次項に記載のものを使用します。 ご利用される場合は、前述の 免責事項 をご理解のうえ、ご利用ください。 ソースコード (Terraform) Terraform ディレクトリ構成 . ├── .github │ └── workflows │ └── terraform.yaml ├── env │ └── demo │ ├── backend.tf │ ├── locals.tf │ ├── main.tf │ └── versions.tf ├── modules │ └── apis │ ├── main.tf │ ├── outputs.tf │ └── variables.tf ├── .gitignore ├── init.sh └── README.md ワークフロー (terraform.yaml) 以下の値をご自身の環境で作成したリソースに置き換えてください。 38行目 : Workload Identity プロバイダ 39行目 :サービスアカウント name : terraform # main ブランチへの Pull request と Merge on : pull_request : branches : - main push : branches : - main # ジョブ (GitHUb runners で実行) jobs : terraform-workflow : runs-on : ubuntu-latest permissions : id-token : write contents : read pull-requests : write strategy : matrix : # tf_working_dir に main.tf (呼び出し側) のディレクトリを指定 tf_working_dir : - ./env/demo steps : - uses : actions/checkout@v4 name : Checkout id : checkout # Workload Identity 連携 # https://cloud.google.com/iam/docs/using-workload-identity-federation#generate-automatic - id : 'auth' name : 'Authenticate to Google Cloud' uses : 'google-github-actions/auth@v2' with : workload_identity_provider : 'projects/1234567890/locations/global/workloadIdentityPools/gha-demo-pool/providers/gha-demo-provider' service_account : 'gha-demo-sa@gha-demo-prj.iam.gserviceaccount.com' # https://github.com/marketplace/actions/setup-tfcmt - uses : shmokmt/actions-setup-tfcmt@v2 name : Setup tfcmt # https://github.com/marketplace/actions/setup-github-comment - uses : shmokmt/actions-setup-github-comment@v2 name : Setup github-comment # https://github.com/actions/setup-node # https://github.com/hashicorp/setup-terraform/issues/84 - uses : actions/setup-node@v4 with : node-version : '18' - uses : hashicorp/setup-terraform@v3 name : Setup terraform - name : Terraform fmt id : fmt run : | cd ${{ matrix.tf_working_dir }} terraform fmt -recursive continue-on-error : true - name : Terraform Init id : init run : | cd ${{ matrix.tf_working_dir }} terraform init -upgrade - name : Terraform Validate id : validate run : | cd ${{ matrix.tf_working_dir }} terraform validate # main ブランチへ pull request した際に terraform plan を実行 - name : Terraform Plan id : plan if : github.event_name == 'pull_request' run : | cd ${{ matrix.tf_working_dir }} export GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} tfcmt -var target:${{ matrix.tf_working_dir }} plan -- terraform plan --parallelism=50 github-comment hide -condition 'Comment.Body contains "No changes."' continue-on-error : true # terraform status で失敗した際に workflow を停止 - name : Terraform Plan Status id : status if : steps.plan.outcome == 'failure' run : exit 1 # main ブランチへ push した際に terraform apply を実行 - name : Terraform Apply id : apply if : github.ref == 'refs/heads/main' && github.event_name == 'push' run : | cd ${{ matrix.tf_working_dir }} export GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} tfcmt -var target:${{ matrix.tf_working_dir }} apply -- terraform apply -auto-approve -input= false --parallelism=50 env/demo 配下 (呼び出し側) # backend.tf terraform { backend " gcs " { bucket = " gha-demo-prj-tfstate " prefix = " terraform/state " } } # locals.tf locals { project_id = " gha-demo-prj " apis = [ " artifactregistry.googleapis.com ", " cloudapis.googleapis.com ", " cloudasset.googleapis.com ", " cloudresourcemanager.googleapis.com ", " iam.googleapis.com ", " iamcredentials.googleapis.com ", " servicemanagement.googleapis.com ", " serviceusage.googleapis.com ", " sts.googleapis.com ", ] } # main.tf module " apis " { source = " ../../modules/apis " project_id = local.project_id apis = local.apis } # versions.tf terraform { required_version = " ~> 1.9.7 " required_providers { google = { source = " hashicorp/google " version = " ~> 6.6.0 " } } } provider " google " { user_project_override = true } modules/apis 配下 (モジュール) # main.tf resource " google_project_service " " apis " { for_each = toset ( var.apis ) project = var.project_id service = each.value disable_on_destroy = false } resource " null_resource " " delay " { provisioner " local-exec " { command = " sleep 180 " } depends_on = [ google_project_service.apis ] } # outputs.tf output " enabled_apis " { description = " List of enabled APIs for the project " value = [ for service in google_project_service.apis : service.id ] } # variables.tf variable " apis " { description = " List of APIs to enable " type = list ( string ) } variable " project_id " { description = " The ID of the project to create resources in " type = string } プルリクエスト (terraform plan) main ブランチへのプルリクエストをトリガーに terraform plan が実行されます。 ※ プルリクエストの場合、 terraform apply はスキップされます。 プルリクエストをトリガーに terraform plan が自動実行 マージ (terraform apply) main ブランチへのマージをトリガーに terraform apply が実行されます。 ※ マージの場合、 terraform plan はスキップされます。 マージをトリガーに terraform apply が自動実行 関連記事 サービスアカウントを必要としない Direct Workload Identity リソースを作成する bash スクリプトについてはこちらをご確認ください。 blog.g-gen.co.jp 武井 祐介 (記事一覧) クラウドソリューション部所属。G-gen唯一の山梨県在住エンジニア Google Cloud Partner Top Engineer 2025 選出。IaC や CI/CD 周りのサービスやプロダクトが興味分野です。 趣味はロードバイク、ロードレースやサッカー観戦です。 Follow @ggenyutakei
アバター