Puedes encontrar el código fuente del post en el siguiente enlace: https://github.com/fjvela/blog-managed-identities

Introducción

Uno de los grandes retos que tenemos hoy en día es gestionar la información sensible (credenciales, certificados, …) que nuestras aplicaciones necesitan.

Azure proporciona Managed Identities para simplificar la autenticación necesaria para acceder a los recursos desplegados en Azure como Azure Key Vault. Puedes comprobar la lista de servicios que soportan la autenticación a través de Managed Identities en el siguiente enlace: https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/managed-identities-status

La utilización de Managed Identities tiene algunas ventajas:

  • No es necesario utilizar y/o gestionar credenciales
  • Permite autenticarnos con cualquier otra aplicación (incluyendo nuestras propias aplicaciones)
  • No tiene un coste extra

Tipos de Managed Identities

Existen dos tipos de Managed Identities:

  • System managed identities: Son creadas automáticamente por Azure cuando se crean algunos servicios como máquinas virtuales:
    • Solo se puede utilizar por el servicio que la ha creado
    • Su ciclo de vida está asociado al ciclo de vida del recurso que lo ha creado (si borras el recurso, se borra la Managed Identity)
    • Automáticamente se crea un Service Principal en Microsoft Entra ID (directorio activo)
    • Debemos autorizar a qué servicios pueden acceder a la Managed Identity
  • User managed identities: Podemos crear un Managed Identity y asignársela a más de una aplicación:
    • Podemos utilizarla en una o varias aplicaciones
    • Debemos autorizar a qué servicios pueden acceder las aplicaciones que usen la Managed Identity creada
    • Automáticamente se crea un Service Principal en Microsoft Entra ID (directorio activo), su ciclo de vida no está asociado al ciclo de vida de la aplicación que lo utiliza

¿Cómo funciona?

Antes de explicar como funciona el proceso de creación y funcionamiento de una managed identity, debemos conocer qué es Azure Instance Metadata Service identity (IMSI):

  • Es un servicio REST interno disponible en la dirección IP: 169.254.169.254
  • Proporciona información sobre las instancias de VM en ejecución: Sistema operativo, mantenimientos programados, …
  • También proporciona tokens de autenticación que obtiene de Microsoft Entra ID

Diagrama funcionamiento managed identities

  1. Azure Resource Manager crea un service principal en Microsoft Entra ID asociado a la Managed Identity creada
  2. A continuación Azure Resource Manager, actualiza Azure Instance Metadata Service identity (IMSI) proporcionando el ID el service principal y los certificados creados por Microsoft Entra ID. Más tarde serán necesarios para poder autenticarse contra Microsoft Entra ID
  3. En este paso, Azure Resource Manager habilita los permisos necesarios para acceder a otros recursos de Azure (Azure RBAC). Por ejemplo, asignar el rol Key Vault Secrets User para poder leer secretos de un Azure Key Vault
  4. Cuando nuestra aplicación necesita acceder al recurso, se comunica con el IMSI, el cual solicita un token de autenticación a Microsoft Entra ID (utilizando el service principal y certificados creados en el paso 2) que será utilizado por la aplicación para poder acceder a otros recursos desplegados en Azure.

Habilitar una Managed Identity en Azure

Como hemos comentado, exiten dos tipos de Managed Identites: System managed identities y User managed identities. Vamos a ver como crear y habilitarlas en Azure.

Una vez creada la managed identity, debemos asignar los permisos correspondientes de acceso.

System Managed Identity

Para crear un System Managed Identity asociado a un recurso de Azure tan solo debemos seleccionarlo desde el portal y en el menu “Identity”, habilitarlo y guardar los cambios realizados.

Como habilitar System Managed Identity en Azure Functions

System Managed Identity en Azure Functions creada

User Managed Identity

Desde el apartado “Managed Identities” podemos crear User Managed Identites, una vez completados los datos requeridos debemos asignar la managed identity al recurso o recursos que harán uso de ella.

Como crear una User Managed Identity

Como asignar una User Managed Identity a una Azure Functions

User Managed Identity asignada a una Azure Functions

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 o implementando el código necesario para poder interactuar con el API REST proporcionado por la IMSI y así obtener los tokens de autenticación para acceder a otros recursos de Azure.

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

  1. Crea una proyecto .NET, en este caso hemos creado un proyecto tipo Azure Functions para facilitar su despliegue en Azure
  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 a través de la IMSI:

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 utilizando 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 nuestra Azure Function es el siguiente:

  [Function("GetSecret")]
  public IActionResult GetSecret([HttpTrigger(AuthorizationLevel.Function, "get")] HttpRequest req, 
      [FromQuery] string name,
      [FromQuery] string credentialType)
  {
      _logger.LogInformation("C# HTTP trigger function processed a request.");
      var kvName = _config["KV_NAME"];

      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");
  }

A continuación podemos ver el resultado de la ejecución de la Azure Function desde local y desde Azure:

Resultado ejecución Azure Function desde local

Resultado ejecución Azure Function desde Azure

Conclusión

La utilización de Managed Identities no solo simplifica la gestión de credenciales, sino que también mejora significativamente la seguridad de las aplicaciones, al eliminar la necesidad de configurar y guardar secretos en archivos de configuración.

Para los desarrolladores y arquitectos, utilizar Managed Identities debería ser una práctica estándar en la mayoría de los escenarios.

Referencias