While I have cleaned up the instructions a bit to make them easier to read I feel this is not accurate enough to fully understand what is happening, nor is it using the new standards like Role Based Access Controls (RBAC).
Create the Key Vault
Key Vault names must be globally unique, so pick a unique name. Vault names must be 3-24 characters long and contain only alphanumeric characters and dashes. Make a note of the vault name you choose, because you need it throughout this exercise.
az provider list --output table
az provider register --namespace Microsoft.KeyVault
az provider register --namespace Microsoft.Web
az provider show -n Microsoft.KeyVault
az provider show -n Microsoft.Web
To create your vault, run the following command in Azure Cloud Shell. Make sure to enter your unique vault name to the --name
parameter. When it finishes, you will see JSON output describing the new vault.
Azure CLI
az keyvault create \
--resource-group "[sandbox resource group name]" \
--location customize \
--name <your-unique-vault-name>
Add Permissions
The next command requires you to use the legacy permission systems. Make sure to go into the portal, open up the keyvault, go to access configuration, and select vault access policy.
Azure CLI
az keyvault set-policy --name drJkeyVault --object-id "e96d1428-b041-404....." --secret-permissions all --key-permissions all --certificate-permissions all
--object-id is located in the keyvaults json
Add the secret
Now, add the secret. Our secret is named SecretPassword
with a value of reindeer_flotilla
. Make sure to replace <your-unique-vault-name>
with the vault name you created in the --vault-name
parameter.
Azure CLI
az keyvault secret set \
--name SecretPassword \
--value reindeer_flotilla \
--vault-name <your-unique-vault-name>
Create the app
Run the following code in Azure CLI to initialize a new Node.js app, install the needed packages, and open a new file in the editor.
mkdir KeyVaultDemoApp
cd KeyVaultDemoApp
npm init -y
npm install @azure/identity @azure/keyvault-secrets express
touch app.js
code app.js
Add code that loads and uses secrets
To demonstrate good use of Key Vault, your app loads secrets from the vault at startup. To demonstrate that your secrets loaded, create an endpoint that displays the value of the SecretPassword
secret.
- To set up the app, paste the following code into the editor. This code imports the necessary packages, sets up the port and vault URI configuration, and creates a new object to hold the secret names and values.
// Importing dependencies
const { DefaultAzureCredential } = require("@azure/identity");
const { SecretClient } = require("@azure/keyvault-secrets");
const app = require('express')();
// Initialize port
const port = process.env.PORT || 3000;
// Create Vault URI from App Settings
const vaultUri = `https://${process.env.VaultName}.vault.azure.net/`;
// Map of key vault secret names to values
let vaultSecretsMap = {};
Make sure to save files as you work on them, especially when you're finished. You can save files either through the "..." menu, or the accelerator key (Ctrl+S on Windows and Linux, Cmd+S on macOS).
- Next, add the code to authenticate to the vault and load the secrets. You add this code as two separate functions. Insert a couple of blank lines after the code you previously added, and then paste in the following code.
const getKeyVaultSecrets = async () => {
// Create a key vault secret client
let secretClient = new SecretClient(vaultUri, new DefaultAzureCredential());
try {
// Iterate through each secret in the vault
listPropertiesOfSecrets = secretClient.listPropertiesOfSecrets();
while (true) {
let { done, value } = await listPropertiesOfSecrets.next();
if (done) {
break;
}
// Only load enabled secrets - getSecret will return an error for disabled secrets
if (value.enabled) {
const secret = await secretClient.getSecret(value.name);
vaultSecretsMap[value.name] = secret.value;
}
}
} catch(err) {
console.log(err.message)
}
}
- To test whether our secret was loaded, create the Express endpoint. Paste in this code.
app.get('/api/SecretTest', (req, res) => {
let secretName = 'SecretPassword';
let response;
if (secretName in vaultSecretsMap) {
response = `Secret value: ${vaultSecretsMap[secretName]}\n\nThis is for testing only! Never output a secret to a response or anywhere else in a real app!`;
} else {
response = `Error: No secret named ${secretName} was found...`
}
res.type('text');
res.send(response);
});
- Call your functions to load the secrets from our vault, then start the app. To complete the app, paste in this last snippet.
(async () => {
await getKeyVaultSecrets();
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
})().catch(err => console.log(err));
- Save the file & Quit.
Create the App Service plan and app
Creating an App Service app is a two-step process: First create the plan, then the app.
The plan name only needs to be unique within your subscription, so you can use the same name: keyvault-exercise-plan
. The app name needs to be globally unique, though, so pick your own.
- In Azure Cloud Shell, run the following command to create an App Service plan.
az appservice plan create \
--name keyvault-exercise-plan \
--sku FREE \
--location centralus \
--resource-group "[sandbox resource group name]"
- Next, to create the Web App that uses the App Service plan you created, run the following command. Make sure to replace
<your-unique-app-name>
with your app's name in the--name
parameter.
az webapp create \
--plan keyvault-exercise-plan \
--runtime "node|22LTS" \
--resource-group "[sandbox resource group name]" \
--name <your-unique-app-name>
Add configuration to the app
To deploy to Azure, follow the App Service best practice of putting the VaultName
configuration in an app setting instead of a configuration file. You also set the SCM_DO_BUILD_DURING_DEPLOYMENT
setting to true
so that App Service restores your app's packages on the server and creates the necessary configuration to run the app. To create the app settings, run this command. Make sure to replace both <your-unique-app-name>
with your app's name in the --name
parameter, and <your-unique-vault-name>
with your vault's name in the --settings
parameter.
az webapp config appsettings set \
--resource-group "[sandbox resource group name]" \
--name <your-unique-app-name> \
--settings 'VaultName=<your-unique-vault-name>' 'SCM_DO_BUILD_DURING_DEPLOYMENT=true'
Enable Managed Identity
Enabling managed identity on an app is a one-liner. To enable it on your app, run the following command. Make sure to replace <your-unique-app-name>
with your app's name in the --name
parameter.
az webapp identity assign \
--resource-group "[sandbox resource group name]" \
--name <your-unique-app-name>
From the resulting JSON output, copy the principalId
value. PrincipalId
is the unique ID of the app's new identity in Microsoft Entra ID, and you're going to use it in the next step.
Grant Access to the Vault
The last step before deploying is to assign Key Vault permissions to your app's managed identity. Make sure to replace both <your-unique-vault-name>
with your vault's name in the --name
parameter, and enter the principalId
value you copied from the previous step as the value for object-id
in the following command. To establish Get
and List
access, run this command.
az keyvault set-policy \
--secret-permissions get list \
--name <your-unique-vault-name> \
--object-id <your-managed-identity-principleid>
Check for secrets
az keyvault secret list --vault-name `<your-unique-vault-name>
Deploy the App and Find out
- All your configuration is set, and you're ready to deploy! The following commands publish the site to the pub folder, zip it up into site.zip, and deploy the zip to App Service. Make sure to replace
<your-unique-app-name>
with your app's name in the--name
parameter.
You'll need to cd
back to the KeyVaultDemoApp directory if you're not still there.
cd KeyVaultDemoApp
zip site.zip * -x node_modules/
az webapp deploy --src-path site.zip -g "[sandbox resource group name]" -n <your-unique-app-name>
- The deployment might take a minute or two to complete. After you get a result that indicates that the site deployed, open
https://<your-unique-app-name>.azurewebsites.net/api/SecretTest
in a browser. The app takes a moment to start up for the first time on the server, but after it does, you should see the secret value, reindeer_flotilla.