Give App Service enough permissions to link SSL certificate from Key Vault - azure

I have a Bicep template where I create an App Service in which I need to link a SSL certificate that exists in Key Vault (both in same resource group).
The Key Vault has Azure RBAC enabled.
I use the following to Bicep template to link the SSL certificate from Key Vault to the App Service:
resource certEncryption 'Microsoft.Web/certificates#2018-02-01' = {
name: '${resourcePrefix}-cert-encryption'
location: location
properties: {
keyVaultId: resourceId('myResourceGroup', 'Microsoft.KeyVault/vaults', keyVaultName)
keyVaultSecretName: '${resourcePrefix}-cert-encryption'
serverFarmId: hostingPlan.id
password: 'SecretPassword'
}
dependsOn: [
webApi
]
}
But it fails with the following message:
The service does not have access to '/subscriptions/3449f-xxxx/resourcegroups/rgabptrialt/providers/microsoft.keyvault/vaults/my-test-vault' Key Vault. Please make sure that you have granted necessary permissions to the service to perform the request operation.
This isn't really telling a lot...
What permission do I need to grant exactly? And to what? And where and how do I even grant these permissions?
Do I have to create a Managed Identity and link that in my App Service? And what Permissions/Roles do I need exactly? Or do I need to do something else to make this work?
I couldn't really find any good info on how to do this.

Give App Service enough permissions to link SSL certificate from Key Vault:
I've imported a self-signed certificate (.pfx) in keyvault -> secrets to authenticate.
To resolve,
The service does not have access to '/subscriptions/3449f-xxxx/resourcegroups/rgabptrialt/providers/microsoft.keyvault/vaults/my-test-vault' Key Vault. Please make sure that you have granted necessary permissions to the service to perform the request operation.
I tried in my environment by referring few steps from this article detailed by #Anuraj and modified accordingly to achieve the expected results.
Step-1: Setting up a Key Vault access policy:
Create a key vault from the portal and Goto Access Policies.
Now creating an access policy to link the ssl certificate by configuring a template as per your requirement.
I've selected key,secret & certificate management to enable the permissions as shown:
Search for the "Name/objectID/AppID" for the respective service principal as keyvault has RBAC enabled.
Note: Register an app under AzureAD -> App registrations if needed.
Review all the permissions and create an access policy:
Step-2: Under App Service -> Web Application -> Certificates, I've added the keyvault certificate ( self-signed certificate (.pfx) in keyvault -> secrets).
1.
2.
3.
Bind the SSL certificate by adding TLS/SSL settings and importing the key vault certificate when it has been added to key vault (.pfx).
Note: Make sure the certificate is in .pfx format to avoid any conflicts.
And I ran below script and deployment got succeeded without any permission blockers.
resource certEncryption 'Microsoft.Web/certificates#2018-02-01' = {
name: 'xcc-cert-encryption'
location: 'EastUS'
properties: {
keyVaultId: '/subscriptions/<subscriptionID>/resourceGroups/xxxxRG/providers/Microsoft.KeyVault/vaults/xxxxxkeyvaults'
keyVaultSecretName: 'jahnss'
password: 'xxxxx' //Certificate protected password
extensionResourceId: '/subscriptions/<subscriptionID>/resourceGroups/xxxxRG/providers/Microsoft.Web/serverfarms/xxxxxappserviceplan'
}
}
Output:

I think yes first you need to give permission in key vault
Ensure that the service principal has all the permissions. The only thing that worked for me though is adding the service principal 24681998-555f-4570-a559-2fced2d7e841 which shows up as Microsoft.Azure.WebSites. You can add this through the portal, by adding an access policy for Microsoft.Azure.WebSites or through arm with the GUID.
I added the following principal to the Key Vault access policies: Microsoft Azure App Service (object id: your object id). Permission to get secrets is enough.
By performing similar the steps mentioned in the below answer
How to access key vault from azure app service
Please let me know if you have any doubts or question. Even if you are facing any issues.

Related

Azure Application Access Only Key Vault Keys

