Commit eb5eb021 authored by Pierre Smeyers's avatar Pierre Smeyers
Browse files

Merge branch '84-azure-deployment-not-supported-in-helm-template-to-be-continuous' into 'main'

Resolve "Azure deployment not supported in Helm template (To Be Continuous)"

Closes #84

See merge request to-be-continuous/helm!121
parents daa2f2d1 9d6dcd88
Loading
Loading
Loading
Loading
+68 −0
Original line number Diff line number Diff line
@@ -760,3 +760,71 @@ The AWS variant template provides:

The authentication uses [GitLab's OIDC integration with AWS](https://docs.gitlab.com/ci/cloud_services/aws/), which means you don't need to manage long-lived AWS credentials in your CI/CD variables.

### AKS variant

This variant allows two different use cases:

1. **publishing your Helm packages** to Azure's [Container Registry](https://learn.microsoft.com/en-us/azure/container-registry/),
2. and **deploying your applications** (as charts) to [Azure Kubernetes Services](https://learn.microsoft.com/en-gb/azure/aks/what-is-aks).

List of requirements before using this variant for publishing your charts:

1. You must have a Container Registry,
2. You must have a managed identity or an application with *Container Registry Repository Writer* role on the registry,
3. You must have federated identity credentials for this managed identity or application.

List of requirements before using this variant for deploying your charts:

1. You must have an AKS cluster,
2. You must have a managed identity or an application with enough permissions to make the required modifications,
3. You must have federated identity credentials for this managed identity or application.

#### Configuration

| Input / Variable                                          | Description                                                                                                               | Default value                                                           |
| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| `TBC_AZURE_PROVIDER_IMAGE`                                | The [Azure Auth Provider](https://gitlab.com/to-be-continuous/tools/azure-auth-provider) image to use (can be overridden) | `registry.gitlab.com/to-be-continuous/tools/azure-auth-provider:latest` |
| `azure-oidc-aud` / `AZURE_OIDC_AUD`                       | The `aud` claim for the JWT token used for [OIDC authentication](https://docs.gitlab.com/ci/cloud_services/azure/)        | `api://AzureADTokenExchange`                                            |
| `azure-client-id` / `AZURE_CLIENT_ID`                     | Client Id of the identity used by the [OIDC authentication](https://docs.gitlab.com/ci/cloud_services/azure/)             | _none_                                                                  |
| `azure-tenant-id` / `AZURE_TENANT_ID`                     | Azure Tenant Id of the target AKS                                                                                         | _none_                                                                  |
| `azure-review-client-id` / `AZURE_REVIEW_CLIENT_ID`       | Client Id of the identity used by the OIDC authentication for `review` env _(only define to override default)_            | _none_                                                                  |
| `azure-review-tenant-id` / `AZURE_REVIEW_TENANT_ID`       | Azure Tenant Id of the target AKS for `review` env _(only define to override default)_                                    | _none_                                                                  |
| `azure-integ-client-id` / `AZURE_INTEG_CLIENT_ID`         | Client Id of the identity used by the OIDC authentication for `integ` env _(only define to override default)_             | _none_                                                                  |
| `azure-integ-tenant-id` / `AZURE_INTEG_TENANT_ID`         | Azure Tenant Id of the target AKS for `integ` env _(only define to override default)_                                     | _none_                                                                  |
| `azure-staging-client-id` / `AZURE_STAGING_CLIENT_ID`     | Client Id of the identity used by the OIDC authentication for `staging` env _(only define to override default)_           | _none_                                                                  |
| `azure-staging-tenant-id` / `AZURE_STAGING_TENANT_ID`     | Azure Tenant Id of the target AKS for `staging` env _(only define to override default)_                                   | _none_                                                                  |
| `azure-prod-client-id` / `AZURE_PROD_CLIENT_ID`           | Client Id of the identity used by the OIDC authentication for `prod` env _(only define to override default)_              | _none_                                                                  |
| `azure-prod-tenant-id` / `AZURE_PROD_TENANT_ID`           | Azure Tenant Id of the target AKS for `prod` env _(only define to override default)_                                      | _none_                                                                  |

#### Example - Deploy to AKS

```yaml
include:
  # main template
  - component: $CI_SERVER_FQDN/to-be-continuous/helm/gitlab-ci-helm@9.5.0
    inputs:
      base-app-name: my-app
      review-enabled: true
      staging-enabled: true
      prod-enabled: true
  # AKS auth variant
  - component: $CI_SERVER_FQDN/to-be-continuous/helm/gitlab-ci-helm-aks@9.5.0
    inputs:
      # Example with one account for every environment
      azure-client-id: "12345678-acbd-abcd-acbd-1234567890ab"
      azure-tenant-id: "abcdef01-2345-6789-0123-abcdef012345"

variables:
  # Configure kubeconfig URLs per environment, here each cluster has the same name but is in a different resource groupe
  HELM_REVIEW_KUBECONFIG: "@url@http://azure-auth-provider/kubeconfig?subscription_id=01020304-abcd-effe-dcba-506070809000&resource_group_name=review_cluster&resource_name=my-app"
  HELM_STAGING_KUBECONFIG: "@url@http://azure-auth-provider/kubeconfig?subscription_id=01020304-abcd-effe-dcba-506070809000&resource_group_name=staging_cluster&resource_name=my-app"
  HELM_PROD_KUBECONFIG: "@url@http://azure-auth-provider/kubeconfig?subscription_id=01020304-abcd-effe-dcba-506070809000&resource_group_name=prod_cluster&resource_name=my-app"
```

#### How it works

The AKS variant template provides:

**AKS kubeconfig via Azure Auth Provider**: Users configure the `HELM_<ENV>_KUBECONFIG` variable with a URL pattern (`@url@http://azure-auth-provider/kubeconfig?subscription_id=...`) that dynamically retrieves a kubeconfig that will be used by the kubelogin exec plugin.

The authentication uses [GitLab's OIDC integration with AWS](https://docs.gitlab.com/ci/cloud_services/azure/), which means you don't need to manage long-lived AAD credentials in your CI/CD variables.
+68 −0
Original line number Diff line number Diff line
@@ -597,6 +597,74 @@
          "advanced": true
        }
      ]
    },
    {
      "id": "aks",
      "name": "Azure Kubernetes Service",
      "description": "Deploy to AKS (Azure Kubernetes Service)",
      "template_path": "templates/gitlab-ci-helm-aks.yml",
      "variables": [
        {
          "name": "TBC_AZURE_PROVIDER_IMAGE",
          "description": "The [Azure Auth Provider](https://gitlab.com/to-be-continuous/tools/azure-auth-provider) image to use",
          "default": "registry.gitlab.com/to-be-continuous/tools/azure-auth-provider:latest",
          "advanced": true
        },
        {
          "name": "AZURE_OIDC_AUD",
          "description": "The `aud` claim for the JWT token used for [OIDC authentication](https://docs.gitlab.com/ci/cloud_services/azure/)",
          "default": "api://AzureADTokenExchange",
          "advanced": true
        },
        {
          "name": "AZURE_CLIENT_ID",
          "description": "Client Id of the identity used by the [OIDC authentication](https://docs.gitlab.com/ci/cloud_services/azure/)"
        },
        {
          "name": "AZURE_TENANT_ID",
          "description": "Azure Tenant Id of the target AKS"
        },
        {
          "name": "AZURE_REVIEW_CLIENT_ID",
          "description": "Client Id of the identity used by the [OIDC authentication](https://docs.gitlab.com/ci/cloud_services/azure/) for `review` env _(only define to override default)_",
          "advanced": true
        },
        {
          "name": "AZURE_REVIEW_TENANT_ID",
          "description": "Azure Tenant Id of the target AKS for `review` env _(only define to override default)_",
          "advanced": true
        },
        {
          "name": "AZURE_INTEG_CLIENT_ID",
          "description": "Client Id of the identity used by the [OIDC authentication](https://docs.gitlab.com/ci/cloud_services/azure/) for `integ` env _(only define to override default)_",
          "advanced": true
        },
        {
          "name": "AZURE_INTEG_TENANT_ID",
          "description": "Azure Tenant Id of the target AKS for `integ` env _(only define to override default)_",
          "advanced": true
        },
        {
          "name": "AZURE_STAGING_CLIENT_ID",
          "description": "Client Id of the identity used by the [OIDC authentication](https://docs.gitlab.com/ci/cloud_services/azure/) for `staging` env _(only define to override default)_",
          "advanced": true
        },
        {
          "name": "AZURE_STAGING_TENANT_ID",
          "description": "Azure Tenant Id of the target AKS for `staging` env _(only define to override default)_",
          "advanced": true
        },
        {
          "name": "AZURE_PROD_CLIENT_ID",
          "description": "Client Id of the identity used by the [OIDC authentication](https://docs.gitlab.com/ci/cloud_services/azure/) for `prod` env _(only define to override default)_",
          "advanced": true
        },
        {
          "name": "AZURE_PROD_TENANT_ID",
          "description": "Azure Tenant Id of the target AKS for `prod` env _(only define to override default)_",
          "advanced": true
        }
      ]
    }

  ]
+117 −0
Original line number Diff line number Diff line
# =====================================================================================================================
# === AKS Auth template variant
# =====================================================================================================================
spec:
  inputs:
    azure-oidc-aud:
      description: The `aud` claim for the JWT token used for [OIDC authentication](https://docs.gitlab.com/ci/cloud_services/azure/)
      default: 'api://AzureADTokenExchange'
    azure-client-id:
      description: Client Id of the identity used by the [OIDC authentication](https://docs.gitlab.com/ci/cloud_services/azure/)
      default: ''
    azure-tenant-id:
      description: Azure Tenant Id of the target AKS
      default: ''
    azure-review-client-id:
      description: Client Id of the identity used by the [OIDC authentication](https://docs.gitlab.com/ci/cloud_services/azure/) for `review` env _(only define to override default)_
      default: ''
    azure-review-tenant-id:
      description: Azure Tenant Id of the target AKS for `review` env _(only define to override default)_
      default: ''
    azure-integ-client-id:
      description: Client Id of the identity used by the [OIDC authentication](https://docs.gitlab.com/ci/cloud_services/azure/) for `integ` env _(only define to override default)_
      default: ''
    azure-integ-tenant-id:
      description: Azure Tenant Id of the target AKS for `integ` env _(only define to override default)_
      default: ''
    azure-staging-client-id:
      description: Client Id of the identity used by the [OIDC authentication](https://docs.gitlab.com/ci/cloud_services/azure/) for `staging` env _(only define to override default)_
      default: ''
    azure-staging-tenant-id:
      description: Azure Tenant Id of the target AKS for `staging` env _(only define to override default)_
      default: ''
    azure-prod-client-id:
      description: Client Id of the identity used by the [OIDC authentication](https://docs.gitlab.com/ci/cloud_services/azure/) for `prod` env _(only define to override default)_
      default: ''
    azure-prod-tenant-id:
      description: Azure Tenant Id of the target AKS for `prod` env _(only define to override default)_
      default: ''


---
variables:
  TBC_AZURE_PROVIDER_IMAGE: registry.gitlab.com/to-be-continuous/tools/azure-auth-provider:latest
  AZURE_OIDC_AUD: $[[ inputs.azure-oidc-aud ]]
  AZURE_CLIENT_ID: $[[ inputs.azure-client-id ]]
  AZURE_TENANT_ID: $[[ inputs.azure-tenant-id ]]
  AZURE_REVIEW_CLIENT_ID: $[[ inputs.azure-review-client-id ]]
  AZURE_REVIEW_TENANT_ID: $[[ inputs.azure-review-tenant-id ]]
  AZURE_INTEG_CLIENT_ID: $[[ inputs.azure-integ-client-id ]]
  AZURE_INTEG_TENANT_ID: $[[ inputs.azure-integ-tenant-id ]]
  AZURE_STAGING_CLIENT_ID: $[[ inputs.azure-staging-client-id ]]
  AZURE_STAGING_TENANT_ID: $[[ inputs.azure-staging-tenant-id ]]
  AZURE_PROD_CLIENT_ID: $[[ inputs.azure-prod-client-id ]]
  AZURE_PROD_TENANT_ID: $[[ inputs.azure-prod-tenant-id ]]

.helm-azure-azki:
  - |
    if [[ "$AZURE_JWT" ]]
    then
      if command -v kubelogin > /dev/null
      then
        echo '[INFO] kubelogin already installed'
      else
        echo '[INFO] Installing kubelogin'
        decoded=$(mktemp)
        errors=$(mktemp)
        if wget -T "${TBC_SECRET_URL_TIMEOUT:-5}" -O /tmp/kubelogin.zip https://github.com/Azure/kubelogin/releases/download/v0.2.17/kubelogin-linux-amd64.zip 2> "${errors}"
        then
          unzip /tmp/kubelogin.zip -d /tmp
          rm /tmp/kubelogin.zip
          mv /tmp/bin/linux_amd64/kubelogin /usr/local/bin/kubelogin
        else
          echo '[ERROR] Failed to download kubelogin'
          cat "${errors}"
        fi
      fi
      echo "Configuring kubelogin for Workload Identity"
      k8s_config=${ENV_KUBE_CONFIG:-${HELM_DEFAULT_KUBE_CONFIG}}
      echo -ne "${k8s_config}" > "$CI_PROJECT_DIR/.azure_kubeconfig"
      export ENV_KUBE_CONFIG="$CI_PROJECT_DIR/.azure_kubeconfig"
      echo "${AZURE_JWT}" > "$CI_BUILDS_DIR/.auth_token.jwt"
      kubelogin convert-kubeconfig --login workloadidentity --kubeconfig "$CI_PROJECT_DIR/.azure_kubeconfig" --federated-token-file "$CI_BUILDS_DIR/.auth_token.jwt"
    else
      echo '[WARN] $AZURE_JWT is not set: cannot setup Azure Kubelogin Workload Identity authentication'
    fi

.helm-env-base:
  services:
    - name: "$TBC_TRACKING_IMAGE"
      command: ["--service", "helm", "9.5.0"]
    - name: "$TBC_AZURE_PROVIDER_IMAGE"
      alias: "azure-auth-provider"
  before_script:
    - !reference [.helm-base, before_script]
    - !reference [.helm-azure-azki]
    - setup_kubeconfig
  variables:
    #  have to be explicitly declared in the YAML to be exported to the service
    AZURE_JWT: $AZURE_JWT
  id_tokens:
    AZURE_JWT:
      aud: "$AZURE_OIDC_AUD"

.helm-publish:
  services:
    - name: "$TBC_TRACKING_IMAGE"
      command: ["--service", "helm", "9.5.0"]
    - name: "$TBC_AZURE_PROVIDER_IMAGE"
      alias: "azure-auth-provider"
  variables:
    #  have to be explicitly declared in the YAML to be exported to the service
    AZURE_JWT: $AZURE_JWT
    HELM_PUBLISH_USER: '00000000-0000-0000-0000-000000000000'
    HELM_PUBLISH_PASSWORD: '@url@http://azure-auth-provider/acr/auth/password'
  id_tokens:
    AZURE_JWT:
      aud: "$AZURE_OIDC_AUD"