This doc shows how to store application secrets for the Surveys app in Azure Key Vault.
Prerequisites:
- Install the Azure Resource Manager Cmdlets.
- Configure the Surveys application as described here.
High-level steps:
- Set up an admin user in the tenant.
- Set up a client certificate.
- Create a key vault.
- Add configuration settings to your key vault.
- Uncomment the code that enables key vault.
- Update the application's user secrets.
To create a key vault, you must use an account which can manage your Azure subscription. Also, any application that you authorize to read from the key vault must be registered in the same tenant as that account.
In this step, you will make sure that you can create a key vault while signed in as a user from the tenant where the Surveys app is registered.
Create an administrator user within the Azure AD tenant where the Surveys application is registered.
- Log into the Azure portal.
- Select the Azure AD tenant where your application is registered.
- Click More service > SECURITY + IDENTITY > Azure Active Directory > User and groups > All users.
- At the top of the portal, click New user.
- Fill in the fields and assign the user to the Global administrator directory role.
- Click Create.
Now assign this user as the subscription owner.
-
On the Hub menu, select Subscriptions.
-
Select the subscription that you want the administrator to access.
-
In the subscription blade, select Access control (IAM).
-
Click Add.
-
Under Role, select Owner.
-
Type the email address of the user you want to add as owner.
-
Select the user and click Save.
-
Run the PowerShell script /Scripts/Setup-KeyVault.ps1 as follows:
.\Setup-KeyVault.ps1 -Subject <<subject>>
For the
Subject
parameter, enter any name, such as "surveysapp". The script generates a self-signed certificate and stores it in the "Current User/Personal" certificate store. The output from the script is a JSON fragment. Copy this value. -
In the Azure portal, switch to the directory where the Surveys application is registered, by selecting your account in the top right corner of the portal.
-
Select Azure Active Directory > App Registrations > Surveys
-
Click Manifest and then Edit.
-
Paste the output from the script into the
keyCredentials
property. It should look similar to the following:"keyCredentials": [ { "type": "AsymmetricX509Cert", "usage": "Verify", "keyId": "29d4f7db-0539-455e-b708-....", "customKeyIdentifier": "ZEPpP/+KJe2fVDBNaPNOTDoJMac=", "value": "MIIDAjCCAeqgAwIBAgIQFxeRiU59eL..... } ],
-
Click Save.
-
Repeat steps 3-6 to add the same JSON fragment to the application manifest of the web API (Surveys.WebAPI).
-
From the PowerShell window, run the following command to get the thumbprint of the certificate.
certutil -store -user my [subject]
For
[subject]
, use the value that you specified for Subject in the PowerShell script. The thumbprint is listed under "Cert Hash(sha1)". Copy this value. You will use the thumbprint later.
-
Run the PowerShell script /Scripts/Setup-KeyVault.ps1 as follows:
.\Setup-KeyVault.ps1 -KeyVaultName <<key vault name>> -ResourceGroupName <<resource group name>> -Location <<location>>
When prompted for credentials, sign in as the Azure AD user that you created earlier. The script creates a new resource group, and a new key vault within that resource group.
-
Run Setup-KeyVault.ps1 again as follows:
.\Setup-KeyVault.ps1 -KeyVaultName <<key vault name>> -ApplicationIds @("<<Surveys app id>>", "<<Surveys.WebAPI app ID>>")
Set the following parameter values:
- key vault name = The name that you gave the key vault in the previous step.
- Surveys app ID = The application ID for the Surveys web application.
- Surveys.WebApi app ID = The application ID for the Surveys.WebAPI application.
Example:
.\Setup-KeyVault.ps1 -KeyVaultName tailspinkv -ApplicationIds @("f84df9d1-91cc-4603-b662-302db51f1031", "8871a4c2-2a23-4650-8b46-0625ff3928a6")
This script authorizes the web app and web API to retrieve secrets from your key vault. See Get started with Azure Key Vault for more information.
-
Run Setup-KeyVault.ps1 as follows:
.\Setup-KeyVault.ps1 -KeyVaultName <<key vault name> -KeyName Redis--Configuration -KeyValue "<<Redis DNS name>>.redis.cache.windows.net,password=<<Redis access key>>,ssl=true"
where
- key vault name = The name that you gave the key vault in the previous step.
- Redis DNS name = The DNS name of your Redis cache instance.
- Redis access key = The access key for your Redis cache instance.
-
At this point, it's a good idea to test whether you successfully stored the secrets to key vault. Run the following PowerShell command:
Get-AzureKeyVaultSecret <<key vault name>> Redis--Configuration | Select-Object *
-
Run Setup-KeyVault.ps1 again to add the database connection string:
.\Setup-KeyVault.ps1 -KeyVaultName <<key vault name> -KeyName Data--SurveysConnectionString -KeyValue <<DB connection string>> -ConfigName "Data:SurveysConnectionString"
where
<<DB connection string>>
is the value of the database connection string.For testing with the local database, copy the connection string from the Tailspin.Surveys.Web/appsettings.json file. If you do that, make sure to change the double backslash ('\\') into a single backslash. The double backslash is an escape character in the JSON file.
Example:
.\Setup-KeyVault.ps1 -KeyVaultName mykeyvault -KeyName Data--SurveysConnectionString -KeyValue "Server=(localdb)\MSSQLLocalDB;Database=Tailspin.SurveysDB;Trusted_Connection=True;MultipleActiveResultSets=true"
-
Open the Tailspin.Surveys solution.
-
In Tailspin.Surveys.Web/Startup.cs, locate the following code block and uncomment it.
//var config = builder.Build(); //builder.AddAzureKeyVault( // $"https://{config["KeyVault:Name"]}.vault.azure.net/", // config["AzureAd:ClientId"], // config["AzureAd:ClientSecret"]);
-
In Tailspin.Surveys.Web/Startup.cs, locate the code that registers the
ICredentialService
. Uncomment the line that usesCertificateCredentialService
, and comment out the line that usesClientCredentialService
:// Uncomment this: services.AddSingleton<ICredentialService, CertificateCredentialService>(); // Comment out this: //services.AddSingleton<ICredentialService, ClientCredentialService>();
This change enables the web app to use Client assertion to get OAuth access tokens. With client assertion, you don't need an OAuth client secret. Alternatively, you could store the client secret in key vault. However, key vault and client assertion both use a client certificate, so if you enable key vault, it's a good practice to enable client assertion as well.
In Solution Explorer, right-click the Tailspin.Surveys.Web project and select Manage User Secrets. In the secrets.json file, delete the existing JSON and paste in the following:
{
"AzureAd": {
"ClientId": "[Surveys web app client ID]",
"ClientSecret": "[Surveys web app client secret]",
"PostLogoutRedirectUri": "https://localhost:44300/",
"WebApiResourceId": "[App ID URI of your Surveys.WebAPI application]",
"Asymmetric": {
"CertificateThumbprint": "[certificate thumbprint. Example: 105b2ff3bc842c53582661716db1b7cdc6b43ec9]",
"StoreName": "My",
"StoreLocation": "CurrentUser",
"ValidationRequired": "false"
}
},
"KeyVault": {
"Name": "[key vault name]"
}
}
Replace the entries in [square brackets] with the correct values.
AzureAd:ClientId
: The client ID of the Surveys app.AzureAd:ClientSecret
: The key that you generated when you registered the Surveys application in Azure AD.AzureAd:WebApiResourceId
: The App ID URI that you specified when you created the Surveys.WebAPI application in Azure AD.Asymmetric:CertificateThumbprint
: The certificate thumbprint that you got previously, when you created the client certificate.KeyVault:Name
: The name of your key vault.
Asymmetric:ValidationRequired
is false because the certificate that you created previously was not signed by a root certificate authority (CA). In production, use a certificate that is signed by a root CA and setValidationRequired
to true.
Save the updated secrets.json file.
Next, in Solution Explorer, right-click the Tailspin.Surveys.WebApi project and select Manage User Secrets. Delete the existing JSON and paste in the following:
{
"AzureAd": {
"ClientId": "[Surveys.WebAPI client ID]",
"WebApiResourceId": "https://tailspin5.onmicrosoft.com/surveys.webapi",
"Asymmetric": {
"CertificateThumbprint": "[certificate thumbprint]",
"StoreName": "My",
"StoreLocation": "CurrentUser",
"ValidationRequired": "false"
}
},
"KeyVault": {
"Name": "[key vault name]"
}
}
Replace the entries in [square brackets] and save the secrets.json file.
For the web API, make sure to use the client ID for the Surveys.WebAPI application, not the Surveys application.