Compartir a través de


Procedimientos recomendados de autenticación con la biblioteca de identidades de Azure para JavaScript

En este artículo se ofrecen instrucciones para ayudarle a maximizar el rendimiento y la confiabilidad de las aplicaciones de JavaScript y TypeScript al autenticarse en los servicios de Azure. Para aprovechar al máximo la biblioteca de identidades de Azure para JavaScript, es importante comprender posibles problemas y técnicas de mitigación.

Uso de credenciales deterministas en entornos de producción

DefaultAzureCredential es la manera más accesible de empezar a trabajar con la biblioteca de identidades de Azure, pero esa comodidad también introduce ciertos compromisos. En particular, no se puede garantizar de antemano la credencial específica de la cadena que será exitosa y se usará para la autenticación de solicitudes. En un entorno de producción, esta imprevisibilidad puede presentar problemas significativos y a veces sutiles.

Por ejemplo, considere la siguiente secuencia hipotética de eventos:

  1. El equipo de seguridad de una organización exige que todas las aplicaciones usen la identidad administrada para autenticarse en los recursos de Azure.
  2. Durante meses, una aplicación de JavaScript hospedada en una máquina virtual (VM) de Azure usa DefaultAzureCredential correctamente para autenticarse a través de una identidad administrada.
  3. Sin indicarlo al equipo de soporte técnico, un desarrollador instala la CLI de Azure en esa máquina virtual y ejecuta el comando az login para autenticarse en Azure.
  4. Debido a este nuevo cambio de configuración independiente en el entorno de Azure, la autenticación a través de la identidad administrada original comienza inesperadamente a producir un error en modo silencioso.
  5. DefaultAzureCredential omite el ManagedIdentityCredential que falló y busca la siguiente credencial disponible, que es AzureCliCredential.
  6. La aplicación comienza a usar las credenciales de la CLI de Azure en lugar de la identidad administrada, lo que puede producir un error o provocar una elevación o reducción inesperada de privilegios.

Para evitar estos tipos de problemas sutiles o errores silenciosos en aplicaciones de producción, reemplace por DefaultAzureCredential una implementación específica TokenCredential , como ManagedIdentityCredential. Consulte la documentación de la biblioteca cliente de Azure Identity para obtener las credenciales disponibles.

Por ejemplo, considere la siguiente DefaultAzureCredential configuración en un proyecto de Express.js:

import { DefaultAzureCredential } from "@azure/identity";
import { SecretClient } from "@azure/keyvault-secrets";
import { BlobServiceClient } from "@azure/storage-blob";

const credential = new DefaultAzureCredential();

const secretClient = new SecretClient("https://keyVaultName.vault.azure.net", credential);
const blobServiceClient = new BlobServiceClient(
  "https://storageAccountName.blob.core.windows.net",
  credential
);

Modifique el código anterior para seleccionar una credencial basada en el entorno en el que se ejecuta la aplicación:

import { AzureDeveloperCliCredential, ManagedIdentityCredential, ChainedTokenCredential, 
         AzureCliCredential } from "@azure/identity";
import { SecretClient } from "@azure/keyvault-secrets";
import { BlobServiceClient } from "@azure/storage-blob";

let credential;

// In production, use only ManagedIdentityCredential
if (process.env.NODE_ENV === 'production') {
  // For user-assigned managed identity, provide the client ID
  credential = new ManagedIdentityCredential(process.env.AZURE_CLIENT_ID);
}
// In development, use a chain of credentials appropriate for local work
else {
  credential = new ChainedTokenCredential(
    new AzureCliCredential(),
    new AzureDeveloperCliCredential()
  );
}

// Initialize Key Vault client
const secretClient = new SecretClient("https://keyVaultName.vault.azure.net", credential);

// Initialize Blob Storage client
const blobServiceClient = new BlobServiceClient(
  "https://storageAccountName.blob.core.windows.net",
  credential
);

En este ejemplo, solo ManagedIdentityCredential se usa en producción. Las necesidades de autenticación del entorno de desarrollo local son atendidas por la secuencia de credenciales definida en la cláusula else.

Reutilización de instancias de credenciales

Vuelva a usar las instancias de credenciales siempre que sea posible para mejorar la resistencia de la aplicación y reducir el número de solicitudes de token de acceso emitidas a Microsoft Entra ID. Cuando se reutiliza una credencial, se intenta capturar un token de la caché de tokens de la aplicación administrada por la dependencia de MSAL subyacente. Para más información, consulte el almacenamiento en caché de tokens de en la biblioteca cliente de Azure Identity.

El comportamiento del almacenamiento en caché de tokens difiere entre entornos de explorador y Node.js. En Node.js aplicaciones, los tokens se almacenan en caché en memoria de forma predeterminada, lo que significa que la memoria caché se pierde cuando se reinicia la aplicación. En las aplicaciones del explorador, los tokens se pueden conservar en el almacenamiento del explorador (localStorage o sessionStorage) en función del flujo de autenticación y la configuración. Comprender estas diferencias es importante al implementar estrategias de reutilización de credenciales para distintos tipos de aplicación.

Importante

Una aplicación de gran volumen que no reutiliza las credenciales puede encontrar respuestas de limitación HTTP 429 de Microsoft Entra ID, lo que puede provocar interrupciones de la aplicación.

La estrategia de reutilización de credenciales recomendada difiere según el marco de trabajo de la aplicación.

