DEV Community

Olivier Miossec
Olivier Miossec

Posted on

1

Azure Machine Configuration, deploy DSC config to Azure VMs.

Azure Machine Configuration (also known as Azure Policy Guest Configuration) allows operators to configure Azure VMs OS as code via an Extension. It is like deploying an infrastructure with Bicep, Terraform, or ARM template, but for OS configuration.
It can use PowerShell DSC (v2 for Windows and v3 for Linux and Windows) or Chef InSpec for Linux.

In this post, I will cover DSC v2 for Windows.

To compile a DSC v2 configuration, you need a Windows OS machine, it won't work on Linux or macOS.
You also need several PowerShell modules, the PSDesiredStateConfiguration (but not the v3), PsdscResources, and GuestConfiguration.

install-module -name PSDesiredStateConfiguration -Repository PSGallery -MaximumVersion 2.99 -force
Enter fullscreen mode Exit fullscreen mode

This allow you to install the latest v2 version of DSC.

  install-module -name PsdscResources -Repository PSGallery -force
Enter fullscreen mode Exit fullscreen mode
Install-Module -Name GuestConfiguration -Repository PSGallery
Enter fullscreen mode Exit fullscreen mode

The DSC for the demo is simple; it just adds a registry key, ExampleKey1, with a value.

configuration demoDevTo {

    Import-DscResource -ModuleName 'PSDSCResources'

    Registry Registydemo
    {
        Ensure      = "Present"  
        Key         = "HKEY_LOCAL_MACHINE\SOFTWARE\ExampleKey1"
        ValueName   = "TestValue"
        ValueData   = "TestData"
        valueType  = "String"
    }
}
Enter fullscreen mode Exit fullscreen mode

The next step is to load the DSC configuration file on a Windows machine and compile it.

. .\demo.dsc.ps1
demoDevTo
Enter fullscreen mode Exit fullscreen mode

The result is a file named localhost.mof in a demoDecTo folder.

The next step is to create a configuration package that can be consumed by Azure Machine configuration.
First the localhost.mof file needs to be renamed to demodevto.mof

rename-item -path .\demoDevTo\localhost.mof -NewName "demodevto.mof" -passThru
Enter fullscreen mode Exit fullscreen mode

Then, with the help of the GuestConfiguration module, we can create the configuration package.

New-GuestConfigurationPackage -name "demodevto" -type "AuditAndSet" -Configuration ".\demoDevTo\demodevto.mof" -force $true 
Enter fullscreen mode Exit fullscreen mode

The cmdlet takes a name, the name of the package, a type that could be Audit (default value), to monitor the machine, or AuditAndSet for setting the state of the OS.

The cmdlet will generate a zip file containing the mof file, a metadata file, and the PowerShell module used by the DSC configuration file.

The demodevto.zip file must be sent to the container in a storage account so that VMs can download it.

$storageAccount = get-azStorageAccount -name "demodscomc001" -resourcegroup "demo-dsc"

set-azStorageBlobContent -container "packages" -file ".\demodevto.zip" -blob "demodevto.zip" -context $storageAccount.context -force 
Enter fullscreen mode Exit fullscreen mode

To execute the package on Azure VMs, they need a special configuration, an extension, AzurePolicyforWindows (or AzurePolicyforLinux for Linux VMs), and a system identity.

You can deploy the configuration with the same Infrastructure as Code you use to deploy the VM (Bicep ARM Template, Terraform).
For existing VMs, you can also use Azure Policy to deploy these requirements. You can use the Built-in initiative (look for “enable machine configuration policies” initiative), or you can use your policies.

Here’s an example for Windows VMs.

For System Managed Identity

For the Extension

After configuring VMs, the DSC configuration can be applied to them. You can use Infrastructure as Code, or you can use Azure Policy on existing and new VMs.

For both methods, you need to have the package's SAS URI.

$today = Get-Date
$expirationDate = $today.AddYears(1)


$strPackageURI = New-AzStorageBlobSASToken -Context $storageAccount.context -Container "packages" -Blob "demodevto.zip" -Permission r -ExpiryTime $expirationDate -FullUri
Enter fullscreen mode Exit fullscreen mode

If you want to deploy the configuration package using IaC, you must provide the sha-256 hash of the package zip file.

$packageHash = Get-FileHash -Path ./demodevto.zip -Algorithm SHA256
Enter fullscreen mode Exit fullscreen mode

Here’s the Bicep template to deploy the configuration to an existing VM.

@description('Name of the Configuration')
param configurationName string

@description('type of assignment')
@allowed([
  'ApplyAndAutoCorrect'
  'ApplyAndMonitor'
  'Audit'
  'DeployAndAutoCorrect'
])
param assignmentType string = 'ApplyAndAutoCorrect'

@description('The SAS URI of the package')
param packageSasUri string

@description('package SHA256 hash')
param packageHash string

@description('Target VM name')
param vmName string

resource targetVM 'Microsoft.Compute/virtualMachines@2021-03-01' existing = {
  name: vmName
}

