4

I'm trying to connect my .Net Core 3.1 app up to an Azure Key Vault. I've followed the quickstart tutorial, and am getting the following error:

Microsoft.Extensions.Configuration.AzureAppConfiguration.KeyVaultReferenceException: 'DefaultAzureCredential authentication failed.. ErrorCode:, Key:Authentication:Twitter:ConsumerAPIKey

The inner exception is:

MsalServiceException: AADSTS70002: The client does not exist or is not enabled for consumers

The CreateHostBuilder method looks like this:

public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder
                    .ConfigureAppConfiguration((hostingContext, config) =>
                    {
                        var settings = config.Build();

                        config.AddAzureAppConfiguration(options =>
                        {
                            options.Connect(settings["ConnectionStrings:AppConfig"])
                                .ConfigureKeyVault(kv =>
                                {
                                    kv.SetCredential(new DefaultAzureCredential());
                                });
                        });
                    })
                    .UseStartup<Startup>();
            });

I've found very little reference to this online, except one post relating to using multiple credentials (which I am not).

Can anyone give me a way forward on this: some clue as to what might be causing it?

EDIT

The following seems to work:

var defaultAzureCredentialsOptions = new DefaultAzureCredentialOptions()
{                                
    SharedTokenCacheTenantId = <tenant id>,
    SharedTokenCacheUsername = <my azure username>,
    ExcludeInteractiveBrowserCredential = false,
    ExcludeEnvironmentCredential = false,
    InteractiveBrowserTenantId = <tenant id>
};

config.AddAzureAppConfiguration(options =>
{                                
    options.Connect(settings["ConnectionStrings:AppConfig"])
        .ConfigureKeyVault(kv =>
        {
            kv.SetCredential(new DefaultAzureCredential(defaultAzureCredentialsOptions));
        });
});

Whilst this does work (as far as it goes), I now have the Tenant ID and my username hard-coded; along with a pop-up when I launch the site asking me to log-in.

Paul Michaels
  • 16,185
  • 43
  • 146
  • 269
  • It could be picking up an account you have authenticated to in Visual Studio to access the Key Vault, but the account is a personal Microsoft account that does not exist in the Azure AD. You can try specifying your Azure AD tenant id as the SharedTokenCacheTenantId (IIRC), as well as other tenant ids in the options object. – juunas May 25 '20 at 08:04
  • @juunas - you might be onto something. If I specify SharedTokenCacheTenantId and SharedTokenCacheUsername I get a forbidden error from Key Vault. Although I've given my username every permission available in the Access Policies blade, and I still get a forbidden message – Paul Michaels May 25 '20 at 13:13
  • Okay that is odd :\ – juunas May 25 '20 at 13:15
  • @juunas following your suggestion, I have sort of got it working (see edit). My guess is that I'm missing some config or setting (clearly I shouldn't have to hard code my tenant id and username into the system) – Paul Michaels May 25 '20 at 13:31
  • Oh the pop-up is pretty weird. Are the interactive credentials disabled in the options for DefaultAzureCredential? – juunas May 25 '20 at 14:22
  • Not explicitly; the docs imply the default setting is not interactive; which is probably borne out by my tests. – Paul Michaels May 25 '20 at 17:48
  • I've faced this problem before. It only worked after I've added the nuget package Microsoft.Azure.Services.AppAuthentication – Thiago Custodio May 27 '20 at 22:02
  • @ThiagoCustodio - tried that, unfortunately, it made no difference – Paul Michaels May 28 '20 at 07:02

1 Answers1

6

The DefaultAzureCredential goes through a number of credentials, such as Managed Identity which is recommended for Azure services as being more secure (no shared access tokens).

You can, however, use environment variables set for your application or even during local development, namely:

  • AZURE_TENANT_ID : tenant ID
  • AZURE_CLIENT_ID : the service principal ID, which must have been granted necessary permissions like list and get for how you're using them in your example
  • AZURE_CLIENT_SECRET : the service principal secret (password), which was shown to you only after it was created

If you use the new preview version of Azure.Identity, it also supports Azure CLI, Visual Studio, and other credentials for development environments. For exampe, if you use the Azure CLI, once you az login, DefaultAzureCredential will just work.

Heath
  • 2,986
  • 18
  • 21
  • Adding the service principal does work locally. I tried installing the preview of Azure.Identity - it made no difference. So, I have a related question around deployment. The deployed version doesn't work - I assume because the environment variables AZURE_CLIENT_ID, etc.. are not set; but surely these need to be encrypted (i.e. in KeyVault)? – Paul Michaels May 28 '20 at 19:10
  • They need to be secured in your application configuration, but cannot be encrypted by Key Vault because they are needed to access Key Vault. If your platform already supports encrypting secrets at rest (e.g. Azure Pipelines or GitHub Actions), those environment variable values would be best kept as secrets; however, why not just use those platforms' secrets then? But for your hosted application, typically adding those required environment variables is common - the hope that very few - and trusted - people can access/change your application's settings. – Heath May 29 '20 at 23:47
  • 1
    That’s sort of what I was getting at. At some stage, you need to store the keys to the castle outside of KeyVault, I’m starting to wonder what the advantage of using it at all is. It seems like wherever you store the key, you might as well store the rest of the values :-) – Paul Michaels May 30 '20 at 05:05
  • That's a good analogy, yes, but to extend that analogy, you don't give the keys to just anyone. Administrators (you and hopefully at least one other person) need to be able to configure the app, update settings, etc. When defining these values in your application as environment variables, or setting up Managed Identity (recommended), they will be able to see those values. But hopefully administrators are trusted. Some - perhaps all - might even be people with access to the Key Vault anyway. That should be a small list. – Heath May 30 '20 at 21:39
  • 1
    (Sorry, this has clearly drifted away from the question). If you’re storing details that allow you to access the KeyVault, then KeyVault is only as secure as its keys. So why not just store everything wherever you would store the KeyVault secret: it’s, by definition, no less secure. – Paul Michaels May 31 '20 at 07:13
  • Again, it's about who can access it. Your application administrators should be a very small list of people. There's also the matter of get/list vs. set access. Who has rights to rotate certificates, for example? Keys also have permissions about who can encrypt or decrypt, sign or verify, etc. There's more management. But a lot of this is mitigate by using Managed Identity intsead of shared access tokens. – Heath Jun 03 '20 at 03:17
  • Hi, What If I host the app into the Azure App Service? I am getting this error only in App Service but not in my local. – Md Aslam Sep 17 '20 at 06:47
  • If you're hosting your application in Azure, use Managed Identity. No password is ever exposed or shared. See https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview for an overview of Managed Identity. As for Paul's comments, if you can't trust your admins, you have another problem. But the issue is separating control from development and runtime. You can set environment variables to authenticate a service principal to production secrets, while developers can use their own. That's what we do in developing the Azure SDKs, and is common in production. – Heath Sep 19 '20 at 15:40
  • 1
    I just want to emphasize @PaulMichaels's point. If you're using KeyVault to store config secrets, and you store your KeyVault credentials in your config, there's no point in using KeyVault. If your config becomes compromised, then your Keyvault is as well, so it defeats the purpose. – Josh Noe Sep 25 '20 at 15:38
  • That's why you don't store your credentials in your application configuration. Use Managed Identity, or set environment variables to which few admins have access. If you have different identities configured, you can even limit which operations each identity can perform, or set up separate vaults if necessary. If you can't trust your admins, that's a whole separate problem. – Heath Sep 25 '20 at 18:43