如何以PowerShell安全的進行自動化登入-以Microsoft Azure平台為例
在 twMVC#34 與 Jamis 聊天時他提出一個 PowerShell 問題,像我們在使用 PowerShell 操作 Microsoft Azure 時都必須進行 Login 的動作,例如,每次下 Connect-AzureRmAccount
都必須先輸入帳號密碼,這有點煩。第二個問題,在 Powershell Script 要進行多訂閱切換很不方便,例如,下 Connect-AzureRmAccount
就是會跳出輸入視窗,這根本無法自動化。
我們先處理跳出的登入視窗。如果是微軟官方提供 PowerShell Cmdlet,通常涉及「憑證」的 Cmdlet 都會提供一個 -Credential
參數,例如查詢在 Connect-AzureRmAccount 文件確認是否有 -Credential
參數:
Connect-AzureRmAccount
[-Environment <String>]
[[-Credential] <PSCredential>]
[-TenantId <String>]
[-Subscription <String>]
[-ContextName <String>]
[-SkipContextPopulation]
[-Force]
[-Scope <ContextModificationScope>]
[-DefaultProfile <IAzureContextContainer>]
[-WhatIf]
[-Confirm]
[<CommonParameters>]
我們就能把「憑證」提供給 -Credential
參數來使用。憑證如果會重覆使用,我們通常會在當下視窗(PowerShell 稱為 Session)的憑證儲存在變數裡重覆使用,例如:
$cred = Get-Credential
Connect-AzureRmAccount -Credential $cred
- 雖然
Get-Credential
還是會跳出輸入視窗,由於我們把值存下來,此後就能重覆使用$cred
的值。$cred
的帳號會是明文,密碼會被加密。 Connect-AzureRmAccount -Credential $cred
單就登入作業而言,已經不會再跳出視窗,算是已經登入的自動化。
另一種用法是:
$cred = Get-Credential
.\YourPowerShell.ps1
在當下 Session,$cred
除非被重新賦值或關閉 Session 視窗,不然值會一直存在。YourPowerShell.ps1 可以直接取 $cred
來使用。換句話說,當我們離開(或關閉)此 PowerShell 的 Session 後,還是免不了要重新製作一個 $cred
,不然 YourPowerShell.ps1 不能正常執行。再者,像自動化腳本根本不可能去手動輸入 Get-Credential
,怎麼辦?這時你可以在 .ps1 中多寫個 function 來取得所需的 PSCredential 物件:
function GetBruceCredential() {
$account = "kkbruce"
$secString = ConvertTo-SecureString "TaiwanNo1" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ($account, $secString)
return $cred
}
這個方法只有唯一一個非常明顯的缺點,就是在你的 PowerShell Script 中需要寫入明文帳密資訊,優點是,它能解決自動化過程中需要輸入帳密的問題。
還有沒有更好解決的辦法,可以完成自動化作業,又能不寫入明文帳密呢?是的,可以。不然枉費標題多加"安全的"三個字。
PowerShell 是個物件的世界,而 PowerShell 提供了一個將這些物件進行匯出的功能:Export-Clixml,說明簡單直白:Creates an XML-based representation of an object or objects and stores it in a file.
。
$cred | Export-Clixml -Path .\bruce-credential.xml
$cred = Import-Clixml -Path .\bruce-credential.xml
你可以先呼叫 Export-Clixml
將憑證物件進行匯出的動作,XML 的內容部份,因為 $cred
本來密碼的部份已被加密,當然匯出的內容也是加密內容。比起我們自己寫的 GetBruceCredential
而言,安全性已提高太多了。
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">
<Obj RefId="0">
<TN RefId="0">
<T>System.Management.Automation.PSCredential</T>
<T>System.Object</T>
</TN>
<ToString>System.Management.Automation.PSCredential</ToString>
<Props>
<S N="UserName">kkbruce</S>
<SS N="Password">d08c9ddf0115d...hash...d98f49b896</SS>
</Props>
</Obj>
</Objs>
當 PowerShell Script 需要憑證時,也只需一行 Import-Clixml
來將憑證資訊匯入,就能在 PowerShell Script 使用,這樣就能完成安全的自動化作業的腳本。改寫一下我們的 function:
function GetBruceCredential() {
$cred = Import-Clixml -Path .\bruce-credential.xml
return $cred
}
注意,Export-Clixml
採用 Windows Data protection API 來進行憑證資訊的加密,也就是說,唯有同一台電腦與同一個帳號才能讀取(Import-Clixml
)使用。如果非同一台電腦或帳號,你應該會看到以下錯誤訊息:
c : Key not valid for use in specified state.
At line:1 char:13
+ $credtest = Import-Clixml -Path .\bruce-credential.xml
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Import-Clixml], CryptographicException
+ FullyQualifiedErrorId : System.Security.Cryptography.CryptographicException,Microsoft.PowerShell.Commands.ImportClixmlCommand
Export-Clixml
與 Import-Clixml
的主機與身份限制或許會造成一些麻煩,但安全本來就需要付出一些些代價。
ConvertTo-SecureString
與ConvertFrom-SecureString
,雖然平常是在本機記憶體內操作,但如果你把System.Security.SecureString
的內容寫至檔案,拿到其他電腦讀入,並轉換為 SecureString 時,你能發現和Import-Clixml
大至相同的錯誤訊息。
最後一個問題,像我有個人、MVP、公司等多個訂閱,我想要進行切換也很簡單,只要將每個訂閱的憑證 XML 事先製作好,需要時載入對應的 XML 憑證進來,這樣就能自由的切換訂閱帳戶的切換。最後注意,使用 -Credential
方法進行登入的帳號不能啟用任何二階段驗證,它可沒有辦法等你去輸入簡訊驗證碼或點擊驗證App!
沒有留言:
張貼留言
感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。