Microsoft Secure Tech Accelerator
Apr 03 2024, 07:00 AM - 11:00 AM (PDT)
Microsoft Tech Community
How to use Group Managed Service Accounts (gMSA) in Azure Automation Hybrid Worker
Published Feb 04 2020 07:21 AM 11.7K Views
Microsoft

 

This post describes how to use Azure Automation Hybrid Worker in on-premises scenarios where you need to authenticate against the local resources you want to automate, all without using any Azure Automation credential/certificatethanks to Group Managed Service Accounts and PsExec. 

 

Introduction

 

Azure Automation Hybrid Worker is a great solution for implementing hybrid automation scenarios, where you have on-premises assets you want to manipulate from the same control plane you use to manage your Azure resources. All your runbooks are stored and invoked in Azure Automation, but you choose whether you run them in the cloud or on-premises. 

 

No matter the environment you are managing, secure authentication against your resources is always a critical aspect of your automation, particularly when you need to access on-premises resources. Azure Automation provides several solutions for authentication: 

 

  1. Run As Accounts (authenticating against Azure resources only)  a service principal is created in Azure AD and can be assigned privileges to whatever Azure resource associated to that Azure AD – by default, it is given Contributor privileges in the Azure subscription in which the Automation Account was created. This solution is normally used by hosted workers, but can also be used with Hybrid Workers (see how to). 
  2. Managed Identity (authenticating against Azure resources only)  this is the recommended solution for Hybrid Workers running in Azure, as there is no need to manage identity certificates and authentication is done in a much simpler way 
  3. CredentialCertificate and Connection assets  shared Automation resources that both hosted and Hybrid Workers can use to retrieve securely stored credentials or certificates that authenticate against Azure or on-premises resources. 

Looking at the authentication options available, only credentials/certificates can be used to authenticate against on-premises resources. However, some organizations may be reluctant in storing such sensitive information in Azure Automation, even more retrieving it over the Internet. Therefore, if Automation Hybrid Worker could use an on-premises identity without dealing with secrets, such as Group Managed Service Accounts (gMSA), there would be no need to store credentials/certificates. Unfortunately, Azure Automation does not natively support gMSA, but if you follow the remainder of this post, there is a way of using gMSA, thanks to the PsExec tool, which can be used to launch a process in the context of any identity, including gMSA. 

 

Solution architecture 

 

This solution assumes that you have one or more Azure Automation Hybrid Workers domain-joined to an on-premises Active Directory according to gMSA requirements. The same gMSA identity can be used across multiple Hybrid Workers, as it is centrally managed by Active Directory. With the required permissions assigned to that gMSA account, Hybrid Workers can be authorized against the resources to perform automation tasks all without dealing with secrets. 

 

As a good practice, if you plan to automate local resources in several administrative tiers or for multiple purposes requiring different permission levels, you should consider using distinct gMSA/Hybrid Workers groups for each administrative tier/permission level. 

 

On-premises Hybrid Workers, orchestrated by Azure Automation and depending on local Domain Controllers to get the gMSA account required to access local resourcesOn-premises Hybrid Workers, orchestrated by Azure Automation and depending on local Domain Controllers to get the gMSA account required to access local resources

 

Implementation details

 

Due to the limited scenarios in which gMSAs can be used, we are left with the only option for Hybrid Workers: using the well-known PsExec tool from Microsoft Sysinternals, which can be used to launch a process in the context of any user, including gMSA. In order to use PowerShell from end to end, one can use the Invoke-PsExec wrapper module, but the PsExec executable can also be directly called from PowerShell, provided it is made available in a well-known local directory in the Hybrid Worker machine. 

 

In order to prepare the gMSA account, you must follow these steps (a good overview of the process can be found here): 

 

1. Create the KDS Root Key in Active Directory (AD), by running the following PowerShell command on a domain controller: 

 

  • Option 1 – if you want to be sure the KDS Root Key propagates across your entire AD topology and you can wait for about 10 hours for the propagation to conclude: 

 

 

 

Add-KdsRootKey -EffectiveImmediately

 

 

 

  • Option 2 – if KDS Root Key propagation across the entire AD topology is not an issue in your scenario: 

 

 

 

Add-KdsRootKey -EffectiveTime ((Get-Date).AddHours(-10)) 

 

 

 

2. Create a security group in the AD for the purpose of grouping all the computers (Hybrid Workers) that will use this gMSA. Make all the Hybrid Worker machines as members of this security group. Reboot the Hybrid Worker machines. 

 

3. [if you chose option 1 in step 1, ensure 10 hours have elapsed] Create the gMSA, by executing the following PowerShell command: 

 

 

 

New-ADServiceAccount -Name "<gMSA name>" -DNSHostName "<gMSA name>.yourdomain.local" -Enabled $True -PrincipalsAllowedToRetrieveManagedPassword <security group created in the previous step> -KerberosEncryptionType AES256  

 

 

 

4. Grant all the needed privileges to the gMSA account. When looking for the gMSA in the AD, refer to it as <gMSA name>$ 

 

5. Install the gMSA in the Hybrid Worker machines using it, by running there this PowerShell command: 

 

 

 

