🔐

【BigQuery】データアクセス監査ログの確認方法

11 min read

はじめに

さて、今回はBigQuery(以降、BQ)に対して実行したSQLクエリについて
「誰が」「いつ」「何を」「どこから」実行したのか把握できるようにしたく
BQのデータアクセス監査ログの確認方法をまとめてみました。

いざ、やってみようと思うとまとまった情報がパッと分からなかったので
公式サイトのどのあたりを見ると良いかも記載しています。

皆さまのお役に立てると幸いです^^

データアクセス監査ログとは

Google Cloud Platform(以降、GCP)の監査ログ(Cloud Audit Logs)には下記4種類があります。

  • 管理アクティビティ監査ログ
  • データアクセス監査ログ
  • システム イベント監査ログ
  • ポリシー拒否監査ログ

https://cloud.google.com/logging/docs/audit?hl=ja#data-access

BQのSQLクエリ実行ログはデータアクセス監査ログに含まれます。
そして、BQのデータアクセス監査ログはデフォルトで有効となっており、無効化ができません。

BigQuery データアクセス監査ログを除き、データアクセス監査ログはデフォルトで無効になっています。BigQuery 以外の Google Cloud サービスのデータアクセス監査ログを書き込むには、明示的に有効にする必要があります。

データアクセス監査ログは、Cloud Logging[1]で確認することができます。
ログ エクスプローラでログ検索するためには下記の権限が必要です。

このログを表示するには、Logging/プライベートログ閲覧者またはプロジェクト/オーナーという IAM 役割が必要です。

データアクセス監査ログの保持期間はデフォルト30日[2]となっています。最大で3,650日まで拡張可能です。

実行環境

Product version
Cloud IAM 2021年3月5日時点
Cloud Logging 2021年3月5日時点
BigQuery 2021年3月5日時点

【前提条件】
・ リージョンは、東京リージョン(asia-northeast1)を利用しています。
・ オーナーでもなく、プライベートログ閲覧者のロールも付与されていないユーザを利用します。
・ BigQueryのSQLクエリは、すでに実行された状態とします。

実施手順

  1. Cloud IAMでロール追加
  2. Cloud Loggingでログ確認

1. Cloud IAMでロール追加

  • GCPコンソールにログインし、[IAMと管理] > [IAM]を開きます。
  • 権限付与するユーザを編集します。
  • [別のロールを追加]ボタンを押し、[Logging] > [プライベートログ閲覧者]を選択します。

  • [保存]します。

2. Cloud Loggingでログ確認

  • [ロギング] > [ログ エクスプローラ]を開きます。
  • 正しくロールが付与されているとクエリ結果に出力されたログが表示されます。

  • 上部のクエリのプレビューに下記クエリを入力します。
resource.type=("bigquery_dataset" OR "bigquery_project") AND
logName:"cloudaudit.googleapis.com"

https://cloud.google.com/logging/docs/view/query-library-preview?hl=ja
  • BQのクエリエディタで実行したログは以下の3つになります。
