Add a KeyVault to the ARM template. migrate the API and storage keys to the keyvault. Use the keyvault instead of the keys in the ARM template and application.
- Lab 7 - Security - KeyVault
- Goal
- Let's code!
- 1. Create an identity for the App
- 2. Create a KeyVault to store secrets
- 3. Give the app access to the KeyVault's secrets
- 4. Move storage account key to KeyVault
- 5. Modify the app to get the Storage Account Keys from KeyVault
- 6. Optional: try to do the same thing with the ComputerVision API key
- Reference
- End
In order to access different azure services our app will need an identity.
- Login to the azure portal
- Use the search bar to get to the "Active Directory" service
- On the left side select "App registrations" then click on "New application registration
- Select a name and assign a Sign-on URL (can be anything and doesn't need to point to a valid website)
- Create a key for you app, click on settings, then keys, then add a new key and click save
- Copy the Application ID and the newly created secret value in a notepad, we'll need them later
- Back to ActiveDirectory blade -> Enterprise applications -> find you app -> copy the "object id" property in a notepad, we'll need it later
- Open the ARM template we created in Lab2
- Add a new resource for KeyVault
{
"type": "Microsoft.KeyVault/vaults",
"apiVersion": "2018-02-14",
"name": "[parameters('keyVaultName')]",
"location": "[resourceGroup().location]",
"properties": {
"enabledForDeployment": true,
"enabledForTemplateDeployment": true,
"enabledForDiskEncryption": true,
"tenantId": "[subscription().tenantId]",
"accessPolicies": [],
"sku": {
"name": "standard",
"family": "A"
},
"resources": [],
"dependsOn": []
}
}
TIP: note that we are using template expressions like
[resourceGroup().location]
and[subscription().tenantId]
to fill out automatically some values relative to the location where the resource will be deployed.
- Add a new parameter named
keyVaultName
and select a default value
"keyVaultName": {
"defaultValue": "gabc-key-vault",
"type": "string"
}
- Run the script to deploy a KeyVault
In order to retrieve a secret from KeyVault you need to give explicit permission.
- Modify the ARM template to add an access policy that will give access to our app
"accessPolicies": [
{
"tenantId" : "[subscription().tenantId]",
"objectId": "[parameters('applicationObjectId')]",
"permissions": {
"secrets": [
"get",
"list"
]
}
}]
- Add a new parameter named
applicationObjectId
and set the default value to theObjectId
we got from Step 1.6
"applicationObjectId": {
"defaultValue": "<YOUR OBJECT ID VALUE HERE>",
"type": "string"
}
Wouldn't it be great if the ARM template could provision the Storage Account and save the dynamically generated access keys to keyVault? Let's see how to do it!
- Modify the ARM template to add a new resource
{
"type": "Microsoft.KeyVault/vaults/secrets",
"name": "[concat(parameters('keyVaultName'), '/ConnectionStrings--ApplicationStorage')]",
"apiVersion": "2016-10-01",
"location": "[resourceGroup().location]",
"properties": {
"value": "[Concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageName')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value)]"
},
"resources": [],
"dependsOn": []
}
This resource will create a new secret in key vault by retrieving automatically the value from the storage account once it's provisioned
Alright now that everything is provisioned correctly in azure, it's time to modify the web application and get the secret from KeyVault instead of using an hardcoded value.
5.1 install the Azure key vault package with dotnet add package Microsoft.Extensions.Configuration.AzureKeyVault
5.2 Open program.cs
and modify the CreateWebHostBuilder
method to
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, config) =>
{
var builtConfig = config.Build();
config.AddAzureKeyVault(
$"https://{builtConfig["Keys:KeyVault:Name"]}.vault.azure.net/",
builtConfig["Keys:KeyVault:AzureADApplicationId"],
builtConfig["Keys:KeyVault:AzureADPassword"]);
})
.UseStartup<Startup>();
5.3 Open appsettings.json
and remove
"ConnectionStrings": {
"ApplicationStorage": "DefaultEndpointsProtocol=https;AccountName=stgnzjquoqzu3sbs;AccountKey=JoPA4L7YY8abPoGHypGu2MLtR+dIk+39Pm14QWRjiuGm2fUMQopMy2dEpL98ESv8NomfDjY+wQlovfLcYgIv0w==;EndpointSuffix=core.windows.net"
},
as it will now be loaded from your key vault.
While you're there add the following keys to your appsetting.json
{
"Keys": {
"KeyVault":{
"Name": "<YOUR KEYVAULT NAME HERE>",
"AzureADApplicationId": "<YOUR KEYVAULT AzureADApplicationId HERE>",
"AzureADPassword": "<YOUR KEYVAULT AzureADPassword HERE>"
}
}
}
5.4 Run the application and make sure everything still work