困擾我一陣子的小問題,今天花點時間寫幾行程式解決。

使用 Azure VM 時,我們需要使用 SSH 或 RDP 遠端登入,但實務上都建議要加限制來源 IP,以防成為攻擊或入侵的目標:

不信的話,在 Internet 放一台 Linux 22 Port 對外全開跑一晚上,隔天用 journalctl -u ssh | grep "from" 檢查,就算你沒對外公佈過 IP,也會看到這種來自機器人的無差別攻擊:

限制 VM 只允許你的 IP 遠端登入是很有效的防護手段。Azure Portal 的設定 UI 頗貼心,有個「My IP address」選項,會自動抓取你的對外 IP 填入。

因此,每次開完 VM,我第一件要做的事就是限定只允許我的 IP 連線。

問題是我的寬頻上網是用浮動 IP (ISP 有給一個固定 IP,我另有他用,平日上網用浮動 IP),每隔一陣子會自動更換,每次換完 IP 得一一重新設定很麻煩。IP 網段選項還有個 Azure Service Tag 選項,類似環境變數,但查了一下似乎無法自訂 Service Tag 指向特定 IP,此路不通。

懶得再花時間研究,寫程式解決吧!

Azure CLI az network nsg list 會傳回 Azure 帳號所有 Network Security Group (NSG) 物件清單,資料以 JSON 格式表示,透過 ConvertFrom-Json 轉成物件集合,接著便能串接 PowerShell 操作,等同擁有無限擴充空間,酷! (還沒用過 Azure CLI 的朋友可從官方教學入門,敲指令做事比滑滑鼠快 N 倍,大推!)

我寫了一個腳本,掃描帳號下所有 NSG 的 securityRules 規則集合,找出其中與 SSH、RDP 相關的設定,將其來源 IP 一律改成目前的對外 IP。如此,每次浮動 IP 異動後,我只需呼叫 https://api.ipify.org/ 取得對外 IP,將 SSH、RDP 規則無腦重刷一輪就好囉~

程式碼如下,說明寫在註解裡:

function Filter-RdpSshPortRules($nsg) {
    # 對 NSG 的 securityRules 集合進行過濾
    $nsg.securityRules | Where-Object {
        # 過濾連到 RDP 3389 及 SSH 22 的規則
        ($_.destinationPortRange -eq "3389" -or $_.destinationPortRange -eq "22")
    }
}
function Get-AllRdpSshRules() {
    (az network nsg list | ConvertFrom-Json | Where-Object { 
        # 找出有包含 RDP、SSH 相關規則的 NSG
        (Filter-RdpSshPortRules $_).Count -gt 0
    }) | ForEach-Object {
        $nsg = $_
        Filter-RdpSshPortRules $_ | ForEach-Object {
            # 展開成一條規則一筆,包含名稱、資源群組、唯一識別碼、Port、來源 IP
            [PSCustomObject]@{
                name = $nsg.name
                grp = $nsg.resourceGroup
                id = $_.id
                port = $_.destinationPortRange
                ip = $_.sourceAddressPrefix
            }
        }
    }
}
# 列舉現有設定
Get-AllRdpSshRules | Format-Table -Property name, port, ip
# 取得目前主機的開放 IP
$myIp = (Invoke-WebRequest -Uri "https://api.ipify.org").Content
# 要求確認是否要全面覆寫
$cnfrm = Read-Host "Update all RDP and SSH rules to $myIp ? (y/n)"
if ($cnfrm -ne "y") {
    Write-Host "Aborting..."
    return
}
Get-AllRdpSshRules | ForEach-Object {
    # 重設來源 IP
    Write-Host "Updating rule $($_.name):$($_.port) to $myIp" -ForegroundColor Yellow
    az network nsg rule update --id $_.id --destination-address-prefix '*' --source-address-prefix $myIp
}
# 顯示覆寫後的主機對外開放 IP
Get-AllRdpSshRules | Format-Table -Property name, port, ip

就醬,再解決一件惱人 Azure 管理瑣事。

It's recommend to restirct source IP for connection to SSH and RDP ports of Azure VMs. This article demostrate how to use Azure CLI and PowerShell to update the source IP in batch.


Comments

# by Leo

感謝黑大分享,這個問題我困擾好久,從來沒想過怎麼用ps來解決,剛試用,太棒了!!!!!

Post a comment