Conditional creation of secrets in KeyVault #2848
-
When creating my keyvault I want to create the secrets empty first time the template runs, but if the secret already there I don't want it created. I found a function in the keyvault object called getSecret which returns the value of the secret if it exists, but if not, it returns an error and I don't know how to make a condition on it. Here is what I have so far... Module Create KeyVault Secret: param keyVaultName string
param secretName string
@secure()
param secretValue string
resource secretNotEmpty 'Microsoft.KeyVault/vaults/secrets@2019-09-01' = if ( !empty(secretValue) ) {
name: '${keyVaultName}/${secretName}'
properties: {
value: secretValue
contentType: 'string'
attributes: {
enabled: true
}
}
} The if part it's not evaluating the error that is happening. module secretModule 'KeyVaultSecret.bicep' = {
name: 'mySecret'
params: {
keyVaultName: keyVault.name
secretName: 'mySecret'
secretValue: keyVault.getSecret('mySecret')
}
} |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
@alessandromoura I believe we have a case of Schrödinger's secret 🙂 The getSecret method was implemented to work with module parameters, which in ARM map to nested deployments. There is no current way to retrieve secrets from the keyvault except as a parameter, based on the current security model. With that, the module parameter is the only place that you can use the getSecret() method in bicep. It's easiest to see what is going on, If you build the bicep file, so that you can view the ARM template that is created. bicep build foo.json resource kv 'Microsoft.KeyVault/vaults@2021-04-01-preview' existing = {
name: 'AEU2-BRW-AOA-P0-kvVLT01'
scope: resourceGroup('AEU2-BRW-AOA-RG-P0')
}
module test 'foo2.bicep' = {
name: 'test'
params: {
secreta: kv.getSecret('localadmin')
}
} sample of foo2.bicep @secure()
param secreta string
output secreta string = secreta which builds down to the following. {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"_generator": {
"name": "bicep",
"version": "0.4.1.14562",
"templateHash": "16332132949097935623"
}
},
"functions": [],
"resources": [
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2019-10-01",
"name": "test",
"properties": {
"expressionEvaluationOptions": {
"scope": "inner"
},
"mode": "Incremental",
"parameters": {
"secreta": {
"reference": {
"keyVault": {
"id": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, 'AEU2-BRW-AOA-RG-P0'), 'Microsoft.KeyVault/vaults', 'AEU2-BRW-AOA-P0-kvVLT01')]"
},
"secretName": "localadmin"
}
}
},
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"_generator": {
"name": "bicep",
"version": "0.4.1.14562",
"templateHash": "10355667585730244035"
}
},
"parameters": {
"secreta": {
"type": "secureString"
}
},
"functions": [],
"resources": [],
"outputs": {
"secreta": {
"type": "string",
"value": "[parameters('secreta')]"
}
}
}
}
}
]
} In particular notice this: keyVault.getSecret('mySecret') maps to this part... The only way to know if the secret exists, is to retrieve it via a parameter. However if you try to retrieve it and it doesn't exist, then you will get an error. I don't know of any way around this,... I agree the getSecret() method seems promising by itself, however it's just a mapping to the parameter. There have been discussions in the past about a listSecrets() method that works with other resource providers to be implemented via keyvault, however it has been determined that it doesn't fit with the security implementation in ARM (Azure Resource Manager). -- It's interesting that an alternative would be something like this. resource kv 'Microsoft.KeyVault/vaults/secrets@2021-04-01-preview' existing = {
name: 'AEU2-BRW-AOA-P0-kvVLT01/localadmin'
scope: resourceGroup('AEU2-BRW-AOA-RG-P0')
}
output kvaults object = kv which builds down to the following "outputs": {
"kvaults": {
"type": "object",
"value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, 'AEU2-BRW-AOA-RG-P0'), 'Microsoft.KeyVault/vaults/secrets', split('AEU2-BRW-AOA-P0-kvVLT01/localadmin', '/')[0], split('AEU2-BRW-AOA-P0-kvVLT01/localadmin', '/')[1]), '2021-04-01-preview', 'full')]"
}
} So this time it's doing a resourceID lookup to the resource first.. then the reference. I am not aware of any way to make a the resourceid(), extensionResourceId() or reference() methods fail silently. I think if there was going to be some feature request, perhaps that would be the one to ask for. |
Beta Was this translation helpful? Give feedback.
-
I'm looking back on this now in 2025. I had the same problem, and found a good solution here: https://fnbk.medium.com/generating-secure-random-passwords-in-azure-bicep-templates-755e962ec639 |
Beta Was this translation helpful? Give feedback.
@alessandromoura I believe we have a case of Schrödinger's secret 🙂
The getSecret method was implemented to work with module parameters, which in ARM map to nested deployments. There is no current way to retrieve secrets from the keyvault except as a parameter, based on the current security model. With that, the module parameter is the only place that you can use the getSecret() method in bicep.
It's easiest to see what is going on, If you build the bicep file, so that you can view the ARM template that is created.
bicep build foo.json