Linux サーバーで Entra ID ログを定期取得する
概要
Microsoft Entra ID のログ収集を Linux ホストで行ってみます。Microsoft Entra ID は 有償プランで 最大30日保存、無料プランでは最大7日保存になっています。(Microsoft Entra データリテンション期間) 過去ログを失う前に1年分ぐらいは Linux ホストに蓄積させておこうということでその方法を試してみました。インターフェイス は Microsoft Graph CLI を使ってみます。
やりたいこと
- Mirosoft Entra ID テナントの 監査ログ、サインインログの1年分保存
- Microsoft Graph CLI でログ取得をスクリプト化
- Linux ホストに収集 (cron の定期実行、logrotate で世代保持管理)
今回利用した環境
- Rocky Linux release 9.6 (Blue Onyx)
- Microsoft Graph CLI (version 1.9.0)
サービス プリンシパルの作成
はじめに行うこととして、Microsoft Entra ID に CLI 接続認証用の サービス プリンシパルを作成します。端的に言うと スクリプトの認証用に Microsoft Entra ID に アプリを登録します。「Microsoft Entra アプリを登録し、サービス プリンシパルを作成する」
留意して頂きたいのは ユーザー オブジェクト(ユーザー プリンシパル)を作成し、いわゆるシステム ユーザー というような利用の仕方をせずに、サービス プリンシパル を利用するようにしましょう。ユーザー プリンシパル を利用していると 2FA を強制された際に対話的な認証を要求されてしまうのでスクリプトを自動で動かすというのが難しくなります。また、最近のセキュリティ事情から組織として全ユーザーに 2FA を強制したいが、システム ユーザーが存在するためにそれが叶わない上にアプリケーションを改修・再テストするにもコストと時間がかかってしまう、という壁に直面している場面を私はそれなりに見てきました。(さらに残念なのは、そのシステムユーザーは大概最低限の権限を与えているわけではなく、最も強力な管理者権限を付与されている場合が多いです。)
- Microsoft Entra アプリ登録
- 「証明書とシークレット」
- 新しいクライアント シークレットを作成。
- アプリケーション ID と、クライアント シークレットの値 をメモします。
- 「API のアクセス許可」
- アクセス許可の追加
AuditLog.Read.All
Directory.Read.All
- 管理者の同意を与えます。
- アクセス許可の追加
- 「証明書とシークレット」
コマンドベースで挙動確認
「Microsoft Graph コマンド ライン インターフェイス (CLI) をインストールする」を参考に Microsoft Graph CLI (Linux) をインストールします。私は /usr/local/bin
に配置しました。
$ ls /usr/local/bin/mgc*
/usr/local/bin/mgc /usr/local/bin/mgc.pdb
mgc コマンドが打てることを確認します。(バージョン確認)
$ mgc --version
1.9.0+9dfb3c248538aad7eb3c72736067832a928ca777
mgc login --help
を確認すると、クライアント シークレットを使った認証は コマンド のオプションで渡さずに 環境変数を使うようになっています。(シークレット値の ハード コーティングの阻止?)
環境変数用のファイルを作成
$ cat > ~/.mgc_env << 'EOF'
export PATH=$PATH:/usr/local/bin
export AZURE_TENANT_ID="********-****-****-****-************"
export AZURE_CLIENT_ID="********-****-****-****-************"
export AZURE_CLIENT_SECRET="****************************************"
EOF
$ chmod 600 ~/.mgc_env
環境変数を使って接続します。
$ source ~/.mgc_env
$ mgc login --strategy Environment
監査ログ、サインインログが取得できるか、まずは確認します。
$ mgc audit-logs directory-audits list --top 1 # 監査ログ
$ mgc audit-logs sign-ins list --top 1 # サインインログ
自動化テスト
とりあえずのスクリプトで前日分のログを取得するもの(エラーハンドリングなし)を作成します。
#!/usr/bin/env bash
readonly OUTPUT_DIR="/var/log/entraid"
readonly OUTPUT_FILE_AUDIT="${OUTPUT_DIR}/directory-audits.json"
readonly OUTPUT_FILE_SIGNIN="${OUTPUT_DIR}/sign-ins.json"
readonly YESTERDAY_START=$(date -d 'yesterday' +%Y-%m-%dT00:00:00Z)
readonly YESTERDAY_END=$(date -d 'yesterday' +%Y-%m-%dT23:59:59Z)
function get_directory_audits() {
mgc audit-logs directory-audits list --filter "activityDateTime ge $YESTERDAY_START and activityDateTime le $YESTERDAY_END" --output json >> ${OUTPUT_FILE_AUDIT}
}
function get_sign_ins() {
mgc audit-logs sign-ins list --filter "createdDateTime ge $YESTERDAY_START and createdDateTime le $YESTERDAY_END" --output json >> ${OUTPUT_FILE_SIGNIN}
}
function main() {
source /home/<username>/.mgc_env
mgc login --strategy Environment
get_directory_audits
get_sign_ins
mgc logout
}
main "$@"
unset AZURE_TENANT_ID
unset AZURE_CLIENT_ID
unset AZURE_CLIENT_SECRET
ログ蓄積用ディレクトリの作成。
$ sudo mkdir /var/log/entraid
$ sudo chown <owner>:<group> /var/log/entraid
logrotate の設定。
$ cat /etc/logrotate.d/entraid
/var/log/entraid/*.json {
daily
rotate 365
dateext
dateformat -%Y%m%d
compress
delaycompress
ifempty
missingok
copytruncate
}
cron設定。logorotate を確認すると 00時から~01時の間に実行されるので、これと重ならないように設定します。
$ cat /usr/lib/systemd/system/logrotate.timer
~~
[Timer]
OnCalendar=daily
AccuracySec=1h
~~
$ crontab -l
00 03 * * * /home/<username>/scripts/get-entraid-logs.sh
実行結果確認。中身も大丈夫そう。
$ ls -1tr /var/log/entraid/
directory-audits.json-20250619.gz
sign-ins.json-20250619.gz
directory-audits.json-20250620.gz
sign-ins.json-20250620.gz
directory-audits.json-20250621
sign-ins.json-20250621
directory-audits.json
sign-ins.json
$
$ zcat sign-ins.json*gz | jq -r '.value[] | [.createdDateTime, .userPrincipalName, .appDisplayName, .ipAddress] | @csv'
"2025-06-17T02:28:39Z","someone@example.com","Azure Portal","123.***.***.***"
"2025-06-18T08:48:18Z","someone@example.com","Azure Portal","123.***.***.***"
"2025-06-18T05:19:34Z","someone@example.com","Azure Portal","123.***.***.***"
"2025-06-18T02:33:30Z","someone@example.com","Azure Portal","123.***.***.***"
ここまで確認ができれば、期間や出力フォーマット、エラーハンドリングなどスクリプトを調整していけばよいです。また Microsoft のドキュメントにはデスクトップ環境を持たない Linux ディストリビューション は gnome-keyring 構成するようになっていますので、この辺も考慮し調整してあげればよいと思います。