I am trying to deploy different types of secrets using modules. The idea is to have "general" secrets, and the "storage related" secrets where the secret value is not passed directly but retrieved from properties of the storage. I designed the following Secret.bicep
:
param keyVaultName string
param secretName string
@secure()
param secretValue string
@allowed([
'general'
'storage_conn_string'
])
param secretType string = 'general'
@description('For secretType = storage_*, this is how we will be passing storage name')
param storageAccountName string = 'dummyvalue123'
resource kv 'Microsoft.KeyVault/vaults@2023-02-01' existing = {
name: keyVaultName
}
resource secret'Microsoft.KeyVault/vaults/secrets@2023-02-01' = if (secretType == 'general') {
parent: kv
name: secretName
properties: {
value: secretValue
}
}
// for secrets related to storage we will need to have storage resource:
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' existing = if (startsWith(secretType, 'storage_')) {
name: storageAccountName
}
// storage connection string
resource secret_conn_string 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = if (secretType == 'storage_conn_string') {
parent: kv
name: secretName
properties: {
value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}'
}
}
Now in main.bicep
I have the following:
@secure()
param secretValueAPIkey string
...
module secretStorageDataConnectionString 'modules/KeyVault/Secret.bicep' = {
// this needs to be a module and not a resource because we need
// to pass a connection string to storage, and storage is declared here as a module
// so we cannot use the listKeys() method
name: 'secretStorageDataConnectionString'
params: {
keyVaultName: kv.outputs.keyVaultName
secretType : 'storage_conn_string'
storageAccountName: storageAccount4data.outputs.dtls.name
secretName: 'secretStorageDataConnectionString'
secretValue: 'some-dummy-secret-value' //passing dummy value, we will retrieve it in via the module
}
}
module secretAPIkey 'modules/KeyVault/Secret.bicep' = {
name: 'secretAPIkey'
params: {
keyVaultName: kv.outputs.keyVaultName
secretType: 'general'
secretName: 'secretAPIkey'
secretValue: secretValueAPIkey
}
}
(Please note I skipped some bits e.g. the keyvault module, or storage module. They get deployed with no issue.)
EDIT:
storage account is created as a module:
module storageAccount4data 'modules/Storage/StorageAccount.bicep' = {
name: storageAccount4dataName
params: {
location: location
storageAccountName: storageAccount4dataName
}
}
StorageAccount.bicep:
param storageAccountName string
...
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
name: storageAccountName
location: location
sku: {
name: storageAccountSkuName
}
kind: 'StorageV2'
}
output dtls object = {
id: storageAccount.id
name: storageAccount.name
apiVersion: storageAccount.apiVersion
}
END OF EDIT
Now when deploying, the secretStorageDataConnectionString
module is created without any issues, but the secreAPIkey
module returns an error:
\"target\": \"/subscriptions/<...>/providers/Microsoft.Resources/deployments/secretAPIkey\"
\"message\": \"The Resource 'Microsoft.Storage/storageAccounts/dummyvalue123' under resource group <resource-group> was not found. ..."
For some reason the storage resource is still attempted to be created despite the if condition...?
I also tested using:
//secret.bicep
param storageAccountName string = ''
...
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' existing = if (!empty(storageAccountName)) {
name: storageAccountName
}
but this one also does not seem to evaluate correctly...
The issue is with the if
condition as it is not correctly evaluated in the bicep code.
Usually, if the storageAccountName
argument is left blank during deployment, the storage resource will not be created. If the storageAccountName
argument is not empty at deployment time, the storage resource is created even if it isn't specified in the secretAPIkey
module.
When you deploy the bicep code, make sure the storage account name is not empty even though it is provided to the module.
Everything worked as expected after giving the storage account name with the same code you used.
param storageAccountName string
secret.bicep:
param keyVaultName string = 'newvaultj'
param secretName string
@secure()
param secretValue string
@allowed([
'general'
'storage_conn_string'
])
param secretType string = 'general'
@description('For secretType = storage_*, this is how we will be passing storage name')
param storageAccountName string = 'xxxxx'
resource kv 'Microsoft.KeyVault/vaults@2023-02-01' existing = {
name: keyVaultName
}
resource secret'Microsoft.KeyVault/vaults/secrets@2023-02-01' = if (secretType == 'general') {
parent: kv
name: secretName
properties: {
value: secretValue
}
}
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' existing = if (startsWith(secretType, 'storage_')) {
name: storageAccountName
}
resource secret_conn_string 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = if (secretType == 'storage_conn_string') {
parent: kv
name: secretName
properties: {
value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}'
}
}
main.bicep:
@secure()
param secretValueAPIkey string = 'newapikey'
param keyVaultName string = 'newvaultj'
param storageAccountName string = 'xxxxx'
module secretStorageDataConnectionString 'secret.bicep' = {
name: 'secretStorageDataConnectionString'
params: {
keyVaultName: kv.name
secretType : 'storage_conn_string'
storageAccountName: storageAccount.name
secretName: 'secretStorageDataConnectionString'
secretValue: 'some-dummy-secret-value'
}
}
module secretAPIkey 'secret.bicep' = {
name: 'secretAPIkey'
params: {
keyVaultName: kv.name
secretType: 'general'
secretName: 'secretAPIkey'
secretValue: secretValueAPIkey
}
}
Updated code:
param secretValueAPIkey string = 'newapikey'
param keyVaultName string = 'newvaultj'
param storageAccountName string = 'jaxxxx9920'
param location string = resourceGroup().location
resource kv 'Microsoft.KeyVault/vaults@2023-02-01' existing = {
name: keyVaultName
}
module storageAccount4data 'StorageAccount.bicep' = {
name: storageAccountName
params: {
location: location
storageAccountName: storageAccountName
}
}
module secretStorageDataConnectionString 'secret.bicep' = {
name: 'secretStorageDataConnectionString'
params: {
keyVaultName: kv.name
secretType : 'storage_conn_string'
storageAccountName: storageAccount4data.name
secretName: 'secretStorageDataConnectionString'
secretValue: 'some-dummy-secret-value' //passing dummy value, we will retrieve it in via the module
}
}
module secretAPIkey 'secret.bicep' = {
name: 'secretAPIkey'
params: {
keyVaultName: kv.name
secretType: 'general'
secretName: 'secretAPIkey'
secretValue: secretValueAPIkey
}
}
Deployment succeeded: