Implementación y configuración de Id. de carga de trabajo de Microsoft Entra en un clúster de Azure Kubernetes Service (AKS)

En este artículo, aprenderá a implementar y configurar un clúster de Azure Kubernetes Service (AKS) con Id. de carga de trabajo de Microsoft Entra. Los pasos de este artículo incluyen:

  • Cree un clúster de AKS nuevo o actualice uno existente mediante el emisor de CLI de Azure o Terraform con openID Connect (OIDC) y Id. de carga de trabajo de Microsoft Entra habilitados.
  • Cree una identidad de carga de trabajo y una cuenta de servicio de Kubernetes.
  • Configurar la identidad administrada para la federación de tokens.
  • Implementar la carga de trabajo y comprobar la autenticación con la identidad de carga de trabajo.
  • Opcionalmente, conceda a un pod del clúster acceso a los secretos de un almacén de claves de Azure.

Requisitos previos

  • Si no tiene una cuenta de Azure, cree una cuenta free antes de comenzar.
  • Este artículo requiere la versión 2.47.0 o posterior del CLI de Azure. Si usa Azure Cloud Shell, la versión más reciente ya está instalada. Ejecute az --version para encontrar la versión. Si necesita instalar o actualizar, consulte Install CLI de Azure.
  • Asegúrese de que la identidad que use para crear el clúster tenga los permisos mínimos adecuados. Para obtener más información, vea Acceso y opciones de identidad para Azure Kubernetes Service (AKS).
  • Si tiene varias suscripciones de Azure, seleccione el identificador de suscripción adecuado en el que se deben facturar los recursos mediante el comando az account set.

Nota:

Puede usar Service Connector para ayudarle a configurar algunos pasos automáticamente. Para más información, consulte Tutorial: Conexión a la cuenta de almacenamiento de Azure en Azure Kubernetes Service (AKS) con Service Connector mediante Id. de carga de trabajo de Microsoft Entra.

Creación del archivo de configuración de Terraform

Los archivos de configuración de Terraform definen la infraestructura que Terraform crea y administra.

  1. Cree un archivo denominado main.tf y agregue el código siguiente para definir la versión de Terraform y especifique el proveedor de Azure:

    terraform {
     required_version = ">= 1.5.0"
     required_providers {
       azurerm = {
         source  = "hashicorp/azurerm"
         version = "~> 4.0"
       }
       kubernetes = {
         source  = "hashicorp/kubernetes"
         version = "~> 2.30"
       }
       random = {
         source  = "hashicorp/random"
         version = "~> 3.6"
       }
     }
    }
    provider "azurerm" {
     features {}
     subscription_id = var.subscription_id
    }
    data "azurerm_client_config" "current" {}
    
  2. Agregue el código siguiente para main.tf definir variables reutilizables y generar nombres únicos para todos los recursos:

    resource "random_string" "suffix" {
     length  = 6
     upper   = false
     special = false
     numeric = true
    }
    locals {
     suffix = random_string.suffix.result
     resource_group_name       = "rg-aks-wi-${local.suffix}"
     cluster_name              = "akswi${local.suffix}"
     managed_identity_name     = "uami-wi-${local.suffix}"
     federated_credential_name = "fic-wi-${local.suffix}"
     key_vault_name            = lower(substr("kvwi${local.suffix}", 0, 24))
     secret_name               = "secret-${local.suffix}"
     service_account_name      = "workload-sa-${local.suffix}"
     service_account_namespace = "default"
     workload_identity_subject = "system:serviceaccount:${local.service_account_namespace}:${local.service_account_name}"
    }
    

Crear un grupo de recursos

Cree un grupo de recursos con el comando az group create.

export RANDOM_ID="$(openssl rand -hex 3)"
export RESOURCE_GROUP="myResourceGroup$RANDOM_ID"
export LOCATION="<your-preferred-region>"
az group create --name "${RESOURCE_GROUP}" --location "${LOCATION}"

Agregue el código siguiente a main.tf para crear un grupo de recursos de Azure. Actualice el valor de location para que coincida con la región de Azure preferida.

resource "azurerm_resource_group" "this" {
 name     = local.resource_group_name
 location = "eastus"
}

Habilitar el emisor de OIDC y el Id. de carga de trabajo de Microsoft Entra en un clúster de AKS

Puede habilitar el emisor OIDC y Id. de carga de trabajo de Microsoft Entra en un clúster AKS nuevo o existente.

Cree un clúster de AKS mediante el comando con el parámetro /> para habilitar Id. de carga de trabajo de Microsoft Entra. En el ejemplo siguiente se crea un clúster con un solo nodo:

export CLUSTER_NAME="myAKSCluster$RANDOM_ID"
az aks create \
    --resource-group "${RESOURCE_GROUP}" \
    --name "${CLUSTER_NAME}" \
    --enable-oidc-issuer \
    --enable-workload-identity \
    --generate-ssh-keys

Transcurridos unos minutos, el comando se completa y devuelve información en formato JSON sobre el clúster.

Agregue el código siguiente a main.tf para crear un clúster de AKS con un emisor de OIDC y Id. de carga de trabajo de Microsoft Entra habilitado:

resource "azurerm_kubernetes_cluster" "this" {
 name                              = local.cluster_name
 location                          = azurerm_resource_group.this.location
 resource_group_name               = azurerm_resource_group.this.name
 dns_prefix                        = local.cluster_name
 oidc_issuer_enabled               = true
 workload_identity_enabled         = true
 role_based_access_control_enabled = true
 default_node_pool {
   name       = "system"
   node_count = 1
   vm_size    = "Standard_B4ms"
 }
 identity {
   type = "SystemAssigned"
 }
}

Recuperación de la dirección URL del emisor de OIDC

Obtenga la dirección URL del emisor de OIDC mediante el az aks show comando y guárdela en una variable de entorno.

export AKS_OIDC_ISSUER="$(az aks show --name "${CLUSTER_NAME}" \
    --resource-group "${RESOURCE_GROUP}" \
    --query "oidcIssuerProfile.issuerUrl" \
    --output tsv)"

La variable de entorno debe contener una dirección URL del emisor similar al ejemplo siguiente:

https://eastus.oic.prod-aks.azure.com/00000000-0000-0000-0000-000000000000/11111111-1111-1111-1111-111111111111/

De manera predeterminada, el emisor tiene establecido usar la dirección URL base https://{region}.oic.prod-aks.azure.com/{tenant_id}/{uuid}, donde el valor {region} coincide con la ubicación en la que se implementa el clúster de AKS. El valor {uuid} representa la clave OIDC, que es un GUID generado aleatoriamente e inmutable para cada clúster.

Agregue el siguiente código a main.tf para recuperar la dirección URL del emisor de OIDC:

output "oidc_issuer_url" {
 value = azurerm_kubernetes_cluster.this.oidc_issuer_url
}

Creación de una entidad administrada

  1. Obtenga el identificador de suscripción y guárdelo en una variable de entorno mediante el az account show comando .

    export SUBSCRIPTION="$(az account show --query id --output tsv)"
    
  2. Use el comando az identity create para crear una identidad administrada asignada por el usuario.

    export USER_ASSIGNED_IDENTITY_NAME="myIdentity$RANDOM_ID"
    az identity create \
        --name "${USER_ASSIGNED_IDENTITY_NAME}" \
        --resource-group "${RESOURCE_GROUP}" \
        --location "${LOCATION}" \
        --subscription "${SUBSCRIPTION}"
    

    En el ejemplo de salida siguiente se muestra la creación correcta de una identidad administrada:

    {
      "clientId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourcegroups/myResourceGroupxxxxxx/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myIdentityxxxxxx",
      "location": "eastus",
      "name": "myIdentityxxxxxx",
      "principalId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "resourceGroup": "myResourceGroupxxxxxx",
      "systemData": null,
      "tags": {},
      "tenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "type": "Microsoft.ManagedIdentity/userAssignedIdentities"
    }
    
  3. Obtenga el identificador de cliente de la identidad administrada y guárdelo en una variable de entorno mediante el az identity show comando .

    export USER_ASSIGNED_CLIENT_ID="$(az identity show \
        --resource-group "${RESOURCE_GROUP}" \
        --name "${USER_ASSIGNED_IDENTITY_NAME}" \
        --query 'clientId' \
        --output tsv)"
    

