How to Read Azure KeyVault Secret in Asp.Net Core Web Api hosted on Azure VM IIS - asp.net-core-webapi

The code below works on my local machine passing DefaultAzureCredential(). But when I host it on IIS on Azure VM, the authentication fails. I tried setting the ApplicationPool's identity to my credential since I have access to the Azure KeyVault, still the same 403 forbidden error. Deploying as AppServices on Azure is not an option currently.
What is the best way to read Azure KeyVault Secrets in this scenario?
string kvUri = "https://mykeyvault.vault.azure.net/";
string secretName = "MyConnectionString";
var client = new SecretClient(new Uri(kvUri), new DefaultAzureCredential());
var secret = await client.GetSecretAsync(secretName);
Console.WriteLine(secret?.Value?.Value);

still the same 403 forbidden error
We need to enable the system-assigned Managed Identity on the VM which we have deployed our Web App.
And provide the permissions for the Identity which you have set in previous step.Run the below command in Azure CLI
az keyvault set-policy --name 'KeyVaultName' --object-id "ObjectID of SystemAssigned Managed Identity" --secret-permissions get list set delete
Make sure you have given access permissions to retrieve the Key Vault.
In Azure Keyvault => Access policies , select the Get,List permissions and provide the Principal - name will be same as your deployed WebApp , continue with the steps and Review +create

Related

How can i use Azure System Assigned Identity in an App Service that connects to an Azure database?

I have an App Service in Azure and have created a System Assigned Identity , it gave a Object (principal) Id . I then went to Azure Active Directory and Under Al applications searched for that Identity, it was there.
I then went to the Sql Server and turned on System assigned managed identity under Identity.
I then went to my connection string in the database and set it as
Server=my-sql-server.database.windows.net,1433;Database=my-database;Authentication=Active
Directory Default
But if i start up my App Service and try to login , it requires a connection to the database but it doesnt connect , it just gives
<appservice_url>?error=database
Any ideas on what is not setup correctly ? or is there a step by step guide on setting this up ?
The part that seems missing is: The managed identity of the app service needs to be granted permissions to access the database
Tutorial is here:
https://learn.microsoft.com/en-us/azure/app-service/tutorial-connect-msi-azure-database?tabs=sqldatabase%2Csystemassigned%2Cnetfx%2Cwindowsclient

Azure SQL authentication using Azure Active Directory

Connection works fine following this tutorial when using:
var connection = (SqlConnection)Database.GetDbConnection();
connection.AccessToken = (new Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProvider()).GetAccessTokenAsync("https://database.windows.net/").Result;
But now the docs say "Microsoft.Azure.Services.AppAuthentication is no longer recommended"
So changing my connection as described in Using Azure Active Directory authentication with SqlClient I get the following errors:
Using Active Directory Integrated authentication
Integrated Windows Auth is not supported for managed users.
Using Active Directory Managed Identity authentication
Tried to get token using Managed Identity. Access token could not be acquired. A socket operation was attempted to an unreachable network. (169.254.169.254:80)
Nothing is blocking that address, but also where is it getting that IP from? The tutorial's code used https://database.windows.net/ to get the token (which resolves 65.55.23.107).
Can/should I override that address somewhere?
Any other config missing?
These auth ways apply to different scenarios, for example, if you want to use Active Directory Integrated authentication, you need to federate the on-premises AD with Azure AD via ADFS, if you want to use Active Directory Managed Identity authentication, you must run your code in an Azure service which supports MSI(need to enable MSI first), because the code essentially makes an API call to the azure instance metadata endpoint to get the access token, then use the token to auth, it is just available in the MSI-supported service.
So if you want to migrate the code from the old sdk to the new one, you need to choose the correct auth way that applies to your scenario. Here I recommend you to use the Active Directory Service Principal authentication, it can apply to any scenario, please follow the steps below.
1.Register an application with Azure AD and create a service principal.
2.Get values for signing in and create a new application secret.
3.Grant the permission to the service principal with CREATE USER [Azure_AD_Object] FROM EXTERNAL PROVIDER.
4.Then use the code here, fix the values with yours and got from step 2.
string ConnectionString = #"Server=demo.database.windows.net; Authentication=Active Directory Service Principal; Database=testdb; User Id=AppId; Password=secret";
using (SqlConnection conn = new SqlConnection(ConnectionString)) {
conn.Open();
}

Can any program running in the VM or any user logged into the VM get a token using the Azure Managed Service Identity?

When we store the Service principal certificate/appKey in the VM (to access the keyvault), we could limit access to that file to just the user account running the program. Other users or accounts wouldn't have access to the secrets in keyvault.
When we use Azure Managed Service Identity to access keyvault from an IaaS VM, my understanding is that any user logged into the VM or any program running on the machine can access the keyvault secrets - is this true?
And if it is, doesn't that decrease the security in case one of the user accounts is compromised?
According to the article access Azure Key Vault, it seems this is true. If MSI is enabled, just need to invoke web request in the VM without e.g. appKey.
And if it is, doesn't that decrease the security in case one of the user accounts is compromised?
It should be, but the prerequisites of the access to the secret in the keyvault is the VM service principal was added as a role in Access control (IAM) and Access policies.
If you want to increase the security, you may need to remove the VM service principal in the Access policies, then it will not be able to access the secret, if you want to the service principal does not have the access to the keyvault at all, remove its role in Access control (IAM).
For more details, you could refer to: Secure your key vault.
Update:
From the doc #Arturo mentioned, it is the fact.
Any code running on that VM, is able to call the managed identities for Azure resources endpoint and request tokens.

