Microsoft SentinelをIaCで運用する(Azure Bicep + GitHub Actions)
こんにちは!松岡です。
みなさんはMicrosoft Sentinelをどのように運用していますか?
SentinelはGUIが充実しており、ほとんどの操作をポータル上で実行できます。GUIによる操作はわかりやすい一方で、差分の追跡、レビュー、再現性の確保には設計書への反映や手作業に頼らざるを得ず、ミスが生じやすいという側面があります。今回はAzure BicepとGitHub Actionsを用いて、検知ルールをIaCで管理する方法を検証します。リポジトリにルール定義(Bicep / KQL)を置き、プッシュをトリガーに Lint → Validate → What‑If → Deploy の流れで検知ルールをSentinelに反映します。
<関連記事>
突き抜けた知的好奇心を武器に学びを深め、会社全体へ還元していく(松岡)
全体像
目的
GitHubのリポジトリで検知ルールをコードとして管理し、main へのプッシュをトリガーにGitHub Actionsで Lint / Validate / What‑If / Deployを順に実行して、Microsoft Sentinelへ安全に反映します。
処理フロー
queries/*.kql・detections/*.bicepを編集してプッシュ- GitHub Actionsが起動し、OIDCでAzureにログイン
- Lint:Bicepの構文・アナライザーで不整合を検出
- Validate:デプロイ前検証(型・参照・権限など)
- What‑If:実環境との差分を表示(意図しない変更の検知)
- 問題がなければデプロイを実行
- Sentinelの検知ルールが更新
リポジトリ構成例
.
├─ infra/
│ ├─ main.bicep
│ └─ modules/
│ └─ scheduledRule.bicep
├─ detections/
│ ├─ signins-mfa-fail.bicep
│ ├─ azureactivity-delete-spike.bicep
│ └─ auditlogs-priv-role-add.bicep
├─ queries/
│ ├─ signins_mfa_fail.kql
│ ├─ azureactivity_delete_spike.kql
│ └─ auditlogs_priv_role_add.kql
├─ env/
│ └─ dev.bicepparam
└─ .github/workflows/
└─ deploy-sentinel-dev.yml
queries/*.kql:KQLクエリ本体detections/*.bicep:クエリを読み込み、検知ルールをインスタンス化infra/modules/*.bicep:再利用可能なモジュールinfra/main.bicep:ルートのエントリーポイント(複数ルールを束ねてデプロイ)env/*.bicepparam:環境ごとのパラメーター.github/workflows/*.yml:GitHub Actionsの定義
検知ルールのサンプル
クエリは queries/*.kql に記述し、ルールは detections/*.bicep で読み込みます。
サインインの MFA 失敗が急増
// queries/signins_mfa_fail.kql
SigninLogs
| where ResultType == "500121"
| summarize Count = count() by UserPrincipalName, IPAddress, bin(TimeGenerated, 1h)
| where Count > 5// detections/signins-mfa-fail.bicep
param workspaceName string
module rule '../infra/modules/scheduledRule.bicep' = {
name: 'scheduled-signins-mfa-fail'
params: {
workspaceName: workspaceName
ruleStableKey: 'signins-mfa-fail'
displayName: 'Sign-in MFA failure spike'
severity: 'Medium'
query: loadTextContent('../queries/signins_mfa_fail.kql')
queryFrequency: 'PT1H'
queryPeriod: 'PT1H'
triggerOperator: 'GreaterThan'
triggerThreshold: 0
tactics: [
'CredentialAccess'
]
entityMappings: [
{
entityType: 'Account'
fieldMappings: [
{ identifier: 'FullName', columnName: 'UserPrincipalName' }
]
}
{
entityType: 'IP'
fieldMappings: [
{ identifier: 'Address', columnName: 'IPAddress' }
]
}
]
}
}
main.bicepとbicepparamの設定
GitHub Actions の流れ
最初のジョブでOIDCによるAzureログイン、Lint / Validate / What‑Ifを実施して不備や意図しない差分を検出し、続くジョブでcreate(デプロイ / 更新)を行います。
# .github/workflows/deploy-sentinel-dev.yml
name: Deploy Microsoft Sentinel (dev)
on:
push:
branches: [ main ]
paths:
- 'infra/**'
- 'detections/**'
- 'queries/**'
- 'env/dev.bicepparam'
- '.github/workflows/deploy-sentinel-dev.yml'
workflow_dispatch:
permissions:
id-token: write
contents: read
env:
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
RESOURCE_GROUP: rg-iac-sentinel-dev
DEPLOYMENT_NAME: sentinel-dev-${{ github.run_number }}
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Azure Login (OIDC)
uses: azure/login@v2
with:
client-id: ${{ env.AZURE_CLIENT_ID }}
tenant-id: ${{ env.AZURE_TENANT_ID }}
subscription-id: ${{ env.AZURE_SUBSCRIPTION_ID }}
- name: Install Bicep CLI
run: az bicep install
- name: Lint (bicep build + analyzers)
run: az bicep build --file infra/main.bicep
- name: Validate
uses: azure/bicep-deploy@v2
with:
type: deployment
operation: validate
scope: resourceGroup
subscription-id: ${{ env.AZURE_SUBSCRIPTION_ID }}
resource-group-name: ${{ env.RESOURCE_GROUP }}
template-file: infra/main.bicep
parameters-file: env/dev.bicepparam
- name: What-If
uses: azure/bicep-deploy@v2
with:
type: deployment
operation: whatIf
scope: resourceGroup
subscription-id: ${{ env.AZURE_SUBSCRIPTION_ID }}
resource-group-name: ${{ env.RESOURCE_GROUP }}
template-file: infra/main.bicep
parameters-file: env/dev.bicepparam
what-if-exclude-change-types: 'Ignore'
deploy:
needs: validate
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Azure Login (OIDC)
uses: azure/login@v2
with:
client-id: ${{ env.AZURE_CLIENT_ID }}
tenant-id: ${{ env.AZURE_TENANT_ID }}
subscription-id: ${{ env.AZURE_SUBSCRIPTION_ID }}
- name: Deploy (create/update)
uses: azure/bicep-deploy@v2
with:
type: deployment
operation: create
scope: resourceGroup
subscription-id: ${{ env.AZURE_SUBSCRIPTION_ID }}
resource-group-name: ${{ env.RESOURCE_GROUP }}
name: ${{ env.DEPLOYMENT_NAME }}
template-file: infra/main.bicep
parameters-file: env/dev.bicepparam
結果
上記設定で GitHub にプッシュするとフローが実行され、正常に Sentinel 上に分析ルールが反映されます。
今回の検証を通じ、BicepとGitHub ActionsによるIaC化により、変更点をコードとして追跡しやすくし、What‑Ifで差分を事前に確認したうえで安心して反映できることがわかりました。また、実際に検証環境を作成してみて、設定項目が多く、初期整備とレビューの負荷が増えやすいという点も感じました。
GUIと比べると、テンプレートやパイプラインの保守、エラー時の切り戻し、環境ごとのパラメーター管理、権限・スコープ設計など、技術的な運用・保守のハードルは上がります。検知ルールの更新頻度が高くない場合は、IaC導入コストがメリットを上回ることも十分考えられます。
SIEMの検知は継続的に改善・更新されるため、コード化して差分をレビューしながら安全に反映できるメリットは大きいです。一方で、IaCによってコードのメンテナンス負荷が増える側面もあります。
今回は、GitHub ActionsとAzure Bicepを使ってMicrosoft Sentinelの検知ルールをIaC化する方法を紹介しました。