Interfaces
This page details the Bicep-specific interfaces/schemas for AVM Resource Modules features/extension resources.
Secrets used inside a module can be exported to a Key Vault reference provided as per the below schema. This implementation provides a secure way around the current limitation of Bicep on providing a secure template output (that can be used for secrets).
The user must
- provide the resource Id to a Key Vault. The principal used for the deployment must be allowed to set secrets in this Key Vault.
- provide a name for each secret they want to store (opt-in). The module will suggest which secrets are available via the implemented user-defined type.
The module returns an output table where the key is the name of the secret the user provided, and the value contains both the secret’s resource Id and URI.
The feature must be implemented as per the below schema. Diversions are only allowed in places marked as>text<
to ensure a consistent user experience across modules.
// ============== //
// Parameters //
// ============== //
@description('Optional. Key vault reference and secret settings for the module\'s secrets export.')
param secretsExportConfiguration secretsExportConfigurationType?
// ============= //
// Resources //
// ============= //
module secretsExport 'modules/keyVaultExport.bicep' = if (secretsExportConfiguration != null) {
name: '${uniqueString(deployment().name, location)}-secrets-kv'
scope: resourceGroup(
split((secretsExportConfiguration.?keyVaultResourceId ?? '//'), '/')[2],
split((secretsExportConfiguration.?keyVaultResourceId ?? '////'), '/')[4]
)
params: {
keyVaultName: last(split(secretsExportConfiguration.?keyVaultResourceId ?? '//', '/'))
secretsToSet: union(
[],
contains(secretsExportConfiguration!, '>secretToExport1<Name')
? [
{
name: secretsExportConfiguration!.>secretToExport1<Name
value: >secretReference1< // e.g., >singularMainResourceType<.listKeys().primaryMasterKey
}
]
: [],
contains(secretsExportConfiguration!, '>secretToExport2<Name')
? [
{
name: secretsExportConfiguration!.>secretToExport2<Name
value:>secretReference2< // e.g., >singularMainResourceType<.listKeys().secondaryMasterKey
}
]
: []
// (...)
)
}
}
// =========== //
// Outputs //
// =========== //
@description('A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret\'s name.')
output exportedSecrets secretsOutputType = (secretsExportConfiguration != null)
? toObject(secretsExport.outputs.secretsSet, secret => last(split(secret.secretResourceId, '/')), secret => secret)
: {}
// =============== //
// Definitions //
// =============== //
type secretsExportConfigurationType = {
@description('Required. The resource ID of the key vault where to store the secrets of this module.')
keyVaultResourceId: string
@description('Optional. The >secretToExport1< secret name to create.')
>secretToExport1<Name: string?
@description('Optional. The >secretToExport2< secret name to create.')
>secretToExport2<Name: string?
// (...)
}
import { secretSetType } from 'modules/keyVaultExport.bicep'
type secretsOutputType = {
@description('An exported secret\'s references.')
*: secretSetType
}
secretsExportConfiguration: {
keyVaultResourceId: '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.KeyVault/vaults/{keyVaultName}'
>secretToExport1<Name: 'myPrimarySecret'
>secretToExport2<Name: 'mySecondarySecret'
// (...)
}
// ============== //
// Parameters //
// ============== //
@description('Required. The name of the Key Vault to set the secrets in.')
param keyVaultName string
@description('Required. The secrets to set in the Key Vault.')
param secretsToSet secretToSetType[]
// ============= //
// Resources //
// ============= //
resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = {
name: keyVaultName
}
resource secrets 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = [
for secret in secretsToSet: {
name: secret.name
parent: keyVault
properties: {
value: secret.value
}
}
]
// =========== //
// Outputs //
// =========== //
@description('The references to the secrets exported to the provided Key Vault.')
output secretsSet secretSetType[] = [
#disable-next-line outputs-should-not-contain-secrets // Only returning the references, not a secret value
for index in range(0, length(secretsToSet ?? [])): {
secretResourceId: secrets[index].id
secretUri: secrets[index].properties.secretUri
}
]
// =============== //
// Definitions //
// =============== //
@export()
type secretSetType = {
@description('The resourceId of the exported secret.')
secretResourceId: string
@description('The secret URI of the exported secret.')
secretUri: string
}
type secretToSetType = {
@description('Required. The name of the secret to set.')
name: string
@description('Required. The value of the secret to set.')
@secure()
value: string
}
When using a module that implements the above interface, you can access its outputs for example in the following ways:
// Get all exported secret references
output exportedSecrets object = >deploymentReference<.outputs.exportedSecrets
// Get the resource Id of just the secret with name >secretToExport1<Name
output specificSecret string = >deploymentReference<.outputs.exportedSecrets.>secretToExport1<Name.secretResourceId
// Get the resource Ids of all secrets set
output exportedSecretResourceIds array = map(
items(>deploymentReference<.outputs.exportedSecrets),
item => item.value.secretResourceId
)
Which returns a JSON-formatted output like
{
"exportedSecrets": {
"Type": "Object",
"Value": {
">secretToExportName1<": {
"secretResourceId": "/subscriptions/<subId>/resourceGroups/<rgName>providers/Microsoft.KeyVault/vaults/<vaultName>/secrets/>secretToExportName1<",
"secretUri": "https://<vaultName>.vault.azure.net/secrets/>secretToExportName1<"
},
">secretToExportName2<": {
"secretResourceId": "/subscriptions/<subId>/resourceGroups/<rgName>providers/Microsoft.KeyVault/vaults/<vaultName>/secrets/>secretToExportName2<",
"secretUri": "https://<vaultName>.vault.azure.net/secrets/>secretToExportName2<"
}
}
},
"specificSecret": {
"Type": "String",
"Value": "/subscriptions/<subId>/resourceGroups/<rgName>providers/Microsoft.KeyVault/vaults/<vaultName>/secrets/>secretToExportName1<"
},
"exportedSecretResourceIds": {
"Type": "Array",
"Value": [
"/subscriptions/<subId>/resourceGroups/<rgName>providers/Microsoft.KeyVault/vaults/<vaultName>/secrets/>secretToExportName1<",
"/subscriptions/<subId>/resourceGroups/<rgName>providers/Microsoft.KeyVault/vaults/<vaultName>/secrets/>secretToExportName2<"
]
}
}