Puedes encontrar el código fuente del post en el siguiente enlace: https://github.com/fjvela/blog-demo-azure-ad-workload-identity

Introducción

En el siguiente post voy a explicar cómo puedes utilizar Azure Managed Identities y Azure Federated Identity Credentials desde un cluster Kubernetes desplegado en Azure. Esto permitirá a las aplicaciones que se ejecutan en el cluster acceder a servicisos desplegados en Azure sin necesidad de utilizar credenciales.

Antes de continuar leyendo el post, te recomiendo que leas los posts sobre Azure Managed Identities y Azure Federated Identity Credentials.

En los posts mencionados, explico cómo acceder a los recursos desplegados en Azure sin necesidad de gestionar secretos y/o certificados:

  • Azure Managed Identities: Se usan en aplicaciones que se ejecutan en servicios de Azure (ej. máquinas virtuales).
  • Azure Federated Identity Credentials: Se usan en aplicaciones y servicios que se ejecutan fuera de Azure (ej. GitHub Workflow).

¿Cómo funciona?

Una federated identity credential permite establecer una relación de confianza entre una User managed identity y un proveedor de identidad externo (external identity provider IdP).

Esta relación permite a Microsoft Identity autenticar una aplicación externa a través del token recibido y el IdP configurado, generando a su vez otro token que permitirá a la aplicación acceder a los recursos desplegados en Azure.

Tras crear la user managed identity, podemos configurar hasta un máximo de 20 federated identity credentials.

