OAuth2 プロキシログを収集する
このドキュメントでは、Google Cloud Storage V2 を使用して OAuth2 Proxy ログを Google Security Operations に取り込む方法について説明します。
OAuth2 Proxy は、OAuth2/OIDC プロバイダ(Google、GitHub、Keycloak、Azure AD など)を使用して認証を行い、メール、ドメイン、グループでアカウントを検証する CNCF Sandbox リバース プロキシです。認証ログ(ログインの成功/失敗)、リクエストログ(ユーザー ID を含むプロキシ HTTP リクエスト)、標準アプリケーション ログが生成されます。OAuth2 Proxy は Kubernetes のコンテナとして実行され、すべてのログを stdout に書き込むため、Kubernetes ネイティブのログコレクタ(Fluentd)を使用して、Google SecOps の取り込み用にログを GCS バケットに転送します。
始める前に
次の前提条件を満たしていることを確認してください。
- Google SecOps インスタンス
- Cloud Storage API が有効になっている GCP プロジェクト
- GCS バケットを作成および管理する権限
- GCS バケットの IAM ポリシーを管理する権限
- OAuth2 Proxy がデプロイされた(Helm チャートまたは手動デプロイ)実行中の Kubernetes クラスタ
- DaemonSet、ConfigMap、Secret、Namespace を作成する権限を持つ Kubernetes クラスタへの
kubectlアクセス - ターゲット GCS バケットに対する
storage.objects.create権限を持つ GCP サービス アカウントの JSON キー
Google Cloud Storage バケットを作成する
- Google Cloud コンソールに移動します。
- プロジェクトを選択するか、新しいプロジェクトを作成します。
- ナビゲーション メニューで、[Cloud Storage > バケット] に移動します。
- [バケットを作成] をクリックします。
次の構成情報を提供してください。
設定 値 バケットに名前を付ける グローバルに一意の名前( oauth2-proxy-logs-bucketなど)を入力します。ロケーション タイプ ニーズに応じて選択します(リージョン、デュアルリージョン、マルチリージョン)。 ロケーション 場所を選択します(例: us-central1)。ストレージ クラス Standard(アクセス頻度の高いログにおすすめ) アクセス制御 均一(推奨) 保護ツール 省略可: オブジェクトのバージョニングまたは保持ポリシーを有効にする [作成] をクリックします。
OAuth2 プロキシのロギングを構成する
OAuth2 プロキシは、標準ログ、認証ログ、リクエストログの 3 種類のログを stdout に書き込みます。3 つすべてがデフォルトで有効になっています。ログにセキュリティ関連の詳細が最大限に含まれるように、次のロギング フラグを使用して OAuth2 Proxy を構成します。
オプション 1: Helm チャート値を使用して構成する
公式の Helm チャートを使用して OAuth2 Proxy をデプロイする場合は、次の内容を
values.yamlファイルに追加します。config: configFile: |- standard_logging = true auth_logging = true request_logging = true silence_ping_logging = true standard_logging_format = "[{{.Timestamp}}] [{{.File}}] {{.Message}}" auth_logging_format = "{{.Client}} - {{.RequestID}} - {{.Username}} [{{.Timestamp}}] [{{.Status}}] {{.Message}}" request_logging_format = "{{.Client}} - {{.RequestID}} - {{.Username}} [{{.Timestamp}}] {{.Host}} {{.RequestMethod}} {{.Upstream}} {{.RequestURI}} {{.Protocol}} {{.UserAgent}} {{.StatusCode}} {{.ResponseSize}} {{.RequestDuration}}"更新された Helm 値を適用します。
helm upgrade oauth2-proxy oauth2-proxy/oauth2-proxy -f values.yaml -n <your-namespace>
オプション 2: コマンドライン フラグを使用して構成する
Kubernetes Deployment マニフェストを使用して OAuth2 Proxy をデプロイする場合は、次の引数をコンテナ仕様に追加します。
args: - --standard-logging=true - --auth-logging=true - --request-logging=true - --silence-ping-logging=true
オプション 3: 環境変数を使用して構成する
OAuth2 Proxy コンテナに次の環境変数を設定します。
env: - name: OAUTH2_PROXY_STANDARD_LOGGING value: "true" - name: OAUTH2_PROXY_AUTH_LOGGING value: "true" - name: OAUTH2_PROXY_REQUEST_LOGGING value: "true" - name: OAUTH2_PROXY_SILENCE_PING_LOGGING value: "true"
OAuth2 プロキシのロギングを確認する
構成を適用したら、OAuth2 Proxy がログを生成していることを確認します。
kubectl logs -l app=oauth2-proxy -n <your-namespace> --tail=20出力には、次のような行が含まれます。
10.0.0.1 - abc123 - user@example.com [2024/01/15 10:30:00] [AuthSuccess] Authenticated via OAuth2 10.0.0.1 - abc123 - user@example.com [2024/01/15 10:30:01] example.com GET 10.0.0.5:8080 "/dashboard" HTTP/1.1 "Mozilla/5.0" 200 1234 0.005
Fluentd 用の GCP サービス アカウントを作成する
Fluentd には、GCS バケットに対する書き込み権限を持つ GCP サービス アカウントが必要です。
- GCP コンソールで、[IAM と管理>サービス アカウント] に移動します。
- [サービス アカウントを作成] をクリックします。
- 次の構成情報を指定します。
- サービス アカウント名: 「
fluentd-gcs-writer」と入力します。 - サービス アカウントの説明:
Service account for Fluentd to write OAuth2 Proxy logs to GCSと入力します。
- サービス アカウント名: 「
- [作成して続行] をクリックします。
- [このサービス アカウントにプロジェクトへのアクセスを許可する] セクションで、次の操作を行います。
- [ロールを選択] をクリックします。
- [ストレージ オブジェクト管理者] を検索して選択します。
- [続行] をクリックします。
- [完了] をクリックします。
サービス アカウント キーを作成してダウンロードする
- [サービス アカウント] リストで、
fluentd-gcs-writerサービス アカウントをクリックします。 - [キー] タブに移動します。
- [鍵を追加>新しい鍵を作成] をクリックします。
- キーのタイプとして [JSON] を選択します。
- [作成] をクリックします。
- ダウンロードした JSON キーファイルを安全に保存します。このファイルは次のステップで使用します。
サービス アカウント キーの Kubernetes Secret を作成する
Fluentd がデプロイされる Namespace に、GCP サービス アカウント キーを含む Kubernetes Secret を作成します。
kubectl create namespace logging kubectl create secret generic fluentd-gcs-key \ --from-file=service-account-key.json=<path-to-downloaded-key>.json \ -n logging
OAuth2 プロキシログを収集する Fluentd DaemonSet をデプロイする
Kubernetes クラスタに Fluentd を DaemonSet としてデプロイし、OAuth2 Proxy Pod からコンテナログを収集して GCS バケットに転送します。
Fluentd ConfigMap を作成する
次の内容で
fluentd-configmap.yamlという名前のファイルを作成します。apiVersion: v1 kind: ConfigMap metadata: name: fluentd-gcs-config namespace: logging data: fluent.conf: | <source> @type tail read_from_head true tag kubernetes.* path /var/log/containers/*oauth2-proxy*.log pos_file /var/log/fluentd-oauth2-proxy.log.pos <parse> @type regexp expression /^(?<time>[^ ]+) (?<stream>stdout|stderr) [^ ]* (?<log>.*)$/ time_format %Y-%m-%dT%H:%M:%S.%N%z </parse> </source> <filter kubernetes.**> @type kubernetes_metadata @id filter_kube_metadata </filter> <match kubernetes.**> @type gcs project YOUR_GCP_PROJECT_ID keyfile /etc/secrets/service-account-key.json bucket oauth2-proxy-logs-bucket path oauth2-proxy-logs/%Y/%m/%d/ object_key_format %{path}%{time_slice}_%{hostname}_%{index}.%{file_extension} <buffer tag,time> @type file path /var/log/fluentd/gcs timekey 300 timekey_wait 60 timekey_use_utc true chunk_limit_size 10MB </buffer> <format> @type json </format> </match>
次の値を置き換えます。
YOUR_GCP_PROJECT_ID: GCP プロジェクト ID(例:my-project-123456)oauth2-proxy-logs-bucket: 前に作成した GCS バケットの名前ConfigMap を適用します。
kubectl apply -f fluentd-configmap.yaml
Fluentd DaemonSet を作成する
次の内容で
fluentd-daemonset.yamlという名前のファイルを作成します。apiVersion: apps/v1 kind: DaemonSet metadata: name: fluentd-gcs namespace: logging labels: k8s-app: fluentd-gcs spec: selector: matchLabels: k8s-app: fluentd-gcs template: metadata: labels: k8s-app: fluentd-gcs spec: tolerations: - key: node-role.kubernetes.io/control-plane effect: NoSchedule - key: node-role.kubernetes.io/master effect: NoSchedule containers: - name: fluentd-gcs image: fluent/fluentd-kubernetes-daemonset:v1-debian-gcs resources: limits: memory: 512Mi requests: cpu: 100m memory: 200Mi volumeMounts: - name: fluentd-gcs-config-volume mountPath: /fluentd/etc/fluent.conf subPath: fluent.conf readOnly: true - name: fluentd-gcs-secrets-volume mountPath: /etc/secrets/service-account-key.json subPath: service-account-key.json readOnly: true - name: varlog mountPath: /var/log - name: dockercontainerlogdirectory mountPath: /var/log/pods readOnly: true - name: fluentd-buffer mountPath: /var/log/fluentd terminationGracePeriodSeconds: 30 volumes: - name: fluentd-gcs-config-volume configMap: name: fluentd-gcs-config - name: fluentd-gcs-secrets-volume secret: secretName: fluentd-gcs-key - name: varlog hostPath: path: /var/log - name: dockercontainerlogdirectory hostPath: path: /var/log/pods - name: fluentd-buffer emptyDir: {}DaemonSet を適用します。
kubectl apply -f fluentd-daemonset.yaml
Fluentd のデプロイを確認する
各ノードで Fluentd Pod が実行されていることを確認します。
kubectl get pods -n logging -l k8s-app=fluentd-gcsFluentd ログで GCS への書き込みが成功したことを確認します。
kubectl logs -l k8s-app=fluentd-gcs -n logging --tail=20ログファイルが GCS バケットに表示されることを確認します。
- GCP Console で、[Cloud Storage] > [バケット] に移動します。
- バケット(
oauth2-proxy-logs-bucketなど)をクリックします。 oauth2-proxy-logs/フォルダに移動します。.jsonファイルが存在し、タイムスタンプが最新であることを確認します。
Google SecOps サービス アカウントを取得する
Google SecOps は、一意のサービス アカウントを使用して GCS バケットからデータを読み取ります。このサービス アカウントにバケットへのアクセス権を付与する必要があります。
サービス アカウントのメールアドレスを取得する
- [SIEM 設定] > [フィード] に移動します。
- [Add New Feed] をクリックします。
- [単一フィードを設定] をクリックします。
- [フィード名] フィールドに、フィードの名前を入力します(例:
OAuth2 Proxy Logs)。 - [ソースタイプ] として [Google Cloud Storage V2] を選択します。
- [ログタイプ] として [Kubernetes Auth Proxy] を選択します。
[サービス アカウントを取得する] をクリックします。一意のサービス アカウントのメールアドレスが表示されます(例:)。
chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.comこのメールアドレスをコピーして、次のステップで使用します。
[次へ] をクリックします。
次の入力パラメータの値を指定します。
ストレージ バケットの URL: 接頭辞パスを含む GCS バケット URI を入力します。
gs://oauth2-proxy-logs-bucket/oauth2-proxy-logs/oauth2-proxy-logs-bucketは、GCS バケット名に置き換えます。
Source deletion option: 必要に応じて削除オプションを選択します。
- なし: 転送後にファイルを削除しません(テストにおすすめ)。
- 転送されたファイルを削除する: 転送が完了した後にファイルを削除します。
転送されたファイルと空のディレクトリを削除する: 転送が完了した後にファイルと空のディレクトリを削除します。
ファイルの最大経過日数: 過去の日数以内に変更されたファイルを含めます(デフォルトは 180 日)。
アセットの名前空間: アセットの名前空間
Ingestion labels: このフィードのイベントに適用されるラベル
[次へ] をクリックします。
[Finalize] 画面で新しいフィードの設定を確認し、[送信] をクリックします。
Google SecOps サービス アカウントに IAM 権限を付与する
Google SecOps サービス アカウントには、GCS バケットに対する Storage オブジェクト閲覧者のロールが必要です。
- [Cloud Storage] > [バケット] に移動します。
- バケット名(
oauth2-proxy-logs-bucketなど)をクリックします。 - [権限] タブに移動します。
- [アクセス権を付与] をクリックします。
- 次の構成情報を指定します。
- プリンシパルの追加: Google SecOps サービス アカウントのメールアドレス(
chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.comなど)を貼り付けます。 - ロールを割り当てる: [Storage オブジェクト閲覧者] を選択します。
- プリンシパルの追加: Google SecOps サービス アカウントのメールアドレス(
- [保存] をクリックします。
OAuth2 プロキシログのリファレンス
次の表に、OAuth2 Proxy によって生成されるログフィールドとそのセキュリティ関連性を示します。
認証ログのフィールド
| フィールド | 例 | 説明 |
|---|---|---|
| クライアント | 10.0.0.1 |
クライアント/リモート IP アドレス(--reverse-proxy=true の場合は X-Real-IP ヘッダーを使用) |
| RequestID | 00010203-0405-4607-8809-0a0b0c0d0e0f |
X-Request-Id ヘッダーの ID をリクエストします(空の場合はランダムな UUID)。 |
| ユーザー名 | user@example.com |
認証リクエストのメールアドレスまたはユーザー名 |
| タイムスタンプ | 2024/01/15 10:30:00 |
認証イベントの日時 |
| ステータス | AuthSuccess |
認証結果: AuthSuccess、AuthFailure、AuthError |
| メッセージ | Authenticated via OAuth2 |
認証試行の詳細 |
リクエストログ フィールド
| フィールド | 例 | 説明 |
|---|---|---|
| クライアント | 10.0.0.1 |
クライアント/リモート IP アドレス |
| RequestID | 00010203-0405-4607-8809-0a0b0c0d0e0f |
リクエスト ID |
| ユーザー名 | user@example.com |
認証済みユーザーのメールアドレス |
| タイムスタンプ | 2024/01/15 10:30:01 |
リクエストの日時 |
| ホスト | app.example.com |
Host ヘッダーの値 |
| RequestMethod | GET |
HTTP リクエスト メソッド |
| アップストリーム | 10.0.0.5:8080 |
リクエストを処理したアップストリーム サーバー |
| RequestURI | /dashboard |
リクエストの URI パス |
| プロトコル | HTTP/1.1 |
リクエスト プロトコル |
| UserAgent | Mozilla/5.0 |
完全なユーザー エージェント文字列 |
| StatusCode | 200 |
HTTP レスポンス ステータス コード |
| ResponseSize | 1234 |
レスポンスのサイズ(バイト単位) |
| RequestDuration | 0.005 |
リクエスト処理時間(秒) |
UDM マッピング テーブル
| ログフィールド | UDM マッピング | ロジック |
|---|---|---|
| about | about | イベントに関する情報 |
| http_req_id_field | additional.fields | 標準の UDM スキーマでカバーされていない追加フィールド |
| http_req_path_field | additional.fields | |
| k8s_pod_app_field | additional.fields | |
| k8s_pod_template_hash_field | additional.fields | |
| k8s_pod_tls_mode_field | additional.fields | |
| k8s_pod_canonical_revision_field | additional.fields | |
| k8s_pod_canonical_name_field | additional.fields | |
| pod_name | additional.fields | |
| cntnr_name | additional.fields | |
| destination_canonical_revision | additional.fields | |
| requested_server | additional.fields | |
| nodename_label | additional.fields | |
| componentName_label | additional.fields | |
| componentVersion_label | additional.fields | |
| azureResourceID_label | additional.fields | |
| producer_label | additional.fields | |
| first_label | additional.fields | |
| last_label | additional.fields | |
| meta_name | additional.fields | |
| resource_version_label | additional.fields | |
| request_apiVersion | additional.fields | |
| request_kind_label | additional.fields | |
| request_type_label | additional.fields | |
| response_apiVersion | additional.fields | |
| response_kind_label | additional.fields | |
| response_type_label | additional.fields | |
| jsonPayload.message | metadata.description | イベントの説明 |
| event_type | metadata.event_type | イベントのタイプ |
| labels.request_id | metadata.product_log_id | プロダクト固有のログ識別子 |
| insertId | metadata.product_log_id | |
| jsonPayload.chartVersion | metadata.product_version | プロダクト バージョン |
| httpRequest.protocol | network.application_protocol | ネットワーク接続で使用されるアプリケーション プロトコル |
| network.direction | network.direction | ネットワーク トラフィックの方向 |
| httpRequest.requestMethod | network.http.method | HTTP メソッド |
| http_method | network.http.method | |
| httpRequest.status | network.http.response_code | HTTP レスポンス コード |
| httpRequest.userAgent | network.http.user_agent | HTTP ユーザー エージェント |
| requestMetadata.callerSuppliedUserAgent | network.http.user_agent | |
| labels.protocol | network.ip_protocol | IP プロトコル |
| httpRequest.responseSize | network.received_bytes | 受信したバイト数 |
| labels.total_received_bytes | network.received_bytes | |
| httpRequest.requestSize | network.sent_bytes | 送信されたバイト数 |
| labels.total_sent_bytes | network.sent_bytes | |
| jsonPayload.session | network.session_id | セッション ID |
| labels.service_authentication_policy | network.tls.cipher | TLS 暗号スイート |
| プリンシパル | プリンシパル | イベントに関与するプリンシパル エンティティ |
| principal_hostname | principal.hostname | プリンシパルのホスト名 |
| prin_userid | principal.user.userid | プリンシパルのユーザー ID |
| security_result | security_result | セキュリティ評価の結果 |
| ターゲット | ターゲット | イベントに関与するターゲット エンティティ |
| target_hostname | target.hostname | ターゲットのホスト名 |
| resource_sub_type | target.resource.resource_subtype | ターゲット リソースのサブタイプ |
| target_userid | target.user.userid | ターゲットのユーザー ID |
| metadata.product_name | metadata.product_name | 製品名 |
| metadata.vendor_name | metadata.vendor_name | ベンダー名 |
変更ログ
さらにサポートが必要な場合 コミュニティ メンバーや Google SecOps のプロフェッショナルから回答を得ることができます。