Hello Folks,
I’ve been working with some colleagues on a shared demo environment, and one issue came up during a session with customers that highlighted a problem. If any of us change the local admin password of the servers or redeploys the environment with a password of their own. We no longer can access it without contacting the group and request the new password.
I started to look a way to regularly update the password from a location that is built specifically for storing passwords and other secrets. Namely, Azure Key Vault.
And, I had just read the PowerShell’s Team blog announcing the general availability of their SecretManagement and SecretStore modules. That seemed like the best candidates to help. The SecretManagement module helps users manage secrets by providing a common set of cmdlets to interface with secrets across vaults. IT utilizes an extensible model where local and remote vaults (including Azure Key Vaults) can be registered and unregistered for use in accessing and retrieving secrets.
The module provides the following cmdlets for accessing secrets and managing SecretVaults:
- Get-Secret
- Get-SecretInfo
- Get-SecretVault
- Register-SecretVault
- Remove-Secret
- Set-Secret
- Set-SecretInfo
- Set-SecretVaultDefault
- Test-SecretVault
- Unregister-SecretVault
The solution
To address our issue, we took the following steps.
1- Created a key vault and created/stored a secret with a complex password. (because it’s in the demo resource group, we can all retrieve the secret when needed)
2- Deployed Azure Automation in our environment and created a Run as account to provide authentication for managing resources in Azure with the Azure cmdlets.
**EDIT**
I forgot at the time of publishing to mention that I had to assign the proper rights to the Run-As account in our Key Vault. To ensure good security, I restricted the automation account to Get and List for Secret Management Operation.
3- Created a new Runbook that would get the secret from Key vault using PowerShell Microsoft.PowerShell.SecretManagement module and using the Azure VMAccess extension would update the local admin password to the one retrieved from Key vault. (The sample code available below). Of course, this is proof of concept at this point and needs to be worked on. However, it does open the door to other usage. This could be re-used and modified to run on a schedule to generate a new complex password and store it in Key Vault, then update all the servers in your environment with the new password on a regular basis.
4- Here is the sample code.
param(
[string]$ResourceGroupName = "Secret-Demo",
[string]$vaultname = "SecretDemoVault"
)
Disable-AzContextAutosave -Scope Process
$VERSION = "1.0"
$currentTime = (Get-Date).ToUniversalTime()
Write-Output "Runbook started. Version: $VERSION at $currentTime"
Write-Output "---------------------------------------------------"
# Authenticate with your Automation Account
$connection = Get-AutomationConnection -Name AzureRunAsConnection
# Wrap authentication in retry logic for transient network failures
$logonAttempt = 0
while(!($connectionResult) -and ($logonAttempt -le 10))
{
$LogonAttempt++
# Logging in to Azure...
$connectionResult = Connect-AzAccount `
-ServicePrincipal `
-Tenant $connection.TenantID `
-ApplicationId $connection.ApplicationID `
-CertificateThumbprint $connection.CertificateThumbprint
Start-Sleep -Seconds 30
}
$AzureContext = Get-AzSubscription -SubscriptionId $connection.SubscriptionID
$SubID = $AzureContext.id
Write-Output "Subscription ID: $SubID"
Write-Output "Resource Group: $ResourceGroupName"
Write-Output "VaultName: $vaultname"
# Get Secret from KeyVault
Register-SecretVault -Name AzKeyVault -ModuleName Az.KeyVault -VaultParameters @{ AZKVaultName = $vaultname; SubscriptionId = $SubID }
$secret = Get-Secret -Vault AzKeyVault -Name sysadmin
Write-Output "SecretValue : $secret"
$Credential = New-Object -TypeName PSCredential -ArgumentList "sysadmin", $secret
# Get a list of all virtual machines in subscription
$VMList = Get-AzVM -ResourceGroupName $ResourceGroupName
foreach ($vm in $VMList)
{
Write-Output "Reseting password on $vm.name"
Set-AzVMAccessExtension -ResourceGroupName $ResourceGroupName -VMName $Vm.Name -Credential $Credential -typeHandlerVersion "2.0" -Name VMAccessAgent
}
The code above required me to import some PowerShell Modules into our Automation environment. The modules I imported from the gallery
The added modules were the following:
- Az.Accounts
- Az.Compute
- AZ.KeyVault
- Microsoft.PowerShell.SecretManagement
- Microsoft.PowerShell.SecretStore
5- Once created and published I linked the Runbook to a schedule that will execute the script nightly.
That's it! a simple solution based on a new PowerShell module that provides us with loads of value. Maybe it will be of value for you too.
Cheers!
Pierre