Agregue el siguiente código a main.tf para crear una identidad administrada:

resource "azurerm_user_assigned_identity" "this" {
 name                = local.managed_identity_name
 location            = azurerm_resource_group.this.location
 resource_group_name = azurerm_resource_group.this.name
}

Creación de una cuenta de servicio de Kubernetes

  1. Conectar al clúster de AKS mediante el comando az aks get-credentials.

    az aks get-credentials --name "${CLUSTER_NAME}" --resource-group "${RESOURCE_GROUP}"
    
  2. Cree una cuenta de servicio de Kubernetes y anótela con el identificador de cliente de la identidad administrada aplicando el siguiente manifiesto mediante el comando kubectl apply.

    export SERVICE_ACCOUNT_NAME="workload-identity-sa$RANDOM_ID"
    export SERVICE_ACCOUNT_NAMESPACE="default"
    cat <<EOF | kubectl apply -f -
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      annotations:
        azure.workload.identity/client-id: "${USER_ASSIGNED_CLIENT_ID}"
      name: "${SERVICE_ACCOUNT_NAME}"
      namespace: "${SERVICE_ACCOUNT_NAMESPACE}"
    EOF
    

    En la salida siguiente se muestra la creación correcta de la identidad de carga de trabajo:

    serviceaccount/workload-identity-sa created
    
  1. Agregue el código siguiente para configurar el acceso a main.tf Kubernetes para permitir la creación de recursos de Kubernetes:

    data "azurerm_kubernetes_cluster" "this" {
     name                = azurerm_kubernetes_cluster.this.name
     resource_group_name = azurerm_resource_group.this.name
    }
    provider "kubernetes" {
     host                   = data.azurerm_kubernetes_cluster.this.kube_config[0].host
     client_certificate     = base64decode(data.azurerm_kubernetes_cluster.this.kube_config[0].client_certificate)
     client_key             = base64decode(data.azurerm_kubernetes_cluster.this.kube_config[0].client_key)
     cluster_ca_certificate = base64decode(data.azurerm_kubernetes_cluster.this.kube_config[0].cluster_ca_certificate)
    }
    
  2. Agregue el siguiente código en main.tf para crear una cuenta de servicio de Kubernetes y anotarla con el ID de cliente de la identidad administrada:

    resource "kubernetes_service_account" "this" {
     metadata {
       name      = local.service_account_name
       namespace = local.service_account_namespace
       annotations = {
         "azure.workload.identity/client-id" = azurerm_user_assigned_identity.this.client_id
       }
     }
    }
    

Creación de la credencial de identidad federada

Cree una credencial de identidad federada entre la identidad administrada, el emisor de cuentas de servicio y el asunto mediante el comando az identity federated-credential create.

export FEDERATED_IDENTITY_CREDENTIAL_NAME="myFedIdentity$RANDOM_ID"
az identity federated-credential create \
    --name ${FEDERATED_IDENTITY_CREDENTIAL_NAME} \
    --identity-name "${USER_ASSIGNED_IDENTITY_NAME}" \
    --resource-group "${RESOURCE_GROUP}" \
    --issuer "${AKS_OIDC_ISSUER}" \
    --subject system:serviceaccount:"${SERVICE_ACCOUNT_NAMESPACE}":"${SERVICE_ACCOUNT_NAME}" \
    --audience api://AzureADTokenExchange

Nota:

