azure-pipelines-tasks: HelmDeploy@0 and Kubernetes@1 do not work with kubelogin

Question, Bug, or Feature? Type: bug

Task Name:

  • HelmDeploy@0
  • Kubernetes@1

Environment

  • Server: Azure Pipelines

  • Agent: Private, ubuntu 18.04, version 2.196.2

Issue Description

Both HelmDeploy@0 and Kubernetes@1 do not work with kubelogin while under the same conditions the plain helm and kubectl binaries do.

We run AKS with AAD integration enabled and avoid using local K8S service accounts. Instead we use an ARM Service Connection with MSI. If you try to use kubectl using an ARM Service Connection on an AKS cluster with AAD integration you will get a prompt for https://microsoft.com/devicelogin which does not work in a devops pipeline context. . The kubelogin utility is a client-go credential plugin for kubectl that implements Azure AD authentication. This works fine when using it from the command prompt, but not when using the HelmDeploy@0 and Kubernetes@1 tasks. Somehow there is a subtle difference in the process context where the kubectl and helm are used from the command line when compared to the invocation done by the tasks.

Below is an example pipeline to illustrate the issue:

  • The first task does an az aks get-credentials, installs kubelogin and converts the kubeconfig file to use kubelogin.
  • The seconds task uses kubectl and helm binaries directly from a bash shell. This works without issues.
  • The third task uses HelmDeploy@0 task to list the deployed charts. This fails when calling the kubelogin credential plugin: getting credentials: exec: executable kubelogin failed with exit code 1.
  • The fourth task uses Kubernetes@1 task to list pods in a namespace. This fails with similar errors as the helm task.
      - task: AzureCLI@2
        displayName: aks non-admin login using kubelogin
        inputs:
          azureSubscription: ${{parameters.serviceConnection}}
          scriptType: bash
          scriptLocation: inlineScript
          inlineScript: |
            az aks get-credentials -n <aks cluster> -g <resource group>
            # install kubelogin
            wget https://github.com/Azure/kubelogin/releases/download/v0.0.10/kubelogin-linux-amd64.zip
            unzip kubelogin-linux-amd64.zip
            mv bin/linux_amd64/kubelogin /usr/bin
            kubelogin convert-kubeconfig -l azurecli
 
      - task: AzureCLI@2
        displayName: test kubectl and helm from bash
        continueOnError: true 
        inputs:
          azureSubscription: ${{parameters.serviceConnection}}
          scriptType: bash
          scriptLocation: inlineScript
          inlineScript: |
            kubectl get pods -n <some namespace>
            helm list --namespace <some namespace>

      - task: HelmDeploy@0
        displayName: test HelmDeploy task
        continueOnError: true 
        inputs:
          connectionType: None
          namespace: <some namespace>
          command: list

      - task: Kubernetes@1
        displayName: test Kubernetes task
        continueOnError: true 
        inputs:
          connectionType: None
          command: get
          arguments: pods -n <some namespace>

Possibly this issue needs to be fixed in the kubelogin project but would like to understand the likely differences on how the tasks call the underlying kubectl and helm binaries when compared to invoking them from bash.

Task logs

See attached logs.zip

Troubleshooting

Checkout how to troubleshoot failures and collect debug logs: https://docs.microsoft.com/en-us/vsts/build-release/actions/troubleshooting

Error logs

2022-01-19T20:33:52.7909008Z ##[debug]set helmExitCode=1
2022-01-19T20:33:52.7910461Z Error: Kubernetes cluster unreachable: Get "https://<aks cluster>-a15872ed.hcp.westeurope.azmk8s.io:443/version?timeout=32s": getting credentials: exec: executable kubelogin failed with exit code 1
2022-01-19T20:33:52.7912489Z helm.go:88: [debug] Get "https://<aks cluster>-a15872ed.hcp.westeurope.azmk8s.io:443/version?timeout=32s": getting credentials: exec: executable kubelogin failed with exit code 1
2022-01-19T20:33:52.7915456Z ##[debug]Processed: ##vso[task.setvariable variable=helmExitCode;issecret=false;]1

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 1
  • Comments: 15 (2 by maintainers)

Most upvoted comments

Will this ever be fixed by MS? The workaround works but it’s something that should work out of the box?

Honestly, it is unbelievable this has not been fixed yet… I mean it’s not that the issue with kubelogin has been announced by the k8s projects months before it took effect; but no, even 1/2 a year+ AFTER kubelogin became mandatory, this has not been fixed yet…

we are working around with step scripts and stuff but this becomes a pain b/c now we need it in multiple repos and have to do version control on steps for AZ devops pipelines that should have been provided by MS…

We will move back to Jenkins, better support there

This workaround only works if you are using self-hosted agents with managed identity. We are using Microsoft hosted agents and thus we cannot use az login --identity, but we are forced to use the AzureCLI@2 task.

A workaround that supports Microsoft hosted agents, you can deploy Helm charts using the AzureCLI@2 task:

- task: AzureCLI@2
  displayName: Login to AKS using kubelogin
  inputs:
    azureSubscription: <service connection>
    scriptType: "bash"
    scriptLocation: "inlineScript"
    inlineScript: |
      set -e

      export KUBECONFIG=$(Build.SourcesDirectory)/.kubeconfig-<aks cluster>

      # Fails if it doesn't exist
      touch .kubeconfig-<aks cluster>
      chmod 600 .kubeconfig-<aks cluster>

      # Populate kubeconfig
      az aks get-credentials \
        --resource-group <resource group> \
        --name <aks cluster> \
        --overwrite-existing \
        --file .kubeconfig-<aks cluster>

      # Pass kubeconfig to kubelogin to access k8s API
      kubelogin convert-kubeconfig -l azurecli

      # confirm it works
      kubectl get pods --namespace default

      # Ensure the kubeconfig path is available to subsequent tasks as an environment variable
      echo "##vso[task.setvariable variable=KUBECONFIG]${KUBECONFIG}"
    displayName: kubelogin - aks-credentials to kubecontext

- task: AzureCLI@2
  displayName: Install Secrets Store CSI Driver Helm chart
  inputs:
    azureSubscription: <service connection>
    scriptType: "bash"
    scriptLocation: "inlineScript"
    inlineScript: |
      export KUBECONFIG=$(Build.SourcesDirectory)/.kubeconfig-<cluster name>

      helm upgrade \
        keyvault-provider \
        csi-secrets-store-provider-azure/csi-secrets-store-provider-azure \
        --install \
        --set secrets-store-csi-driver.syncSecret.enabled=true \
        --set secrets-store-csi-driver.enableSecretRotation=true

Came here to see the solution for problem like many other problems. I don’t really understand how huge organizations are being pushed to use these MS products which is nothing but wasting time on troubleshooting. How is a company like Microsoft getting away.

I don’t understand why this doesn’t work yet and no acceptable workaround has been found after at least 1 year. Is there any communication from the people working on this? Starting from scratch with pipelines this is the most obvious flow, and it doesn’t even work. Moreover, there is barely anything to be found about this online. So now instead of using the pre-packaged script I need to infer what that probably does and rewrite it so that it works. Not an amazing dev experience.