Skip to content
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

Azure.Identity: support MSI_CLIENT_ID or AZURE_CLIENT_ID env var for User Assigned Identities #18253

Closed
ppanyukov opened this issue Jan 28, 2021 · 8 comments
Assignees
Labels
Azure.Identity Client This issue points to a problem in the data-plane of the library. customer-reported Issues that are reported by GitHub users external to the Azure organization. needs-team-attention Workflow: This issue needs attention from Azure service team or SDK team question The issue doesn't require a change to the product in order to be resolved. Most issues start as that

Comments

@ppanyukov
Copy link

Library or service name.
Azure.Identity.

Is your feature request related to a problem? Please describe.

This affects App Services and Function Apps with user assigned identity.

The standard method to obtain credential in app service is this:

credentials = new DefaultAzureCredential();

As per docs, this will try to obtain token using this chain: Environment, Managed Identity, Visual Studio, VS Code, Azure CLI.

All good and well, except that does not work with User Assigned Managed Identities, it only works with System Assigned MSIs.

The reason for this is we need to specify client id of User Assigned MSI.

This leads to many undesirable things:

  • Separate code paths just for User Assigned MSI.
  • Figuring out if we run locally on in Azure to support local machine scenarios. E.g. this is the kind of code we need to write:
TokenCredential credentials;
var _isLocal = string.IsNullOrEmpty(Environment.GetEnvironmentVariable("WEBSITE_HOSTNAME"));
if (_isLocal)
{
    Console.WriteLine("Using local DefaultAzureCredential");
    credentials = new DefaultAzureCredential();
}
else
{
    Console.WriteLine("Using MSI credentials");
    credentials = new ManagedIdentityCredential(msiClientId);
}

Proposal

Support MSI_CLIENT_ID env variable or repurpose existing AZURE_CLIENT_ID.

We can set this in App Settings, either during terraform, or during deployment. If MSI_CLIENT_ID is set, the library will use client id specified there when getting MSI token.

For example, add support for env var here: https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/identity/Azure.Identity/src/EnvironmentVariables.cs#L19

internal class EnvironmentVariables
{
    // Either reuse this.
    public static string ClientId => Environment.GetEnvironmentVariable("AZURE_CLIENT_ID");
    // ...
    public static string MsiEndpoint => Environment.GetEnvironmentVariable("MSI_ENDPOINT");
    public static string MsiSecret => Environment.GetEnvironmentVariable("MSI_SECRET");
    // Or add this.
    public static string MsiClientId => Environment.GetEnvironmentVariable("MSI_CLIENT_ID");
}

Here is how the code might look here: https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/identity/Azure.Identity/src/AppServiceV2017ManagedIdentitySource.cs#L54

protected override Request CreateRequest(string[] scopes)
{
    // covert the scopes to a resource string
    string resource = ScopeUtilities.ScopesToResource(scopes);

    Request request = Pipeline.HttpPipeline.CreateRequest();

    request.Method = RequestMethod.Get;
    request.Headers.Add("secret", _secret);
    request.Uri.Reset(_endpoint);
    request.Uri.AppendQuery("api-version", AppServiceMsiApiVersion);
    request.Uri.AppendQuery("resource", resource);

    if (!string.IsNullOrEmpty(_clientId))
    {
        request.Uri.AppendQuery("clientid", _clientId);
    } 
    // Add a couple of extra else ifs.
    else if (!string.IsNullOrEmpty(EnvironmentVariables.MsiClientId))
    {
        // Use client id from env var if present.
        request.Uri.AppendQuery("clientid", EnvironmentVariables.MsiClientId);
    }
    else if (!string.IsNullOrEmpty(EnvironmentVariables.ClientId))
    {
        // Repurpose exisitng AZURE_CLIENT_ID if present.
        request.Uri.AppendQuery("clientid", EnvironmentVariables.ClientId);
    }

    return request;
}

Benefits

  • Uniform workflow regardless of auth method, works both locally and in Azure transparently.
  • Setting MSI_CLIENT_ID or AZURE_CLIENT_ID is easy via App Settings. It is terraformable, or easy to set during deployments. The use of AZURE_CLIENT_ID is already supported and documented, so this change will not be out of line.
  • Other features like Key Vault references may start to work with User Assigned Identities, if they use Azure.Identity library under the hood.
@ghost ghost added needs-triage Workflow: This is a new issue that needs to be triaged to the appropriate team. customer-reported Issues that are reported by GitHub users external to the Azure organization. question The issue doesn't require a change to the product in order to be resolved. Most issues start as that labels Jan 28, 2021
@jsquire jsquire added Azure.Identity Client This issue points to a problem in the data-plane of the library. needs-team-attention Workflow: This issue needs attention from Azure service team or SDK team labels Jan 28, 2021
@ghost ghost removed the needs-triage Workflow: This is a new issue that needs to be triaged to the appropriate team. label Jan 28, 2021
@jsquire
Copy link
Member

jsquire commented Jan 28, 2021

Thank you for your feedback. Tagging and routing to the team member best able to assist.

@ppanyukov
Copy link
Author

OK, while I was testing this proposal, I discovered that this is already implemented with AZURE_CLIENT_ID in Azure.Identity 1.3.0, if not earlier! But it does not seem to be documented anywhere.

So if you set just AZURE_CLIENT_ID in app settings to the id of User Assigned Identity, everything works as per this proposal. The code in question which actually sets this is here: https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/identity/Azure.Identity/src/DefaultAzureCredentialOptions.cs#L57

I've just tested it with 1.3.0 nuget package and yes it works as required.

Thoughts on this? If this is officially supported thing, should we document it? If "unsupported" then why?

@ppanyukov
Copy link
Author

ppanyukov commented Jan 28, 2021

No it doesn't quite do @christothes . The example there shows that we need to specify client id in the code. Specifically just for the case of User Assigned Identity. The proposal here is that it should work transparently by means of env vars as it simplifies so many workflows.

@christothes
Copy link
Member

Thanks for clarifying. To your follow up question:

So if you set just AZURE_CLIENT_ID in app settings to the id of User Assigned Identity, everything works as per this proposal.
Thoughts on this? If this is officially supported thing, should we document it? If "unsupported" then why?

This appears to be a documentation oversight. I'll file an issue to get the docs updated.

Thanks for pointing this out!

@christothes
Copy link
Member

Will add docs with #18264

@ppanyukov
Copy link
Author

Thanks @christothes . Do you know where to raise an issue/feature request for Key Vault refs not working with User Assigned Identities? For this thing: https://docs.microsoft.com/en-us/azure/app-service/app-service-key-vault-references

@mattchenderson
Copy link

@ppanyukov Normally for a feature request like this we'd ask for this to be filed on our uservoice, but I actually don't see that item already filed, strangely. That said, we do have support for it lined up to be available very soon. I can't give a specific timeline, but it shouldn't be too much longer.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Azure.Identity Client This issue points to a problem in the data-plane of the library. customer-reported Issues that are reported by GitHub users external to the Azure organization. needs-team-attention Workflow: This issue needs attention from Azure service team or SDK team question The issue doesn't require a change to the product in order to be resolved. Most issues start as that
Projects
None yet
Development

No branches or pull requests

4 participants