🔑

サブスクリプション作成・削除を検出して通知する

に公開

はじめに

大規模に Azure 環境を運用している場合、多数のサブスクリプションを管理する必要があります。特に部署ごとに管理を委任しており、自由にサブスクリプションを作成・削除できる場合に全体管理者としてサブスクリプションの把握が難しくなるケースがあります。
そのため、サブスクリプション作成・削除を検出し、通知する仕組みを考えます。

全体の処理の流れ

全体の流れは以下の通りです。

  1. Azure Functions で 以下の PowerShell スクリプトを定期的に実行 (今回の実装では 1 週間に 1 回の想定)

    • マネージド ID で Azure PowerShell を実行しサブスクリプションの一覧を取得
    • 前回の一覧を BLOB ストレージから取得
    • 前回と今回の一覧を比較し、差分ファイルを JSON 形式で作成
    • 上記の一覧と差分の結果を BLOB ストレージに保存
  2. Logic Apps で BLOB ファイル作成をトリガーに差分ファイルを取得し、HTML テーブルに変換してメール送信

Azure Functions で PowerShell スクリプト実行

TimerTriger で関数を作成します。(以下の場合は毎週月曜に 0:00:00 UTC に実行)

function.json
{
  "bindings": [
    {
      "name": "Timer",
      "type": "timerTrigger",
      "direction": "in",
      "schedule": "0 0 0 * * 1"
    }
  ]
}

TimerTriger で実行する PowerShell スクリプトのサンプルは以下です。

powershell script sample
# Input bindings are passed in via param block.
param($Timer)

# モジュールのインポート
Import-Module -Name Az.Accounts
Import-Module -Name Az.Storage

# 本日の日付と一週間前の日付を yyyymmdd 形式で取得
$Today = (Get-Date).ToString("yyyyMMdd")
$LastWeekDay = (Get-Date).AddDays(-7).ToString("yyyyMMdd")

# パラメータを指定
$SubscriptionId = "<subscriptionId of Storage Account>"
$resourceGroup = "myrg"
$StorageAccountName = "mystorage"
$ContainerName = "sbsclist"
$TmpFolder = "_tmp"  # ダウンロード先フォルダ
$SbscListJsonFile = "sbsclist_$Today.json"
$SbscListLastWeekJsonFile = "sbsclist_$LastWeekDay.json"
$SbscDiffJsonFile = "sbscdiff_$Today.txt"  # 後続の Logic Apps で使用するため txt で保存

# 作業フォルダ作成
if (!(Test-Path $TmpFolder)) {
    New-Item -ItemType Directory -Path $TmpFolder | Out-Null
}

### Step 1: 現在のサブスクリプション一覧を取得 ### ### ### ### ###

# Azure にログイン(マネージド ID を使用)
Connect-AzAccount -Identity
# Connect-AzAccount

# サブスクリプションを指定
Set-AzContext -SubscriptionId $SubscriptionId

# サブスクリプション一覧を取得
$SbscList = Get-AzSubscription | Select-Object -Property TenantId, Id, Name, State

# JSON データを出力
$SbscList | ConvertTo-Json -Depth 2 | Set-Content -Path $TmpFolder\$SbscListJsonFile -Encoding UTF8
Write-Host "save $SbscListJsonFile"


### Step 2: 一週間前のサブスクリプション一覧を取得 ### ### ### ###
# ストレージアカウントのキーなしで認証(マネージド ID 使用)
$StorageAccount = Get-AzStorageAccount -ResourceGroupName $resourceGroup -Name $StorageAccountName
$Context = New-AzStorageContext -StorageAccountName $StorageAccount.StorageAccountName -UseConnectedAccount

# 1 週間前の BLOB ファイルをダウンロード
Get-AzStorageBlobContent -Container $ContainerName -Blob $SbscListLastWeekJsonFile -Destination $TmpFolder -Context $Context -Force

# ダウンロードしたファイルをを取得
$SbscListLastWeek = Get-Content -Path $TmpFolder\$SbscListLastWeekJsonFile | ConvertFrom-Json


### Step 3: 差分チェック ### ### ### ### ### ### ### ### ### ###

# 1 週間前のサブスクリプション一覧と現在のサブスクリプション一覧を比較
$SbscDiff = Compare-Object -ReferenceObject $SbscListLastWeek -DifferenceObject $SbscList -Property TenantId, Id, Name, State -PassThru