(1) クエリジョブの作成開始
{
  "protoPayload": {
    "@type": "type.googleapis.com/google.cloud.audit.AuditLog",
    "status": {},
    "authenticationInfo": {
      "principalEmail": "<ユーザアカウント>"
    },
    "requestMetadata": {
      "callerIp": "<接続元IPアドレス>",
      "callerSuppliedUserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36,gzip(gfe),gzip(gfe)",
      "requestAttributes": {},
      "destinationAttributes": {}
    },
    "serviceName": "bigquery.googleapis.com",
    "methodName": "google.cloud.bigquery.v2.JobService.InsertJob",
    "authorizationInfo": [
      {
        "resource": "projects/<プロジェクト名>",
        "permission": "bigquery.jobs.create",
        "granted": true,
        "resourceAttributes": {}
      }
    ],
    "resourceName": "projects/<プロジェクト名>/jobs/bquxjob_xxxxxxxx_xxxxxxxxxxx",
    "metadata": {
      "jobInsertion": {
        "reason": "JOB_INSERT_REQUEST",
        "job": {
          "jobStatus": {
            "jobState": "RUNNING"
          },
          "jobConfig": {
            "queryConfig": {
              "priority": "QUERY_INTERACTIVE",
              "destinationTable": "projects/<プロジェクト名>/datasets/_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/tables/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
              "writeDisposition": "WRITE_TRUNCATE",
              "statementType": "SELECT",
              "query": "SELECT * FROM `<プロジェクト名>.<データセット名>.<テーブル名>` LIMIT 1000",
              "createDisposition": "CREATE_IF_NEEDED"
            },
            "type": "QUERY"
          },
          "jobStats": {
            "queryStats": {},
            "startTime": "2021-03-05T03:20:00.766Z",
            "createTime": "2021-03-05T03:20:00.293Z"
          },
          "jobName": "projects/<プロジェクト名>/jobs/bquxjob_xxxxxxxx_xxxxxxxxxxx"
        }
      },
      "@type": "type.googleapis.com/google.cloud.audit.BigQueryAuditMetadata"
    }
  },
  "insertId": "y4yrhoe1q4x7",
  "resource": {
    "type": "bigquery_project",
    "labels": {
      "location": "asia-northeast1",
      "project_id": "<プロジェクト名>"
    }
  },
  "timestamp": "2021-03-05T03:20:00.853415Z",
  "severity": "INFO",
  "logName": "projects/<プロジェクト名>/logs/cloudaudit.googleapis.com%2Fdata_access",
  "operation": {
    "id": "xxxxxxxxxxxxx-<プロジェクト名>:bquxjob_xxxxxxxx_xxxxxxxxxxx",
    "producer": "bigquery.googleapis.com",
    "first": true
  },
  "receiveTimestamp": "2021-03-05T03:20:01.823827629Z"
}
(2) クエリジョブの作成完了
{
  "protoPayload": {
    "@type": "type.googleapis.com/google.cloud.audit.AuditLog",
    "status": {},
    "authenticationInfo": {
      "principalEmail": "<ユーザアカウント>"
    },
    "requestMetadata": {
      "callerIp": "<接続元IPアドレス>",
      "callerSuppliedUserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36,gzip(gfe),gzip(gfe)"
    },
    "serviceName": "bigquery.googleapis.com",
    "methodName": "google.cloud.bigquery.v2.JobService.InsertJob",
    "authorizationInfo": [
      {
        "resource": "projects/<プロジェクト名>",
        "permission": "bigquery.jobs.create",
        "granted": true
      }
    ],
    "resourceName": "projects/<プロジェクト名>/jobs/bquxjob_xxxxxxx_xxxxxxxxxxx",
    "metadata": {
      "jobChange": {
        "after": "DONE",
        "job": {
          "jobName": "projects/<プロジェクト名>/jobs/bquxjob_xxxxxxxx_xxxxxxxxxxx",
          "jobConfig": {
            "type": "QUERY",
            "queryConfig": {
              "query": "SELECT * FROM `<プロジェクト名>.<データセット名>.<テーブル名>` LIMIT 1000",
              "destinationTable": "projects/<プロジェクト名>/datasets/_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/tables/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
              "createDisposition": "CREATE_IF_NEEDED",
              "writeDisposition": "WRITE_TRUNCATE",
              "priority": "QUERY_INTERACTIVE",
              "statementType": "SELECT"
            }
          },
          "jobStatus": {
            "jobState": "DONE"
          },
          "jobStats": {
            "createTime": "2021-03-05T03:20:00.293Z",
            "startTime": "2021-03-05T03:20:00.766Z",
            "endTime": "2021-03-05T03:20:01.056Z",
            "queryStats": {
              "totalProcessedBytes": "73983527",
              "totalBilledBytes": "74448896",
              "billingTier": 1,
              "referencedTables": [
                "projects/<プロジェクト名>/datasets/<データセット名>/tables/<テーブル名>"
              ],
              "outputRowCount": "1000"
            },
            "totalSlotMs": "115"
          }
        }
      },
      "@type": "type.googleapis.com/google.cloud.audit.BigQueryAuditMetadata"
    }
  },
  "insertId": "y4yrhoe1q4xl",
  "resource": {
    "type": "bigquery_project",
    "labels": {
      "location": "asia-northeast1",
      "project_id": "<プロジェクト名>"
    }
  },
  "timestamp": "2021-03-05T03:20:01.060748Z",
  "severity": "INFO",
  "logName": "projects/<プロジェクト名>/logs/cloudaudit.googleapis.com%2Fdata_access",
  "operation": {
    "id": "xxxxxxxxxxxxx-<プロジェクト名>:bquxjob_xxxxxxxx_xxxxxxxxxxx",
    "producer": "bigquery.googleapis.com",
    "last": true
  },
  "receiveTimestamp": "2021-03-05T03:20:01.823827629Z"
}
(3) SQLクエリの実行
{
  "protoPayload": {
    "@type": "type.googleapis.com/google.cloud.audit.AuditLog",
    "status": {},
    "authenticationInfo": {
      "principalEmail": "<ユーザアカウント>"
    },
    "requestMetadata": {
      "callerIp": "<接続元IPアドレス>",
      "callerSuppliedUserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36,gzip(gfe),gzip(gfe)"
    },
    "serviceName": "bigquery.googleapis.com",
    "methodName": "google.cloud.bigquery.v2.JobService.InsertJob",
    "authorizationInfo": [
      {
        "resource": "projects/<プロジェクト名>/datasets/<データセット名>/tables/<テーブル名>",
        "permission": "bigquery.tables.getData",
        "granted": true
      }
    ],
    "resourceName": "projects/<プロジェクト名>/datasets/<データセット名>/tables/<テーブル名>",
    "metadata": {
      "tableDataRead": {
        "fields": [
          "<フィールド名1>",
          "<フィールド名2>",
          "<フィールド名3>",
          "<フィールド名4>",
          "<フィールド名5>"
        ],
        "reason": "JOB",
        "jobName": "projects/<プロジェクト名>/jobs/bquxjob_xxxxxxxx_xxxxxxxxxxx"
      },
      "@type": "type.googleapis.com/google.cloud.audit.BigQueryAuditMetadata"
    }
  },
  "insertId": "y4yrhoe1q4xn",
  "resource": {
    "type": "bigquery_dataset",
    "labels": {
      "project_id": "<プロジェクト名>",
      "dataset_id": "<データセット名>"
    }
  },
  "timestamp": "2021-03-05T03:20:01.060952Z",
  "severity": "INFO",
  "logName": "projects/<プロジェクト名>/logs/cloudaudit.googleapis.com%2Fdata_access",
  "receiveTimestamp": "2021-03-05T03:20:01.823827629Z"
}

