Key Vault & Secrets Management With Azure Bicep - Create, Reference, Output Examples
Key Vault is one of the core Azure services which comes in handy in many software solutions. It is the preferred service to manage secrets, certificates, and keys in the Azure environment.
Azure Key Vault Microsoft.KeyVault/vaults
and Secrets Microsoft.KeyVault/vaults/secrets
resources can be managed using Azure Bicep. Leveraging infrastructure as code (IaC) approach helps simplify resource deployment and increase maintainability of the overall system.
Azure Bicep is a great alternative to well-known ARM templates, it provides superior development experience and also feature parity when compared to ARM templates.
In this post, we will discuss how to deploy a key vault and secret using Azure Bicep. We also cover use cases such as how to add a secret to an existing key vault, reference it in another template, and more.
Contents:
Overview
In the first part of the post, we talk about the key vault resource type.
It contains the discussion of key vault resource properties, differences between permission models, and provides an annotated example of a Bicep template which deploys a key vault.
The second part is devoted to secrets management and related use cases.
Creating KV Secrets section shows how to create a secret using Bicep. We cover deployment of a secret together with its parent key vault, as well as adding a secret to an existing vault.
In the Using KV Secret’s Value section, we see how to use an existing key vault secret as an input to another template deployment, and also provide a quick example of outputting secret value if you want to do this.
Key Vault
Creating a key vault using Bicep is quite easy, the template is not that long and takes little time to get familiar with. However, there are some subtleties that one should be aware of.
We are not going to provide a comprehensive overview of the key vault capabilities in this post, but rather highlight features that are important when working with key vaults using Bicep and infrastructure as code approach. Read more about Key Vault in the documentation.
Access Policies vs Role-Based Access Control (RBAC)
Let’s say, we have a key vault with secrets, certificates, or keys in it. Now, we need to manage which applications or users are allowed, for example, to view, modify, or delete secrets.
Azure Key Vault has two alternative models of managing permissions to secrets, certificates, and keys:
- Access policies - an access policy allows us to specify which security principal (e.g. user, application, or group) what operations it can perform on secrets, certificates, or keys. Note that this is applied to all secrets/certificates/keys in the vault.
- Role-based access control (RBAC) - this model was introduced later, it leverages Azure RBAC to provide better control at the individual secret/certificate/key level.
The bottom line is that RBAC enables more fine-grained control over individual secrets, certificates, or keys compared to Access Policies. For example, using RBAC we can enforce that an application can read secret A, but cannot read any other secret in this vault.
Read detailed comparison of the models in Vault access policies to Azure RBAC migration guide.
Example Template Using Azure Bicep
Below is a simple Bicep file which declares a key vault resource. Feel free to use it as a base for your own key vault deployment.
Please note that this example shows many properties available for a Key Vault, but definitely not all, for example, we don’t cover networking part. For the full list please visit Microsoft.KeyVault/vaults.
The next section Vault Properties Explained describes these properties in detail.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// ========== keyvault.bicep ==========
resource keyVault 'Microsoft.KeyVault/vaults@2019-09-01' = {
name: 'kv-contoso3'
location: 'westus2'
properties: {
sku: {
family: 'A'
name: 'standard'
}
tenantId: subscription().tenantId
enableRbacAuthorization: false // Using Access Policies model
accessPolicies: [
{
objectId: 'd89101d9-cf97-4b6c-9656-c6da457d8add'
tenantId: tenantId
permissions: {
secrets: [
'all'
]
certificates: [
'all'
]
keys: [
'all'
]
}
}
]
enabledForDeployment: true // VMs can retrieve certificates
enabledForTemplateDeployment: true // ARM can retrieve values
enablePurgeProtection: true // Not allowing to purge key vault or its objects after deletion
enableSoftDelete: true
softDeleteRetentionInDays: 7
createMode: 'default' // Creating or updating the key vault (not recovering)
}
}
Vault Properties Explained
In this section, we briefly cover what certain properties from the template above are responsible for. This can help understand whether we need them in our template or not.
- accessPolicies - this property is required unless RBAC permissions model is used or
createMode
is set torecover
, e.g. we soft deleted the vault and now bringing it back - enabledForDeployment - Azure Virtual Machines and Virtual Machine Scale Sets integrate with Key Vault to retrieve certificates and install them on VMs when this setting is set to true
- enabledForTemplateDeployment - when set to true, Azure Resource Manager can retrieve secrets from this key vault during template deployment, this use case is described in “Use Key Vault Secret As Parameter” {link}
- enableRbacAuthorization - this setting determines which access model to use, these models are discussed in “Access Policies vs Role-Based Access Control (RBAC)” {link}
- tenantId - Azure Active Directory tenant ID
- SKU - there are two options:
standard
andpremium
, the only difference is that premium tier provides HSM-protected keys, where HSM stands for hardware security module. In most cases, the standard tier is used. - enableSoftDelete - if enabled then deleting a key vault or key/certificate/secret will not remove it completely, but it will be in soft deleted mode for the number of days specified in
softDeleteRetentionInDays
. This setting is set totrue
by default and cannot be changed tofalse
after vault is created. - softDeleteRetentionInDays - specifies for how long key vault will be kept in soft deleted mode before being deleted permanently. The value can be between 7 and 90 days. Note that without purge protection we still can go and irrecoverably delete an object in soft deleted state.
- enablePurgeProtection - if enabled (soft delete must also be enabled), then nobody can purge (permanently delete) the key vault or its keys/certificates/secrets in the soft deleted state, so it will irrecoverably deleted only when period of time specified in
softDeleteRetentionInDays
passes. For example, this won’t allow an adversary to completely delete secrets or certificates even if they get necessary permissions. - createMode - two possible values
default
andrecover
which are quite self-explanatory
Secrets
In this section, we discuss how to work with key vault secrets. In the first part, we cover creation and updates of secrets, and in the second part, we look at a couple of ways how to one might want to consume or use these secrets.
Creating KV Secrets
Secret is a child resource of a key vault, in other words, this means that secret cannot exist on its own and has to be created in the context of some key vault. The type of the secret resource is Microsoft.KeyVault/vaults/secrets
which suggests that it’s located inside of a key vault.
To learn more about child resources, please check out the post Child Resources In Azure Bicep - 3 Ways To Declare, Loops, Conditions.
The schema of the secret resource is quite simple and doesn’t have many properties, in the following examples we will only use value
property in addition to the secret name.
To learn more about additional properties such as content type, not before and expiration time, please refer to Microsoft.KeyVault/vaults/secrets bicep template reference.
Create/Set Key Vault Secret
In the following examples, we are declaring a basic key vault along with a secret deployed inside of it. We show two slightly different approaches both of which are described in 3 Ways To Declare Child Resources.
NOTE: The key vault in the snippets below has only the bare minimum set of properties just to illustrate the point, your key vault template will likely be more complicated.
[Option 1]
The first option is to declare the key vault and then pass its symbolic name to the parent
property of the secret resource definition, this is an implementation of declare child resource outside parent using “parent” property.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// ========== create-kv-secret-1.bicep ==========
// Create some simple key vault
resource keyVault 'Microsoft.KeyVault/vaults@2019-09-01' = {
name: 'kv-contoso'
location: resourceGroup().location
properties: {
sku: {
family: 'A'
name: 'standard'
}
tenantId: subscription().tenantId
accessPolicies: []
}
}
// Create a secret outside of key vault definition
resource secret 'Microsoft.KeyVault/vaults/secrets@2019-09-01' = {
name: 'mySecret'
parent: keyVault // Pass key vault symbolic name as parent
properties: {
value: 'mySecretValue'
}
}
[Option 2]
The second option is to declare secret resource inside of the key vault’s resource definition, this is an implementation of declare child resource within parent resource.
Note that the resource type of the secret is only secrets
, the rest is inferred from the parent resource.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// ========== create-kv-secret-2.bicep ==========
// Create some key vault
resource keyVault 'Microsoft.KeyVault/vaults@2019-09-01' = {
name: 'kv-contoso'
location: resourceGroup().location
properties: {
sku: {
family: 'A'
name: 'standard'
}
tenantId: subscription().tenantId
accessPolicies: []
}
// Create secret within parent key vault
resource secret 'secrets' = { // No need for full type name
name: 'mySecret'
properties: {
value: 'mySecretValue'
}
}
}
Add Secret To Existing Key Vault
It is possible to create a secret in an existing key vault without deploying the vault in the same template, this is due to the fact that secret is a child resource. So, even though it needs a reference to the parent, it can still be deployed separately.
The three options below are just different ways of creating a secret within a parent key vault, you can read more about 3 Ways To Declare Child Resources.
NOTE: In the code samples below, we assume that key vault kv-contoso
already exists in the same resource group where the deployment takes place.
[Option 1]
The first option is to declare a secret resource and specify the key vault name as the first segment in the secret resource’s name. See the example below for details.
Note that the property name
(line 6) consists of two segments separated by /
, where the first part is key vault name, and the second part is secret name.
Read more about how to declare child resource outside parent without “parent” property.
1
2
3
4
5
6
7
8
9
10
// ========== add-secret-to-existing-kv-1.bicep ==========
param vaultName string = 'kv-contoso'
resource secret 'Microsoft.KeyVault/vaults/secrets@2019-09-01' = {
name: '${vaultName}/mySecret' // The first part is KV's name
properties: {
value: 'mySecretValue'
}
}
[Option 2]
Another option is to declare symbolic name (line 5) for the key vault (keyVault
in the example below) and then pass it in the parent property of the secret resource (line 11).
Read more about ways how to reference existing resource in the post Reference New Or Existing Resource In Azure Bicep.
Read more about how to declare child resource outside parent with “parent” property.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// ========== add-secret-to-existing-kv-2.bicep ==========
param vaultName string = 'kv-contoso'
// Declaring a symbolic name for an existing key vault
resource keyVault 'Microsoft.KeyVault/vaults@2019-09-01' existing = {
name: vaultName
}
resource secret 'Microsoft.KeyVault/vaults/secrets@2019-09-01' = {
name: 'mySecret'
parent: keyVault // Passing key vault symbolic name as a parent for the secret
properties: {
value: 'mySecretValue'
}
}
[Option 3]
The idea here is similar to the previous option 2, but here we can put secret resource declaration inside of the parent key vault, this avoids the need to specify parent
property.
Note the type of the secret resource, in this case it’s just secrets
(line 7), this is because the rest is inferred from the parent including version.
Read more about how to declare child resource within parent resource.
1
2
3
4
5
6
7
8
9
10
11
12
13
param vaultName string = 'kv-contoso'
// Declaring a symbolic name for an existing KV
resource keyVault 'Microsoft.KeyVault/vaults@2019-09-01' existing = {
name: vaultName
resource secret 'secrets' = { // Type of the resource is just "secret"
name: 'mySecret' // Secret name, only one segment
properties: {
value: 'mySecretValue'
}
}
}
Using KV Secret’s Value
Key vault is the recommended way to store secrets, certificates, and keys in the Azure environment. Moreover, key vault can be used to store secrets not only for services inside of Azure but also those outside of it.
Since almost all Azure services require some sort of sensitive values to provide useful capabilities, it is not surprising that many Azure services provide integration with Key Vault service to directly retrieve secrets without the need for user to touch the values.
Reference Key Vault Secret In a Parameter
One very common way of using key vault secrets is to pass them to an ARM or Bicep template as a parameter, and then use secret when creating some resource.
We can pass a secret as a secure parameter into a template or a module:
- Template parameter - use a parameter file to specify which secret in which key vault we want to pass, details are described in Key Vault Secret Through Parameter File
- Module parameter - use Bicep’s
getSecret
function to retrieve and pass secret to a module, see details in Passing Key Vault Secret into Module
Output Key Vault Secret
This section describes a way to return the value of a secret from the template deployment using output
capabilities.
NOTE: Outputting secrets in the template deployment is insecure and not recommended, the value is passed in plaintext and also logged in the deployment history. Only consider this for non-production, e.g. testing or experimentation, purposes.
You might have noticed that Microsoft.KeyVault/vaults/secrets
resource has property named value
which we use it to set the value of the secret. However, this property doesn’t allow us to retrieve the actual value, this behavior is by design.
The workaround is to first pass secret’s value as a secure parameter in the way it’s described in the previous section Reference Key Vault Secret In a Parameter, and then return it in the outputs of the template.
To implement the approach described above, we will need two files: main template and parameters file. Read more in the post Using Key Vault Secrets As Secure Parameters In Azure Bicep - Template & Module Inputs.
1
2
3
4
5
// ========== output-secret.bicep ==========
@secure()
param secretValue string
output secretValue string = secretValue
Here is output-secret.parameters.json
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"secretValue": {
"reference": {
"keyVault": {
"id": "/subscriptions/3c6de895-4ccf-409f-8f18-ff8171a2a800/resourceGroups/rg-contoso/providers/Microsoft.KeyVault/vaults/kv-contoso"
},
"secretName": "mySecret"
}
}
}
}
Related Posts
- Using Key Vault Secrets As Secure Parameters In Azure Bicep - Template & Module Inputs
- Parameters In Azure Bicep - Ultimate Guide With Examples
- Variables In Azure Bicep - From Basics To Advanced
- Reference New Or Existing Resource In Azure Bicep
- Storage Account SAS Tokens, Access Keys, And Connection Strings In Azure Bicep
- Learn Modules In Azure Bicep - Basics To Advanced, How It Works, Nested Modules, Outputs, Scopes
- Child Resources In Azure Bicep - 3 Ways To Declare, Loops, Conditions
- 5 Ways To Deploy Bicep File With Parameters - Azure DevOps, PowerShell, CLI, Portal, Cloud Shell
- Deploy Azure Bicep In YAML and Classic Release Pipelines (CI/CD) - Azure DevOps
- Nested Loops In Azure Bicep - 4 Use Cases, For-Loop, Solutions & Workarounds