# SbscDiff が空でない場合
if ($SbscDiff.Count -ne 0) {

    # SideIndicator に従って Action 項目を追加し Add / Remove を追加
    $SbscDiff | ForEach-Object {
        if ($_.SideIndicator -eq "<=") {
            $_ | Add-Member -MemberType NoteProperty -Name Changes -Value "Remove" -Force
        } elseif ($_.SideIndicator -eq "=>") {
            $_ | Add-Member -MemberType NoteProperty -Name Changes -Value "Add" -Force
        }
    }

    # SideIndicator を除外
    $SbscDiff = $SbscDiff | Select-Object -Property TenantId, Id, Name, State, Changes

    # JSON に変換
    $SbscDiffJson = $SbscDiff | ConvertTo-Json -Depth 2 

    # Array になっていない場合 (1 レコードのみの場合) に [] を追加
    if ($SbscDiffJson -notmatch "^\[") {
        $SbscDiffJson = "[$SbscDiffJson]"
    }

    # JSON データを出力
    $SbscDiffJson | Set-Content -Path $TmpFolder\$SbscDiffJsonFile -Encoding UTF8
    Write-Host "save $SbscDiffJsonFile"
}

### Step 4: 現在のサブスクリプション一覧と Diff を BLOB ストレージに格納 ### ### ###
# ファイルをアップロード
Set-AzStorageBlobContent -Container $ContainerName -File $TmpFolder\$SbscListJsonFile -Blob $SbscListJsonFile -Context $Context -Properties @{"ContentType"="application/json"} -Force

if($SbscDiff.Count -ne 0){
    Set-AzStorageBlobContent -Container $ContainerName -File $TmpFolder\$SbscDiffJsonFile -Blob diff/$SbscDiffJsonFile -Context $Context -Properties @{"ContentType"="application/json"} -Force
}

Write-Host "アップロード完了"

# _tmp 配下のフォルダやファイルを削除
Remove-Item -Path $TmpFolder -Recurse -Force
Write-Host "ローカルファイルを削除しました。"
Write-Host "全処理が完了しました。"

Azure PowerShell を利用するため、[アプリファイル] で requirements.psd1'Az' = '13.*' をコメントアウトします。


BLOB ストレージへの書き込みとサブスクリプション一覧取得のため、マネージド ID を有効化し、以下のロールを付与します。

  • 操作するストレージ アカウントに対して閲覧者と BLOB データ共同作成者
  • 一覧表示させるサブスクリプションへの閲覧者


こちらを実行すると、指定した BLOB ストレージのコンテナ内に以下のサブスクリプション一覧と差分のファイル作成されます。

sbsclist_yyyymmdd.json
[
  {
    "TenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "Id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "Name": "Azure Subscription 1",
    "State": "Enabled"
  },
  {
    "TenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "Id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "Name": "Azure Subscription 2",
    "State": "Enabled"
  }
]
diff/sbscdiff_yyyymmdd.txt
[
  {
    "TenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "Id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "Name": "Azure Subscription 2",
    "State": "Enabled",
    "Changes": "Add"
  },
  {
    "TenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "Id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "Name": "Visual Studio Enterprise Subscription",
    "State": "Enabled",
    "Changes": "Remove"
  }
]

Logic Apps で差分を通知

BLOB ストレージに格納した差分ファイルを Logic Apps で読み込んで通知します。
まず BLOB ストレージにアクセスするために [ID] からマネージド ID を有効化し、閲覧者とストレージ BLOB データ閲覧者を付与します。


全体のワークフローはこのようなイメージです。


[BLOB が追加または変更されたとき] をトリガーに設定します。接続方式はマネージド ID にします。チェック対象のコンテナーは差分ファイルが格納されるコンテナ/ディレクトリを指定します。


[BLOB コンテンツを取得する (V2)] コネクタを使用し、トリガーで検出したファイルを取得します。


取得した BLOB コンテンツを [Parse JSON] でパースします。Schema は差分ファイルを [サンプルのペイロードを使用してスキーマを生成する] から読み込ませることで作成可能です。


パースしたデータを [Create HTML table] で HTML テーブルに変換します。


HTML テーブルを Outlook の [メールの送信] で通知します。レイアウトを整えるため、コードビューに切り替えて CSS を追加します。

<style>
    table {
        width: 100%;
        border-collapse: collapse;
        font-family: Arial, sans-serif;
    }
    th, td {
        padding: 12px;
        border: 1px solid #ddd;
        text-align: left;
    }
    th {
        background-color: #f2f2f2;
        color: #333;
    }
    tr:nth-child(even) {
        background-color: #f9f9f9;
    }
    tr:hover {
        background-color: #f1f1f1;
    }
    .table-container {
        margin: 20px 0;
        overflow-x: auto;
    }
    .header {
        font-size: 18px;
        font-weight: bold;
        margin-bottom: 10px;
    }
    .footer {
        font-size: 14px;
        color: #666;
        margin-top: 20px;
    }
</style>

<div class="header">監視対象サブスクリプションの差分を検出しました。</div>

<div class="table-container">
@{body('Create_HTML_table')}
</div>

以下のようなメールが通知されます。(アップデートは Add と Remove のセットで通知)

まとめ

本記事では、Azure Functions と Logic Apps を活用して、サブスクリプションの作成・削除を検出し、通知する仕組みを検討しました。この方法により、管理者はサブスクリプションの変動を効率的に監視し、適切な対応を行うことができるようになるかと思います。

Microsoft (有志)

Discussion