Para aplicaciones desplegadas en un cluster de Kubernetes, se requiere la siguiente información:

  • issuer: Dirección URL del proveedor de identidades externo del cluster (IdP).
  • namespace: Nombre del namespace donde se ejecutarán los pods.
  • service account: Nombre del service account (SA) asociado a los pods de nuestro workload.
  • audiences: Indica qué plataforma de identidad de Microsoft debe aceptar el token entrante (por defecto: api://AzureADTokenExchange - el valor depende del entorno cloud utilizado - Fairfax, Mooncake, USNat o USSec).

Nota: La combinación de namespace y service account debe ser única en la user managed identity.

Diagrama de funcionamiento federated identity credential

  1. Cuando Kubernetes inicia un nuevo POD, AD Workload Identity crea un token en un path determinado.
  2. La aplicación solicita un token a Microsoft identity platform, utilizando el token generado en el paso 1.
  3. Microsoft identity platform valida el token incluido en la petición contra el servicio de validación externo que se ha registrado previamente (OIDC del cluster). Si el token es válido, se genera un token de autenticación para autenticarse contra otros servicios desplegados en Azure (hay que asignar los permisos necesarios en el servicio).
  4. La aplicación utiliza el token generado para acceder a los recursos desplegados en Azure.

Configurar federated identity credentials (Kubernetes)

Para comenzar, necesitamos un proveedor de identidad externo para crear la relación de confianza entre nuestro cluster y las managed identities utilizadas por las aplicaciones que se ejecutan en nuestro cluster.

Azure nos proporciona el servicio OpenID Connect (OIDC). Para activarlo podemos usar el siguiente comando:

az aks update --resource-group myResourceGroup --name myAKScluster --enable-oidc-issuer

Si estás utilizando Amazon Elastic Kubernetes (EKS) o Google Kubernetes Engine (GKE) revisa la siguiente documentación:

A continuación, vamos a configurar una federated identity credential para permitir que la aplicación pueda acceder a recursos desplegados en Azure.

Desde el menú “Managed Identities” podemos crear una User Managed Identity.

Cómo crear una User Managed Identity

Una vez creada, añadimos una federated identity credential:

  1. Azure nos da la opción de configuración para diferentes escenarios, en nuestro caso seleccionamos la opción para configurar Kubernetes.
  2. Completamos la información que nos solicita:
  • Namespace donde se ejecuta la aplicación.
  • Service Account (SA) que utiliza la aplicación.
  • URL del emisor de OIDC de nuestro cluster, puedes consultarla en el portal o través del comando: az aks show --name myAKScluster --resource-group myResourceGroup --query "oidcIssuerProfile.issuerUrl" -o tsv.

Cómo añadir federated identity credential

Cómo configurar GitHub federated identity credential

Después de crear la user managed identity y configurados los federated identity credentials, debemos asignar los permisos correspondientes de acceso.

Asignar un rol a la user Managed Identity

Como acceder a un recurso en Azure utilizando una Managed Identity utilizando .NET

Podemos hacer uso de las Managed Identities creadas en Azure a través de los diferentes SDKs disponibles.

Vamos a describir cómo podemos acceder a un Azure Key Vault utilizando código .NET y la librería Azure.Identity:

  1. Crea un proyecto .NET, en este caso hemos creado un proyecto tipo Web.
  2. Añade la referencia a la librería Azure.Identity dotnet add package Azure.Identity.

Azure.Identity proporciona varias clases que encapsulan la lógica necesaria para poder obtener un token de autenticación de Microsoft Entra ID haciendo uso de la Managed Identity configurada:

DefaultAzureCredential: Intenta realizar la autenticación a través de diferentes mecanismos hasta que consigue conectarse con uno de ellos. Diagrama funcionamiento DefaultAzureCredential

var credential = new DefaultAzureCredential();
var client = new SecretClient(new Uri("https://mykv.vault.azure.net/"), credential);

ChainedTokenCredential: Intenta realizar la autenticación a través de la Managed Identity. Si no lo consigue, intenta conectarse a través de Azure CLI

var credential = new ChainedTokenCredential();
var client = new SecretClient(new Uri("https://mykv.vault.azure.net/"), credential);

ManagedIdentityCredential: Utiliza la Managed Identity para solicitar el token de autenticación

var credential = new ManagedIdentityCredential();
var client = new SecretClient(new Uri("https://mykv.vault.azure.net/"), credential);

El código final de nuestro API controlador es el siguiente:

 [ApiController]
 [Route("[controller]")]
 public class SecretController : ControllerBase
 {
     private readonly ILogger<SecretController> _logger;
     private readonly IConfiguration _config;

     public SecretController(ILogger<SecretController> logger, IConfiguration config)
     {
         _logger = logger;
         _config = config;
     }

     [HttpGet(Name = "GetSecret")]
     public IActionResult Get(string name, string credentialType = "DefaultAzureCredential")
     {
         var kvName = _config["KV_NAME"];
         _logger.LogInformation($"C# HTTP trigger function processed a request. {name} {credentialType} {kvName}");

         var tokenCredential = GetTokenCredential(credentialType);
         var client = new SecretClient(new Uri($"https://{kvName}.vault.azure.net/"), tokenCredential);

         return new OkObjectResult(client.GetSecret(name));
     }

     private TokenCredential GetTokenCredential(string credentialType)
     {
         switch (credentialType)
         {
             case "DefaultAzureCredential":
                 return new DefaultAzureCredential();
             case "ChainedTokenCredential":
                 return new ChainedTokenCredential();
             case "ManagedIdentityCredential":
                 return new ManagedIdentityCredential();
         }

         throw new Exception($"The credential type {credentialType} is not valid");
     }
 }

Como configurar Managed Identity en el cluster

Para configurar la Managed Identity en el cluster es necesario crear y asignar una Service Account (SA) a nuestra aplicación.

Utilizando las anotaciones azure.workload.identity/client-id y azure.workload.identity/tenant-id podemos configurar la Managed Identity creada previamente y que utilizaremos con nuestra aplicación. A continuación puedes ver un ejemplo:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: sa-app-1
  namespace: develop
  annotations:
    azure.workload.identity/client-id: "3d49c3ea-369c-4af2-b770-3a5de4d0aca2"
    azure.workload.identity/tenant-id: "xxxxxx-xxx-x-x-x"

Además es necesario añadir la etiqueta azure.workload.identity/use a los pods de nuestra aplicación para indicarle a Azure AD Workload Identity que debe crear un token de autenticación en el POD utilizando los datos de configuración proporcionados en la Service Account (SA).

A continuación puedes encontrar el código yaml necesario para desplegar la aplicación en el cluster kubernetes haciendo uso de una Managed Identity creada previamente:

apiVersion: v1
kind: Namespace
metadata:
  name: develop
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: sa-app-1
  namespace: develop
  annotations:
    azure.workload.identity/client-id: "3d49c3ea-369c-4af2-b770-3a5de4d0aca2"
    azure.workload.identity/tenant-id: "xxxxxx-xxx-x-x-x"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: myapp
  name: myapp
  namespace: develop
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myapp
  strategy: {}
  template:
    metadata:
      labels:
        app: myapp
        azure.workload.identity/use: "true"
    spec:
      serviceAccountName: sa-app-1
      containers:
        - image: acrqi99.azurecr.io/app:1.0.0
          name: app
          ports:
            - containerPort: 8080
          env:
            - name: KV_NAME
              value: kv-qi99
          resources: {}

Una vez desplegada la aplicación podemos comprobar como Azure AD Workload Identity ha modificado la configuración del POD para que la aplicación pueda acceder a los servicios desplegados en Azure haciendo uso de la Managed Identity configurada:

POD valores inyectados por <em>Azure AD Workload Identity</em>

Realizando una llamada GET para consultar la información del secreto secret-sauce, podemos comprobar que la Managed Identity ha sido configurada correctamente:

Resultado contenido secreto

Conclusión

La implementación de Azure Managed Identities junto con Azure Federated Identity Credentials y Azure AD Workload Identity proporciona una solución robusta y segura para gestionar el acceso a servicios de Azure a aplicaciones que se ejecutan en un cluster de Kubernetes.

Esta solución elimina la necesidad de gestionar credenciales manualmente, reduciendo significativamente los riesgos de seguridad asociados con el manejo de secretos y certificados.

Las ventajas principales de esta solución son:

  • Eliminar la gestión manual de credenciales.
  • Mayor seguridad al no almacenar secretos en el código o en el cluster.
  • Escalabilidad para múltiples aplicaciones y servicios.
  • Compatibilidad con múltiples entornos y proveedores de Kubernetes.

Referencias