Azure Bastion の共有リンクを定期的に掃除する

azure
Published: 2022-11-22

Azure Bastion に共有リンクという機能が追加されました。Azure AD による認証なしで特定の仮想マシンにのみ接続できる直リンクを作成する機能です。共有リンクを利用すれば、初期構築やメンテナンスなどの単発の要件で仮想マシンにアクセスするために Azure Bastion を使う人に対して、Azure AD のアカウントを払い出したりゲスト招待したりする必要がなくなります。

共有リンクのログイン画面

共有リンクの URL は https://bst-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.bastion.azure.com/#/url-metadata/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx なので、32桁の Azure Bastion の GUID と32桁の接続先 VM の GUID の両方を総当たりで突破できれば、悪意ある第三者が共有リンクにアクセスできてしまいます。突破される確率は天文学的ですがゼロではないので、共有リンクを作りっぱなしにするのではなく利用終了後に速やかに削除する運用が望ましいでしょう。

Azure Bastion の機能として共有リンクに有効期限を設定できればよいのですが、2022年11月現在、機能はありません。ですが、共有リンクはそのプロパティとして作成日時を保持しており、かつ API によって操作できるため、次のようなスクリプトを定期実行することで定期的なお掃除が可能です。忘れっぽい方は実装をご検討ください

共有リンクの詳細

{
  "value": [
    {
      "vm": {
        "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/rhel/providers/Microsoft.Compute/virtualMachines/rhelvm01"
      },
      "bsl": "https://bst-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.bastion.azure.com/api/shareable-url/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "createdAt": "2022-11-22T10:11:22.0516104Z"
    }
  ]
}

共有リンクの取得・削除の API

サンプルスクリプト

$ErrorActionPreference = "stop"

$lifetimeOfBsl = 1
# 共有リンク機能が有効になっている Bastion を取得
$bastions = Get-AzResource -ResourceType "Microsoft.Network/bastionHosts" -ExpandProperties | Where-Object { ($_.Sku.Name -eq "Standard") -and ($_.Properties.enableShareableLink -eq $True) }

$now = (Get-Date).ToUniversalTime()

foreach ($bastion in $bastions) { 

    # Bastion の共有リンクを取得
    $res = Invoke-AzRest -Method POST -Uri "https://management.azure.com$($bastion.Id)/getShareableLinks?api-version=2022-05-01" 
    $shareablelinks = ($res.Content | ConvertFrom-Json -Depth 100).value

    # 共有リンクの作成日時を取得
    foreach ( $shareablelink in $shareablelinks) {
        Write-Output "Found $($shareablelink.bsl) created at $($shareablelink.createdAt)"
        # 作成日時+有効期限が現在の時刻を過ぎていたら、対象の共有リンクを削除
        if ( $now -gt ($shareablelink.createdAt).AddDays($lifetimeOfBsl) ) {
            Write-Output "$($shareablelink.bsl) needs to be deleted. Because it runs over $lifetimeOfBsl day"
            $body = @{
                "vms" = @(
                    @{
                        "vm" = @{
                            "id" = $shareablelink.vm.id
                        }
                    }
                )
            } | ConvertTo-Json -Depth 100
            Invoke-AzRest -Method POST -Uri "https://management.azure.com$($bastion.Id)/deleteShareableLinks?api-version=2022-05-01" -Payload $body
        }
    }
}