This tutorial shows how to create the infrastructure required to host a web app which can retrieve secrets from a secure store (Keyvault) using Azure identity. In this tutorial, we’ll store the key for a storage account in Keyvault, but it could be anything. We’ll cover the following steps:
Start by creating the three main resources we need: a web app, storage account and key vault in the following order:
open Farmer
open Farmer.Builders
let datastore = storageAccount {
name "<storage name goes here>"
}
let webapplication = webApp {
name "<web app name goes here>"
}
let secretsvault = keyVault {
name "<key vault name goes here>"
}
Let’s now add the storage account key to the key vault:
let secretsvault = keyVault {
name "isaacsupersecret"
add_secret ("storagekey", datastore.Key)
}
Now we have KeyVault grant permission to the web app:
let webapplication = webApp {
...
system_identity
}
let secretsvault = keyVault {
...
add_access_policy (AccessPolicy.create webapplication.SystemIdentity)
}
The AccessPolicy.create
builder method has several overloads; this one grants basic GET and LIST permissions to the web application’s built-in system identity, which we have just activated above. You can also supply other permissions as a secondary argument to the create
method.
Now, we use Farmer’s Web App / Keyvault integration to seamlessly provide access to key vault secrets:
let webapplication = webApp {
...
link_to_keyvault (ResourceName "<key vault name goes here>")
secret_setting "storagekey"
}
or
let kv = keyVault {
name "keyvault"
}
let webapplication = webApp {
...
link_to_keyvault kv
secret_setting "storagekey"
}
The first keyword “links” the vault with the web app, and tells Farmer that all “secret” settings should now be read from this vault. We cannot reference the keyvault directly in this case because it’s declared after the web application, so we construct a ResourceId
reference ourselves.
The second keyword actually adds the secret to the web app. If you hadn’t added the link_to_keyvault
keyword, this would be rendered into ARM as a secret parameter, but in this case because we’ve linked the vault in, it gets redirected to point there instead.
To prevent accidentally mistyping the secret or vault names, you should bind the magic strings into symbols at the top of the template and replace usages in the template.
let secretName = "storagekey"
let vaultName = "<key vault name goes here>"
Add all the resources into an arm
builder and then deploy the template as normal.
let template = arm {
location Location.WestEurope
add_resources [
secretsvault
datastore
webapplication
]
}
You now have a web application that can read the secret from the vault without using any keyvault connection string. If you log into the portal, you’ll see that the secret setting is indeed in the Configuration section, but will have a green tick and a “Key vault reference” message next to it:
The value of the secret will look something like this:
@Microsoft.KeyVault(SecretUri=https://<key vault name goes here>.vault.azure.net/secrets/storagekey)
The App Service will transparently retrieve the secret from the vault for you when you try to access the setting.
By default, even you will not be able to access the secret from key vault! If you want to grant yourself access to the secret in the vault, you can use the
AccessPolicy.findUsers
method in code to retrieve your principal and grant access to the secret through Farmer. Alternatively, you can manually grant yourself access through the Portal etc.