Para implementar la reutilización de credenciales en aplicaciones de JavaScript, cree una única instancia de credenciales y reutilícela en todos los objetos de cliente:

import { DefaultAzureCredential, ManagedIdentityCredential } from "@azure/identity";
import { SecretClient } from "@azure/keyvault-secrets";
import { BlobServiceClient } from "@azure/storage-blob";

// Create a single credential instance
const credential = process.env.NODE_ENV === 'production'
  ? new ManagedIdentityCredential(process.env.AZURE_CLIENT_ID)
  : new DefaultAzureCredential();

// Reuse the credential across different client objects
const secretClient = new SecretClient("https://keyVaultName.vault.azure.net", credential);
const blobServiceClient = new BlobServiceClient(
  "https://storageAccountName.blob.core.windows.net",
  credential
);

En Express.js aplicaciones, puede almacenar las credenciales en la configuración de la aplicación y acceder a ellas en los controladores de ruta:

import express from "express";
import { DefaultAzureCredential, ManagedIdentityCredential } from "@azure/identity";
import { SecretClient } from "@azure/keyvault-secrets";
import { BlobServiceClient } from "@azure/storage-blob";

const app = express();

// Create a single credential instance at app startup
app.locals.credential = process.env.NODE_ENV === 'production'
  ? new ManagedIdentityCredential(process.env.AZURE_CLIENT_ID)
  : new DefaultAzureCredential();

// Reuse the credential in route handlers
app.get('/api/secrets/:secretName', async (req, res) => {
  const secretClient = new SecretClient(
    "https://keyVaultName.vault.azure.net", 
    req.app.locals.credential
  );
  
  try {
    const secret = await secretClient.getSecret(req.params.secretName);
    res.json({ name: secret.name, value: secret.value });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Add this route to the existing Express app
app.get('/api/blobs/:containerName', async (req, res) => {
  const blobServiceClient = new BlobServiceClient(
    "https://storageAccountName.blob.core.windows.net", 
    req.app.locals.credential
  );
  
  try {
    // Get reference to a container
    const containerClient = blobServiceClient.getContainerClient(req.params.containerName);
    
    // List all blobs in the container
    const blobs = [];
    for await (const blob of containerClient.listBlobsFlat()) {
      blobs.push({
        name: blob.name,
        contentType: blob.properties.contentType,
        size: blob.properties.contentLength,
        lastModified: blob.properties.lastModified
      });
    }
    
    res.json({ containerName: req.params.containerName, blobs });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

app.listen(3000, () => console.log('Server running on port 3000'));

Comprender cuándo se necesita la duración del token y la lógica de almacenamiento en caché

Si usa una credencial de biblioteca de identidades de Azure fuera del contexto de una biblioteca cliente de Azure SDK, se convierte en su responsabilidad administrar la duración del token y el comportamiento del almacenamiento en caché en la aplicación.

La propiedad refreshAfterTimestamp de AccessToken, que proporciona una indicación a los consumidores sobre cuándo se puede intentar refrescar el token, será utilizada automáticamente por las bibliotecas cliente del SDK de Azure que dependen de la biblioteca de Azure Core para actualizar el token. Para el uso directo de las credenciales de la biblioteca de Azure Identity que admiten la caché de tokens, la caché de MSAL subyacente se actualiza automáticamente cuando se produce el refreshAfterTimestamp tiempo. Este diseño permite al código de cliente llamar a TokenCredential.getToken() cada vez que se necesita un token y delegar la actualización en la biblioteca.

Para llamar solo a TokenCredential.getToken() cuando sea necesario, observe la fecha de refreshAfterTimestamp e intente actualizar el token de forma proactiva después de ese tiempo. La implementación específica queda a discreción del cliente.

Comprender la estrategia de reintento de identidad administrada

La biblioteca de identidades de Azure para JavaScript permite autenticarse a través de una identidad administrada con ManagedIdentityCredential. La forma en que se usa ManagedIdentityCredential afecta a la estrategia de reintento aplicada:

  • Cuando se usa a través de DefaultAzureCredential, no se intenta ningún reintento cuando se produce un error en el intento inicial de adquisición de tokens o se agota el tiempo de espera tras un breve período de tiempo. Esta es la opción menos resistente porque está optimizada para "fallar rápidamente" para un bucle interno de desarrollo eficaz.
  • Cualquier otro enfoque, como ChainedTokenCredential o ManagedIdentityCredential directamente:
    • El intervalo de tiempo entre reintentos empieza en 0,8 segundos y se intenta un máximo de cinco reintentos de forma predeterminada. Esta opción está optimizada para resistencia, pero presenta retrasos potencialmente no deseados en el bucle interno de desarrollo.
    • Para cambiar cualquiera de los valores de reintento predeterminados, use la propiedad retryOptions en el parámetro options. Por ejemplo, vuelva a intentar un máximo de tres veces, con un intervalo inicial de 0,5 segundos:
import { ManagedIdentityCredential } from "@azure/identity";

const credential = new ManagedIdentityCredential(
  process.env.AZURE_CLIENT_ID, // For user-assigned managed identity
  {
    retryOptions: {
      maxRetries: 3,           // Maximum number of retry attempts
      retryDelayInMs: 500,     // Initial delay between retries (in milliseconds)
      maxRetryDelayInMs: 5000  // Maximum delay between retries (in milliseconds)
    }
  }
);

Para obtener más información sobre cómo personalizar las directivas de reintento para la identidad administrada, consulte una de las siguientes opciones que se extienden desde TokenCredentialOptions: