Install ssl certificate from azure key vault with Automation Accounts - azure

i have some issues.
I have in key vault some SSL certs from LetsEncrypt,and i want to automate installing certificates to VM in azure. I create runbook with some code:
$connectionName = "AzureRunAsConnection"
try
{# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection=Get-AutomationConnection -Name $connectionName
"Logging in to Azure..."
Add-AzureRmAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
catch {if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
} else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}$certUrl = (Get-AzureKeyVaultSecret -VaultName "MyVault" -Name "letsecrypt-my-cert").Id;
$vm=Get-AzureRmVM -ResourceGroupName "MyRS" -Name "MyVm"
$vaultId=(Get-AzureRmKeyVault -VaultName "MyVault").ResourceId
$certStore = "MySSL"
$vm = Add-AzureRmVMSecret -VM $vm -SourceVaultId $vaultId -CertificateStore $certStore -CertificateUrl $certURL
Update-AzureRmVM -ResourceGroupName "MyRS" -VM $vm
It install ssl to my VM, but i want to check some parameters of certificate and run this script, for example: if certificate updated run install to vm and if not do nothing. What parameters i must use and how check them. Maybe someone do similar task?

I solve this issues with these code modification:
$connectionName = "AzureRunAsConnection"
try
{
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection=Get-AutomationConnection -Name $connectionName
"Logging in to Azure..."
Add-AzureRmAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
catch {
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
} else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
$certUrl = (Get-AzureKeyVaultSecret -VaultName "MyVault" -Name "letsecrypt-MyCert").Id
$vm=Get-AzureRmVM -ResourceGroupName "MyRG" -Name "MyVm"
$certUrlOnVM=$vm.osProfile.secrets.vaultCertificates.certificateUrl
$vaultId=(Get-AzureRmKeyVault -VaultName "MyVault").ResourceId
$curentDate = Get-Date
$d = $curentDate.day
$m = $curentDate.month
$y = $curentDate.year
$curentDateStr = "$d/$m/$y"
$certStore = "MySSL_"+$curentDateStr
if ($certUrl.equals($certUrlOnVM)){
"Certificate already installed on VM"
} else {
Get-AzureRmVM -ResourceGroupName "MyRG" -Name "MyVm" | Remove-AzureRmVMSecret | Update-AzureRmVM
$vm = Add-AzureRmVMSecret -VM $vm -SourceVaultId $vaultId -CertificateStore $certStore -CertificateUrl $certURL
Update-AzureRmVM -ResourceGroupName "MyRG" -VM $vm
"Certificate installed on VM successfully"
}
I add some variables for get certificate url in key vault and section certificateUrl from OSProfile on vm. I check if cert in keyvault and vm are identical, i do nothing, if not i do remove old section on vm and install new cert.

Related

Azure Automation Runbook Workflow looses AzContext

I have written the following runbook workflow, but from time to time I see the error when it try's to start or stop a VM:
Start-AzVM : Your Azure credentials have not been set up or have expired, please run Connect-AzAccount to set up your
Azure credentials.
At StartStopVmByTag:46 char:46
+
+ CategoryInfo : CloseError: (:) [Start-AzVM], ArgumentException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.Compute.StartAzureVMCommand
I have tried passing the $azContext variable in, but I still get this issue, how can I further investigate?
workflow StartStopVmByTag {
$connectionName = "AzRunAsConnection2042";
try {
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection = Get-AutomationConnection -Name $connectionName
Write-Output "Logging in to Azure..."
$null = Add-AzAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
catch {
if (!$servicePrincipalConnection) {
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
}
else {
Write-Error -Message $_.Exception
throw $_.Exception
}
}
[DateTime]$now = [System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId((Get-Date), 'GMT Standard Time')
$startTag = 'Start Schedule'
Write-Output "*** $now - Runbook Started ***"
# Get Subscriptions
$Subscriptions = Get-AzSubscription
ForEach ($Subscription in $Subscriptions) {
$azContext = Set-AzContext -SubscriptionId $Subscription.Id
# Get all VM's with a Start or Stop Schedule
Write-Output "$($Subscription.Name): Getting VM's..."
[Array]$taggedVms = Get-AzResource -TagName $startTag -ResourceType 'Microsoft.Compute/virtualMachines'
$taggedVms = $taggedVms | Sort-Object -Property Name -Unique
# For each VM, check if start schedule is valid for now
Foreach -Parallel ($taggedVm in $taggedVms) {
Write-Output "$($Subscription.Name): Found Tagged VM: $($taggedVm.Name), $($startTag): $($taggedVm.Tags.$startTag -replace '\s', '')"
$WORKFLOW:null = Start-AzVM -ResourceGroupName $taggedVm.ResourceGroupName -Name $taggedVm.Name -DefaultProfile $azContext -NoWait
}
}
}
I have been struggling with this issue for a while, and I've tried dozens of different workarounds and nothing has worked. I finally resolved it with these registry settings that force .NET applications to use TLS 1.2. I find it very strange that this solution works, but possibly because the TLS 1.2 set as part of any parent task doesn't get passed on to the job.
They probably aren't all required, but it seems to be a best practice these days anyway.
set-itemproperty "HKLM:\SOFTWARE\Microsoft\.NETFramework\v2.0.50727" -name SystemDefaultTlsVersions -value 1 -Type DWord
set-itemproperty "HKLM:\SOFTWARE\Microsoft\.NETFramework\v4.0.30319" -name SchUseStrongCrypto -value 1 -Type DWord
set-itemproperty "HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v2.0.50727" -name SystemDefaultTlsVersions -value 1 -Type DWord
set-itemproperty "HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319" -name SchUseStrongCrypto -value 1 -Type DWord

How to start vm from different subscription using Azure Automation Account

I have three subscription in same tenant say Sub1, Sub2 and Sub3. I have created Automation Account is in Sub1 and my VMs are in Sub3. (Cant create Automation account in Sub3 due to some restrictions). I want to write a powershell script which will start Sub3 VM.
When I ran Get-AzureRmSubscription it is giving me only my current subscription i.e. Sub1
My azure automation script is as below -
$connectionName = "AzureRunAsConnection"
try
{
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection=Get-AutomationConnection -Name $connectionName
"Logging in to Azure..."
Add-AzureRmAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
catch {
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
} else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
Get-AzureRmSubscription
# $context = Get-AzureRmSubscription -SubscriptionId {subId}
# Set-AzureRmContext $context
# Start-AzureRmVM -ResourceGroupName "ResourceName" -Name "VMName"
Can you please guide how can I go this?
Since your subscriptions are in the same tenant, you can directly assign an Azure RABC role to your Azure Automation connection(service principal ) in your Sub3. Then you can manage Azure resource in Sub3
For example
Get the Connection Application ID
Assign role
Connect-AzAccount
$sp=Get-AzADServicePrincipal -ApplicationId < the appId you copy>
Set-AzContext -SubscriptionId <the id of sub3>
#assign Contributor role to the connection at subsciprion level
New-AzRoleAssignment -ObjectId $sp.id -RoleDefinitionName Contributor
Test
$connectionName = "AzureRunAsConnection"
try
{
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection=Get-AutomationConnection -Name $connectionName
"Logging in to Azure..."
Add-AzureRmAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
catch {
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
} else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
Get-AzureRmSubscription

Azure PowerShell Runbook Get Set Az-Disk dynamically

The team is trying to automate a snapshot restore, which was achieved successfully. However I am not able to figure out how to dynamically get the previous disk within the resource group; As well as set the next disk with a new name.
In the code below "AZR-001_OsDisk_7" has to set dynamically to "AZR-001_OsDisk_8" the next time it runs:
$diskConfig = New-AzDiskConfig -Location $snapshot.Location -SourceResourceId $snapshot.Id -CreateOption Copy
$disk = New-AzDisk -Disk $diskConfig -ResourceGroupName "ETD-RFT" -DiskName "AZR-001_OsDisk_7"
$disk1 = Get-AzDisk -ResourceGroupName "ETD-RFT" -Name "AZR-001_OsDisk_7"
Not a final solution, but I have a quick idea. You may use Get-AzDisk -ResourceGroupName 'ResourceGroupName ' to get all the disks. And then you can get the disk name.
As you named the disk with appropriate rule, you may split the name string by _, then you will get a string array which contains all the parts. In this way, you will be able to get the version.
A sample:
$disks = Get-AzDisk -ResourceGroupName JackVS2019
foreach($disk in $disks){
$arr = $disk.Name.Split('_')
Write-Host $arr[2]
}
The output:
1
Then you can generate the new disk name.
$connectionName = "AzureRunAsConnection"
try
{
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection = Get-AutomationConnection -Name $connectionName
"Logging in to Azure..."
$account = Connect-AzAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
catch {
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
} else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
Select-AzSubscription -SubscriptionName 101-Prototyping
$vm = Get-AzVM -ResourceGroupName "ETD-RFT" -Name "AZR-101-007-001"
$snapshot = Get-AzSnapshot -ResourceGroupName "ETD-RFT" -SnapshotName "SNAPSHOT-DEC-2019"
$diskConfig = New-AzDiskConfig -Location $snapshot.Location -SourceResourceId $snapshot.Id -CreateOption Copy
$disks = Get-AzDisk -ResourceGroupName "ETD-RFT"
$attached = $disks | Where-Object ManagedBy -ne $null
foreach($disk in $attached)
{
$arr = $disk.Name.Split('_')
$arr[2]
}
$a = $arr[2] -as [int]
$a=$a+1
Write-Host $a
$newname = $arr[0] + "_" + $arr[1] + "_" + $a
$disknew = New-AzDisk -Disk $diskConfig -ResourceGroupName "ETD-RFT" -DiskName $newname
$disk1 = Get-AzDisk -ResourceGroupName "ETD-RFT" -Name $newname
Set-AzVMOSDisk -VM $vm -ManagedDiskId $disk1.Id -Name $disk1.Name
Update-AzVM -ResourceGroupName "ETD-RFT" -VM $vm

Azure Start/Stop VM via webhook

We have multiple VM's in our azure environment with multiple resourcegroups. Some of the resourcegroups have multiple VM's. We are now using an URL triggers webhook that will start or stop VM's. This is working, but when a resourcegroup contains multiple VM's all the VM's will start or all the VM's will stop instead of the one you want to start/stop.
Tried multiple scripts but it's isn't working or give me errors.
param(
[Parameter(Mandatory=$false)]
[object]
$WebHookData
)
write output "Data WebHook $WebHookData"
#retrieve ResourceGroup
$ResourceGroupName = $WebHookData.RequestBody
write output "Data ResourceGroup $ResourceGroupName"
$Conn = Get-AutomationConnection -Name AzureRunAsConnection
Connect-AzureRmAccount -ServicePrincipal -Tenant $Conn.TenantID -ApplicationId $Conn.ApplicationID -CertificateThumbprint $Conn.CertificateThumbprint
$VMs = Get-AzureRmVM -ResourceGroupName $ResourceGroupName
if(!$VMs)
{
Write-Output -InputObject 'No VMs were found in the specified Resource Group.'
}
else
{
ForEach ($VM in $VMs)
{
$StartVM = Stop-AzureRmVM -ResourceGroupName $ResourceGroupName -Name $VM.Name -Force #-ErrorAction SilentlyContinue
}
}
$message = ConvertTo-Json -Compress -InputObject ([ordered]#{
headers = #{'content-type' = 'text/plain'}
body = ''
statusCode = 200
})
You could try below script for Start/Stop Virtual machine.
Start VM
$connectionName = "AzureRunAsConnection"
$servicePrincipalConnection = Get-AutomationConnection -Name $connectionName
$null = Add-AzureRmAccount -ServicePrincipal -TenantId $servicePrincipalConnection.TenantId -ApplicationId $servicePrincipalConnection.ApplicationId -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
$VMs = Get-AzureRmResource|Where-Object {$_.Tags.Keys -eq "owner" -and $_.Tags.Values -eq "daneum"}
foreach ($VM in $VMs) {
if ($VM.ResourceType -eq "Microsoft.Compute/virtualMachines") {
Start-AzureRmVM -ResourceGroupName $VM.ResourceGroupName -Name $VM.Name -Verbose
}
}
Stop VM
$connectionName = "AzureRunAsConnection"
$servicePrincipalConnection = Get-AutomationConnection -Name $connectionName
$null = Add-AzureRmAccount -ServicePrincipal -TenantId $servicePrincipalConnection.TenantId -ApplicationId $servicePrincipalConnection.ApplicationId -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
$VMs = Get-AzureRmResource|Where-Object {$_.Tags.Keys -eq "owner" -and $_.Tags.Values -eq "daneum"}
foreach ($VM in $VMs) {
if ($VM.ResourceType -eq "Microsoft.Compute/virtualMachines") {
Stop-AzureRmVM -ResourceGroupName $VM.ResourceGroupName -Name $VM.Name -Force -Verbose
}
}
For webhook integration procedure you could take a look here

Azure PS Automation Provided subscription "xxxx" does not exists

I wish to select a subscription available for my service principle within an Azure Automation PS job. Running the following code locally works fine, but within the automation job, I only get the following error
Provided subscription xxxx-xxxx-xxxx-xxx-xxxx does not exist.
The subscription does exist, and the service principal has access to it when I log onto it locally.
$id = "someid"
$pass = "somepass"
$securePass = $pass | ConvertTo-SecureString -AsPlainText -Force
$cred = new-object -TypeName System.Management.Automation.PsCredential -ArgumentList $id, $securePass
$tenantId = "someID"
Add-AzureRmAccount -Credential $cred -TenantId $tenantId -ServicePrincipal
Select-AzureRmSubscription -SubscriptionId "someID"
Finally, I figured out this issue, after some days.
This issue is already reported here.
It is due to the issue related to Add-AzureRmAccount cmdlets with Service Principal.
There is a workaround to solve this issue, as mentioned by Hariharan
$connectionAssetName = "AzureRunAsConnection"
$conn = Get-AutomationConnection -Name $ConnectionAssetName
Login-AzureRmAccount `
-ServicePrincipal `
-CertificateThumbprint $conn.CertificateThumbprint `
-ApplicationId $conn.ApplicationId `
-TenantId $conn.TenantID `
-Environment AzureGermanCloud
Refer this S.O
For using Azure Automation, you should create the Automation account with AzureRunAsConnection enabled. Then from the script you utilize it like this
$connectionName = "AzureRunAsConnection"
try {
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection = Get-AutomationConnection -Name $connectionName
"Logging in to Azure..."
Connect-AzureRmAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
catch {
if (!$servicePrincipalConnection) {
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
}
else {
Write-Error -Message $_.Exception
throw $_.Exception
}
}
Hope this helps

Resources