La credencial de identidad federada tarda unos segundos en propagarse después de agregarla. Si se realiza una solicitud de token inmediatamente después de agregar la credencial de identidad federada, es posible que se produzca un error en la solicitud hasta que se actualice la memoria caché. Para evitar este problema, puede agregar un ligero retraso después de agregar la credencial de identidad federada.

Agregue el siguiente código a main.tf para crear una credencial de identidad federada entre la identidad administrada, el emisor de la cuenta de servicio y el sujeto:

resource "azurerm_federated_identity_credential" "this" {
 name                = local.federated_credential_name
 resource_group_name = azurerm_resource_group.this.name
 parent_id           = azurerm_user_assigned_identity.this.id
 issuer              = azurerm_kubernetes_cluster.this.oidc_issuer_url
 subject             = local.workload_identity_subject
 audience            = ["api://AzureADTokenExchange"]
}

Para obtener más información sobre las credenciales de identidad federada en Microsoft Entra, consulte Información general de las credenciales de identidad federada en Microsoft Entra ID.

Creación de un almacén de claves con autorización de RBAC de Azure

En el ejemplo siguiente se muestra cómo usar el modelo de permisos de control de acceso basado en rol (RBAC) de Azure para conceder al pod acceso al almacén de claves. Para obtener más información sobre el modelo de permisos de Azure RBAC para Azure Key Vault, consulte Conceder permiso a las aplicaciones para acceder a un almacén de claves de Azure mediante Azure RBAC.

  1. Cree un almacén de claves con protección de purga y con la autorización de Azure RBAC habilitada mediante el comando az keyvault create. También puede usar un almacén de claves existente si está configurado para la protección de purga y la autorización de RBAC de Azure.

    export KEYVAULT_NAME="keyvault-workload-id$RANDOM_ID" # Ensure the key vault name is between 3-24 characters
    az keyvault create \
        --name "${KEYVAULT_NAME}" \
        --resource-group "${RESOURCE_GROUP}" \
        --location "${LOCATION}" \
        --enable-purge-protection \
        --enable-rbac-authorization
    
  2. Obtenga el identificador de recurso del almacén de claves y guárdelo en una variable de entorno mediante el comando az keyvault show.

    export KEYVAULT_RESOURCE_ID=$(az keyvault show --resource-group "${RESOURCE_GROUP}" \
        --name "${KEYVAULT_NAME}" \
        --query id \
        --output tsv)
    

Agregue el código siguiente a main.tf para crear un almacén de claves con autorización de RBAC de Azure.

resource "azurerm_key_vault" "this" {
 name                          = local.key_vault_name
 location                      = azurerm_resource_group.this.location
 resource_group_name           = azurerm_resource_group.this.name
 tenant_id                     = data.azurerm_client_config.current.tenant_id
 sku_name                      = "standard"
 rbac_authorization_enabled    = true
}

Asignar permisos de RBAC para la administración de almacenes de claves

  1. Obtenga el identificador de objeto del autor de la llamada y guárdelo en una variable de entorno mediante el az ad signed-in-user show comando .

    export CALLER_OBJECT_ID=$(az ad signed-in-user show --query id -o tsv)
    
  2. Asígnese el rol Azure RBAC Key Vault Secrets Officer para que pueda crear un secreto en la nueva bóveda de claves mediante el comando az role assignment create.

    az role assignment create --assignee "${CALLER_OBJECT_ID}" \
        --role "Key Vault Secrets Officer" \
        --scope "${KEYVAULT_RESOURCE_ID}"
    

Agregue el siguiente código a main.tf para asignarse el rol Agente de secretos de Key Vault de Azure RBAC y poder crear un secreto en el nuevo Key Vault y asignar el rol Usuario de secretos de Key Vault a la identidad administrada asignada por el usuario:

resource "azurerm_role_assignment" "user" {
 scope                = azurerm_key_vault.this.id
 role_definition_name = "Key Vault Secrets Officer"
 principal_id         = data.azurerm_client_config.current.object_id
}
resource "azurerm_role_assignment" "identity" {
 scope                = azurerm_key_vault.this.id
 role_definition_name = "Key Vault Secrets User"
 principal_id         = azurerm_user_assigned_identity.this.principal_id
}

