I'm attempting to connect to an Azure Key Vault instance from a .NET 4.7
application running locally under IIS and the debugger (Visual Studio 2022 17.4.4
) but am encountering the below exception(s) from the Azure.Identity
package when it attempts to retrieve a token to authenticate to Azure when calling to perform a KeyVault action such as GetSecretAsync()
.
DefaultAzureCredential failed to retrieve a token from the included credentials. See the troubleshooting guide for more information. https://aka.ms/azsdk/net/identity/defaultazurecredential/troubleshoot
- ManagedIdentityCredential authentication unavailable. Multiple attempts failed to obtain a token from the managed identity endpoint.
- Visual Studio Token provider can't be accessed at C:\WINDOWS\system32\config\systemprofile\AppData\Local.IdentityService\AzureServiceAuth\tokenprovider.json
I need to connect to the KeyVault instance via a User Assigned Managed Identity in cloud environments such as production, whereas in development environments, we therefore need to connect via the developer's Visual Studio account to authenticate them to access the service, similarly. Perhaps I have misunderstood, but I believed this is possible via the DefaultAzureCredential
option, which will try various methods of authentication in order (such as environment variables, managed identities, then Visual Studio credentials, etc) until one succeeds.
When inspecting the inner exception(s) relating to the Visual Studio Credentials flow, I see the System.Exception {System.IO.DirectoryNotFoundException}
exception message states...
"Could not find a part of the path 'C:\WINDOWS\system32\config\systemprofile\AppData\Local.IdentityService\AzureServiceAuth\tokenprovider.json'.
Previously, this message had stated the below message (which I understand to be the more recent location for this file), until I attempted to run under Visual Studio 2019 for comparison, at which point, it changed to the above message.
"Could not find a part of the path C:\Users[AppPoolName]\AppData\Local.IdentityService\AzureServiceAuth\tokenProvider.json".
At first, I noticed the path didn't exist from .IdentityService
onward, and so followed the suggestion on this MSFT forum post to restore the AppAuthentification
extension from VS2019 into VS2022's configuration to restore the C:\Users\<AppPoolName>\AppData\Local\.IdentityService\AzureServiceAuth\tokenprovider.json
file and providers the TokenProviders
as a path to C:\Program Files (x86)\Microsoft Visual Studio\<version>\Enterprise\Common7\IDE\Extensions\<random dir name>\TokenService\Microsoft.Asal.TokenService.exe
. On the next build, I noticed .IdentityService
had been created, but not the proceeding directory or file.
I then tried logging out and into Visual Studio a number of times, but this did not seem to create the remaining missing directory and file. Creating the directory and file manually of course resolve the System.IO.DirectoryNotFoundException
, but the error message then informs me that the file schema is incorrect. I'm unable to find an example with the correct schema and values.
In terms of client configuration options, I've been explicitly limiting the modes of authentication flow to just ManagedIdentity
and VisualStudioCredential
for simplicity after noticing other methods (e.g. AzureCLI
and Azure PowerShell Module` also failed, despite being logged in to them).
_client = new SecretClient(new Uri(options.KeyVaultUri), new DefaultAzureCredential(
new DefaultAzureCredentialOptions
{
ExcludeManagedIdentityCredential = false,
ExcludeVisualStudioCredential = false,
ExcludeInteractiveBrowserCredential = true,
ExcludeAzurePowerShellCredential = true,
ExcludeAzureCliCredential = true,
ExcludeEnvironmentCredential = true,
ExcludeVisualStudioCodeCredential = true,
ExcludeSharedTokenCacheCredential = true,
ManagedIdentityClientId = options.ManagementIdentityClientId
}
));
I've also tried the suggestions on Azure SDK GitHub Issue #4590 of settings setProfileEnvironment
and loadUserProfile
to true
in case it's an IIS permissions issue, but this made no difference - the same errors continue.
Finally, the only other reference I've found to the tokenProvider.json
file is in Microsoft's documentation for App Authentication, but the re-authenticate button doesn't exist in the Tools > Options > Azure Service Authentication
window as suggested.
"If you run into problems using Visual Studio, such as errors that involve the token provider file, carefully review the preceding steps.
You may need to reauthenticate your developer token. To do so, select Tools > Options, and then select Azure Service Authentication. Look for a Re-authenticate link under the selected account. Select it to authenticate."
As I'm able to locate C:\Program Files (x86)\Microsoft Visual Studio\<version>\Enterprise\Common7\IDE\Extensions\<random dir name>\TokenService\Microsoft.Asal.TokenService.exe
and its related configuration file, I suspect it's the missing tokenProvider.json
file that's the issue, but I'm not aware of what is responsible for creating that, nor what it should contain.
Any insight or pointers would be appreciated.
Notable packages and their versions in use:
Edit (1)
As one might expect, I'm able to configure an alternative flow to work by granting an RBAC record upon the Key Vault for an Azure AD Application Registration and then using the ClientSecretCredential
flow in place of the DefaultAzureCredentials
flow (as below). But this doesn't solve the problem in the best way so I'd be interested if anyone can spot where I'm going wrong with the DefaultAzureCredentials
flow, if at all.
_client = new SecretClient(new Uri(options.KeyVaultUri),
new ClientSecretCredential(options.TenantId, options.ClientId, options.Secret)
);
CodePudding user response:
Having found this question on SO, I found that tokenProvider.json
existed in the same directory under C:\Users\<local user account>
(via %LOCALAPPDATA%.IdentityService\AzureServiceAuth\
) and was able to analyse it for reference and duplicate it to the IIS.
As suggested by Johnny5, it seems VisualStudioCredentials
executes as the signed-in domain user, but IIS is running as the ApplicationPoolIdentity
, hence it doesn't access the file under the domain user location and doesn't create one as it's not signed into Visual Studio. After a little research on how to alter this, I was able to set the IIS Application Pool identity as my domain user which matched the signed-in Visual Studio account.
To do this, follow these steps
- Open
IIS Manager
> Go toApplication Pools
- Right-click the relevant pool, then click
Advanced Settings...
- Click the 3-dot button next to the
Identity
settings (likelyApplicationPoolIdentity
) - Select
Custom Account
and enter your credentials (including any domain prefix - e.g.DOMAIN\MyUser
)
If you aren't sure of your domain, open a command prompt and enter echo %USERDOMAIN%
to find it.
I then set the SecretClient
authentication flow back to utilise DefaultAzureCredential
like so, re-tested locally, and success - secrets retrieved.
_client = new SecretClient(new Uri(options.KeyVaultUri), new DefaultAzureCredential(
new DefaultAzureCredentialOptions()
{
ExcludeEnvironmentCredential = true,
ExcludeVisualStudioCodeCredential = true,
ExcludeAzureCliCredential = true,
ExcludeAzurePowerShellCredential = true,
ExcludeSharedTokenCacheCredential = true,
ExcludeInteractiveBrowserCredential = true,
ExcludeManagedIdentityCredential = false,
ExcludeVisualStudioCredential = false,
ManagedIdentityClientId = options.ManagementIdentityClientId,
}));