How to authenticate via MSI locally
See original GitHub issueThis question was originally asked in the wrong repository. @shahabhijeet asked me to create a new issue here.
I want to login with MSI when I develop locally. The documentation isn’t update because I see nothing about the method:
SdkContext.AzureCredentialsFactory.FromMSI(new MSILoginInformation(MSIResourceType.AppService), AzureEnvironment.AzureGlobalCloud)
How can I develop locally with MSI so it will use the user selected from the Visual Studio 2017 (latest version) option “Azure Service Authentication”.
You can use this in example for getting values out of a keyvault via a KeyVaultClient
.
var azureServiceTokenProvider = new AzureServiceTokenProvider();
var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
You could also generate accesstokens in this way:
var azureServiceTokenProvider = new AzureServiceTokenProvider();
string token await azureServiceTokenProvider.GetAccessTokenAsync(RESOURCE HERE, TENANTID HERE);
After that, you could use the token to call a rest api. But I don’t want that, I want to use this library with MSI.
Getting MSI to work in Azure with fluent can be done with this workaround. I’m more interested in the local development part.
public async Task<Azure.IAuthenticated> GetAzureConnection()
{
if (_azure != null)
{
return _azure;
}
AzureCredentials credentials;
string localDevelopment = Environment.GetEnvironmentVariable("LocalDevelopment", EnvironmentVariableTarget.Process);
if (!string.IsNullOrEmpty(localDevelopment) &&
string.Equals(localDevelopment, "true", StringComparison.InvariantCultureIgnoreCase))
{
Log.LogDebug($"Get the local service principal for local login");
var localDevSp = new Principal
{
UserPrincipalName = "LocalLogin",
AppId = Environment.GetEnvironmentVariable("ClientId", EnvironmentVariableTarget.Process),
TenantId = Environment.GetEnvironmentVariable("TenantId", EnvironmentVariableTarget.Process)
};
string clientSecret = Environment.GetEnvironmentVariable("ClientSecret", EnvironmentVariableTarget.Process);
Log.LogDebug($"AppId: {localDevSp.AppId}, TenantId: {localDevSp.TenantId}");
credentials = SdkContext
.AzureCredentialsFactory
.FromServicePrincipal(localDevSp.AppId, clientSecret, localDevSp.TenantId, AzureEnvironment.AzureGlobalCloud);
}
else
{
Log.LogDebug($"Get the MSI credentials");
// Because MSI isn't really nicely supported in this nuget package disable it for now and user workaround
////credentials = SdkContext
//// .AzureCredentialsFactory
//// .FromMSI(new MSILoginInformation(MSIResourceType.AppService), AzureEnvironment.AzureGlobalCloud);
try
{
// START workaround until MSI in this package is really supported
string tenantId = Environment.GetEnvironmentVariable("TenantId", EnvironmentVariableTarget.Process);
Log.LogDebug($"TenantId: {tenantId}");
AzureServiceTokenProvider astp = new AzureServiceTokenProvider();
string graphToken = await astp.GetAccessTokenAsync("https://graph.windows.net/", tenantId);
AzureServiceTokenProvider astp2 = new AzureServiceTokenProvider();
string rmToken = await astp2.GetAccessTokenAsync("https://management.azure.com/", tenantId);
Log.LogDebug("Logging with tokens from Token Provider");
AzureCredentials customTokenProvider = new AzureCredentials(
new TokenCredentials(rmToken),
new TokenCredentials(graphToken),
tenantId,
AzureEnvironment.AzureGlobalCloud);
RestClient client = RestClient
.Configure()
.WithEnvironment(AzureEnvironment.AzureGlobalCloud)
.WithLogLevel(HttpLoggingDelegatingHandler.Level.Basic)
//.WithRetryPolicy(new RetryPolicy(new HttpStatusCodeErrorDetectionStrategy(), new IncrementalRetryStrategy(2, TimeSpan.FromSeconds(30), TimeSpan.FromMinutes(1))))
.WithCredentials(customTokenProvider)
.Build();
return Azure.Authenticate(client, tenantId);
// END workaround until MSI in this package is really supported
}
catch (Exception ex)
{
Log.LogError(ex, ex.Message);
if (ex.InnerException != null)
{
Log.LogError(ex.InnerException, ex.InnerException.Message);
}
throw;
}
}
ServiceClientTracing.AddTracingInterceptor(new MicrosoftExtensionsLoggingTracer(Log));
ServiceClientTracing.IsEnabled = true;
_azure = Azure
.Configure()
.WithDelegatingHandler(new HttpLoggingDelegatingHandler())
.WithLogLevel(HttpLoggingDelegatingHandler.Level.None)
.Authenticate(credentials);
return _azure;
}
Issue Analytics
- State:
- Created 5 years ago
- Reactions:8
- Comments:7 (1 by maintainers)
Top GitHub Comments
I went down the path of using Azure.Identity.DefaultAzureCredential which has logic to work locally and on Azure app service and call the REST endpoint https://management.azure.com directly.
I just wish SDK would leverage Azure.Identity package rather than reinventing for Fluent SDK. Other SDK like Azure.Security.KeyVault.Secrets.SecretClient supports this already. It would be nice to be able to use the same authentication mechanism when working with different azure libraries/SDK for .NET
33 months later the new SDK is still in beta and we still can’t use Fluent MSI implementation locally during development. I realize we have a (painful) workaround, but I really would like to see this incorporated into the Fluent API.