microsoft-graph-apisharepoint-onlineazure-aksazure-managed-identity

How can an AKS-hosted application securely access SharePoint data?


We are working on a project where an application running in Azure Kubernetes Service (AKS) needs to fetch CSV/XLS files from a specific SharePoint site. Currently, we're using an App Registration in Azure AD (Microsoft Entra ID) with a client ID and client secret to authenticate and access the SharePoint data via Microsoft Graph API. However, our security team is concerned about the risk of secrets being leaked or exposed.

However, our security team raised an issue that setting up the connection like that is not secure enough, and they would like us to consider alternatives where leaking the Client ID/Secret combination is not possible.

So, we’re looking for a more secure solution, preferably one that:

One solution that I think might work is to create a Managed Identity for the AKS pod that fetches the data from SharePoint, and give that Managed Identity the correct access on the Microsoft Graph API (on site level).

High-level schema showing possible integration

That way, all authentication and authorization is handled by Azure, and we don't have to manage Client ID and Client Secret combinations anymore.


Solution

  • You can use Azure Workload Identity for AKS with federated tokens instead of client secrets. Set up an OIDC-enabled AKS cluster, create a user-assigned managed identity, link it to a Kubernetes service account, and configure token volume projection. Your pod can then use this identity to securely obtain tokens and access SharePoint data via Microsoft Graph.

    I tested this end-to-end approach in my environment successfully. Please find the workaround below:

    Install > kubectl az cli and helm

    Create an aks cluster with enabling workload identity along with oidc:

    az aks create \
      --resource-group anji-rg \
      --name my-aks \
      --enable-oidc-issuer \
      --enable-workload-identity \
      --node-count 1 \
      --generate-ssh-keys
    

    Configure the credentials to communicate with clusters:

    az aks get-credentials --resource-group anji-rg --name my-aks
    

    Then get the oidc issuer url: (you will need this later) az aks show --resource-group anji-rg --name my-aks --query "oidcIssuerProfile.issuerUrl" -o tsv

    Save this whenever we call this OIDC_ISSUERR it will be triggering the value:

    OIDC_ISSUER=$(az aks show --resource-group anji-rg --name my-aks --query "oidcIssuerProfile.issuerUrl" -o tsv)
    

    The OIDC URL looks like >

    https://centralindia.oic.prod-aks.azure.com/xxxxxxxxxxx/xxxxxxxxxxxxxxxx/
    

    Create a User-Assigned Managed Identity:

    az identity create --name my-akspod-identity --resource-group anji-rg
    

    Save these outputs to call these values:

    CLIENT_ID=$(az identity show --name my-akspod-identity --resource-group anji-rg --query 'clientId' -o tsv)
    IDENTITY_ID=$(az identity show --name my-akspod-identity --resource-group anji-rg --query 'id' -o tsv)
    

    You can directly configure the federation credentials by going into portal > managed identity > your app (ex: in my case > my-akspod-identity) > federation credentials > add credentials > scenario> others issuer is your OIDC url > subject identifier > system:serviceaccount:spdemo:workload-sa > name it and save it.

    enter image description here

    Annotate Kubernetes Service Account to use Managed Identity: Create a name space:

    kubectl create namespace spdemo
    kubectl create serviceaccount workload-sa -n spdemo
    

    Annotate the service account with the managed identity client ID:

    kubectl annotate serviceaccount workload-sa \
      --namespace spdemo \
      azure.workload.identity/client-id=$CLIENT_ID
    

    This pod uses a Kubernetes service account linked to an Azure Managed Identity and mounts a federated token.
    The token allows Azure CLI in the container to authenticate securely with Microsoft Entra ID without secrets.

    apiVersion: v1
    kind: Pod
    metadata:
      name: graph-test
      namespace: spdemo
    spec:
      serviceAccountName: workload-sa
      automountServiceAccountToken: true
      containers:
      - name: test-container
        image: mcr.microsoft.com/azure-cli
        command: ["sleep"]
        args: ["3600"]
        volumeMounts:
        - name: azure-identity-token
          mountPath: /var/run/secrets/tokens
          readOnly: true
      volumes:
      - name: azure-identity-token
        projected:
          sources:
          - serviceAccountToken:
              audience: api://AzureADTokenExchange
              expirationSeconds: 3600
              path: azure-identity-token
    
    

    Apply it > kubectl apply -f pod.yaml

    I have successfully logged into the pod and access the azure service

    enter image description here

    enter image description here

    I am now able to log in to my pod, and it is up and running. I successfully communicated with Azure services from the pod. Let me know if you have any thoughts or doubts, and I will be glad to clear them. -Thank you. @Titulum