Crear y configurar el acceso a secretos

  1. Cree un secreto en el almacén de claves mediante el comando az keyvault secret set.

    export KEYVAULT_SECRET_NAME="my-secret$RANDOM_ID"
    az keyvault secret set \
        --vault-name "${KEYVAULT_NAME}" \
        --name "${KEYVAULT_SECRET_NAME}" \
        --value "Hello\!"
    
  2. Obtenga el identificador principal de la identidad administrada asignada por el usuario y guárdelo en una variable de entorno con el comando az identity show.

    export IDENTITY_PRINCIPAL_ID=$(az identity show \
        --name "${USER_ASSIGNED_IDENTITY_NAME}" \
        --resource-group "${RESOURCE_GROUP}" \
        --query principalId \
        --output tsv)
    
  3. Asigne el rol Key Vault Secrets User a la identidad administrada asignada por el usuario mediante el comando az role assignment create. En este paso se proporciona permiso a la identidad administrada para leer secretos de la bóveda de claves.

    az role assignment create \
        --assignee-object-id "${IDENTITY_PRINCIPAL_ID}" \
        --role "Key Vault Secrets User" \
        --scope "${KEYVAULT_RESOURCE_ID}" \
        --assignee-principal-type ServicePrincipal
    
  4. Cree una variable de entorno para la dirección URL del almacén de claves mediante el az keyvault show comando .

    export KEYVAULT_URL="$(az keyvault show \
        --resource-group "${RESOURCE_GROUP}" \
        --name ${KEYVAULT_NAME} \
        --query properties.vaultUri \
        --output tsv)"
    

Agregue el código siguiente a main.tf para crear un secreto en el almacén de claves:

resource "azurerm_key_vault_secret" "this" {
 name         = local.secret_name
 value        = "Hello from Key Vault"
 key_vault_id = azurerm_key_vault.this.id
}

Implementación de un pod de comprobación y prueba de acceso

  1. Implemente un pod para verificar que la identidad de la carga de trabajo puede acceder al secreto en el almacén de claves. En el ejemplo siguiente se usa la imagen de ghcr.io/azure/azure-workload-identity/msal-go, que contiene una aplicación de ejemplo que recupera un secreto de Azure Key Vault mediante Id. de carga de trabajo de Microsoft Entra:

    kubectl apply -f - <<EOF
    apiVersion: v1
    kind: Pod
    metadata:
        name: sample-workload-identity-key-vault
        namespace: ${SERVICE_ACCOUNT_NAMESPACE}
        labels:
            azure.workload.identity/use: "true"
    spec:
        serviceAccountName: ${SERVICE_ACCOUNT_NAME}
        containers:
          - image: ghcr.io/azure/azure-workload-identity/msal-go
            name: oidc
            env:
              - name: KEYVAULT_URL
                value: ${KEYVAULT_URL}
              - name: SECRET_NAME
                value: ${KEYVAULT_SECRET_NAME}
        nodeSelector:
            kubernetes.io/os: linux
    EOF
    
  2. Espere a que el pod esté en el estado Ready utilizando el comando kubectl wait.

    kubectl wait --namespace ${SERVICE_ACCOUNT_NAMESPACE} --for=condition=Ready pod/sample-workload-identity-key-vault --timeout=120s
    
  3. Compruebe que la SECRET_NAME variable de entorno está establecida en el pod mediante el kubectl describe comando .

    kubectl describe pod sample-workload-identity-key-vault | grep "SECRET_NAME:"
    

    Si se ejecuta correctamente, la salida debe ser similar al ejemplo siguiente:

    SECRET_NAME: ${KEYVAULT_SECRET_NAME}
    
  4. Verifique que los pods puedan obtener un token y acceder al recurso mediante el comando kubectl logs.

    kubectl logs sample-workload-identity-key-vault
    

    Si se ejecuta correctamente, la salida debe ser similar al ejemplo siguiente:

    I0114 10:35:09.795900       1 main.go:63] "successfully got secret" secret="Hello\\!"
    

    Importante

    Las asignaciones de roles de RBAC en Azure pueden tardar hasta 10 minutos en propagarse. Si el pod no puede acceder al secreto, es posible que tenga que esperar a que se propague la asignación de roles. Para obtener más información, consulte Troubleshoot Azure RBAC.