asp.net secrets in PROD

I have been using the new .net 4.7.1 functionality to manage secrets locally in DEV but now I want to publish my web app and of course that doesn't work in PROD.
I am using a service principal to access Azure key vault in my app and was storing the App Id and Password in the local secrets file. I can of course store all of my secrets in Key vault but I still need to supply it the service principal details to connect to that in the first place.
What's the best option here?
You can use Managed Identities so you don't have to store any secret in your app:
How to use managed identities for App Service and Azure Functions
Once configured, add a reference to these nuget packages: Microsoft.Azure.Services.AppAuthentication and Microsoft.Azure.KeyVault
In you application, you can access key vault secrets like that:
using Microsoft.Azure.KeyVault;
using Microsoft.Azure.Services.AppAuthentication;
...
var azureServiceTokenProvider = new AzureServiceTokenProvider();
var keyVaultClient = new KeyVaultClient(
new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
var secret = await keyVaultClient.GetSecretAsync(
"https://{{my-vault-name}}.vault.azure.net/", "{{my-secret}}");
You need to store the values you use to open the key vault in the App settings of your application. If your production environment is Azure, you can access the App settings of your application and set them there.
Read this article to get an idea of the full picture. But the jist is that you can use application secrets in a Azure key valut and then use app settings to store the credentials to access that key vault later on.

Storing Azure Vault Client ID and Client Secret

I am using .NET Core 2.0 and ASP.NET Core 2.0 for application development. The "test" application is a .NET Core Console application. The core code I am writing is a class library. Once proper testing. I choose to do this since I won't be putting this to use for awhile (it's replacing older ASPNET code).
Anyway, since I have to work with a LOT of API keys for various services I decided to use Microsoft Azure Key Vault for storing the keys. I have this all setup and understand how this works. The test application uses a test Azure account so it's not critical. And since this is replacing legacy code and it's in the infancy, I am the sole developer.
Basically, I'm running into this issue. There's not too much information on Azure Key Vault from what I can see. A lot of examples are storing the Client ID and Secret in a plain text json file (for example: https://www.humankode.com/asp-net-core/how-to-store-secrets-in-azure-key-vault-using-net-core). I really don't understand how this can be secure. If someone were to get those keys they could easily access stored information Azure, right?
The Microsoft MSDN has a powershell command that grants access (I lost the original link, this is closest I can find: https://www.red-gate.com/simple-talk/cloud/platform-as-a-service/setting-up-and-configuring-an-azure-key-vault/) My development operating system is Windows 10 and my primary server operating system is Debian.
How would I approach this?
Yes, you are right, the plain text config file could be used only during development, not for production purpose. And in general, available options depend on where and how you host an App.
If you have an Azure Web App, you have at least next built-in options (from the documentation):
add the ClientId and ClientSecret values for the AppSettings in the Azure portal. By doing this, the actual values will not be in the web.config but protected via the Portal where you have separate access control capabilities. These values will be substituted for the values that you entered in your web.config. Make sure that the names are the same.
authenticate an Azure AD application is by using a Client ID and a Certificate instead of a Client ID and Client Secret. Following are the steps to use a Certificate in an Azure Web App:
Get or Create a Certificate
Associate the Certificate with an Azure AD application
Add code to your Web App to use the Certificate
Add a Certificate to your Web App
You may also find an approach that uses env variables to store credentials. This may be OK only if you can guarantee that it's not possible to do a snapshot of env variable on prod machine. Look into Environment Variables Considered Harmful for Your Secrets for more details.
And the last one thing: there is also a technic that based on the idea, that you need to store/pass only a ClientSecret value while ClientId should be constructed based on machine/container details where the App is hosted (e.g. docker container id). I have found an example for Hashicorp Vault and an App hosted on AWS, but the general idea is the same: Secret management with Vault
In addition to the first answer, with the context of running applications on Azure VM, instead of using client_secret to authenticate, you can use client certificate authentication as explained in this documentation: Authenticate with a Certificate instead of a Client Secret.
In the picture above:
Application is authenticating to AAD by proving that it has the private key of the certificate (which is basically stored in CNG if you are using Windows).
Application get back the access_token and then use it to access the Key Vault.
The developer does not need to know the private key value of the certificate in order for their app to be successfully authenticated. Instead, they only need to know the location of the imported pfx (a container for private key and its certificate) in the Certificate Store.
At least on Windows, you as secret administrator can convert the private key and the certificate into pfx format which is password protected, and then deploy it into the Windows Certificate store. This way no one could know the private key unless they know the password of the pfx file.
The other approach specifics for Azure Compute, is to use Azure Managed Service Identity. Using Azure MSI, Azure will automatically assign your resources such as VM with an identity / Service Principal, and you can fire requests at a specific endpoint that are only accessible by your resource to get the access_token. But be wary that Azure MSI are still under public preview, so please review the known issues before using it.
The picture above explain how Azure Resource Manager assign a Service Principal identity to your VM.
When you enable MSI in a VM, Azure will create a service principal in your AAD.
Azure will then deploy a new MSI VM extension to your VM. This provides an endpoint at http://localhost:50432/oauth2/token to be used to get the access_token for the service principal.
You can then use the access_token to access the resources such as Key Vault which authorize the service principal access.

Resources