I have a multi-tenant application.
I need this application to:
Be able to read the keys in all vaults of all of the tenants (that grant consent).
Not be able to read any of the secrets.
I manage to get full access to the Vaults using delegated permission (user impersonation).
However that isn't what I want cause this permission provide me with access to the secrets as well.
I saw ( here ) that there's a role for only accessing the keys.
The role name is: Key Vault Crypto Officer (id: 14b46e9e-c2b7-41b4-b07b-48a6ebf60603)
Question is:
Is it possible to make my application require (only?) this role. Which will allow it to read keys but not secrets? Not sure I'm thinking about roles the right way, I don't have a lot of experience with it.
Note that I don't mind asking for delegated / application permissions, if it matters.
Thanks
Note that, it's not possible to read keys in vaults of all tenants using multi-tenant application.
Assigning Key Vault Crypto Officer role to multi-tenant application under subscription gives access in reading only keys of all key vaults in only one tenant linked to that subscription, not other tenants.
I tried to reproduce the same in my environment and got below results:
I created one key vault named srikv07 by selecting Azure role-based access control in Access configuration like below:
In the above keyvault, I created few keys and secrets like this:
Keys:
Secrets:
Now, I registered one multi-tenant Azure AD application named KVmultiapp like below:
Under my subscription, I assigned Key Vault Crypto Officer role to that multi-tenant application:
Go to Azure Portal -> Subscriptions -> Select Subscription -> Access control(IAM) -> Add role assignment
Now, I generated access token using client credentials flow via Postman like below:
POST https://login.microsoftonline.com/common/oauth2/v2.0/token
client_id: <appID>
grant_type:client_credentials
scope: https://vault.azure.net/.default
client_secret: <secret>
Response:
When I used this token to read keys of RBAC enabled key vault, I got error like below:
GET https://<yourkvname>.vault.azure.net//keys?api-version=7.3
Response:
To resolve the error, you need to include tenantID while generating access token like below:
POST https://login.microsoftonline.com/<tenantID>/oauth2/v2.0/token
client_id: <appID>
grant_type:client_credentials
scope: https://vault.azure.net/.default
client_secret: <secret>
Response:
Now, I used this token to retrieve keys and got response successfully like below:
GET https://<yourkvname>.vault.azure.net//keys?api-version=7.3
Response:
When I used the same token to get secrets of keyvault, I got 403 Forbidden error as the role gives access to only keys.
GET https://<yourkvname>.vault.azure.net//secrets?api-version=7.3
Response:

Key Vault returns 401 using ManagedIdentityCredential for App Service (Azure.Identity 1.3.0)

In my Startup.cs I add key vault clients as such:
services.AddAzureClients(s =>
{
var keyVaultUri = new Uri(Configuration["KeyVault:Uri"]);
s.AddCertificateClient(keyVaultUri);
s.AddSecretClient(keyVaultUri);
s.UseCredential(new DefaultAzureCredential(new DefaultAzureCredentialOptions
{
VisualStudioTenantId = Configuration["AzureAd:TenantId"]
}));
});
Locally, I can authenticatie with the VisualStudioCredential. All works fine. When deployed I run into the following error:
The key vault returns a 401 even though I successfully got a token. I am using Access Control on the key vault and it my Managed Identity is a Key Vault Administrator.
What could be going on here and how can I debug this further? I have been stuck on this for a while now.
EDIT:
Title is misleading and what I thought was happening was not happening. There was no authentication issue but it looked as such in the logs due to another exception I was getting. This was occurring due to the fact my App Service Plan didn't have SSL/TLS functionality required to work with certificates, I needed a more expensive App Service Plan.
Please see this GitHub issue: https://github.com/dotnet/runtime/issues/30658#issuecomment-523987878
You need to give your Managed Identity an access policy on the Key Vault, not an RBAC access.
RBAC in this case is for management plane operation. Access policies are for data plane operations - which is what you want.
https://learn.microsoft.com/en-us/azure/key-vault/general/secure-your-key-vault

Error "The parameter keyVaultCsmId has an invalid value" while adding App Service Certificates to KeyVault

I have generated a wildcard certificate using Azure's App Service Certificate.
After this Azure asks you to configure the certificate in a KeyVault, and this is where I am getting stuck.
I have a Keyvault which is in the same region, same subscription, same resource group.
I have the necessary permissions to the key vault. I am a User Admin, Cert officer, Secrets officer, contributor to the key vault .
This step is failing with an error
Failed to link certificate with the selected Key Vault. Check below errors for more detail.
The Activity Log under App Service Certificate shows :
Operation Name : Add or Update Certificate
Status : Failed
Summary :
Operation name : Add or Update Certificate
Time stamp : Tue Jan 19 2021 07:10:46 GMT+1100 (Australian Eastern Daylight Time)
Event initiated by: xxxx
Error code: BadRequest
Message : The parameter keyVaultCsmId has an invalid value.
The JSON has the following important information :
"authorization": {
"action": "Microsoft.CertificateRegistration/certificateOrders/certificates/write",
"scope": "/subscriptions/xxx/resourceGroups/yyyyyyy/providers/Microsoft.CertificateRegistration/certificateOrders/InternalWildCard/certificates/InternalWildCard"
}
"properties": {
"statusCode": "BadRequest",
"serviceRequestId": null,
"statusMessage": "{\"Code\":\"BadRequest\",\"Message\":\"The parameter keyVaultCsmId has an invalid value.\",\"Target\":null,\"Details\":[{\"Message\":\"The parameter keyVaultCsmId has an invalid value.\"},{\"Code\":\"BadRequest\"},{\"ErrorEntity\":{\"ExtendedCode\":\"51008\",\"MessageTemplate\":\"The parameter {0} has an invalid value.\",\"Parameters\":[\"keyVaultCsmId\"],\"Code\":\"BadRequest\",\"Message\":\"The parameter keyVaultCsmId has an invalid value.\"}}],\"Innererror\":null}",
"eventCategory": "Administrative",
"entity": "/subscriptions/xxx/resourceGroups/xxx/providers/Microsoft.CertificateRegistration/certificateOrders/InternalWildCard/certificates/InternalWildCard",
"message": "Microsoft.CertificateRegistration/certificateOrders/certificates/write",
"hierarchy": "xxxx"
}
Any help on this or direction you can provide will be really appreciated :)
There should be a service principal in the Azure AD, if not you can create it.
Get-AzADServicePrincipal -DisplayName microsoft.azure.certificateregistration
You need to assign that permission to keyvault via either access policies OR RBAC.
In Azure Key Vault, supported certificate formats are PFX and PEM.
• .pem file format contains one or more X509 certificate files.
• .pfx file format is an archive file format for storing several cryptographic objects in a single file i.e. server certificate (issued for your domain), a matching private key, and may optionally include an intermediate CA.
Certificates used by App Service first needs to be converted to (and marked as) application/x-pkcs12. Re-importing the cert from a pfx file with the --password parameter (az keyvault certificate import), and after that import it from the key vault to the webapp might help. You may refer to this Blog might be helpful.
Also, look if Cert and the Key Vault are in their original resource group.
Additional details: https://learn.microsoft.com/en-us/azure/key-vault/certificates/tutorial-import-certificate
https://azure.github.io/AppService/2016/05/24/Deploying-Azure-Web-App-Certificate-through-Key-Vault.html
Stuff which I didn't mention in the original question..
The existing key vault Permission Model is using RBAC for policies which is in preview [ Azure role-based access control (preview) ].
It has "Selected Networks" open and allows Trusted MS Networks..
It already has another wildcard cert in it as a secret ( different name )
I temporarily switched the Key Vault Permission Model to Vault access policy, and tried linking - and it worked.
Looks like a bug with the Permission Model using Azure RBAC.
To fix the issue:
https://github.com/Azure/azure-quickstart-templates/tree/master/quickstarts/microsoft.web/app-service-certificate-standard
By default, 'Microsoft.CertificateRegistration' and 'Microsoft.Web' RPs don't have access to the Key Vault specified in the template hence you need to authorize these RPs by executing the following PowerShell commands before deploying the template:
Login-AzureRmAccount
Set-AzureRmContext -SubscriptionId AZURE_SUBSCRIPTION_ID
Set-AzureRmKeyVaultAccessPolicy -VaultName KEY_VAULT_NAME -ServicePrincipalName f3c21649-0979-4721-ac85-b0216b2cf413 -PermissionsToSecrets get,set,delete
Set-AzureRmKeyVaultAccessPolicy -VaultName KEY_VAULT_NAME -ServicePrincipalName abfa0a7c-a6b6-4736-8310-5855508787cd -PermissionsToSecrets get
ServicePrincipalName parameter represents these RPs in user tenant and will remain same for all Azure subscriptions. This is a onetime operation. Once you have a configured a Key Vault properly, you can use it to store as many App Service Certificates as you want without executing these PowerShell commands again.

Use a certificate in the keyvault to access multi-tenant application in other tenant

