Ching Kuo
Ching Kuo

Reputation: 21

Programmatically authenticate AKS with Azure AD and Managed Identity

I'm new to AKS and the Azure Identity platform. I have an AKS cluster that is using the Azure AD integration. From an Azure VM that has a user assigned managed identity, I'm trying to run a C# console app to authenticate against Azure AD, get the kubeconfig contents and then work with the kubernetes client to perform some list operations. When the code below is run I get an Unauthorized error when attempting to perform the List operation. I've made sure that in the cluster access roles, the user assigned managed identity has the Owner role.

The code does the following:

I've pulled information from this POST as well from this POST.

I'm not sure if the scopes of TokenRequestContext is correct and if the resource parameter of the oauth token request is correct.

string userAssignedClientId = "0f2a4a25-e37f-4aba-942a-5c58f39eb136";
    var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions { ManagedIdentityClientId = userAssignedClientId });

    var defaultToken = credential.GetToken(new TokenRequestContext(new[] { "https://management.azure.com/.default" })).Token;
    var defaultTokenCredentials = new Microsoft.Rest.TokenCredentials(defaultToken);
    var azureCredentials = new Microsoft.Azure.Management.ResourceManager.Fluent.Authentication.AzureCredentials(defaultTokenCredentials, defaultTokenCredentials, null, AzureEnvironment.AzureGlobalCloud);
    var azure = Microsoft.Azure.Management.Fluent.Azure.Authenticate(azureCredentials).WithSubscription("XXX");

    var kubeConfigBytes = azure.KubernetesClusters.GetUserKubeConfigContents(
        "XXX",
        "XXX"
    );

    var kubeConfigRaw = KubernetesClientConfiguration.LoadKubeConfig(new MemoryStream(kubeConfigBytes));

    var authProvider = kubeConfigRaw.Users.Single().UserCredentials.AuthProvider;
    if (!authProvider.Name.Equals("azure", StringComparison.OrdinalIgnoreCase))
        throw new Exception("Invalid k8s auth provider!");

    var httpClient = new HttpClient();
    var token = string.Empty;
    using (var requestMessage =
                new HttpRequestMessage(HttpMethod.Get, $"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource={Uri.EscapeUriString("6dae42f8-4368-4678-94ff-3960e28e3630/.default")}&client_id={userAssignedClientId}"))
    {
        requestMessage.Headers.Add("Metadata", "true");

        var response = await httpClient.SendAsync(requestMessage);
        token = await response.Content.ReadAsStringAsync();

        Console.WriteLine(token);
    }

    var tokenNode = JsonNode.Parse(token);

    authProvider.Config["access-token"] = tokenNode["access_token"].GetValue<string>();
    authProvider.Config["expires-on"] = DateTimeOffset.UtcNow.AddSeconds(double.Parse(tokenNode["expires_in"].GetValue<string>())).ToUnixTimeSeconds().ToString();

    var kubeConfig = KubernetesClientConfiguration.BuildConfigFromConfigObject(kubeConfigRaw);
    var kubernetes = new Kubernetes(kubeConfig);

    var namespaces = kubernetes.CoreV1.ListNamespace();
    foreach (var ns in namespaces.Items)
    {
        Console.WriteLine(ns.Metadata.Name);
        var list = kubernetes.CoreV1.ListNamespacedPod(ns.Metadata.Name);
        foreach (var item in list.Items)
        {
            Console.WriteLine(item.Metadata.Name);
        }
    }

Any help is appreciated!

Upvotes: 1

Views: 1632

Answers (2)

Nikos Sideris
Nikos Sideris

Reputation: 26

Try to use 6dae42f8-4368-4678-94ff-3960e28e3630/.default instead for accessing k8s related access.

The difference between management.azure.com/.default and 6dae42f8-4368-4678-94ff-3960e28e3630/.default lies in their usage and contexts within Azure.

https://management.azure.com/.default: This is a common resource identifier used to obtain an access token for Azure's management API. It's primarily associated with managing Azure resources such as virtual machines, storage accounts, and databases. When requesting tokens via Azure AD, you would use this URL as the resource or scope to interact with Azure management services.

6dae42f8-4368-4678-94ff-3960e28e3630: This is the application ID for the Azure Kubernetes Service (AKS) AAD Server. It is a fixed identifier across all Azure environments, used when authenticating AKS clusters that are integrated with Azure Active Directory (AAD). Access tokens intended to interact with the Kubernetes API server on AKS are issued for this application ID. For example, this application ID is used in the kubelogin tool when obtaining tokens to authenticate Kubernetes API requests​( Azure )​( GitHub )​( Welcome | Omnia Radix ).

In summary, while https://management.azure.com/.default is used for general Azure resource management, 6dae42f8-4368-4678-94ff-3960e28e3630 is specific to AKS-related access.

Upvotes: 0

marenzi
marenzi

Reputation: 1

Try using the resource in the token request without /.default.

So it should be:

resource=6dae42f8-4368-4678-94ff-3960e28e3630

Upvotes: 0

Related Questions