I have an Azure App Service Web App using Key Vault References for several application settings. All resources are deployed and configured through an Bicep/ARM template. The secrets in Key Vault and Access Policies are set through the Bicep/ARM template as well. The Web App works great and has access to Key Vault through those references until I re-deploy the Bicep / ARM template to modify some unrelated values. After running "az deployment group create" the references break (showing red cross in application settings). I found two workarounds to make them connect again:
Restart Web App
Create another app setting / modify a setting in the portal and save
I would like to understand the root cause / possible mistake and why the work-arrounds help. I checked, and the Secrets in Key Vault are not changed / updated when re-deploying the template. My assumption is that this is caused by the Key Vault API removing and re-creating the Access Policies each time the template gets deployed. A what-if deployment of the template tells me that the removal and re-creation of the Access Policies is happening.
As mentioned by #Deepdave in the comment section. ARM does not allow a key vault to be redeployed with out clearing existing access polices.
Please submit your feedback here https://feedback.azure.com/forums/34192--general-feedback
Related
I have:
Azure App Service with a Docker container running in it. Inside the Docker container, there is a Python FastAPI Web App.
Azure Key Vault with some App specific secrets in it (e.g. Public API Client Secret for a side service to send requests to)
I'm trying to set secrets to the App.
There are several examples when an app directly reads the secrets from Key Vault (e.g. official MS documentation), but I believe the provisioning should not be the responsibility of the App.
Probably, secrets should be set as environment variables with the CD pipeline (correct me if it's a bad idea). Otherwise, the App knows details about the infrastructure where it's running, which, I guess, is not the best practice.
Is there a proper way to provision Key Vault secrets to the App environment?
I tried to reproduce the same issue in my environment and got the below results
I have created the app service
The azure key vaults supplies a way to store keys & secrets outside of an application, Using access polices we can allow the application to access the keys with in keyvault
To access the keyvault as a environment variables in the azure app service we have to setup the polices mentioned as below
In the app services => identity => click on status is ON
Go to the keyvault and the polices settings click on add polices
And the access polices page set any permissions for keys and secrets
In the select principal page search for the app service name and select then the app service can access as a environment variables
After that we have to add specific secrets in the app service and copy its in secret identifier as below format
#microsoft.keyvault(secretUri={secret url from the keyvault})
After adding the secret it will look like as below
By following the above steps we can access the secrets as a environment variables
I am trying to link Azure Key Vault secrets to a variable group in Azure Pipelines (part in Azure DevOps). Microsoft documentation here.
However, the "Authorize" button does not seem to work. It spins endlessly. Screenshot.
My target Azure Key Vault already has the service principal included in its access policy with Get and List permissions. Screenshot.
Anyone seen this issue before?
This workaround also seems like a bug for Azure Key Vault deployments using ARM templates.
If the service principal in question is added to the Azure Key Vault (AKV) access policies through an ARM template by referencing the service principal's Object ID (as Microsoft documentation calls for), permission errors with Azure Pipelines follow.
However, if I manually add the service principal to the AKV's access policies by referencing the service principal's application (client) ID, the permissions errors go away entirely.
Again, feels like a bug. And now my automated deployment pipeline doesn't quite work because of this manual step.
Also, in the AKV ARM template, if I were to combine the mandatory field objectId with the optional field applicationId, the service principal shows up as a "compound identity". That does not fix the permissions issues in Azure Pipelines. I do not see a way of adding a service principal properly without doing it manually.
Firstly, please make sure the service connection is working correctly. Then refresh the page and try it again. Alternately you can also try in browser inprivate session.
Just as the message said "The specified Azure service connection needs to have "Get, List" secret management permissions on the selected key vault."
Basically, we need to click the "Authorize" button to enable Azure Pipelines to set these permissions for the specific service connection.
If that doesn't work, we can also manually set the permissions for the specific service connection.
Go to Project settings - > Service connections -> Select the
specific ARM service connection
Click Edit to popup the Update Authentication for xxx dialog
Click the "use the full version of the service connection dialog."
link, to get the Service principal client ID
Go to your key vault in Azure portal -> Access Policies -> Add a new
Access Policy -> Select a template (e.g Key&Secret Management) - >
Select Get, List for Secret permissions.
Click Select Principal -> Copy and paste the Service principal client ID
to search the user/application -> Select the searched
user/application
After that you can see the new APPLICATION access policy.
Try it again after successfully adding the application access policy.
UPDATE:
Generally in Azure DevOps we need to create a ARM service connection (the client which can access the azure sources) first before deploying an Azure Key Vault through an ARM template.
Actually when you select the Azure subscription then click Authorize in Azure resource group deployment task
, the ARM service connection is created automatically. You just need to check the AppID and get the ObjectID to use in the ARM template.
We can get the Service principal client ID (AppID) by following above steps. After that we can get ObjectId by the AppID with running the following command: (See Find service principal object ID using PowerShell for details.)
$(Get-AzureADServicePrincipal -Filter "AppId eq 'a89c3dee-f5bf-4ea1-a805-d4c729a4add3'").ObjectId
Then you can specific the ObjectId when deploying the Azure Key Vault through an ARM template.
I am seeking some clarity on the best way to integrate Key Vault in ARM deployments within Azure DevOps.
For example, deploying an App Service and creating a Managed Service Identity so that it can get secrets from the key vault for a pre-existing Database.
1) In the Azure portal, I have manually created a new Service Principal for the App service with "Get" and "List" permissions in the access policy.
2) In My DevOps Project under the project settings I have created a service connection.
3) I have created a Variable group in DevOps with relevant Key Vault Secrets.
4) In my App Service ARM template i have referenced the Service Identity with reference to the Variable Parameters.
Is this the correct way to integrate Key Vault with a DevOps Deployment?
Whenever I need to deploy a new service to the environment (say now I want to deploy an API), do I need to manually create another Managed Identity in Azure for the Key Vault Access or is there a way to create it as part of the initial deployment of the API service?
Thank you in advance for your assistance.
If you are using MSI it is recommend to set this in the ARM template by putting
"identity": {
"type": "SystemAssigned"
},
In defining the app service. This will recreate the MSI with every deployment. It will be named the same but will have a different thumbprint in AD after each deployment. For purposes with Key Vault this is perfectly fine.
Within your Key Vault ARM template (if it's not all in the same template) The access policy can reference the MSI by:
"tenantID": "[subscription().tenantId]",
"objectId": "[reference(resourceId('Microsoft.Web/sites', INSERT APP SERVICE NAME), '2018-02-01', 'Full').identity.principalId]",
This will reference the ID being created by the App Service deployment.
If using this be sure to have the App Service config depend on the Key Vault and secrets (if referencing secrets in the ARM template), the Access Policy depends on the Key Vault and App Service creation, and any secret being created set to depend on the Key Vault as well to ensure assignments happen in the right order.
I am following directions here for learning the AzureKeyVault config settings
Key Vault Configuration Provider sample application (ASP.NET Core 2.x)
This sample illustrates the use of the Azure Key Vault Configuration
Provider for ASP.NET Core 2.x. For the ASP.NET Core 1.x sample, see
Key Vault Configuration Provider sample application (ASP.NET Core
1.x).
For more information on how the sample works, see the Azure Key Vault
configuration provider topic.
Using the sample
Create a key vault and set up Azure Active Directory (Azure AD) for the application following the guidance in Get started with Azure Key
Vault.
Add secrets to the key vault using the AzureRM Key Vault PowerShell Module available from the
PowerShell
Gallery,
the Azure Key Vault REST API, or the Azure
Portal. Secrets are created as either
Manual or Certificate secrets. Certificate secrets are certificates for use by apps and services but are not supported by the
configuration provider. You should use the Manual option to create
name-value pair secrets for use with the configuration provider.
Simple secrets are created as name-value pairs. Azure Key Vault secret names are limited to alphanumeric characters and dashes.
Hierarchical values (configuration sections) use -- (two dashes) as a separator in the sample. Colons, which are normally used
to delimit a section from a subkey in ASP.NET Core
configuration, aren't allowed
in secret names. Therefore, two dashes are used and swapped for a
colon when the secrets are loaded into the app's configuration.
Create two Manual secrets with the following name-value pairs. The first secret is a simple name and value, and the second
secret creates a secret value with a section and subkey in the secret
name:
SecretName: secret_value_1
Section--SecretName: secret_value_2
Register the sample app with Azure Active Directory.
Authorize the app to
access the key vault. When you use the
Set-AzureRmKeyVaultAccessPolicy PowerShell cmdlet to authorize the
app to access the key vault, provide List and Get access to
secrets with -PermissionsToSecrets list,get.
Update the app's appsettings.json file with the values of Vault, ClientId, and ClientSecret.
Run the sample app, which obtains its configuration values from IConfigurationRoot with the same name as the secret name. *
Non-hierarchical values: The value for SecretName is obtained with
config["SecretName"]. * Hierarchical values (sections): Use :
(colon) notation or the GetSection extension method. Use either of
these approaches to obtain the configuration value:
config["Section:SecretName"]
config.GetSection("Section")["SecretName"]
Okay so I have copied the name of my application into Azure Active Directory as an 'Enterprise Application'. And I have added 'Access policies' for 'get' and 'list' in Azure for my ADD object I just created. Yet I get this error in the program when attempting to start the application:
Exception: {"error":"unauthorized_client","error_description":"AADSTS70001:
Application with identifier '(guid)' was not found in the directory ...(continues)
Update 8-4-18
Okay I found out that Azure uses the 'ClientId' and 'ClientSecret' in the local appsettings.json to connect to what Azure registers in this tutorial: https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal#log-in-as-the-application
I get the clientId in appsettings.json from the applicationId on ADD I create with ADD>App Registrations>New
I click settings in ADD on the app I just created and create a key with an expiration to store as ClientSecret in appsettings.json.
I change my 'Vault' in appsettings to my named vault.
I run the powershell above to give access or else do it in ADD.
So now I am getting a simpler error:
'Microsoft.Azure.KeyVault.Models.KeyVaultErrorException: 'Access denied''
I have tried running as Administrator in Visual Studio. I went under Subscriptions in Azure>Access Control>(IAM)>set my new apps to Reader.
So the reason your powershell is failing is because you are trying to assign a User Principal - a user - when actually you want a Service Principal.
I can’t see your C# to support more there than saying when you use the SDK to log in as the Service Principal you use the application id of the Application/Service Principal (its the same id).
The service principal acts like a user in the local directory but you log in as the application.
Edit:
I looked at the example you posted and ran it myself and had very similar problems. However I have got it working. Here's the steps:
Creating the Application
Create the Registered Application. I do this through the Azure Portal so
a Service Principal is created automatically. Make a note of the ApplicationId.
Generate a key credential on the created application and make a note of it.
In the Application click on the link to the Managed app in local directory. This is the Service Principal, make a note of the ObjectId
Creating the Key Vault
Create KeyVault - I used PowerShell to do this. New-AzureRmKeyVault
Apply the Service Principal to the Key Vault.
Set-AzureRmKeyVaultAccessPolicy -VaultName <vault> -ResourceGroupName <ResourceGroupName> -ObjectId <Object Id of the Created Service Principal> -PermissionsToSecrets Get,List
Running the Sample App
In your application settings follow this format:
{
"Vault": <the name of your vault>,
"ClientId": <ApplicationId of the Registered Application>,
"ClientSecret": <Credential generated from the Registered Application>
}
This worked for me and allowed me to run the sample and retrieve the secrets from the vault.
The ultimate problem for me became that running 'Set-AzureRmKeyVaultAccessPolicy' was not needed and for whatever reason it was easier to just ignore it and follow this subsection: https://azure.microsoft.com/documentation/articles/key-vault-get-started/#authorize
I kept trying to set up Object Id and Keys and really I had just overlooked a section mentioning a 'ServerPrincipalName'
They set one commandlet for keys
Set-AzureRmKeyVaultAccessPolicy -VaultName '<vaultName>' -ServicePrincipalName <ApplicationIdGuid> -PermissionsToKeys decrypt,sign
They set one commandlet for secrets
Set-AzureRmKeyVaultAccessPolicy -VaultName '<vaultName>' -ServicePrincipalName <ApplicationIdGuid> -PermissionsToSecrets Get, List
But I decided to follow the immediate proceeding section on doing it all in the Portal. The key take away for me was that the instructions were not wrong. Just vague when it says: "Register a sample app" then "Authorize the App". Really they should be saying
Register a sample app (https://learn.microsoft.com/en-us/azure/key-vault/key-vault-get-started#register)
Authorize the app with Key Vault (https://azure.microsoft.com/documentation/articles/key-vault-get-started/#authorize)
Ultimately all the information is there it was just confusing if you happen to already have a vault and an application and don't understand the prerequisite is that really you need to have a 1. A Vault, 2. An ADD Web Application, 3. Associate permissions for 2 in 1.
I have an app with 2 slots. I have stored connection strings in the key vault. I have enabled MSI on the app and 2 slots. Also, within the vault's access policy, I have added the app (production slot). However I am not able to add the slots to the access policy. E.g. My app's name is XYZ20180706 and the slots are XYZ20180706/dev and XYZ20180706/test. But when I type in XYZ20180706/dev or XYZ20180706-dev in the service principal, it is not found.
How do I create an access policy for a deployment slot?
Just having it enabled on the main slot is not enough. I currently get access denied (to vault) if I deploy the app to the dev slot and run it.
Thanks.
AFAIK, we could access it after enabling MSI for deployment slot, you could check my test steps.
1.I have two slots, then I enable MSI of both of them in the portal.
You could check them in the Azure Active Directory -> Enterprise applications in the portal, refer to the screenshot.
Note: You should specify the Application Type option with All Applications when you are searching.
3.Add Add access policy in the azure keyvault, you could find the slots in the principle (hover your cursor over it).
On the key vault "Add access policy" section (printsceen 3 from Joy Wang), when you selecting the principal type this: YourWebAppName/slots/YourDeploymentSlotName
After you type the entire string the autocomplete check will be green and you can select the principal from the list.