azure-devopsdefaultazurecredential

How to Get Azure Access Token using DefaultAzureCredential without storing secrets


I am trying to setup my environment to be able to to access Azure resources from outside Azure.

While looking at different options I cam across mainly below options of many others

Option 1: Creating a Service Principal with the Azure CLI and use client secrets for Token retrieval and accessing Resources Get Client secrets Run Time

Option 2: Using DefaultAzureCredential (Azure.Identity) for Token retrieval and accessing Resources DefaultAzureCredential

I am currently trying out DefaultAzureCredential option to be able to access Azure resources such as ADF, Blob storage etc.

I am able to do this using the Visual Studio credentials (VS 2019). However challenge remains to perform same action via a Pipeline running outside Azure. I do not want to save any secrets in the code. Does this means that I cannot use environment variables for the Purpose?

If indeed this is still possible then need help with the code.

Environment: . Net Framework 4.8/Core 3.1

Desired Flow:

Use Visual Studio Credentials for local Development and Test.

Use Environment Variables OR other tasks supported by DefaultAzureCredential via DevOps Pipeline task.

Code:

var tokenCredential = new DefaultAzureCredential();
var accessToken = await tokenCredential.GetTokenAsync(
    new TokenRequestContext(scopes: new string[] { ResourceId + "/.default" }) { }
);

Solution

  • I was able to solve this using DefaultAzureCredential. We followed the below approach to solve this

    1. Added code to read the secrets from appsetting.json
    2. Add secrets to environment variables
    3. Use DefaultAzureCredential* to reach to correct override.
    4. Add replace token task in Build/Release pipelines to replace client secret variables with secrets from pipeline parameters.
    5. Code when executed from Visual studio does not find actual value to secret variables from appsetting.json and then uses VisualStudio Credentials.

    Read values

        string AZURE_CLIENT_SECRET = ConfigurationHelper.GetByName("AZURE_CLIENT_SECRET");
        string AZURE_CLIENT_ID = ConfigurationHelper.GetByName("AZURE_CLIENT_ID");
        string AZURE_TENANT_ID = ConfigurationHelper.GetByName("AZURE_TENANT_ID");
    
            // Check whether the environment variable exists.
    
            if (AZURE_CLIENT_SECRET != "{{AZURE_CLIENT_SECRET}}"
                && AZURE_CLIENT_ID != "{{AZURE_CLIENT_ID}}" &&
                AZURE_TENANT_ID != "{{AZURE_TENANT_ID}}")
            {
                Environment.SetEnvironmentVariable("AZURE_CLIENT_SECRET", AZURE_CLIENT_SECRET);
                Environment.SetEnvironmentVariable("AZURE_CLIENT_ID", AZURE_CLIENT_ID);
                Environment.SetEnvironmentVariable("AZURE_TENANT_ID", AZURE_TENANT_ID);
    
                Console.WriteLine("Setting Environment Variables");
            }
    

    Call DefaultAzureCredential

    var objDefaultAzureCredentialOptions = new DefaultAzureCredentialOptions
                    {
                        ExcludeEnvironmentCredential = false,
                        ExcludeManagedIdentityCredential = true,
                        ExcludeSharedTokenCacheCredential = true,
                        ExcludeVisualStudioCredential = false,
                        ExcludeVisualStudioCodeCredential = false,
                        ExcludeAzureCliCredential = true,
                        ExcludeInteractiveBrowserCredential = true
                    };
    
     var tokenCredential = new DefaultAzureCredential(objDefaultAzureCredentialOptions);
    
    ValueTask<AccessToken> accessToken = tokenCredential.GetTokenAsync(
                            new TokenRequestContext(scopes: new[] { "https://management.azure.com/.default" }));