We have a multi-tenant application in our Azure AD tenant. It is authorized in some other tenants (we know which ones). And it has multiple certificates registered to it to be used as client credentials.
We want to remove the certificates from the local stores and use a certificate in the key vault to request a token for one of the external tenant. According to the documentation this is one of the use cases.
Our tenant (id: xxxx):
Has app registration (app id: abcd-xxx-xxxx-xxx)
has keyvault
has managed service principal (with access to the key vault)
other tenant (id: yyyy):
Executed Admin consent for our application.
Question 1:
How do I create a certificate in the Key vault that is connected to an existing application (app id: abcd-xxx-xxxx-xxx)? It is important to note that since the application is already approved by several third party admins, it cannot be recreated. Same counts for creating a new certificate after it would be expired.
Question 2:
How to I setup the Microsoft.Azure.Services.AppAuthentication library to:
Use the managed identity to access the key vault in our tenant (xxxx).
Use the certificate in the key vault to request a token for our app (abcd-xxx-xxxx-xxx) in other companies tenant (yyyy)
Answer 1:
You could use az ad sp credential reset command like below. If you don't want to overwrite the existing certificate of the App, please pass the --append parameter.
az ad sp credential reset --name '<application-id>' --keyvault joykeyvault --cert cer136 --create-cert --append
Answer 2:
1.To use the MSI access the keyvault in your tenant, just use the code below.
No code changes are required, when you run your code on an Azure App Service or an Azure VM with a managed identity enabled, the library automatically uses the managed identity, see this link.
The environment variable AzureServicesAuthConnectionString has to be set to any credential with access to the keyvault. RunAs=Developer; DeveloperTool=AzureCli for dev or RunAs=App; for managed service identity (automatically in azure).
using Microsoft.Azure.Services.AppAuthentication;
using Microsoft.Azure.KeyVault;
// Instantiate a new KeyVaultClient object, with an access token to Key Vault
var azureServiceTokenProvider1 = new AzureServiceTokenProvider();
var kv = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider1.KeyVaultTokenCallback));
2.If you want to use the service principal along with its certificate stored in the keyvault to get the token for the resources in another tenant, the connection string on the AzureServiceTokenProvider has to be set to RunAs=App;AppId={TestAppId};KeyVaultCertificateSecretIdentifier={KeyVaultCertificateSecretIdentifier} then you can get tokens for other tenants like.
const string appWithCertConnection = "RunAs=App;AppId={TestAppId};KeyVaultCertificateSecretIdentifier=https://myKeyVault.vault.azure.net/secrets/myCert";
Then use the code to get the token, e.g. for the resource https://management.azure.com/.
var azureServiceTokenProvider2 = new AzureServiceTokenProvider(appWithCertConnection);
string accessToken = await azureServiceTokenProvider2.GetAccessTokenAsync("https://management.azure.com/", "tenant-id-of-thridh-party-tenant").ConfigureAwait(false);

Access denied linking variable group to key vault in VSTS

When I try to link a variable group to key vault in VSTS, every time I select my endpoint, it tells me:
"Specified Azure endpoint needs to have "Get, List" secret management permissions on the selected key vault. Click "Authorize" to enable VSTS to set these permissions or manage secret permissions in Azure portal."
It makes no sense. That specific endpoint has Get and List for secrets, keys, certificates. The endpoint is using the correct Service Principal Client ID- I know because I pulled its corresponding app registration up in Azure by searching with that ID. And the app registration is specifically listed in the key vault's Access policies, with the correct permissions.
Trying to click "Authorize" in VSTS just give me
"Resource not found for the segment 'DirectoryDataService.getServicePrincipalsByAppIds'. For troubleshooting refer to https://go.microsoft.com/fwlink/?linkid=835898"
and the endpoint is broken until I re-verify it.
I'm kind of at my wit's end here- everything is set exactly as https://learn.microsoft.com/en-us/vsts/build-release/concepts/library/variable-groups?view=vsts says it should be.
Edit: Turns out the Azure tried to add the app reg as a person instead of an app when I listed it in the ARM template by object ID (app ID most definitely does not work there). So now I just need to figure out how to add it as an application in the ARM template...
Edit Edit: Soooo... the Object ID the Azure Portal shows for an App Registration? That's not the Object ID the ARM template wants. It wants the... I'm not sure what you'd call it. In Powershell, you use it with -Object ID, but when you list the properties, it's under "Id". Whatever. To get it, you run
Get-AzureRmADServicePrincipal -SearchString "[your-app-reg-name]"
And it shows up under Id. That's what you want to use as an object ID in your ARM template.
According to the error Resource not found for the segment 'DirectoryDataService.getServicePrincipalsByAppIds, the issue seems more related to Azure side.
To access azure-keyvault you need four things :
- clientId = "<client id of your application registed on Azure AD>";
- domain = "<your talnet id>";
- secret = "<client key of your application registed on Azure AD>";
- subscription = "<your subscription id>";
Then these will combine ApplicationTokenCredentials, finally Authorize to KeyVaultClient . Suggest you take a look at this question: Azure keyvault client 1.0.0 initiate client
Besides also double check/confirm the specific endpoint has Get and List for secrets, keys, certificates.

Resources