Deshabilitación de Id. de carga de trabajo de Microsoft Entra en un clúster de AKS

Deshabilite Id. de carga de trabajo de Microsoft Entra en el clúster de AKS donde se ha habilitado y configurado, actualice el clúster de AKS mediante el comando az aks update con el parámetro --disable-workload-identity.

az aks update \
    --resource-group "${RESOURCE_GROUP}" \
    --name "${CLUSTER_NAME}" \
    --disable-workload-identity

Desplegar un pod de verificación

Agregue el siguiente código en main.tf para implementar un pod de verificación que use la identidad de carga de trabajo para obtener acceso al secreto en el almacén de claves:

resource "kubernetes_pod" "test" {
 metadata {
   name      = "workload-identity-test"
   namespace = local.service_account_namespace
   labels = {
     "azure.workload.identity/use" = "true"
   }
 }
 spec {
   service_account_name = kubernetes_service_account.this.metadata[0].name
   container {
     name  = "test"
     image = "ghcr.io/azure/azure-workload-identity/msal-go"
     env {
       name  = "KEYVAULT_URL"
       value = azurerm_key_vault.this.vault_uri
     }
     env {
       name  = "SECRET_NAME"
       value = azurerm_key_vault_secret.this.name
     }
   }
 }
}

Inicialización de Terraform

Inicialice Terraform en el directorio que contiene el archivo main.tf usando el comando terraform init. Este comando descarga el proveedor de Azure necesario para administrar Azure recursos con Terraform.

terraform init

Creación de un plan de ejecución de Terraform

Cree un plan de ejecución de Terraform mediante el comando terraform plan. Este comando muestra los recursos que Terraform creará o modificará en la suscripción de Azure.

terraform plan

Aplica la configuración de Terraform

Después de revisar y confirmar el plan de ejecución, aplique la configuración de Terraform mediante el terraform apply comando . Este comando crea o modifica los recursos definidos en tu archivo main.tf en tu suscripción de Azure.

terraform apply

Comprobación de la implementación

  1. Conectar al clúster de AKS mediante el comando az aks get-credentials.

    az aks get-credentials --name <cluster-name> --resource-group <resource-group>
    
  2. Compruebe el estado del pod de comprobación mediante el kubectl get pods comando .

  3. Una vez que el pod alcance un estado Ready, compruebe que puede obtener acceso al secreto del almacén de claves comprobando los registros del pod mediante el comando kubectl logs.

    kubectl logs workload-identity-test
    

En este artículo, ha implementado un clúster de Kubernetes y lo ha configurado para usar un Id. de carga de trabajo de Microsoft Entra como preparación para que las cargas de trabajo de la aplicación se autentiquen con esa credencial. Ahora está listo para implementar la aplicación y configurarla para usar la identidad de carga de trabajo con la versión más reciente de Azure Identity biblioteca cliente. Si no puede volver a escribir la aplicación para usar la versión más reciente de la biblioteca cliente, puede configurar el pod de la aplicación para autenticarse usando la identidad administrada con la identidad de carga de trabajo como solución de migración a corto plazo.

La integración Service Connector ayuda a simplificar la configuración de conexión para cargas de trabajo de AKS y servicios de respaldo de Azure. Controla de forma segura la autenticación y las configuraciones de red y sigue los procedimientos recomendados para conectarse a servicios de Azure. Para obtener más información, consulte Conexión a Azure OpenAI en Foundry Models en AKS mediante Identidad de carga de trabajo de Microsoft Entra y la Introducción al Conector de servicio.