Skip to content
This repository was archived by the owner on Jun 17, 2024. It is now read-only.

Commit 685c12e

Browse files
tzhanljongio
authored andcommitted
Move to Track2 (#7)
1 parent e6ff686 commit 685c12e

File tree

10 files changed

+519
-1203
lines changed

10 files changed

+519
-1203
lines changed

README.md

Lines changed: 91 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -2,157 +2,133 @@
22
page_type: sample
33
languages:
44
- javascript
5+
- nodejs
56
products:
6-
- azure
7-
description: "For Service-to-Azure-Service authentication, the approach so far involved creating an Azure AD application and associated credential,"
8-
urlFragment: app-service-msi-keyvault-node
7+
- azure-key-vault
8+
- azure-app-service
9+
description: "How to set and get secrets from Azure Key Vault with Azure Managed Identities and Node.js."
10+
urlFragment: get-set-keyvault-secrets-managed-id-nodejs
911
---
1012

11-
# Use Key Vault from App Service with Managed Service Identity and Nodejs
13+
# How to set and get secrets from Azure Key Vault with Azure Managed Identities and Node.js
1214

13-
## Background
14-
For Service-to-Azure-Service authentication, the approach so far involved creating an Azure AD application and associated credential, and using that credential to get a token. While this approach works well, there are two shortcomings:
15-
1. The Azure AD application credentials are typically hard coded in source code. Developers tend to push the code to source repositories as-is, which leads to credentials in source.
16-
2. The Azure AD application credentials expire, and so need to be renewed, else can lead to application downtime.
15+
## SDK Versions
16+
In this sample, you will find the following folders:
17+
* **v3** - references Key Vault SDK v3
18+
* **v4** - references Key Vault SDK v4
1719

18-
With [Managed Service Identity (MSI)](https://docs.microsoft.com/en-us/azure/app-service/app-service-managed-service-identity), both these problems are solved. This sample shows how a Web App can authenticate to Azure Key Vault without the need to explicitly create an Azure AD application or manage its credentials.
20+
## Introduction
21+
This sample will show how a Web App gets a secret at runtime from Azure Key Vault using a developer account during development, and using Azure Managed Identities when deployed to Azure, without any code changes between local development environment and Azure. As a result, you don't have to explicitly handle a service principal credential to authenticate to Azure AD to get a token to call Key Vault. You also don't have to worry about renewing the service principal credential either, since Azure Managed Identities takes care of that.
1922

20-
>Here's another sample that how to use MSI from inside an Azure VM with a Managed Service Identity (MSI) - [https://github.com/Azure-Samples/resource-manager-node-manage-resources-with-msi](https://github.com/Azure-Samples/resource-manager-node-manage-resources-with-msi)
2123

2224
## Prerequisites
2325
To run and deploy this sample, you need the following:
24-
1. An Azure subscription to create an App Service and a Key Vault.
26+
* [Node.js]
27+
* [Git]
28+
* An Azure subscription to create a Key Vault and other services, such as App Service, used in this sample.
29+
* An App registration to authenticate.
2530

26-
### Step 1: Create an App Service with a Managed Service Identity (MSI)
27-
<a href="https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure-Samples%2Fapp-service-msi-keyvault-node%2Fmaster%2Fazuredeploy.json" target="_blank">
28-
<img src="http://azuredeploy.net/deploybutton.png"/>
29-
</a>
31+
If you don't have an Azure subscription or App registration, create a [free account] or [App registration] before you begin.
3032

31-
Use the "Deploy to Azure" button to deploy an ARM template to create the following resources:
32-
1. App Service with MSI.
33-
2. Key Vault with a secret, and an access policy that grants the App Service access to **Get Secrets**.
34-
>Note: When filling out the template you will see a textbox labelled 'Key Vault Secret'. Enter a secret value there. A secret with the name 'secret' and value from what you entered will be created in the Key Vault.
33+
### Step 1: Create an Azure Key Vault and add a secret
34+
* Create an [Azure Key Vault] from Azure Portal.
35+
* [Add a secret].
3536

36-
Review the resources created using the Azure portal. You should see an App Service and a Key Vault. View the access policies of the Key Vault to see that the App Service has access to it.
37-
38-
### Step 2: Grant yourself data plane access to the Key Vault
39-
Using the Azure Portal, go to the Key Vault's access policies, and grant yourself **Secret Management** access to the Key Vault. This will allow you to run the application on your local development machine.
40-
41-
1. Search for your Key Vault in “Search Resources dialog box” in Azure Portal.
42-
2. Select "Overview", and click on Access policies
43-
3. Click on "Add New", select "Secret Management" from the dropdown for "Configure from template"
44-
4. Click on "Select Principal", add your account
45-
5. Save the Access Policies
46-
47-
You can also create an Azure service principal either through
48-
[Azure CLI](https://azure.microsoft.com/documentation/articles/resource-group-authenticate-service-principal-cli/),
49-
[PowerShell](https://azure.microsoft.com/documentation/articles/resource-group-authenticate-service-principal/)
50-
or [the portal](https://azure.microsoft.com/documentation/articles/resource-group-create-service-principal-portal/)
51-
and grant it the same access.
37+
### Step 2: Grant yourself Secret Management access to the Key Vault
38+
From the Azure Portal, go to the Key Vault's access policies, and grant yourself **Secret Management** access to the Key Vault. This will allow you to run the application on your local development machine.
5239

40+
* On your Key Vault **Settings** pages, Select **Access policies**.
41+
* Click on **Add Access Policy**.
42+
* Set **Configure from template (optional)** to **Secret Management**.
43+
* Click on **Select Principal**, add your App registration.
44+
* Click on **Add**.
45+
* Click on **Save** to save the Access Policies.
5346

5447
## Local dev installation
48+
1. Clone the repository.
5549

56-
1. If you don't already have it, [get node.js](https://nodejs.org).
50+
``` bash
51+
git clone https://github.com/Azure-Samples/azure-sdk-for-js-keyvault-secrets-get-nodejs-managedid.git
52+
```
5753

54+
2. Run the following command to install dependencies for "SDK version 3" and "SDK version 4":
5855

59-
1. Clone the repository.
56+
- SDK version 4
6057

61-
```
62-
git clone https://github.com/Azure-Samples/app-service-msi-keyvault-node.git
58+
``` cmd
59+
cd v4
60+
npm install
6361
```
6462

65-
2. Install the dependencies using pip.
63+
- SDK version 3
6664

67-
```
68-
cd app-service-msi-keyvault-node
65+
``` cmd
66+
cd v3
6967
npm install
7068
```
7169

72-
3. Set up the environment variable `KEY_VAULT_URL` with your KeyVault URL or replace the variable in the index.js file.
73-
74-
1. Export these environment variables into your current shell or update the credentials in the index.js file.
70+
3. Set up the following environment variables or replace these variables in the index.js file.
7571

72+
Linux
73+
``` bash
74+
export KEY_VAULT_URL = "<YourKeyVaultUrl>"
75+
export SECRET_NAME = "<YourSecretName>"
76+
export SECRET_VERSION = "<YourSecretVersion>"
77+
export AZURE_TENANT_ID = "<YourTenantId>"
78+
export AZURE_CLIENT_ID = "<YourClientId>"
79+
export AZURE_CLIENT_SECRET = "<YourClientSecret>"
7680
```
77-
export AZURE_TENANT_ID={your tenant id}
78-
export AZURE_CLIENT_ID={your client id}
79-
export AZURE_CLIENT_SECRET={your client secret}
81+
82+
Windows
83+
``` cmd
84+
setx KEY_VAULT_URL "<YourKeyVaultUrl>"
85+
setx SECRET_NAME "<YourSecretName>"
86+
setx SECRET_VERSION "<YourSecretVersion>"
87+
setx AZURE_TENANT_ID "<YourTenantId>"
88+
setx AZURE_CLIENT_ID "<YourClientId>"
89+
setx AZURE_CLIENT_SECRET "<YourClientSecret>"
8090
```
81-
> [AZURE.NOTE] On Windows, use `set` instead of `export`.
8291

83-
1. Run the sample.
92+
4. Run the sample.
8493

85-
```
94+
``` cmd
8695
node index.js
8796
```
8897

89-
1. This sample exposes two endpoints:
90-
91-
- `/ping` : This just answers "Hello World!!!" and is a good way to test if your packages are installed correctly without testing Azure itself.
92-
- `/` : The MSI sample itself
93-
94-
## Installation on Azure
95-
96-
1. Set the `KEY_VAULT_URI` environment variable using the "Application Settings" of your WebApp. You can also change the value of the variable from `null` in the index.js file.
97-
98-
1. This repo is ready to be deployed using local git. Read this tutorial to get more information on [how to push using local git through portal](https://docs.microsoft.com/en-us/azure/app-service/app-service-deploy-local-git)
98+
## Deploy this sample to Azure
99+
1. Create a [Node.js Web App] in Azure.
99100

100-
## At a glance
101+
2. Set environment variables in the **Settings** > **Configuration** > **Application Settings** of your Web App. You can also change the value of the variables from `null` in the index.js file.
101102

102-
Using the `loginWithAppServiceMSI()` method from [ms-rest-azure](https://www.npmjs.com/package/ms-rest-azure) will autodetect if you're on a WebApp and get the token from the MSI endpoint. Then, the code is simply:
103-
104-
```javascript
105-
function getKeyVaultCredentials(){
106-
return msRestAzure.loginWithAppServiceMSI({resource: 'https://vault.azure.net'});
107-
}
108-
109-
function getKeyVaultSecret(credentials) {
110-
let keyVaultClient = new KeyVault.KeyVaultClient(credentials);
111-
return keyVaultClient.getSecret(KEY_VAULT_URI, 'secret', "");
112-
}
113-
114-
getKeyVaultCredentials().then(
115-
getKeyVaultSecret
116-
).then(function (secret){
117-
console.log(`Your secret value is: ${secret.value}.`);
118-
}).catch(function (err) {
119-
throw (err);
120-
});
121-
```
122-
123-
If you want to execute this same code in your local environment machine, just use the appropriate login method.
124-
125-
If you need a fallback mechanism to allow this code to switch automatically from MSI to another approach, you can test for environment variables:
126-
127-
```javascript
128-
function getKeyVaultCredentials(){
129-
if (process.env.APPSETTING_WEBSITE_SITE_NAME){
130-
return msRestAzure.loginWithAppServiceMSI({resource: 'https://vault.azure.net'});
131-
} else {
132-
return msRestAzure.loginWithServicePrincipalSecret(clientId, secret, domain);
133-
}
134-
}
135-
```
136-
137-
## Summary
138-
139-
The web app was successfully able to get a secret at runtime from Azure Key Vault using your developer account during development, and using MSI when deployed to Azure, without any code change between local development environment and Azure.
140-
As a result, you did not have to explicitly handle a service principal credential to authenticate to Azure AD to get a token to call Key Vault. You do not have to worry about renewing the service principal credential either, since MSI takes care of that.
141-
142-
## Azure Functions
143-
144-
Azure Functions being powered by Azure WebApp, MSI is also available. You can copy the relevant code from the example into your Azure Functions with the right import.
103+
3. This repository is ready to be deployed using local git. Read this tutorial to get more information on [how to push using local git through portal].
145104

146105
## Troubleshooting
147-
148-
### Common issues when deployed to Azure App Service:
149-
150-
1. MSI is not setup on the App Service.
151-
152-
Check the environment variables MSI_ENDPOINT and MSI_SECRET exist using [Kudu debug console](https://azure.microsoft.com/en-us/resources/videos/super-secret-kudu-debug-console-for-azure-web-sites/). If these environment variables do not exist, MSI is not enabled on the App Service. Note that after enabling MSI, you need to restart your WebApp.
153-
154106
### Common issues across environments:
107+
* Access denied
108+
109+
The principal used does not have access to the Key Vault. The principal used in show on the web page. Grant that user (in case of developer context) or application **Get secret** access to the Key Vault.
110+
111+
## Contributing
112+
This project welcomes contributions and suggestions. Most contributions require you to agree to a
113+
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
114+
the rights to use your contribution. For details, visit https://cla.microsoft.com.
115+
116+
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
117+
a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions
118+
provided by the bot. You will only need to do this once across all repos using our CLA.
119+
120+
This project has adopted the [Microsoft Open Source Code of Conduct]. For more information see the [Code of Conduct FAQ] or contact [[email protected]] with any additional questions or comments.
121+
122+
<!-- LINKS -->
123+
[free account]: https://azure.microsoft.com/free/?WT.mc_id=A261C142F
124+
[App registration]: https://azure.microsoft.com/documentation/articles/resource-group-create-service-principal-portal/
125+
[Azure Key Vault]:https://docs.microsoft.com/en-us/azure/key-vault/quick-create-portal
126+
[Add a secret]: https://docs.microsoft.com/en-us/azure/key-vault/quick-create-portal#add-a-secret-to-key-vault
127+
[Node.js]: https://nodejs.org/en/download/
128+
[Git]: https://www.git-scm.com/
129+
[Node.js Web App]: https://docs.microsoft.com/en-us/azure/app-service/app-service-web-get-started-nodejs
130+
[how to push using local git through portal]: https://docs.microsoft.com/en-us/azure/app-service/app-service-deploy-local-git
131+
[Microsoft Open Source Code of Conduct]: https://opensource.microsoft.com/codeofconduct/
132+
[Code of Conduct FAQ]: https://opensource.microsoft.com/codeofconduct/faq/
133+
155134

156-
1. Access denied
157-
158-
The principal used does not have access to the Key Vault. The principal used in show on the web page. Grant that user (in case of developer context) or application "Get secret" access to the Key Vault.

azure-pipelines.yml

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Node.js Express Web App to Linux on Azure
2+
# Build a Node.js Express app and deploy it to Azure as a Linux web app.
3+
# Add steps that analyze code, save build artifacts, deploy, and more:
4+
# https://docs.microsoft.com/azure/devops/pipelines/languages/javascript
5+
6+
trigger:
7+
- master
8+
9+
variables:
10+
11+
# Azure Resource Manager connection created during pipeline creation
12+
azureSubscription: '8ae4228e-79a7-4f32-bc0b-f0de98831791'
13+
14+
# Web app name
15+
webAppName: 'prjwebapptest'
16+
17+
# Environment name
18+
environmentName: 'prjwebapptest'
19+
20+
# Agent VM image name
21+
vmImageName: 'ubuntu-latest'
22+
23+
stages:
24+
- stage: Build
25+
displayName: Build stage
26+
jobs:
27+
- job: Build
28+
displayName: Build
29+
pool:
30+
vmImage: $(vmImageName)
31+
32+
steps:
33+
- task: NodeTool@0
34+
inputs:
35+
versionSpec: '10.x'
36+
displayName: 'Install Node.js'
37+
38+
- script: |
39+
npm install
40+
npm run build --if-present
41+
npm run test --if-present
42+
displayName: 'npm install, build and test'
43+
44+
- task: ArchiveFiles@2
45+
displayName: 'Archive files'
46+
inputs:
47+
rootFolderOrFile: '$(System.DefaultWorkingDirectory)'
48+
includeRootFolder: false
49+
archiveType: zip
50+
archiveFile: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
51+
replaceExistingArchive: true
52+
53+
- upload: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
54+
artifact: drop
55+
56+
- stage: Deploy
57+
displayName: Deploy stage
58+
dependsOn: Build
59+
condition: succeeded()
60+
jobs:
61+
- deployment: Deploy
62+
displayName: Deploy
63+
environment: $(environmentName)
64+
pool:
65+
vmImage: $(vmImageName)
66+
strategy:
67+
runOnce:
68+
deploy:
69+
steps:
70+
- task: AzureWebApp@1
71+
displayName: 'Azure Web App Deploy: prjwebapptest'
72+
inputs:
73+
azureSubscription: $(azureSubscription)
74+
appType: webAppLinux
75+
appName: $(webAppName)
76+
runtimeStack: 'NODE|10.10'
77+
package: $(Pipeline.Workspace)/drop/$(Build.BuildId).zip
78+
startUpCommand: 'npm run start'

0 commit comments

Comments
 (0)