This will be a three part blog series on Automatically domain join Azure VMs from ARM template deployment with Key Vault secured domain join credentials
- 1: Prerequisites and Key Vault
- 2: ARM Template and JsonADDomainExtension, details
- 3: Summary, Thoughts and flaws
Prerequisites and Key Vault.
When using ARM templates to automate provisioning of VMs you will need to
domain join the VMs eventually. There are several ways of doing this, the three
most common ones i have seen are all based on extensions on the Azure VM.
- JsonADDomainExtension
- CustomScriptExtension
- DSC
The result is the same, VM is domain joined, but the effort, management and operations for these three methods are very different.
For this post i will focus on JsonADDomainExtension directly in ARM template, with fetching credentials for domain joining from Keyvault.
We leverage keyvault because we do not want to expose the credentials in a template! (This i write some more about in a part 3…)
Extensions
There are several posts about this on the web but in general i think the documentation around this is lacking. You do not get to much info about the extension and how they work in the backend, i will point out what i mean in this post. I tried to do a deeper dive into this about 2 years ago while doing some activities with it. Got things working and have worked since, recently i had the need to revisit this again and experience the same lack of documentation.
But also to be fair, currently there are 1189 extension if i look in “West Europe”. That is alot to document, most are versions but still many to document.
The JsonADDomanExtension exist in three versions (What is different in these versions?)
Some prerequisites to point out for the Extension and the Keyvault combo to work, list for quick check and details follows below.
- OU Path cannot be the default Computers
- ARM template needs secrets passed in as parameters
- Keyvault needs to allow ARM engine to read the secrets
- User/ServicePrincipal (the one deploying the ARM template) must have “Microsoft.KeyVault/vaults/deploy/action” permission
Username in Keyvault needs to be in format “domainName\userName” (not anymore)
OU Path cannot be the default Computers
Commonly you tend not have the default OU as landing zone for new computer objects, but this is something that i would have liked to be able to read from a documentation on the extensions. So make sure you have another OU ready for the domain joining, i have one called AzureVM
The error messages you get when deploying the ARM does not hint you about Computers not beeing a valid OU. You need to find the log on the server to figure this out, the log is actually great to know where to find for any extension troubleshooting.
ARM template needs secrets passed in as parameters
Parameter File
This is a small pain at the moment, that you need to reference the secrets from keyvault, resulting in needing a parameter or linked/nested template.
A pain because depending on how you deploy your template you might want to keep the deployment in a single template for that resource.
Many customer have a cloud management portal on top of clouds (Azure, AWS, GCP etc) and building ARM templates that these portals initiate is common. So you need to run the template directly not using a parameter file.
But just having a Parameters file is easy enough you can manage.
Linked/Nested Template
In the cases when you have an additional tool for provisioning like a Portal or some ITSM like ServiceNow you need to deploy the actual template and not the parameter file.
You could in many scenarios just have a PowerShell script called from the portal or ITSM that would run the Parameter file and the template, but in most cases i have encountered this has not been an option.
So linked (or nested) template is the option here
This is an excellent post on multiple ways to pass secrets to ARM Templates: https://devkimchi.com/2019/04/24/6-ways-passing-secrets-to-arm-templates/ thanks to @devkimchi
Keyvault needs to allow ARM engine to read the secrets
Have the “enabledForTemplateDeployment” property enabled on the keyvault. This property must be true before the template deployment process can access the secrets that are defined in the key vault.
User/ServicePrincipal
(the one deploying the ARM template) must have “Microsoft.KeyVault/vaults/deploy/action” permission
If you are the Owner or Contributor you have the access and can assing access to potential Service Principal or similar, but you can create a custom role definition and assign only the “Microsoft.KeyVault/vaults/deploy/action” permissions.
Important
If a user has Contributor permissions to a key vault management plane, the user can grant themselves access to the data plane by setting a Key Vault access policy. You should tightly control who has Contributor role access to your key vaults. Ensure that only authorized persons can access and manage your key vaults, keys, secrets, and certificates.
Important
Key Vault access policies apply at the vault level. When a user is granted permission to create and delete keys, they can perform those operations on all keys in that key vault.
Important
If a user has Contributor permissions to a key vault management plane, the user can grant themselves access to the data plane by setting a Key Vault access policy. You should tightly control who has Contributor role access to your key vaults. Ensure that only authorized persons can access and manage your key vaults, keys, secrets, and certificates.
Read this too understand the Access model with Data plan and management plane for Keyvault.
Read how to setup KeyVault here
Secure your Keyvault
https://docs.microsoft.com/en-us/azure/key-vault/key-vault-secure-your-key-vault
Additional Links to read
- Key Vault troubleshooting: https://azidentity.azurewebsites.net/ by @KeyVaultGuy
- NetJoinDomain Functions: https://docs.microsoft.com/en-us/windows/win32/api/lmjoin/nf-lmjoin-netjoindomain?redirectedfrom=MSDN
Good read and very well explained.
Regarding the Key Vaults it is also interesting to check the azSK https://github.com/azsk/DevOpsKit-docs/blob/master/02-Secure-Development/ControlCoverage/Feature/KeyVault.md
Thanks for the comment, make sure you check the “flaws” section in part 3.
I touch on the AzSK in this post also.
http://azurefabric.com/quick-tip-for-azure-subscription-and-resource-security-baseline/
You have a very nice and informative blog here. In any case, I manage to deploy on VMs and to join existing VMs to domain.
Only I can’t manage to merge this process, so that a VM is automatically deployed via an ARM template and joined to on-prem domain in the same template. I have already set something up in KeyVault to be allowed to join with that account, but the template is not good somewhere. I hope you can help with this?