Install-ADServiceAccount -Identity <gMSA name> 

 

 

 

6. Test if the gMSA was correctly installed in the Hybrid Worker: 

 

 

 

Test-ADServiceAccount -Identity <gMSA name> 

 

 

 

Now that the gMSA is ready to be used, we must set up Azure Automation. In many scenariosAutomation runbooks have hundreds of lines, variables, HTML code, etc. Because of this complexity, we might be obliged to run the script from the Hybrid Worker local file system, instead of just passing it inline to PsExec. However, as we don’t want to have automation code permanently stored in the Hybrid Worker local file system, we will use two Azure Automation Runbooks: the first one with the PsExec orchestration; and the other one with the actual automation we want to execute (please, note that it won’t be triggered as a normal runbook, but will rather be temporarily downloaded to the local file system to be later called by PsExec). To make this solution possible, we will need to: 

 

  • Ensure we have a configured Azure RunAs Account in the Automation Account (see instructions). 
  • Install the Azure PowerShell module in the Hybrid Worker (see instructions). 
  • Install the Azure RunAs Account certificate in the Hybrid Worker (see instructions). We will need this certificate to connect to Azure to download the main automation script. 
  • Install the Invoke-PsExec module in the Hybrid Worker 
  • Create the PsExec orchestration Runbook (see sample script below). This runbook: 
    • Downloads the main script from Azure Automation 
    • Searches and replaces (in the main script) for the parameters placeholder with the actual parameters we want to pass 
    • Saves the final script in the local file system 
    • Calls Invoke-PsExec in the context of the gMSA account 
  • Create the main automation Runbook, ensuring we assign the expected JSON parameters variable with a parameters placeholder, e.g., “JSONParametersPlaceHolder” (see sample script below) 
  • Invoke the orchestration runbook, passing to it the required parameters 
    • RunbookName – the name of the main automation runbook to be called with PsExec in the context of gMSA
    • AutomationAccountName – the Automation Account where the main runbook is stored 
    • AutomationAccountResourceGroup – resource group for the Automation Account above 
    • gMSAName – the name of the gMSA account, in the format of “domain\accountname$” 
    • ParametersJson  the parameters to send to the main runbook, as a JSON valid string 

 

PsExec Orchestration Runbook 

 

 

 

<#Sample scripts provided are not supported under any Microsoft standard support program or service. The sample scripts are provided AS IS without warranty of any kind. Microsoft disclaims all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or documentation, even if Microsoft has been advised of the possibility of such damages.#>  

Param( 

    [string] $RunbookName, 

    [string] $AutomationAccountName, 

    [string] $AutomationAccountResourceGroup, 

    [string] $gMSAName, 

    [string] $ParametersJson 

) 

 

$servicePrincipalConnection = Get-AutomationConnection -Name "AzureRunAsConnection" 

 

"Logging in to Azure..." 

Add-AzAccount ` 

    -ServicePrincipal ` 

    -TenantId $servicePrincipalConnection.TenantId ` 

    -ApplicationId $servicePrincipalConnection.ApplicationId ` 

    -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint  

Export-AzAutomationRunbook -ResourceGroupName $AutomationAccountResourceGroup -AutomationAccountName $AutomationAccountName -Name $RunbookName -Slot Published -OutputFolder . 

$ScriptFilePath = (Get-Item -Path ".\").FullName + "\" + $RunbookName + ".ps1" 

Write-Output "Replacing JSONParametersPlaceHolder with $ParametersJson ..." 

(Get-Content $ScriptFilePath).replace('JSONParametersPlaceHolder', $ParametersJson) | Set-Content $ScriptFilePath 

Write-Output "Using credential $gMSAName ..." 

#  we must use ~ as a password replacement for the gMSA account 

$creds = New-Object System.Management.Automation.PSCredential ($gMSAName, (ConvertTo-SecureString "~" -AsPlainText -Force)) 

Invoke-PsExec -Credential $creds -ComputerName $env:computername -PSFile $ScriptFilePath 

 

 

Main automation Runbook sample 

 

 

 

$ParametersJson    =   "JSONParametersPlaceHolder" 

<# 
As an example, we are going to disable a user account sent as a JSON parameter, with the schema { 'Name': 'Account Name', 'SamAccountName' : 'SAM account name' } 
#> 

$user = ConvertFrom-Json -InputObject $ParametersJson 

Write-Output "About to disable $($user.Name)..." 

Disable-ADAccount $user.SamAccountName 

Write-Output "Done." 

 

 

 

 

 

 

Conclusion 

 

This post described how to use Azure Automation Hybrid Worker in scenarios where you need to authenticate against on-premises resources without using secrets or certificates, thanks to gMSA accounts and PsExec.  

 

The orchestration runbook and main automation sample script above are an example of a more complex scenario, in which you need to pass parameters to the main script. However, if the command to execute in the context of the gMSA account is simple enough, you can call the PowerShell command right from the Invoke-PsExec cmdlet and you don’t even need to use Azure Automation Run As Accounts as you don’t need to export the main script to the local file system. 

 

Thanks for reading!

Co-Authors
Version history
Last update:
‎Mar 15 2021 02:33 AM
Updated by: