Elastic StackでGoogleドライブ監査をやってみた #elastic #elasticsearch

この記事は1年以上前に投稿されました。情報が古い可能性がありますので、ご注意ください。
はじめに
これまで、WindowsファイルサーバでOfficeファイルの共有や管理していたが
昨今では、パブリックのオンラインストレージサービスに移行をされている企業がかなり増えたのではないでしょうか?
G SuiteのGoogleドライブに移行してファイル管理されている方も多いと感じています。
オンラインストレージに移行することでファイルシステムの管理負担から解放される一方
利用状況を適切に把握しておかないと機密情報のセキュリティを維持することができません。
そのため、GSuiteではドライブの監査ログのレポート機能が実装されています。
利用できるG Suiteのエディションに制約がありますので、事前にチェックしましょう!
この機能は、G Suite Business、G Suite for Education、G Suite Enterprise、G Suite Essentials でご利用いただけます。
本投稿は、G Suiteのドライブの監査ログをElastic Stackに取り込んで
セキュリティ監査をするための環境構築とKibanaでの簡単な操作をまとめた内容になっています。
まだベータ版ですが、Filebeat 7.9からFilebeat Modulesとして登場したGSuite moduleを利用します。
利用環境
| product | version |
|---|---|
| Filebeat | 7.9.0 |
| Elasticsearch | 7.9.0 |
| Kibana | 7.9.0 |
| OS (GCE VM) | CentOS 7 (centos-7-v20200811) |
【構成図】

前提条件
- GCPの東京リージョン(asia-northeast1)のVMを利用していますが、GCP以外でも可能です。
- VMのOSにはCentOS7を利用していますが、Elastic Stack 7.9以降が導入可能なOSであればOKです。
- 動作検証のため、Filebeat・Elasticsearch・Kibanaを同じVM上で稼働させています。
- KibanaへのアクセスをHTTPとしていますが、本番ではHTTPSによる暗号化を推奨します。
- 契約しているG Suiteの管理者アカウントを用意する必要があります。
補足説明
- Googleドライブの監査ログの取得には、Admin SDK APIを利用します。
- G Suite Moduleの仕様として、GCPのサービスアカウントを使用したOAUTH2認証が必要になります。
- サービスアカウントに対して、「G Suiteドメイン全体の権限の委任」が必要になります。
- G Suite Module用のKibanaのダッシュボードは存在しません。(ダッシュボードのロードは不要)
In order for filebeat to ingest data from the Google Reports API you must set up a ServiceAccount that has access to the Admin SDK API.
Additionally Domain-Wide Delegation is required for your application to work properly.
実施手順
- Admin SDK API (Report API) の有効化
- サービスアカウント作成
- G Suiteへの登録
- Elastic Stackのインストール
- Filebeatの設定 (Gsuite moduleの有効化)
- Kibanaでの監査ログ検証
1. Admin SDK API (Report API) の有効化
- G Suite Admin SDK > Create reports > Quickstart guideを開きます。
-
G Suiteの管理者アカウントでログインします。

-
Enable the Reports APIをクリックします。

-
[Enter new project name]にプロジェクト名を入力し、[NEXT]をクリックします。(名前は何でもOKです)

-
何もダウンロードせずに[DONE]をクリックして閉じます。
- G Suiteの管理者アカウントでGoogle Cloudのコンソールにログインします。
- 作成したGet-ReportAPI-Filebeatのプロジェクトを選択します。
- メニューから[APIとサービスの有効化] > [ダッシュボード]を選択し、Admin SDKが存在していることを確認します。

2. サービスアカウント作成
- そのまま、Google Cloudのコンソールで[IAMと管理] > [サービスアカウント]を選択します。
-
[+サービスアカウントを作成]をクリックします。

-
サービスアカウント名を入力して、[作成]をクリックします。 (今回は、driveapiとしています)

-
[ロールを選択]は何でも良いので、適当に[Project] > [オーナー]とし、[続行]をクリックします。

-
[ユーザにこのサービスアカウントへのアクセス権を付与(オプション)]は何も設定せずに[完了]をクリックします。
- 作成したサービスアカウントを選択し、[編集]モードにします。
-
[ドメイン全体の委任の表示]を開き、[G Suiteドメイン全体の委任を有効にする]にチェックを入れます。

-
そのままキーで[鍵を追加]をクリックし、秘密鍵を新規作成します。

-
JSONを指定し、作成するとサービスアカウントに紐づくクレデンシャルファイルがダウンロードされます。

※今回は、get-reportapi-fi-XXXXXXXXXXXXX-30ebcd8990be.jsonというファイル名となりました。
3. G Suiteへの登録
- 管理者アカウントでG Suite管理コンソールにログインします。
-
[セキュリティ] > [アプリのアクセス制御] > [ドメイン全体の委任]でドメイン全体の委任を管理をクリックします。

-
[新しく追加]をクリックします。

-
[クライアントID]と[Oauthスコープ]を入力し、[承認]をクリックします。

※クライアントIDは、ダウンロードしたクレデンシャルファイル内に記載されています。
※Oauthスコープは、Configure the moduleに記載されています。(oauth2 scope)
4. Elastic Stackのインストール
- Google Cloudのコンソールで[VPCネットワーク] > [ファイアウォール]でファイアウォールルールを作成します。
【ファイルウォールルール】
| 設定項目 | 設定値 |
|---|---|
| 名前 | kibana-allow-access |
| ネットワーク | default |
| 優先度 | 999 |
| トラフィックの方向 | 上り |
| 一致したときのアクション | 許可 |
| ターゲット | 指定されたターゲットタグ |
| ターゲットタグ | elastic |
| ソースフィルタ | IP範囲 |
| ソースIPの範囲 | xxx.xxx.xxx.xxx/32 |
| プロトコルとポート | tcp:5601 |
※ソースIPの範囲には、許可するIPアドレスを各自設定してください。(Kibanaへのアクセス制御になります)
- CloudShellで作成する場合は、以下の通りになります。
$ gcloud compute firewall-rules create kibana-allow-access \ --network=default \ --priority=999 \ --direction=INGRESS \ --action=ALLOW \ --target-tags=elastic \ --source-ranges=xxx.xxx.xxx.xxx/32 \ --rules=tcp:5601
- 次は、[Compute Engine] > [VMインスタンス]でインスタンスを作成します。
【インスタンス設定】
| 設定項目 | 設定値 |
|---|---|
| 名前 | elastic-vm01 |
| リージョン | asia-northeast1 (東京) |
| ゾーン | asia-northeast1-a |
| マシンタイプ | n2-standard-1 (2vCPU、8GBメモリ) |
| CPUプラットフォーム | 自動 |
| オペレーティングシステム | CentOS |
| バージョン | CentOS 7 |
| ブートディスクの種類 | 標準の永続ディスク |
| サイズ(GB) | 20 |
| ネットワーク タグ | elastic |
| ネットワーク インターフェース | default |
- CloudShellで作成する場合は、以下の通りになります。
$ gcloud compute instances create elastic-vm01 \ --zone=asia-northeast1-a \ --machine-type=n2-standard-2 \ --min-cpu-platform=Automatic \ --image-project=centos-cloud \ --image-family=centos-7 \ --boot-disk-type=pd-standard \ --boot-disk-size=20GB \ --tags=elastic \ --subnet=default
- インスタンス作成後、OSにログインします。(今回は、ブラウザウィンドウから接続します)
- yumコマンドでElastic Stackをインストールするため、リポジトリ定義を設定します。
$ sudo vi /etc/yum.repos.d/elastic.repo [elasticstack] name=Elasticsearch repository for 7.x packages baseurl=https://artifacts.elastic.co/packages/7.x/yum gpgcheck=1 gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch enabled=0 autorefresh=1 type=rpm-md
- PGP鍵をインポートし、yumコマンドでElasticsearch、Kibana、Filebeatをインストールします。
$ sudo rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch $ sudo yum install --enablerepo=elasticstack elasticsearch kibana filebeat $ sudo yum list installed | grep elastic elasticsearch.x86_64 7.9.0-1 @elasticstack filebeat.x86_64 7.9.0-1 @elasticstack kibana.x86_64 7.9.0-1 @elasticstack
- 再起動しても良いように自動起動設定を行います。
$ sudo systemctl daemon-reload $ sudo systemctl enable elasticsearch kibana filebeat
- Elasticsearchを起動します。(正常起動していることも確認します)
$ sudo systemctl start elasticsearch $ sudo systemctl status elasticsearch
- ElasticsearchのAPIを叩き、ステータスを確認します。
$ curl localhost:9200
{
"name" : "elastic-vm01",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "_TBVxxybReOVe2az4wrBkg",
"version" : {
"number" : "7.9.0",
"build_flavor" : "default",
"build_type" : "rpm",
"build_hash" : "a479a2a7fce0389512d6a9361301708b92dff667",
"build_date" : "2020-08-11T21:36:48.204330Z",
"build_snapshot" : false,
"lucene_version" : "8.6.0",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
- 外部からKibanaアクセスできるようにserver.hostに以下を追記します。
$ sudo vi /etc/kibana/kibana.yml server.host: "0.0.0.0"
- Kibanaを起動します。(正常起動していることを確認します)
$ sudo systemctl start kibana $ sudo systemctl status kibana
5. Filebeatの設定 (Gsuite moduleの有効化)
- 手順2のサービスアカウント作成でダウンロードした秘密鍵ファイルの中身を貼り付けます。
$ sudo vi /etc/filebeat/credentials.json
{
"type": "service_account",
"project_id": "get-reportapi-fi-XXXXXXXXXXXXX",
"private_key_id": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"private_key": "-----BEGIN PRIVATE KEY-----\nXXXXXXXXXXXXX\n-----END PRIVATE KEY-----\n",
"client_email": "driveapi@get-reportapi-fi-XXXXXXXXXXXXX.iam.gserviceaccount.com",
"client_id": "11792526XXXXXXXXXXXXX",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/driveapi%40get-reportapi-fi-XXXXXXXXXXXXX.iam.gserviceaccount.com"
}
- FilebeatのGSuite moduleを有効化します。
$ sudo filebeat modules enable gsuite Enabled gsuite $ sudo filebeat modules list Enabled: gsuite
- GSuite Moduleの設定をします。(YAML形式のインデントには気を付けましょう)
- drive以外はenabled: falseとする
- 今回は、過去1時間分の監査ログを取得し、以降10分間隔で更新分を取得する
(Google Driveに関係する箇所の抜粋)
$ sudo vi /etc/filebeat/modules.d/gsuite.yml
drive:
enabled: true
var.jwt_file: "/etc/filebeat/credentials.json"
var.delegated_account: "xxxxxx@xxxxxxxxxxxxxxxx"
var.initial_interval: 1h
var.http_client_timeout: 30s
# var.user_key: all
var.interval: 10m
※ちなみに上記のYAMLのインデントを間違えると以下のようなエラーが/var/log/messagesに出ます。
Sep 24 23:11:47 elastic-vm01 filebeat: 2020-09-24T23:11:47.670Z ERROR instance/beat.go:951 Exiting: Failed to start crawler: creating module reloader failed: 1 error: invalid config: yaml: line 39: mapping values are not allowed in this context
【gsuite.yml driveのパラメータ】
| 設定項目 | デフォルト値 | 説明 |
|---|---|---|
| var.jwt_file | credentials.json | サービスアカウントの秘密鍵ファイルの配置パス |
| var.delegated_account | admin@example.com | 契約しているG Suiteの管理者アカウント |
| var.initial_interval | 24h | モジュール起動時の初回API実行におけるログ取得対象期間 |
| var.http_client_timeout | 60s | モジュールによるHTTPリクエストのタイムアウト値 |
| var.user_key | all | Drive監査レポートを取得するユーザーキー |
| var.interval | 2h | 2回目以降のAPIポーリング間隔 |
※ var.delegated_accountの値は、契約しているG Suite管理者アカウントを記載ください。
※ デフォルトでは、過去24時間分のデータを初回取得し、以降は2時間おきに更新分を取得します。
- Filebeatのプロセスを起動します。(正常起動していることを確認します)
$ sudo systemctl start filebeat $ sudo systemctl status filebeat
※ 何度も繰り返しFilebeatプロセスを再起動するとvar.initial_intervalの設定値によっては、重複取り込みが発生する点は注意してください。
- 正常にAdmin SDK APIにアクセスできていると以下のようなログが/var/log/messagesに出ます。
Sep 25 13:15:08 elastic-vm01 filebeat: 2020-09-25T22:15:08.136+0900 INFO [httpjson] httpjson/input.go:574 Process another repeated request. {"url": "https://www.googleapis.com/admin/reports/v1/activity/users/all/applications/drive"}
【参考】
・Filebeat quick start: installation and configuration
・Configure Filebeat module
・GSuite modules
4. Kibanaでの監査ログ検証
-
ブラウザでhttp://[Kibanaの外部IPアドレス]:5601にアクセスします。(今回は35.200.36.186となります)

-
[Management] > [Dev Tools]で GET _cat/indices/filebeat-*?v&s を実施し、Indexが生成されていることを確認します。

-
[Management] > [Stack Management] > [Kibana] > [Index Patterns]でCreate index patternをクリックします。

-
[Index pattern name]に[filebeat-*]と入力し、[Next step]をクリックします。

-
[Time field]に[@timestamp]を指定し、[Create index pattern]をクリックします。

-
G Suiteの管理者画面のドライブの監査レポートが以下のような状態だとします。

-
KibanaのDiscoverでファイルダウンロードされたログを絞り込みます。(event.actionがdownloadでフィルタします)

-
以下が絞り込まれた状態です。

-
ちなみにJSON形式で表示した場合のログは以下のようになっています。
{
"<em>index": "filebeat-7.9.0-2020.09.25-000001",
"_type": "_doc",
"_id": "yp7CxXQBeOr77_njx38</em>",
"_version": 1,
"_score": null,
"_source": {
"agent": {
"hostname": "elastic-vm01",
"name": "elastic-vm01",
"id": "722bb940-eb44-48e4-b555-67493a0bb555",
"ephemeral_id": "30945104-f535-413c-8de9-e883be48f621",
"type": "filebeat",
"version": "7.9.0"
},
"source": {
"geo": {
"continent_name": "Asia",
"region_iso_code": "JP-14",
"city_name": "Kawasaki",
"country_iso_code": "JP",
"region_name": "Kanagawa",
"location": {
"lon": 139.6285,
"lat": 35.57
}
},
"as": {
"number": xxxx,
"organization": {
"name": "xxxxxxxxxxxxxxx"
}
},
"ip": "xxx.xxx.4.212",
"user": {
"domain": "xxxxxxxx.com",
"name": "xxxxxx",
"id": "115361142755381498172",
"email": "xxxxxx@xxxxxxxx.com"
}
},
"fileset": {
"name": "drive"
},
"tags": [
"forwarded"
],
"cloud": {
"availability_zone": "asia-northeast1-a",
"instance": {
"name": "elastic-vm01",
"id": "391729035646255624"
},
"provider": "gcp",
"machine": {
"type": "n2-standard-2"
},
"project": {
"id": "xxxxxxxxxxxxxxx"
}
},
"input": {
"type": "httpjson"
},
"@timestamp": "2020-09-25T14:48:09.916Z",
"file": {
"owner": "xxxxx",
"extension": "repo",
"name": "elastic.repo",
"type": "file"
},
"ecs": {
"version": "1.5.0"
},
"related": {
"ip": [
"xxx.xxx.4.212"
],
"user": [
"kanri"
]
},
"service": {
"type": "gsuite"
},
"organization": {
"id": "xxxxxxxxx"
},
"event": {
"ingested": "2020-09-25T14:55:10.621843Z",
"original": "{\"actor\":{\"email\":\"xxxxxx@xxxxxxxx.com\",\"profileId\":\"115361142755381498172\"},\"etag\":\"\\"kUnwYYg1BVyzlZxLWewcY0fcrpfz6LbI3xDE6gsvPl4/CTJxYgt9gTToAF2TbAn6F4qXKs0\\"\",\"events\":{\"name\":\"download\",\"parameters\":[{\"boolValue\":true,\"name\":\"primary_event\"},{\"boolValue\":true,\"name\":\"billable\"},{\"name\":\"doc_id\",\"value\":\"XXXXXXXF80yY96EvBbrLM2gRPjtYm-bb4\"},{\"name\":\"doc_type\",\"value\":\"unknown\"},{\"name\":\"doc_title\",\"value\":\"elastic.repo\"},{\"name\":\"visibility\",\"value\":\"private\"},{\"boolValue\":false,\"name\":\"actor_is_collaborator_account\"},{\"name\":\"owner\",\"value\":\"xxxxxx@xxxxxxxx.com\"},{\"boolValue\":false,\"name\":\"owner_is_shared_drive\"},{\"boolValue\":false,\"name\":\"owner_is_team_drive\"}],\"type\":\"access\"},\"id\":{\"applicationName\":\"drive\",\"customerId\":\"C02h1tm9p\",\"time\":\"2020-09-25T14:48:09.916Z\",\"uniqueQualifier\":\"2898828301120224173\"},\"ipAddress\":\"xxx.xxx.4.212\",\"kind\":\"admin#reports#activity\"}",
"provider": "drive",
"created": "2020-09-25T14:55:08.597Z",
"module": "gsuite",
"action": "download",
"id": "2898828301120224173",
"category": [
"file"
],
"type": [
"info"
],
"dataset": "gsuite.drive"
},
"gsuite": {
"kind": "admin#reports#activity",
"event": {
"type": "access"
},
"drive": {
"actor_is_collaborator_account": false,
"file": {
"owner": {
"email": "xxxxxx@xxxxxxxx.com",
"is_shared_drive": false
},
"id": "xxxxxxF80yY96EvBbrLM2gRPjtYm-bb4",
"type": "unknown"
},
"visibility": "private",
"primary_event": true,
"owner_is_team_drive": false,
"billable": true
}
}
},
"fields": {
"event.ingested": [
"2020-09-25T14:55:10.621Z"
],
"@timestamp": [
"2020-09-25T14:48:09.916Z"
],
"event.created": [
"2020-09-25T14:55:08.597Z"
],
"suricata.eve.timestamp": [
"2020-09-25T14:48:09.916Z"
]
}
}
まとめ
長文の記事となってしまいましたが、いかがでしたでしょうか?
これまでは、PythonやPHP、Goなどでライブラリを使って、APIを叩いていたReport APIですが
Filebeat Modulesを利用することで比較的簡単且つリアルタイム性のある監査や監視ができるようになりました。
共同プロジェクトのため、社外にも公開しているGoogleドライブ内の大事なドキュメントが
許可していないIPアドレスから不正にダウンロードされていることを監視することは非常に重要なことです。
今回取り込んだログにおいて、以下の項目を監視に利用することで速やかに不正を検知することができます。
・いつ: @timestampフィールド
・誰が: source.user.emailフィールド
・何を: file.nameフィールド
・どこから: source.ipフィールド
・ダウンロードしたのか: event.actionフィールドがdownload

リモートワークが続き、送信元IPアドレスが会社の固定IPで特定できないケースが増えています。
その場合、source.as.organization.nameフィールドのISP名を利用することができます。
従業員のご自宅で契約しているISPと異なる場合、不正なログインである可能性があるかもしれません。
ドライブの監査ログの保持期間は、6ヶ月です。
年間の利用傾向を見たい場合には、今回のような仕組みが必要になります。
無償の範囲で簡単に試すことができますので、ぜひ試してみてください!!
