1

I have an issue similar to Retrieve a secret from keyvault in Bicep and use as input for Synapse Workspace creation

(Though I can’t continue the discussion there since I don’t have enough rep)

I need to have keyvault's and vm's created in the same bicep deployment template file. A secret generated in keyvault bicep module file should be used to set the password for local admin for the VM. All though it is not a requirement that the secret must be created at keyvault module level, I dont see any other way in order for the deployment to be secure.

This is the relevant part of the main bicep template:

module kv './modules/keyvault.bicep' = {     
  name: '${deployment().name}-kv'     
  scope: rg     
  params: {     
    keyvaultName: kvName    
    createLocalAdmin: true     
  }     
} 

resource kvRef 'Microsoft.KeyVault/vaults@2019-09-01' existing = {     
  name: kvName     
  scope: rg     
}      

module vm './modules/vm.bicep' = {     
  name: '${deployment().name}-vm-${vm.hostShortName}'     
  scope: rg     
  params: {     
    adminPassword: kvRef.getSecret('localadmin')     
    adminUsername: 'localadmin'     
  }     
  dependsOn: [     
    network     
    kv     
  ]     
} 

The challenge here is that when the bicep is deployed I get error: The specified KeyVault '<KEYVAULT_ID>’ could not be found. If I replace kvRef.getSecret('localadmin') with random valued string, the template is working fine.

In ARM template this can be solved with for example:

"adminPassword": {"Value":{
    "reference": { 
        "keyVault": { 
            "id":"concat(subscription().Id,'/resourceGroups/',variables('rgName'),'/providers/Microsoft.KeyVault/vaults/',reference('deploy-keyvault').outputs.KeyvaultName.value)]" 
         }, 
        "secretName": "[variables('localAdminSecretname')]" 
        } 
    } 
} 

Is there any way to do the same approach in bicep as the ARM example or solve this in any other way?

Sam Hall
  • 13
  • 3

2 Answers2

0

This is an order of operations/parallelism problem.

module kv './modules/keyvault.bicep' = {     
  name: '${deployment().name}-kv'     
  scope: rg     
  params: {     
    keyvaultName: kvName    
    createLocalAdmin: true     
  }     
} 

resource kvRef 'Microsoft.KeyVault/vaults@2019-09-01' existing = {     
  name: kvName     
  scope: rg     
}      

Each module runs as a sub-deployment, potentially in parallel. Bicep relies on reference usage to generate dependsOn references. i.e. if you had your module output a name property, then reference it as follows:

resource kvRef 'Microsoft.KeyVault/vaults@2019-09-01' existing = {     
  name: kv.outputs.name
  scope: rg     
}   

Bicep would be able to understand that one has to run before the other automatically. Since you're not doing that, you have to explicitly tell it.

The solution is to add a dependsOn to your existing keyvault, so it knows to wait for the prior module to complete.

resource kvRef 'Microsoft.KeyVault/vaults@2019-09-01' existing = {     
  name: kvName     
  scope: rg     
  dependsOn: [ kv ]
}   
Daniel Mann
  • 57,011
  • 13
  • 100
  • 120
  • Thanks for feedback. I tried that as well, but the property "dependsOn" is available not in "Microsoft.KeyVault/vaults". Does it work for you? Is dependsOn a preview feature on "Microsoft.KeyVault/vaults" ? I error message ; 'The property "dependsOn" is not allowed on objects of type "Microsoft.KeyVault/vaults".' – Sam Hall Dec 23 '21 at 10:38
  • You can't use dependsOn on existing resources – Guillaume LaHaye May 04 '23 at 06:46
0

Maybe you can consider splitting the deployment of Key Vault and the resources that need the instance you have just created like this:

https://github.com/mariomeyrelles/bicep-functions-cosmos-keyvault/blob/main/src/main.bicep

Mário Meyrelles
  • 1,594
  • 21
  • 26