SalesforceのイベントモニタリングのログをGCSに定期的にアップロードするスクリプト

# はじめに

今回は[Salesforce Shield](https://www.salesforce.com/jp/products/platform/products/shield/)のイベントモニタリングのログを定期的にGCSにアップロードを行うためのスクリプトとGitHub Actionsを書きます。

# イベントモニタリングの注意点

:::note alert
定期的にログファイルが保存されるが

- ログファイルが格納されるまで最大24時間かかる
- サーバー上での保管期間は30日
:::

以上のことから、
30日以上のログを遡ることがいつでもできるように
定期的に1日分のログをアップロードしておく必要があります。

https://help.salesforce.com/s/articleView?id=000396295&type=1

# イベントモニタリングとは

>イベントモニタリングにより、誰が、いつ、どこから、重要なビジネスデータにアクセスしているかを確認できます。
チェックマーク
重要なイベントをリアルタイムで、またはログファイルを使い監視
チェックマーク
トランザクションセキュリティポリシーでデータ漏えいを防止
チェックマーク
内部脅威の検知および異常の報告
チェックマーク
ユーザーの行動を監査し、カスタムアプリケーションのパフォーマンスを測定
![event-monitoring-application-lifecyle-management.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445600/52617000-48f1-c82d-8ceb-bd36ed2b9f61.jpeg)

## 参考記事

- [Salesforceのイベントモニタリングを使ってみた](https://dev.classmethod.jp/articles/salesforce_eventmonitoring/)

- [イベントモニタリングのログデータを出力する](https://qiita.com/TaaaZyyy/items/e0270ca2976a7110b0a1)
- 公式ヘルプ
  - [イベントモニタリングログファイルにアクセスしてダウンロードする方法](https://help.salesforce.com/s/articleView?id=000390089&type=1)

# 取得できるイベント

[サポートされてるイベント種別](https://developer.salesforce.com/docs/atlas.ja-jp.242.0.object_reference.meta/object_reference/sforce_api_objects_eventlogfile_supportedeventtypes.htm)にあるイベントがログファイルとして蓄積できるようになります。

これは取れるのかな？といろんな人が気になりそうな部分を以下に列挙しました。

- ダウンロード系
  -  [コンテンツ転送イベント種別](https://developer.salesforce.com/docs/atlas.ja-jp.242.0.object_reference.meta/object_reference/sforce_api_objects_eventlogfile_contenttransfer.htm)
  -  [ドキュメント添付ファイルのダウンロードイベント種別](https://developer.salesforce.com/docs/atlas.ja-jp.242.0.object_reference.meta/object_reference/sforce_api_objects_eventlogfile_documentattach.htm)
  - [レポートのエクスポートイベント種別](https://developer.salesforce.com/docs/atlas.ja-jp.242.0.object_reference.meta/object_reference/sforce_api_objects_eventlogfile_reportexport.htm)
- 閲覧系
  - [Lightning ページビューイベント種別](https://developer.salesforce.com/docs/atlas.ja-jp.242.0.object_reference.meta/object_reference/sforce_api_objects_eventlogfile_lightningpageview.htm)
  - [検索イベント種別](https://developer.salesforce.com/docs/atlas.ja-jp.242.0.object_reference.meta/object_reference/sforce_api_objects_eventlogfile_search.htm)

- ログイン履歴
  - [ログインイベント種別](https://developer.salesforce.com/docs/atlas.ja-jp.242.0.object_reference.meta/object_reference/sforce_api_objects_eventlogfile_login.htm)
 - API実行系
   - [SOAP API イベント種別](https://developer.salesforce.com/docs/atlas.ja-jp.242.0.object_reference.meta/object_reference/sforce_api_objects_eventlogfile_api.htm)
   - [REST API イベント種別](https://developer.salesforce.com/docs/atlas.ja-jp.242.0.object_reference.meta/object_reference/sforce_api_objects_eventlogfile_restapi.htm)
   - [メタデータ API 操作イベント種別](https://developer.salesforce.com/docs/atlas.ja-jp.242.0.object_reference.meta/object_reference/sforce_api_objects_eventlogfile_supportedeventtypes.htm)

# 詳しく書かないこと

- 接続アプリケーションの作成
- GCS周辺
- サービスアカウントの設定

# 事前準備

## 1. 接続アプリケーションの作成

以下の記事を参考にしました。
クライアントログイン情報フローを使用しています。

https://qiita.com/shunkosa/items/ec5fab901401c364ee7a

![スクリーンショット 2023-12-22 1.01.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445600/d077a66a-34ff-0e2d-fae7-8a9a6e9fcd78.png)

## 2. GCSの準備

ストレージクラスについてはご自身の利用頻度によって決めてください。
ライフサイクルを決めてストレージクラスを変更するようにするとか、[Autoclass](https://cloud.google.com/storage/docs/autoclass?hl=ja)を使うようにするといいかもですね。

https://cloud.google.com/storage/docs/creating-buckets?hl=ja

## 3. GCSにアクセス可能なサービスアカウントのJSONキーを取得

https://cloud.google.com/iam/docs/creating-managing-service-account-keys?hl=ja


# ログファイルのダウンロード

以下のスクリプトを参考に作成させていただきました。

https://github.com/atorman/elfBash/blob/master/elfCLI_mac.sh

イベントログ自体は、EventLogFileオブジェクトにデータが入っています。

処理の流れは以下の通りです。

- 1\. `クライアントログイン情報フロー`で認証
- 2\. SOQLで`EventLogFile`からダウンロードするログファイルの情報を取得
- 3\. ファイルダウンロード


`BASE_URL="https://{組織のドメイン}.my.salesforce.com"`にはイベントモニタリング対象のSalesforce組織のドメインを入れてください。

```shell:get_event_logs.sh
#!/bin/bash

API_VERSION=${API_VERSION:-v59.0}

if [ -z "$CLIENT_ID" ]; then
  echo "コンシューマーキーを設定してください。"
  exit 1
fi

if [ -z "$CLIENT_SECRET" ]; then
  echo "コンシューマーキーの秘密鍵を設定してください。"
  exit 1
fi

BASE_URL="https://{組織のドメイン}.my.salesforce.com"

# 1. 認証
ACCESS_TOKEN=$(curl -X POST "${BASE_URL}/services/oauth2/token" \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode "client_id=${CLIENT_ID}" \
--data-urlencode "client_secret=${CLIENT_SECRET}" | jq '.access_token')
ACCESS_TOKEN="${ACCESS_TOKEN//\"}"

# 2. ログファイルの一覧を取得
TARGET_DAY=${TARGET_DAY:-Yesterday} # ログファイル生成日
INTERVAL=${INTERVAL:-'Daily'}
WHERE="WHERE+CreatedDate+=+${TARGET_DAY}+AND+Interval='${INTERVAL}'"

logs=$(curl ${BASE_URL}/services/data/${API_VERSION}/query?q=SELECT+Id+,+EventType+,+LogDate+,+LogFile+From+EventLogFile+${WHERE} -H "Authorization: Bearer ${ACCESS_TOKEN}" -H "X-PrettyPrint:1" -H "Content-Type: application/json")
logFiles=($(echo ${logs} | jq -r ".records[].LogFile"))
eventTypes=( $(echo ${logs} | jq -r ".records[].EventType") )
logDates=( $(echo ${logs} | jq -r ".records[].LogDate" | sed 's/'T.*'//' ) ) # イベント発生日

# 3. ログファイルのダウンロード
for i in "${!logFiles[@]}"; do   
    echo "${i}: ${logFiles[$i]}"
    echo "${i}: ${eventTypes[$i]}"
    echo "${i}: ${logDates[$i]}"
    mkdir "./logs/${eventTypes[$i]}"

    curl --compressed "${BASE_URL}${logFiles[$i]}" -H "Authorization: Bearer ${ACCESS_TOKEN}" -H "X-PrettyPrint:1" -o "./logs/${eventTypes[$i]}/${logDates[$i]}.csv"
done
```

## 実行

```bash
export CLIENT_ID={接続アプリケーションのコンシューマー鍵}
export CLIENT_SECRET={接続アプリケーションのコンシューマーの秘密鍵}
./get_event_logs.sh
```

実行すると `logs/イベント名/`に1日単位のCSVでログファイルがダウンロードされます。

![スクリーンショット 2023-12-22 1.23.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445600/4e8f1c0e-861a-5372-2026-a5c87c18b656.png)

# GitHub ActionsでGCSに定期アップロード

scheduleで作ったスクリプトを定期実行させます。

## GitHub にシークレットを保存

https://docs.github.com/ja/actions/security-guides/using-secrets-in-github-actions

|環境変数名|値|
|---|---|
|CLIENT_ID| 接続アプリケーションのコンシューマー鍵 |
|CLIENT_SECRET| 接続アプリケーションのコンシューマーの秘密鍵 |
|GCP_CREDENTIALS| GCSにアクセスできるサービスアカウントのJSON鍵 |


## GitHub Actions

```yml: .github/workflows/log-to-gcs.yml
name: log-to-gcs

on:
  schedule:
    - cron: "0 0 * * *" # JST 9:00 に前日に生成されたイベントログファイルをGCSにアップロードする
  workflow_dispatch:

env:
  CLIENT_ID: ${{ secrets.CLIENT_ID }}
  CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }}

jobs:
  upload_file_gcs:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: 'google-github-actions/auth@v1'
        with:
          credentials_json: ${{ secrets.GCP_CREDENTIALS }}
      - name: make logs dir
        run: mkdir logs
      - name: get logs
        run: ./get_event_logs.sh
      - name: upload-gcs
        uses: google-github-actions/upload-cloud-storage@v2
        with:
          path: ./logs
          destination: salesforce-logs
          parent: false

```

## 実行結果


イベントごとに1日のログファイルをアップロードできました。

![スクリーンショット 2023-12-22 1.35.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445600/af137a13-4f5c-a457-880c-be49f1765522.png)

![スクリーンショット 2023-12-22 1.35.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445600/56ae1b56-3a50-a209-1758-8876517e2f0a.png)

# 最後に

イベントログファイルですが、セキュリティ面にも利用できますが
作ったレポートやリストビューが見られているかどうかのチェックにも利用できます。
積極的に利用していきましょう。

結構簡単に`デフォルトの保持期間30日問題`を解決できるので、対策したかったけど
できていなかったみたいな人の役に立つ記事になっていると嬉しいです。
ありがとうございました。