-
Notifications
You must be signed in to change notification settings - Fork 353
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding Credential Probe logic #5116
Conversation
@@ -152,8 +152,9 @@ private async Task<AuthenticationResult> SendTokenRequestForManagedIdentityAsync | |||
|
|||
await ResolveAuthorityAsync().ConfigureAwait(false); | |||
|
|||
ManagedIdentityClient managedIdentityClient = | |||
new ManagedIdentityClient(AuthenticationRequestParameters.RequestContext); | |||
ManagedIdentityClient managedIdentityClient = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gladjohn - we discussed that you'd start a feature branch? The base branch for this PR is main.
|
||
namespace Microsoft.Identity.Client.ManagedIdentity | ||
{ | ||
internal class CredentialManagedIdentitySource : AbstractManagedIdentity |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: maybe we just call it SLC or MSIv2 ? Credential is such an overloaded term.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact, should it be ImdsV2Source
? I would imagine that Arc, SF etc. will be sligthly different.
HttpContent httpContent = request.CreateHttpContent(); | ||
|
||
_logger.Info($"[Credential Probe] Sending request to {CredentialEndpoint}"); | ||
_logger.Verbose(() => $"[Credential Probe] Request Headers: {string.Join(", ", request.Headers)}"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a little dangerous to log headers and body. Maybe don't do it unless we really need it.
} | ||
catch (Exception ex) | ||
{ | ||
_logger.Error($"[Credential Probe] Exception during probe: {ex.Message}"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not really an error is it? It is part of the normal flow. It will confuse ppl. We've did this before in regional and ppl complained that the logs are too noisy. Pls use info level.
I also recommend you do not print the full exception here, just the message should be suficient.
{ | ||
if (response == null) | ||
{ | ||
_logger.Error("[Credential Probe] No response received from the server."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not an error ?
|
||
if (response.Body != null) | ||
{ | ||
_logger.Verbose(() => $"[Credential Probe] Response Body: {response.Body}"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
avoid printing entire reponse body. it could have PII or worse, some secrets.
|
||
LogResponseDetails(response); | ||
|
||
return EvaluateProbeResponse(response); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it worth recording in telemetry about this? I guess we will know MSAL version and MSI source already - will this be enough?
|
||
LogResponseDetails(response); | ||
|
||
return EvaluateProbeResponse(response); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private readonly AbstractManagedIdentity _identitySource; | ||
|
||
public ManagedIdentityClient(RequestContext requestContext) | ||
internal static async Task<ManagedIdentityClient> CreateAsync(RequestContext requestContext, CancellationToken cancellationToken = default) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the requestContext has the cancellation token, but it's ok to move it as last param. But I recommend you do not use a default.
{ | ||
_identitySource = SelectManagedIdentitySource(requestContext); | ||
throw new ArgumentNullException(nameof(requestContext), "RequestContext cannot be null."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't be null. Don't throw.
{ | ||
ManagedIdentitySource.ServiceFabric => ServiceFabricManagedIdentitySource.Create(requestContext), | ||
ManagedIdentitySource.AppService => AppServiceManagedIdentitySource.Create(requestContext), | ||
ManagedIdentitySource.MachineLearning => MachineLearningManagedIdentitySource.Create(requestContext), | ||
ManagedIdentitySource.CloudShell => CloudShellManagedIdentitySource.Create(requestContext), | ||
ManagedIdentitySource.AzureArc => AzureArcManagedIdentitySource.Create(requestContext), | ||
ManagedIdentitySource.Credential => CredentialManagedIdentitySource.Create(requestContext), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
naming: avoid using "credential". Maybe "ImdsV2" or smth
/// <param name="cancellationToken"></param> | ||
/// <returns></returns> | ||
/// <exception cref="ArgumentNullException"></exception> | ||
public static async Task<ManagedIdentitySource> GetManagedIdentitySourceAsync( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logic is too complex. Why do we have 2 public methods - one with the probe and one without the probe?
/// <param name="logger"></param> | ||
/// <param name="cancellationToken"></param> | ||
/// <returns></returns> | ||
private static async Task<ManagedIdentitySource> ComputeManagedIdentitySourceAsync( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please have a look at all these method names and consolidate. They are so many "select source", "compute source", etc.
|
||
if (s_cachedManagedIdentitySource.HasValue) | ||
{ | ||
return s_cachedManagedIdentitySource.Value; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't Azure SDK need a way to reset this? For their tests?
Maybe it's time we expose a "ResetCachesForTest()" method in the extensibility namespace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- feature branch
- retry policy
- reset caches for test
Fixes #5115
Changes proposed in this request
This pull request introduces significant changes to the managed identity authentication process in the Microsoft Identity Client. The changes include adding new classes for handling credential-based managed identity, updating existing methods to support asynchronous operations, and improving logging and error handling.
Key Changes:
New Classes and Methods:
CredentialManagedIdentitySource
: A new class to handle credential-based managed identity, including a factory method for creating instances and a method to create minimal valid requests.ImdsCredentialProbeManager
: A new class to probe the IMDS credential endpoint and evaluate the response to determine if the endpoint is supported.Asynchronous Operations:
ManagedIdentityClient
: Updated to include an asynchronous factory methodCreateAsync
and to use the newCredentialManagedIdentitySource
as a potential identity source.SendTokenRequestForManagedIdentityAsync
: Updated to use the asynchronous creation method forManagedIdentityClient
.Logging and Error Handling:
ManagedIdentityClient
andImdsCredentialProbeManager
to provide detailed information about the managed identity source selection and probe execution. [1] [2]Public API Changes:
Credential
toManagedIdentitySource
to indicate the use of credential-based managed identity.GetManagedIdentitySourceAsync
inManagedIdentityApplication
to detect the managed identity source in the environment.Retry logic
These changes aim to improve the flexibility and reliability of the managed identity authentication process by supporting new identity sources and enhancing the existing mechanisms.
Testing
unit tests been added
Performance impact
Before we fallback to IMDS we check for /credential endpoint so sources like App Service, Azure ARC that are determined by environment variables should not have any issues. However, for Resource providers that do not plan to use /credential endpoint and rely on the IMDS fallback logic will have one more source detection before the fallback.
Documentation