【ログの見方】

  • クエリジョブの作成開始、作成終了、SQLクエリの実行の3件のログが出力されます。
  • protoPayload.authenticationInfo.principalEmailで誰が実行したのか判断できます。
  • timestampでいつ実行したか判断できます。
  • protoPayload.metadata.jobInsertion.job.jobConfig.queryConfig.queryでどんなSQLクエリを実行したか判断できます。
  • protoPayload.requestMetadata.callerIpでどこから実行したか判断できます。
  • protoPayload.authorizationInfo.permissionを見ることでどのAPIをコールしたログか、ある程度判断できます。(1と2件目のログはbigquery.jobs.createになっています。ジョブ作成に関するログです。3件目のログはbigquery.tables.getDataになっています。テーブルからデータ取得したことが分かります)

まとめ

さて、いかがでしたでしょうか?
これでBQでどんなデータが参照されたのか、誰がいつ参照したか判断できますね。

しかし、Cloud LoggingのログエクスプローラのUIでは少し分析するには時間がかかりそうです。
Cloud Loggingは下記の5つの出力先にエクスポートができます。

  • Cloud Storage
  • BigQuery
  • Pub/Sub
  • Cloud Logging のログバケット
  • Splunk

Splunkに出力できますし、Pub/Sub経由でElasticsearch[3]にも連携できます。
監査ログの分析環境も色々と工夫ができそうですね^^

https://cloud.google.com/logging/docs/export/configure_export_v2?hl=ja
脚注
  1. Cloud Logging ↩︎

  2. ログの保持期間 ↩︎

  3. Cloud LoggingをElasticsearchにエクスポートするシナリオ ↩︎

Discussion

ログインするとコメントできます