Bicep – Create secret if not exists in KeyVault

I wanted to set a password for the admin account of the VM I was creating via Bicep. But I ran into some limitations there. Here how I solved it.

The first issue I ran into: I setup my bicep template in such a way, that a new password was generated on each deployment and added to the KeyVault. The new value was also assigned to the VM admin account in the bicep template. However, when the VM already existed, the password wasn’t changed. This caused some pain after a few deployments to figure out which password was valid.

So I figured I need to change my bicep template in a way, so it only generates a new password when the secret is not already present in KeyVault. If not present, it will generate one. Of course you could also check if the VM already exists, but I chose for the secret check.

Unfortunately there is no built in functionality in bicep (yet) that let’s you do these things. So I had to use some custom powershell script as a deployment script within bicep to support this scenario.

Here the bicep I came up with:

@description('The name of the key vault.')
param keyVaultName string
@description('The name of the secret that needs to be added.')
param secretName string
param location string = resourceGroup().location
param utcValue string = utcNow()

var userAssignedIdentityName = 'keyVaultHandler'

// First create a user assigned managed identity, that has access to the keyvault and can list and add the secret
resource userAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
  name: userAssignedIdentityName
  location: location
}

resource keyVault 'Microsoft.KeyVault/vaults@2021-10-01' existing = {
  name: keyVaultName
}

resource userAssignedIdentityKeyVaultAccessPolicy 'Microsoft.KeyVault/vaults/accessPolicies@2021-06-01-preview' = {
  name: 'add'
  parent: keyVault
  properties: {
    accessPolicies: [
      {
        permissions: {
          secrets: [
            'get'
            'list'
            'set'
          ]
        }
        tenantId: userAssignedIdentity.properties.tenantId
        objectId: userAssignedIdentity.properties.principalId
      }
    ]
  }
}

// Check if secret exists.
resource checkIfSecretExistsInKeyVault 'Microsoft.Resources/deploymentScripts@2020-10-01' = {
  name:  'checkIfSecretExistsInKeyVault'
  location: location
  kind: 'AzurePowerShell'
  identity: {
    type: 'UserAssigned'
    userAssignedIdentities: {
      '${ userAssignedIdentity.id }': {}
    }
  }
  properties: {
    azPowerShellVersion: '8.1'
    forceUpdateTag: utcValue // required for unique per deployment
    retentionInterval: 'PT1H'
    timeout: 'PT30M'
    cleanupPreference: 'Always'
    arguments: '-keyVaultName ${keyVaultName} -secretName ${secretName}'
    scriptContent: '''
      param([string] $keyVaultName, [string]$secretName)

      # Check if the secret already exists
      $secret = Get-AzKeyVaultSecret -VaultName $keyVaultName -Name $secretName

      if($secret -eq $null){
          Write-Host "Secret [$secretName] doesn't exist yet in keyVault [$keyVaultName]"

          #Generate a random password with length 20. 
          $secretValue = ConvertTo-SecureString (-join([char[]](42..122) | Get-Random -Count 20)) -AsPlainText -Force

          Set-AzKeyVaultSecret -VaultName $keyVaultName -Name $secretName -SecretValue $secretValue
      }

      Write-Host "Secret exists."
    '''
  }
  dependsOn: [
    userAssignedIdentityKeyVaultAccessPolicy
  ]
}

First I had to create a user assigned identity that has access to the KeyVault to verify if the secret is already present and create one if needed.

Next I use a deployment script running as the just created user assigned identity, to check if the secret is present. If that’s the case it will end there. If it doesn’t exists it generates a random password with the length of 20.

Hope this helps.

The type or namespace name ‘ServiceBus’ does not exist in the namespace ‘Microsoft.Azure’

I was trying to create an Azure Function with an NServicebus trigger, but kept receiving the error in the title on build. Since it took me some time figure out what was actually causing it, here what I discovered. So I started of creating a new Azure Function with Service Bus trigger in Visual Studio […]

Azure Functions – May not scale error – modified configuration

One of the things I love to add to my Azure Functions are environments specific app settings files. Anybody that has been working with ASP .NET Core will be familiar with them and in my opinion, they are great to store your non-secret environment-specific settings. Since Microsoft start supporting them easily in Azure Functions, I […]

Onvoldoende opslagruimte Samsung Galaxy S5 – SD-kaart slim inzetten

Eerder schreef ik hier al hoe je ruimte op je Samsung Galaxy S5 (of andere Android telefoon) kunt maken door de cache gegevens zo nu en dan op te schonen. Een nadeel hiervan is dat het na verloop van tijd niet echt heel veel meer oplevert, zelfs ookal heb je voldoende ruimte op je SD-kaart beschikbaar. Hier nu een […]

Solve your storage problems on Samsung Galaxy S5 with Adoptable Storage

One of the most annoying things on my Samsung Galaxy S5 is the fact it I am running out of internal storage capacity all the time. Every time I was cleaning the cache or trying to move apps to the SD card, but each time an updated was installed the apps were back on my internal […]