resource myConfiguration 'Microsoft.GuestConfiguration/guestConfigurationAssignments@2020-06-25' = {
  name: configurationName
  scope: targetVM
  location: resourceGroup().location
  properties: {
    guestConfiguration: {
      name: configurationName
      contentUri: packageSasUri
      contentHash: packageHash
      version: '1.0.0'
      assignmentType: assignmentType
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

to deploy the configuration

New-AzResourceGroupDeployment -Name ParamDeployment -ResourceGroupName demo-dsc -TemplateFile ./deploy/bicep/main.bicep -configurationName "demodevto" -packageSasUri $strPackageURI -packageHash $packageHash.Hash -vmName "vm01"

Enter fullscreen mode Exit fullscreen mode

To create an Azure Policy for deploying the configuration package, you need to use the New-GuestConfigurationPolicy cmdlet to help you to create the policy.

$guid = new-guid

New-GuestConfigurationPolicy -policyId $guid.Guid -ContentUri $strPackageURI -DisplayName "demoDevTo" -Description "Demo Policy for Dev.to" -path "./deploy/policy/" -platform "windows" -policyVersion "1.0.0" -Mode "ApplyAndAutoCorrect"
Enter fullscreen mode Exit fullscreen mode

You need to have a Guid for the policy name, you need the blob URI of the package, a display Name and a description, the path to the folder to locally store the policy, the platform, the version of the configuration, and the mode (ApplyAndMonitor, ApplyAndAutoCorrect, or Audit).

You don't have to provide the SHA256 hash, the command will do it for you.

The command generates a deploy if not exist.

If you edit the policy, you need to ensure that the guestConfiguration metadata matches the deployment section in the policy.

        "metadata": {
            "category": "Guest Configuration",
            "version": "1.0.0",
            "requiredProviders": [
                "Microsoft.GuestConfiguration"
            ],
            "guestConfiguration": {
                "name": "demodevto",
                "version": "True",
                "contentType": "Custom",
                "contentUri": "https://demodscomc001.blob.core.windows.net/packages/demodevto.zip?sv=2023-08-03&se=2026-05-06T05%3A03%3A10Z&sr=b&sp=r&sig=6wKnMoLQ2hR4OD5cgUXBdHWOjBBDz95%2BfAT8BHOMk60%3D",
                "contentHash": "8A7AEFF27A8BA4F9806E757AA9927A2A41C45F5C6ACB25024A55BA37ED17908D"
            }
        }        "metadata": {
            "category": "Guest Configuration",
            "version": "1.0.0",
            "requiredProviders": [
                "Microsoft.GuestConfiguration"
            ],
            "guestConfiguration": {
                "name": "demodevto",
                "version": "True",
                "contentType": "Custom",
                "contentUri": "https://demodscomc001.blob.core.windows.net/packages/demodevto.zip?sv=2023-08-03&se=2026-05-06T05%3A03%3A10Z&sr=b&sp=r&sig=6wKnMoLQ2hR4OD5cgUXBdHWOjBBDz95%2BfAT8BHOMk60%3D",
                "contentHash": "8A7AEFF27A8BA4F9806E757AA9927A2A41C45F5C6ACB25024A55BA37ED17908D"
            }
        }
Enter fullscreen mode Exit fullscreen mode
                                            "guestConfiguration": {
                                                "name": "demodevto",
                                                "version": "True",
                                                "contentType": "Custom",
                                                "contentUri": "https://demodscomc001.blob.core.windows.net/packages/demodevto.zip?sv=2023-08-03&se=2026-05-06T05%3A03%3A10Z&sr=b&sp=r&sig=6wKnMoLQ2hR4OD5cgUXBdHWOjBBDz95%2BfAT8BHOMk60%3D",
                                                "contentHash": "8A7AEFF27A8BA4F9806E757AA9927A2A41C45F5C6ACB25024A55BA37ED17908D",
                                                "assignmentType": "ApplyAndAutoCorrect"
                                            }
Enter fullscreen mode Exit fullscreen mode

Also, pay attention to the "version" property in the Guest configuration; the command sets the value to "True" while it should be "1.0.0".

The "deploy if not exist" section targets Azure Virtual Machines, Azure ARC machines, and Azure Scale Set. You can remove this deployment if not needed.

The policy can be added in Azure and assigned to a VM, the deployment can be made when a new VM is created or when a remediation task is created.

At the end, you can see the result in the Azure Portal of the configuration.

Image description

Sentry image

Make it make sense

Only get the information you need to fix your code that’s broken with Sentry.

Start debugging →

Top comments (1)

Collapse
 
pherman profile image
Paige Herman

Great walkthrough! Deploying DSC configs with Azure Machine Configuration really streamlines OS management as code. Thanks for the clear steps!

ACI image

ACI.dev: Fully Open-source AI Agent Tool-Use Infra (Composio Alternative)

100% open-source tool-use platform (backend, dev portal, integration library, SDK/MCP) that connects your AI agents to 600+ tools with multi-tenant auth, granular permissions, and access through direct function calling or a unified MCP server.

Check out our GitHub!