はじめに
Microsoft Sentinel のデモや POC で「オンプレのネットワーク機器やアプリのログを取り込むとどう見えるか」を見せたい場面はよくあります。本記事では、Azure 上に次の 2 つのログ収集方式を同じ Log Analytics ワークスペースへ取り込む環境を、コマンドをコピー&ペーストするだけで構築できるようにまとめました。
(注) 個人の学習用のメモになります。内容の確実性を保証するものではありません。
| 方式 | 仕組み | 格納先テーブル |
|---|---|---|
| Syslog 収集 | Linux フォワーダー(rsyslog)+ Azure Monitor Agent(AMA)、Syslog via AMA / CEF via AMA コネクタ |
Syslog / CommonSecurityLog
|
| Logstash 収集 | Logstash + Microsoft Sentinel 出力プラグイン、Logs Ingestion API(DCR ベース) |
LogstashDemo_CL(カスタム) |
本記事は POC・デモ用途の手順です。冗長化(VMSS + ロードバランサー)、TLS による Syslog の暗号化、Azure Arc によるオンプレミス サーバーの接続、詳細なサイジングは扱いません。
本記事のコマンドの使い方
- コードブロックの見出し(例:
Cloud Shell、vm-syslog-fwd)は どこで実行するか を表しています。 - プロンプト記号(
$)は付けていないので、ブロックをそのまま貼り付けて実行できます。 - 値を自分の環境に合わせて変えるのは 「0. 変数の定義」だけ です。以降のコマンドはこの変数を参照します。
- VM 側で必要になる値(DCE の URI など)は、Cloud Shell で 貼り付け用のコマンドを生成 してから VM に貼る形にしています。手で書き写す必要はありません。
全体構成
作成するリソース
| 区分 | 名前(既定値) | 用途 | 設定 |
|---|---|---|---|
| リソースグループ | rg-sentinel-poc | 一式の格納 | japaneast |
| Log Analytics | law-sentinel-poc | ログ格納・Sentinel 基盤 | 保持 30 日 |
| VNet | vnet-sentinel-poc | 検証用ネットワーク | 10.10.0.0/16 |
| サブネット | snet-collector | フォワーダー・Logstash | 10.10.1.0/24 |
| サブネット | snet-source | ログ送信元 | 10.10.2.0/24 |
| NAT Gateway | natgw-sentinel-poc | VM のアウトバウンド通信 | Standard パブリック IP |
| VM | vm-syslog-fwd | Syslog フォワーダー | Ubuntu 22.04 / Standard_B2s |
| VM | vm-logstash | Logstash | Ubuntu 22.04 / Standard_B2ms / システム割り当てマネージド ID |
| VM | vm-logsource | ログ送信元の模擬 | Ubuntu 22.04 / Standard_B1ms |
| DCR | dcr-syslog-demo / dcr-cef-demo | Syslog・CEF 収集 | Sentinel コネクタから作成 |
| DCE | dce-sentinel-poc | Logs Ingestion API の受付 | japaneast |
| DCR | dcr-logstash-demo | Logstash 用 | テーブル作成ウィザードで作成 |
通信要件
| 送信元 | 宛先 | ポート | 用途 |
|---|---|---|---|
| vm-logsource | vm-syslog-fwd | TCP/UDP 514 | Syslog・CEF |
| vm-logsource | vm-logstash | TCP 5000 | JSON ログ |
| vm-syslog-fwd | Azure Monitor | HTTPS 443 | AMA による送信 |
| vm-logstash | DCE(*.ingest.monitor.azure.com)、Microsoft Entra ID |
HTTPS 443 | Logs Ingestion API |
同一 VNet 内の通信は既定の NSG ルール(AllowVnetInBound)で許可されるため、POC では受信規則の追加は不要です。
前提条件
- Azure サブスクリプションと、リソースグループに対する 所有者(Owner) 権限
- DCR へのロール割り当てを行うため、共同作成者のみの場合は「ユーザー アクセス管理者」も必要です。
- Microsoft Sentinel 共同作成者、Log Analytics 共同作成者、監視共同作成者 相当の権限
- Azure Cloud Shell(Bash)を使える環境
Microsoft Sentinel は Microsoft Defender ポータルでの利用が推奨されています。本記事のポータル操作は Azure ポータルの画面名で書いていますが、Defender ポータルでも同等のメニュー(Microsoft Sentinel > 構成 > データ コネクタ など)から実施できます。
0. 変数の定義
Azure ポータル右上から Cloud Shell(Bash) を開き、次のブロックを貼り付けます。名前を変えたい場合はここだけ編集してください。
RG=rg-sentinel-poc
LOC=japaneast
LAW=law-sentinel-poc
VNET=vnet-sentinel-poc
NATGW=natgw-sentinel-poc
DCE=dce-sentinel-poc
DCR_LOGSTASH=dcr-logstash-demo
ADMIN=azureuser
az account show --query "{name:name, id:id}" -o table
Cloud Shell はしばらく操作しないとセッションが切れ、変数が消えます。途中で切れた場合は、このブロックをもう一度貼り付けてから続きを実行してください。
1. 共通基盤の構築
1-1. リソースグループと Log Analytics ワークスペース
az group create -n "$RG" -l "$LOC"
az monitor log-analytics workspace create -g "$RG" -n "$LAW" -l "$LOC" --retention-time 30
1-2. Microsoft Sentinel の有効化
- Azure ポータルで Microsoft Sentinel を開き、+作成 を選択します。
-
law-sentinel-pocを選択して 追加 をクリックします。 - (推奨)Defender ポータル(security.microsoft.com)の システム > 設定 > Microsoft Sentinel からワークスペースを接続します。
1-3. ネットワーク(VNet・サブネット・NAT Gateway)
VM にはパブリック IP を付けず、アウトバウンド通信は NAT Gateway 経由にします。
az network vnet create -g "$RG" -n "$VNET" --address-prefix 10.10.0.0/16 \
--subnet-name snet-collector --subnet-prefixes 10.10.1.0/24
az network vnet subnet create -g "$RG" --vnet-name "$VNET" -n snet-source \
--address-prefixes 10.10.2.0/24
az network public-ip create -g "$RG" -n "pip-$NATGW" --sku Standard
az network nat gateway create -g "$RG" -n "$NATGW" --public-ip-addresses "pip-$NATGW"
az network vnet subnet update -g "$RG" --vnet-name "$VNET" -n snet-collector --nat-gateway "$NATGW"
az network vnet subnet update -g "$RG" --vnet-name "$VNET" -n snet-source --nat-gateway "$NATGW"
1-4. 仮想マシン 3 台
az vm create -g "$RG" -n vm-syslog-fwd --image Ubuntu2204 --size Standard_B2s \
--vnet-name "$VNET" --subnet snet-collector --private-ip-address 10.10.1.4 \
--public-ip-address "" --nsg-rule NONE \
--admin-username "$ADMIN" --generate-ssh-keys
az vm create -g "$RG" -n vm-logstash --image Ubuntu2204 --size Standard_B2ms \
--vnet-name "$VNET" --subnet snet-collector --private-ip-address 10.10.1.5 \
--public-ip-address "" --nsg-rule NONE --assign-identity \
--admin-username "$ADMIN" --generate-ssh-keys
az vm create -g "$RG" -n vm-logsource --image Ubuntu2204 --size Standard_B1ms \
--vnet-name "$VNET" --subnet snet-source --private-ip-address 10.10.2.4 \
--public-ip-address "" --nsg-rule NONE \
--admin-username "$ADMIN" --generate-ssh-keys
SSH 秘密鍵は Cloud Shell の ~/.ssh/id_rsa に作成されます。Bastion 接続で使うので、次のコマンドで中身を表示し、作業端末にファイル(例:id_rsa)として保存しておきます。
cat ~/.ssh/id_rsa
1-5. Azure Bastion で VM に接続
- Azure ポータルで対象 VM を開き、接続 > Bastion を選択します。
- 対応リージョンであれば Developer SKU(追加サブネット不要)を利用できます。Basic 以上を使う場合は、VNet に
AzureBastionSubnet(/26 以上)を作成してからデプロイします。 - 認証の種類に ローカル ファイルからの SSH 秘密キー を選び、ユーザー名
azureuserと保存した秘密鍵で接続します。
コスト削減のため、各 VM の 操作 > 自動シャットダウン を設定しておくのがおすすめです。
2. Syslog 収集環境(Azure Monitor Agent)
Syslog via AMA / CEF via AMA コネクタは、フォワーダー上の rsyslog で受信したメッセージを AMA が DCR に従って Log Analytics に転送する方式です。DCR を作成して VM を関連付けると、AMA は自動でインストールされます。
2-1. コンテンツ ハブからソリューションをインストール
- Microsoft Sentinel > コンテンツ管理 > コンテンツ ハブ を開きます。
- Syslog を検索してインストールします。
- CEF もデモする場合は Common Event Format もインストールします。
2-2. Syslog 用 DCR(Syslog via AMA)
- データ コネクタ で Syslog via AMA を開き、+データ収集ルールの作成 を選択します。
- ルール名
dcr-syslog-demo、リソースグループrg-sentinel-pocを指定します。 -
リソース タブで
vm-syslog-fwdを選択します。 - 収集 タブを次のように設定して作成します。
| ファシリティ | 最小ログレベル | 備考 |
|---|---|---|
| LOG_AUTH / LOG_AUTHPRIV | LOG_INFO | SSH 認証失敗のデモ用 |
| LOG_DAEMON / LOG_SYSLOG / LOG_USER | LOG_WARNING | 一般的なシステムログ |
| LOG_LOCAL0 | LOG_INFO | 機器ログ想定(任意) |
| LOG_LOCAL4 | none(収集しない) | CEF 用に予約 |
2-3. CEF 用 DCR(任意:CEF via AMA)
- Common Event Format (CEF) via AMA を開き、+データ収集ルールの作成 を選択します。
- ルール名
dcr-cef-demo、リソースにvm-syslog-fwdを指定します。 - 収集 タブで LOG_LOCAL4 のみ 最小ログレベル LOG_WARNING とし、その他は none にします。
Syslog 用と CEF 用の DCR で同じファシリティを収集すると、同じメッセージが Syslog と CommonSecurityLog の両方に入り、取り込み量が重複します。本記事では CEF を LOCAL4 に分けています。
AMA がインストールされたかは Cloud Shell で確認できます(数分かかります)。
az vm extension list -g "$RG" --vm-name vm-syslog-fwd --query "[].{name:name, state:provisioningState}" -o table
AzureMonitorLinuxAgent が Succeeded になれば OK です。
2-4. フォワーダーの構成
Bastion で vm-syslog-fwd に接続し、Microsoft 提供のスクリプトを実行します。rsyslog が TCP/UDP 514 で受信するよう構成されます。
cd ~
wget -O Forwarder_AMA_installer.py https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/DataConnectors/Syslog/Forwarder_AMA_installer.py
sudo python3 Forwarder_AMA_installer.py
待ち受けと AMA の状態を確認します。
sudo ss -lntup | grep ':514'
systemctl status azuremonitoragent --no-pager
2-5. 送信元の構成
Bastion で vm-logsource に接続し、すべての Syslog を TCP でフォワーダーに転送するよう設定します(@@ は TCP、@ は UDP)。
echo '*.* @@10.10.1.4:514' | sudo tee /etc/rsyslog.d/90-forward-to-collector.conf
sudo systemctl restart rsyslog
2-6. テストログの送信
SSH ブルートフォースを模したメッセージを 6 件と、CEF メッセージを 1 件送ります。
for i in $(seq 1 6); do
logger -p auth.warning -t sshd "Failed password for invalid user demo from 10.10.2.4 port 5000$i ssh2"
done
logger -n 10.10.1.4 -P 514 -T -p local4.warning -t CEF "CEF:0|Contoso|DemoFirewall|1.0|100|Port scan detected|7|src=10.10.2.4 dst=10.10.1.4 spt=51515 dpt=22 act=blocked"
フォワーダー側で受信を確認したい場合は次を実行し、送信元でもう一度上のコマンドを流します(Ctrl + C で終了)。
sudo tcpdump -i any port 514 -A -c 5
2-7. 取り込みの確認
DCR 作成直後は、最初のデータが表示されるまで 20 分程度かかることがあります。Microsoft Sentinel > ログ(Defender ポータルでは 高度な検索)で実行します。
Syslog
| where TimeGenerated > ago(30m)
| summarize Count = count() by Computer, Facility, SeverityLevel
CommonSecurityLog
| where TimeGenerated > ago(30m)
| project TimeGenerated, DeviceVendor, DeviceProduct, Activity, SourceIP, DestinationIP, DestinationPort, DeviceAction
3. Logstash 収集環境(Logs Ingestion API)
Microsoft Sentinel 用 Logstash 出力プラグイン(microsoft-sentinel-log-analytics-logstash-output-plugin)は、Logs Ingestion API(DCR ベース)で任意のログをカスタムテーブルや標準テーブルに送信します。本記事では VM のシステム割り当てマネージド ID で認証し、クライアント シークレットを VM に置かない構成にします。
プラグインが対応する Logstash のバージョンはリリースごとに更新されます。導入前に、プラグインの README(RubyGems または GitHub の Azure-Sentinel リポジトリ)で対応バージョンを確認してください。本記事では対応一覧にある 9.4.0 を例にしています。
3-1. Logstash のインストール
Bastion で vm-logstash に接続して実行します。
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg --dearmor --yes -o /usr/share/keyrings/elastic-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/elastic-keyring.gpg] https://artifacts.elastic.co/packages/9.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-9.x.list
sudo apt-get update
sudo apt-get install -y apt-transport-https logstash=1:9.4.0-1
sudo apt-mark hold logstash
logstash=1:9.4.0-1 が見つからないと言われた場合は、apt-cache madison logstash で利用可能なバージョンを確認し、プラグインの対応一覧にあるものを指定してください。
検証したタイミングでは、レポジトリ経由で9.4.0は選択できませんでした。とりあえず最新のものを選択して、PluginをインストールすることができたのでFYIとさせてください。
https://www.elastic.co/docs/release-notes/logstash
プラグインの推奨に従い、ECS 互換モードを無効化します。
echo "pipeline.ecs_compatibility: disabled" | sudo tee -a /etc/logstash/logstash.yml
3-2. 出力プラグインのインストール
sudo /usr/share/logstash/bin/logstash-plugin install microsoft-sentinel-log-analytics-logstash-output-plugin
sudo /usr/share/logstash/bin/logstash-plugin list --verbose | grep microsoft
3-3. サンプルファイルの生成
カスタムテーブルのスキーマを定義するため、プラグインの サンプル出力機能 で実データと同じ形式の JSON を作ります。プラグインは最大 10 件のイベントを集め、10 件そろった時点(または Logstash の正常終了時)にファイルを出力します。
sudo install -d -o logstash -g logstash /var/lib/logstash/sample
sudo tee /etc/logstash/conf.d/demo.conf > /dev/null <<'EOF'
input {
tcp {
port => 5000
codec => json_lines
}
}
output {
microsoft-sentinel-log-analytics-logstash-output-plugin {
create_sample_file => true
sample_file_path => "/var/lib/logstash/sample"
}
}
EOF
sudo systemctl enable --now logstash
起動には 1 分ほどかかります。次のコマンドで Pipeline started が出れば準備完了です(Ctrl + C で終了)。
sudo tail -f /var/log/logstash/logstash-plain.log
vm-logsource からデモ用 JSON イベントを 10 件送ります。
for i in $(seq 1 10); do
echo '{"EventType":"LoginFailed","UserName":"alice","SrcIp":"10.10.2.4","App":"demo-web","Severity":"High"}' | nc -q 1 10.10.1.5 5000
done
vm-logstash でファイルを確認し、表示された JSON 全体をコピーして作業端末に sample.json という名前で保存します。
sudo ls -l /var/lib/logstash/sample/
sudo sh -c 'cat /var/lib/logstash/sample/sampleFile*.json'
3-4. データ収集エンドポイント(DCE)の作成
az extension add -n monitor-control-service --upgrade --yes
az monitor data-collection endpoint create -g "$RG" -n "$DCE" -l "$LOC" --public-network-access Enabled
3-5. カスタムテーブルと DCR の作成(ポータル)
- Azure ポータルで
law-sentinel-pocを開き、テーブル > +作成 > 新しいカスタム ログ(DCR ベース) を選択します。 - テーブル名に
LogstashDemoを入力します(実際のテーブル名はLogstashDemo_CL)。 -
新しいデータ収集ルールの作成 で
dcr-logstash-demoを作成し、データ収集エンドポイントにdce-sentinel-pocを選択します。 -
スキーマと変換 で 3-3 の
sample.jsonをアップロードします。 -
TimeGenerated列がないという警告が出たら、変換エディター に次を入力して適用します。
source
| extend TimeGenerated = todatetime(ls_timestamp)
- 作成 をクリックします。
3-6. マネージド ID への権限付与
vm-logstash のマネージド ID に、DCR に対する Monitoring Metrics Publisher ロールを付与します。
PRINCIPAL_ID=$(az vm show -g "$RG" -n vm-logstash --query identity.principalId -o tsv)
DCR_RESOURCE_ID=$(az monitor data-collection rule show -g "$RG" -n "$DCR_LOGSTASH" --query id -o tsv)
az role assignment create \
--assignee-object-id "$PRINCIPAL_ID" \
--assignee-principal-type ServicePrincipal \
--role "Monitoring Metrics Publisher" \
--scope "$DCR_RESOURCE_ID"
ロールの反映には最大 30 分程度かかることがあります。反映前に送信すると 403 エラーになります。
3-7. 接続情報を VM に渡す(貼り付け用コマンドの生成)
Cloud Shell で次を実行すると、vm-logstash にそのまま貼り付けるコマンド が出力されます。
DCE_URI=$(az monitor data-collection endpoint show -g "$RG" -n "$DCE" --query logsIngestion.endpoint -o tsv)
DCR_IMMUTABLE_ID=$(az monitor data-collection rule show -g "$RG" -n "$DCR_LOGSTASH" --query immutableId -o tsv)
STREAM_NAME=$(az monitor data-collection rule show -g "$RG" -n "$DCR_LOGSTASH" --query "keys(streamDeclarations)[0]" -o tsv)
cat <<EOF
===== ここから下を vm-logstash に貼り付け =====
sudo tee /etc/default/logstash > /dev/null <<'EOT'
DCE_URI="${DCE_URI}"
DCR_ID="${DCR_IMMUTABLE_ID}"
STREAM_NAME="${STREAM_NAME}"
EOT
sudo chmod 600 /etc/default/logstash
===== ここまで =====
EOF
出力例:
===== ここから下を vm-logstash に貼り付け =====
sudo tee /etc/default/logstash > /dev/null <<'EOT'
DCE_URI="https://dce-sentinel-poc-xxxx.japaneast-1.ingest.monitor.azure.com"
DCR_ID="dcr-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
STREAM_NAME="Custom-LogstashDemo_CL"
EOT
sudo chmod 600 /etc/default/logstash
===== ここまで =====
罫線の間の行を vm-logstash に貼り付けて実行します。/etc/default/logstash は Logstash の systemd サービスが起動時に読み込む環境変数ファイルなので、パイプライン設定から ${DCE_URI} のように参照できます。
3-8. 出力設定を本番用に切り替え
sudo tee /etc/logstash/conf.d/demo.conf > /dev/null <<'EOF'
input {
tcp {
port => 5000
codec => json_lines
}
}
output {
microsoft-sentinel-log-analytics-logstash-output-plugin {
data_collection_endpoint => "${DCE_URI}"
dcr_id => "${DCR_ID}"
stream_name => "${STREAM_NAME}"
}
}
EOF
sudo -u logstash bash -c 'set -a; . /etc/default/logstash; /usr/share/logstash/bin/logstash --path.settings /etc/logstash -t'
sudo systemctl restart logstash
Configuration OK と表示されれば構文は正しいです。client_id / client_secret / tenant_id を指定しない場合、プラグインは VM のマネージド ID を自動で使います。
マネージド ID を使えない環境(オンプレミスの Logstash など)では、アプリ登録を作成して client_id、client_secret、tenant_id を出力設定に追加します。その場合、値は Logstash キーストアに保存し、設定ファイルに平文で書かないようにしてください。
3-9. テスト送信と取り込みの確認
vm-logsource から 3-3 と同じコマンドで 10 件送ります。
for i in $(seq 1 10); do
echo '{"EventType":"LoginFailed","UserName":"alice","SrcIp":"10.10.2.4","App":"demo-web","Severity":"High"}' | nc -q 1 10.10.1.5 5000
done
送信エラーがないかは vm-logstash のログで確認できます。
sudo tail -n 50 /var/log/logstash/logstash-plain.log
数分後、ログ画面で確認します。
LogstashDemo_CL
| where TimeGenerated > ago(30m)
| project TimeGenerated, EventType, UserName, SrcIp, App, Severity
4. デモシナリオ
4-1. Syslog:SSH ブルートフォースの検知
Microsoft Sentinel > 分析 > +作成 > スケジュール済みクエリ ルール で登録します。実行間隔 5 分、参照期間 1 時間を目安に、エンティティ マッピングで Host に Computer、IP に SrcIp を割り当てます。
Syslog
| where Facility in ("auth", "authpriv")
| where SyslogMessage has_any ("Failed password", "Invalid user")
| extend SrcIp = extract(@"from (\d{1,3}(?:\.\d{1,3}){3})", 1, SyslogMessage)
| summarize FailedCount = count(), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated) by Computer, SrcIp
| where FailedCount >= 5
4-2. Logstash:アプリのログイン失敗の連続検知
カスタムテーブルのデータも標準テーブルと同じように分析ルールで使えることを示すシナリオです。Account に UserName、IP に SrcIp を割り当てます。
LogstashDemo_CL
| where EventType == "LoginFailed"
| summarize FailedCount = count() by UserName, SrcIp, bin(TimeGenerated, 5m)
| where FailedCount >= 5
4-3. デモの流れ
- vm-logsource からテストログ(2-6、3-9 のコマンド)を送信する
- ログ画面で
Syslog、CommonSecurityLog、LogstashDemo_CLに取り込まれたことを見せる - 分析ルールの次回実行後にインシデントが作成されることを確認し、エンティティや調査グラフを紹介する
- 必要に応じて、ブックや自動化ルール(プレイブック)との連携を紹介する
5. トラブルシューティング
| 事象 | 主な原因 | 確認・対処 |
|---|---|---|
| Syslog テーブルにデータが入らない | DCR の関連付け漏れ、AMA が動いていない、514 番ポートで待ち受けていない | DCR のリソースに vm-syslog-fwd があるか確認。systemctl status azuremonitoragent、sudo ss -lntup | grep ':514' を確認。Azure-Sentinel リポジトリの Sentinel_AMA_troubleshoot.py で診断 |
| 同じログが Syslog と CommonSecurityLog に重複 | Syslog 用と CEF 用 DCR で同じファシリティを収集 | ファシリティを分ける(本記事では CEF を LOCAL4 に限定) |
| VM から外に通信できない | 既定のアウトバウンド アクセスがない | サブネットに NAT Gateway が関連付けられているか確認 |
| Logstash の送信で 403 | ロール未付与・反映待ち、スコープ誤り | DCR スコープで Monitoring Metrics Publisher が付いているか確認し、最大 30 分待つ |
| Logstash の送信で 400 / 404 | ストリーム名、DCR 不変 ID、DCE URI の誤り | 3-7 のコマンドを再実行し、/etc/default/logstash を作り直す |
| サンプルファイルができない | 出力先の権限不足、10 件未満 | 出力先の所有者が logstash か確認し、10 件送るか sudo systemctl stop logstash で正常終了させる |
| Logstash が起動しない | 設定の構文誤り、環境変数ファイルがない | 3-8 の -t による構文チェック、journalctl -u logstash、logstash-plain.log を確認 |
6. 後片付け
POC が終わったらリソースグループごと削除します。Defender ポータルにワークスペースを接続した場合は、先に接続を解除してください。
az group delete -n "$RG" --yes --no-wait
参考
- Ingest syslog and CEF messages to Microsoft Sentinel with the Azure Monitor Agent(Microsoft Learn)
- Forwarder_AMA_installer.py(GitHub Azure/Azure-Sentinel)
- Microsoft Sentinel Logstash 出力プラグイン(GitHub Azure/Azure-Sentinel DataConnectors)
- microsoft-sentinel-log-analytics-logstash-output-plugin(RubyDoc)
- Logstash Secrets Keystore(Elastic)
