Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When using the Azure Fluent SDK in an Azure Function how can I create an azure object using a Managed Service Identity?

I am writing an Azure function which will update an Azure DNS zone. The function has a Managed Service Identity (MSI) attached to it.

I am able to use the non-fluent SDK to read the current records in the DNS zone. However when I try and do the same thing using the fluent libraries I get the following error:

[07/11/2018 14:36:37] Executed 'Function1' (Failed,Id=8d34472e-956a-4ff3-a1b1-16ea6186934a)

[07/11/2018 14:36:37] System.Private.CoreLib: Exception while executing function: Function1.Microsoft.Azure.Management.ResourceManager.Fluent: Value cannot be null.

[07/11/2018 14:36:37] Parameter name: MSI_ENDPOINT.

So that I can easily test the difference between the two libraries, I have put together a test function.

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Azure.Management.ResourceManager.Fluent.Authentication;
using Microsoft.Azure.Management.ResourceManager.Fluent;
using Microsoft.Azure.Management.Fluent;
using Microsoft.Azure.Services.AppAuthentication;
using Microsoft.Rest;
using Microsoft.Azure.Management.Dns;
using Microsoft.Azure.Management.ResourceManager.Fluent.Core;

namespace UpdateDNS
{
    public static class Function1
    {
        [FunctionName("Function1")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", Route = "{subscription}/{rg_name}/{zone_name}/{lib}")] HttpRequest req,
            string subscription,
            string rg_name,
            string zone_name,
            string lib,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            int count = 0;
            dynamic records;

            // determine the lib to use to get the dns data
            switch (lib)
            {
                case "fluent":

                    AzureCredentialsFactory factory = new AzureCredentialsFactory();
                    MSILoginInformation msi = new MSILoginInformation(MSIResourceType.AppService);
                    AzureCredentials msiCred = factory.FromMSI(msi, AzureEnvironment.AzureGlobalCloud);
                    var azureAuth = Azure.Configure().WithLogLevel(HttpLoggingDelegatingHandler.Level.BodyAndHeaders).Authenticate(msiCred);

                    // set the subscription to work with
                    var azure = azureAuth.WithSubscription(subscription);

                    var dnszone = azure.DnsZones.GetByResourceGroup(rg_name, zone_name);

                    records = dnszone.ListRecordSets();

                    break;

                default:

                    // get the token from the managed service identity
                    AzureServiceTokenProvider token_provider = new AzureServiceTokenProvider();
                    string token = await token_provider.GetAccessTokenAsync("https://management.azure.com");

                    TokenCredentials token_creds = new TokenCredentials(token);

                    // create the dns client
                    DnsManagementClient client = new DnsManagementClient(token_creds);
                    client.SubscriptionId = subscription;

                    records = client.RecordSets.ListAllByDnsZone(rg_name, zone_name);

                    break;
            }

            foreach (var record in records)
            {
                Console.WriteLine(record.Name);
                count++;
            }

            return new OkObjectResult($"Records: {count}");

        }
    }
}

This is an HTTP triggered Azure function and allows the subscription, resource group and DNS zone to be passed in as parameters as well as the library to use.

So in order to test the non-fluent libs I can call the following:

http://localhost:7071/api/ee65837a-8b52-4fed-9820-f2eb0bb11baf/my_rg/my_zone/stable

This will return something like:

Records: 3

However if I try and run the same query but using the fluent libs I get the error as shown above:

http://localhost:7071/api/ee65837a-8b52-4fed-9820-f2eb0bb11baf/my_rg/my_zone/fluent

Am I missing a parameter that needs to be passed in? I am not sure where the 'MSI_ENDPOINT' would be set and what it should be set to. My feeling is that this should be done for me.

The versions of the libraries that are in use are:

Microsoft.Azure.Management.DNS 3.0.1

Microsoft.Azure.Management.Fluent 1.17.0

Microsoft.Azure.Services.AppAuthentication 1.0.3

I am running this locally within Visual Studio which is logged into an account with the appropriate access to Azure.

like image 222
Russell Seymour Avatar asked Oct 29 '22 01:10

Russell Seymour


1 Answers

I am running this locally within Visual Studio which is logged into an account with the appropriate access to Azure.

You don't have Manage Service Identity on your local machine so you could not work well with the first method in local. As junnas said, you could use Azure Services Authentication Extension with AzureServiceTokenProvider which retrieves your account to access to Azure.

For more details, you could refer to this article.

So, firstly you need to do is go to you yourappname.scm.azurewebsites.net and select Environment to check if there is MSI_ENDPOINT variable in it. Which means you have set up MSI successfully.

Secondly, publish the function to Azure and it will work fine.

like image 61
Joey Cai Avatar answered Nov 15 '22 04:11

Joey Cai