😊

今接続されているネットワークに限定して SSH と RDP を許可する

2023/05/16に公開

今接続されているネットワークに限定して SSH と RDP を許可する

Azure CLI でいうと az vm open-port というのが提供されていますが、これの PowerShell 版を作ってみる、という感じです。
Azure CLI 版の docs はこちらです。

https://learn.microsoft.com/cli/azure/vm?view=azure-cli-latest#az-vm-open-port

ぱっと使うには便利に思うのですが、実際に設定された内容を確認すると、送信元を指定しない (any) のため、どこからでもアクセス可能になってしまいます。
この問題点も踏まえつつ、PowerShell 版を考えてみました。

そもそもそれなりのエンタープライズであれば Azure VM に大して直接 Public IP アドレスを付与してアクセスする、というケースは少ないと思いますが。

実装例

ということでまた ChatGPT にさくっと作ってもらい、エラーが起きたよ、とかやり取りしながらいったん完成したものがこちらです。

function Add-MyAzNSGRuleForMgmtFromHere {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$ResourceGroup,

        [Parameter(Mandatory = $true)]
        [string]$VMName
    )

    # Get the source IP address
    $sourceIP = (Invoke-WebRequest -Uri 'https://ifconfig.me/ip').Content.Trim()

    try {
        # Get the VM
        $vm = Get-AzVM -ResourceGroupName $ResourceGroup -Name $VMName -ErrorAction Stop

        # Get the NIC
        $nic = Get-AzNetworkInterface -ResourceGroupName $ResourceGroup -Name $vm.NetworkProfile.NetworkInterfaces[0].Id.Split("/")[-1]

        # Get the NSG associated with the subnet of the NIC
        $subnetId = $nic.IpConfigurations[0].Subnet.Id
        $subnet = Get-AzVirtualNetworkSubnetConfig -ResourceId $subnetId
        $nsg = Get-AzNetworkSecurityGroup -ResourceGroupName $ResourceGroup -Name $subnet.NetworkSecurityGroup.Id.Split("/")[-1]

        # Get the existing priorities and calculate the next available priority
        $existingPriorities = $nsg.SecurityRules.Priority
        $existingPriorities = $existingPriorities | Sort-Object -Descending
        $priority = 100

        while ($existingPriorities -contains $priority) {
            $priority += 10
        }

        # Add the rule to the NSG
        $ruleName = "AllowMgmtFromHere"
        $protocol = "Tcp"
        $portRange = "22","3389"
        $sourceAddressPrefix = $sourceIP

        $rule = $nsg.SecurityRules | Where-Object { $_.Name -eq $ruleName }
        if ($rule -eq $null) {
            $rule = New-AzNetworkSecurityRuleConfig -Name $ruleName -Protocol $protocol -Direction Inbound -Priority $priority -SourceAddressPrefix $sourceAddressPrefix -SourcePortRange * -DestinationAddressPrefix * -DestinationPortRange $portRange -Access Allow
            $nsg.SecurityRules.Add($rule)
            $nsg | Set-AzNetworkSecurityGroup | Out-Null
            Write-Host "A new rule has been added to the NSG."
        } else {
            Write-Host "The same rule already exists."
        }
        
        # Get the Public IP address associated with the NIC
        $publicIP = Get-AzPublicIpAddress -ResourceGroupName $ResourceGroup -Name $nic.IpConfigurations.PublicIpAddress.Id.Split("/")[-1]
        Write-Host "The IP address of the Public IP resource associated with the NIC: $($publicIP.IpAddress)"
    } catch {
        Write-Host "An error occurred: $_"
    }
}

az vm open-port と比べていろいろ足りていない部分もありますが、自分の用途としてはいい感じなので良しとしています。

使い方

使い方は簡単で、Resource group と Azure VM の名前を指定して実行するだけです。

Add-MyAzNSGRuleForMgmtFromHere -ResourceGroup "simple-ubuntu2204" -VMName "vm-hub00"

実装方針

実装方針としては以下のような感じです。

  • NSG は NIC ではなく subnet に適用されている前提 (az vm open-port では既定が NIC、--apply-to-subnet をつければ subnet の NSG を変更する動作)
  • 送信元 IP アドレスの確認には https://ifconfig.me へとアクセスしているため、Web の traffic と SSH / RDP の経路が異なるネットワークの場合にはうまくいかない可能性がある (Web の traffic には proxy を適用している、とか)
  • SSH (22/tcp) と RDP (3389/tcp) をポート開放する
  • priority は 100 番を基準とし、被っているようであれば 110 番、という感じで 10 ずつ増やしていく
  • NIC はひとつしかついていない前提
  • 実行後に関連付いている Public IP アドレスを表示する (すぐに SSH とか mstsc.exe が実行できるように)

まとめ

とくにまとめるものでもないですが、某環境が定期的に NSG の rule を削除して回っているので、気づいたら接続できない、となってめんどいのでこのようなものを作成しました。

Microsoft (有志)

Discussion