wangzhibo
2026-05-09 53418655c061ac26f66058253f39200aced1ab1d
1
{"version":3,"file":"workloadIdentityCredential.js","sourceRoot":"","sources":["../../../src/credentials/workloadIdentityCredential.ts"],"names":[],"mappings":";AAAA,uCAAuC;AACvC,kCAAkC;;;AAGlC,mDAAsE;AAEtE,iFAA2E;AAC3E,4CAA0D;AAE1D,+DAAyD;AACzD,+CAA4C;AAE5C,MAAM,cAAc,GAAG,4BAA4B,CAAC;AACpD;;;;;;GAMG;AACU,QAAA,qCAAqC,GAAG;IACnD,iBAAiB;IACjB,iBAAiB;IACjB,4BAA4B;CAC7B,CAAC;AACF,MAAM,MAAM,GAAG,IAAA,6BAAgB,EAAC,cAAc,CAAC,CAAC;AAChD;;;;;;;;;;;;;GAaG;AACH,MAAa,0BAA0B;IAC7B,MAAM,CAAwC;IAC9C,8BAA8B,GAAuB,SAAS,CAAC;IAC/D,SAAS,GAAuB,SAAS,CAAC;IAC1C,sBAAsB,CAAqB;IAEnD;;;;OAIG;IACH,YAAY,OAA2C;QACrD,kDAAkD;QAClD,MAAM,WAAW,GAAG,IAAA,2BAAc,EAAC,6CAAqC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9F,MAAM,CAAC,IAAI,CAAC,8CAA8C,WAAW,EAAE,CAAC,CAAC;QAEzE,MAAM,iCAAiC,GAAG,OAAO,IAAI,EAAE,CAAC;QACxD,MAAM,QAAQ,GAAG,iCAAiC,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;QAC3F,MAAM,QAAQ,GAAG,iCAAiC,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;QAC3F,IAAI,CAAC,sBAAsB;YACzB,iCAAiC,CAAC,aAAa,IAAI,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC;QAC5F,IAAI,QAAQ,EAAE,CAAC;YACb,IAAA,gCAAa,EAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAClC,CAAC;QACD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,sCAA0B,CAClC,GAAG,cAAc;qIAC4G,CAC9H,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,sCAA0B,CAClC,GAAG,cAAc;qIAC4G,CAC9H,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,sBAAsB,EAAE,CAAC;YACjC,MAAM,IAAI,sCAA0B,CAClC,GAAG,cAAc;qIAC4G,CAC9H,CAAC;QACJ,CAAC;QAED,MAAM,CAAC,IAAI,CACT,sDAAsD,QAAQ,eAAe,iCAAiC,CAAC,QAAQ,uCAAuC,CAC/J,CAAC;QACF,IAAI,CAAC,MAAM,GAAG,IAAI,wDAAyB,CACzC,QAAQ,EACR,QAAQ,EACR,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,EAChC,OAAO,CACR,CAAC;IACJ,CAAC;IAED;;;;;;;OAOG;IACI,KAAK,CAAC,QAAQ,CACnB,MAAyB,EACzB,OAAyB;QAEzB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,YAAY,GAAG,GAAG,cAAc;;;;iKAIqH,CAAC;YAC5J,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAC1B,MAAM,IAAI,sCAA0B,CAAC,YAAY,CAAC,CAAC;QACrD,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,oDAAoD,CAAC,CAAC;QAClE,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/C,CAAC;IAEO,KAAK,CAAC,gBAAgB;QAC5B,2CAA2C;QAC3C,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,IAAI,IAAI,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC;YACjF,IAAI,CAAC,8BAA8B,GAAG,SAAS,CAAC;QAClD,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,sBAAsB,EAAE,CAAC;YACjC,MAAM,IAAI,sCAA0B,CAClC,GAAG,cAAc,gDAAgD,IAAI,CAAC,sBAAsB,GAAG,CAChG,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,8BAA8B,EAAE,CAAC;YACzC,MAAM,IAAI,GAAG,MAAM,IAAA,mBAAQ,EAAC,IAAI,CAAC,sBAAsB,EAAE,MAAM,CAAC,CAAC;YACjE,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAC1B,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,MAAM,IAAI,sCAA0B,CAClC,GAAG,cAAc,4CAA4C,IAAI,CAAC,sBAAsB,GAAG,CAC5F,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,8BAA8B,GAAG,KAAK,CAAC;gBAC5C,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC9B,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC,8BAA8B,CAAC;IAC7C,CAAC;CACF;AAzGD,gEAyGC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { AccessToken, GetTokenOptions, TokenCredential } from \"@azure/core-auth\";\nimport { credentialLogger, processEnvVars } from \"../util/logging.js\";\n\nimport { ClientAssertionCredential } from \"./clientAssertionCredential.js\";\nimport { CredentialUnavailableError } from \"../errors.js\";\nimport type { WorkloadIdentityCredentialOptions } from \"./workloadIdentityCredentialOptions.js\";\nimport { checkTenantId } from \"../util/tenantIdUtils.js\";\nimport { readFile } from \"node:fs/promises\";\n\nconst credentialName = \"WorkloadIdentityCredential\";\n/**\n * Contains the list of all supported environment variable names so that an\n * appropriate error message can be generated when no credentials can be\n * configured.\n *\n * @internal\n */\nexport const SupportedWorkloadEnvironmentVariables = [\n  \"AZURE_TENANT_ID\",\n  \"AZURE_CLIENT_ID\",\n  \"AZURE_FEDERATED_TOKEN_FILE\",\n];\nconst logger = credentialLogger(credentialName);\n/**\n * Workload Identity authentication is a feature in Azure that allows applications running on virtual machines (VMs)\n * to access other Azure resources without the need for a service principal or managed identity. With Workload Identity\n * authentication, applications authenticate themselves using their own identity, rather than using a shared service\n * principal or managed identity. Under the hood, Workload Identity authentication uses the concept of Service Account\n * Credentials (SACs), which are automatically created by Azure and stored securely in the VM. By using Workload\n * Identity authentication, you can avoid the need to manage and rotate service principals or managed identities for\n * each application on each VM. Additionally, because SACs are created automatically and managed by Azure, you don't\n * need to worry about storing and securing sensitive credentials themselves.\n * The WorkloadIdentityCredential supports Microsoft Entra Workload ID authentication on Azure Kubernetes and acquires\n * a token using the SACs available in the Azure Kubernetes environment.\n * Refer to <a href=\"https://learn.microsoft.com/azure/aks/workload-identity-overview\">Microsoft Entra\n * Workload ID</a> for more information.\n */\nexport class WorkloadIdentityCredential implements TokenCredential {\n  private client: ClientAssertionCredential | undefined;\n  private azureFederatedTokenFileContent: string | undefined = undefined;\n  private cacheDate: number | undefined = undefined;\n  private federatedTokenFilePath: string | undefined;\n\n  /**\n   * WorkloadIdentityCredential supports Microsoft Entra Workload ID on Kubernetes.\n   *\n   * @param options - The identity client options to use for authentication.\n   */\n  constructor(options?: WorkloadIdentityCredentialOptions) {\n    // Logging environment variables for error details\n    const assignedEnv = processEnvVars(SupportedWorkloadEnvironmentVariables).assigned.join(\", \");\n    logger.info(`Found the following environment variables: ${assignedEnv}`);\n\n    const workloadIdentityCredentialOptions = options ?? {};\n    const tenantId = workloadIdentityCredentialOptions.tenantId || process.env.AZURE_TENANT_ID;\n    const clientId = workloadIdentityCredentialOptions.clientId || process.env.AZURE_CLIENT_ID;\n    this.federatedTokenFilePath =\n      workloadIdentityCredentialOptions.tokenFilePath || process.env.AZURE_FEDERATED_TOKEN_FILE;\n    if (tenantId) {\n      checkTenantId(logger, tenantId);\n    }\n    if (!clientId) {\n      throw new CredentialUnavailableError(\n        `${credentialName}: is unavailable. clientId is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - \"AZURE_CLIENT_ID\".\n        See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,\n      );\n    }\n\n    if (!tenantId) {\n      throw new CredentialUnavailableError(\n        `${credentialName}: is unavailable. tenantId is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - \"AZURE_TENANT_ID\".\n        See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,\n      );\n    }\n\n    if (!this.federatedTokenFilePath) {\n      throw new CredentialUnavailableError(\n        `${credentialName}: is unavailable. federatedTokenFilePath is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - \"AZURE_FEDERATED_TOKEN_FILE\".\n        See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,\n      );\n    }\n\n    logger.info(\n      `Invoking ClientAssertionCredential with tenant ID: ${tenantId}, clientId: ${workloadIdentityCredentialOptions.clientId} and federated token path: [REDACTED]`,\n    );\n    this.client = new ClientAssertionCredential(\n      tenantId,\n      clientId,\n      this.readFileContents.bind(this),\n      options,\n    );\n  }\n\n  /**\n   * Authenticates with Microsoft Entra ID and returns an access token if successful.\n   * If authentication fails, a {@link CredentialUnavailableError} will be thrown with the details of the failure.\n   *\n   * @param scopes - The list of scopes for which the token will have access.\n   * @param options - The options used to configure any requests this\n   *                TokenCredential implementation might make.\n   */\n  public async getToken(\n    scopes: string | string[],\n    options?: GetTokenOptions,\n  ): Promise<AccessToken> {\n    if (!this.client) {\n      const errorMessage = `${credentialName}: is unavailable. tenantId, clientId, and federatedTokenFilePath are required parameters. \n      In DefaultAzureCredential and ManagedIdentityCredential, these can be provided as environment variables - \n      \"AZURE_TENANT_ID\",\n      \"AZURE_CLIENT_ID\",\n      \"AZURE_FEDERATED_TOKEN_FILE\". See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`;\n      logger.info(errorMessage);\n      throw new CredentialUnavailableError(errorMessage);\n    }\n    logger.info(\"Invoking getToken() of Client Assertion Credential\");\n    return this.client.getToken(scopes, options);\n  }\n\n  private async readFileContents(): Promise<string> {\n    // Cached assertions expire after 5 minutes\n    if (this.cacheDate !== undefined && Date.now() - this.cacheDate >= 1000 * 60 * 5) {\n      this.azureFederatedTokenFileContent = undefined;\n    }\n    if (!this.federatedTokenFilePath) {\n      throw new CredentialUnavailableError(\n        `${credentialName}: is unavailable. Invalid file path provided ${this.federatedTokenFilePath}.`,\n      );\n    }\n    if (!this.azureFederatedTokenFileContent) {\n      const file = await readFile(this.federatedTokenFilePath, \"utf8\");\n      const value = file.trim();\n      if (!value) {\n        throw new CredentialUnavailableError(\n          `${credentialName}: is unavailable. No content on the file ${this.federatedTokenFilePath}.`,\n        );\n      } else {\n        this.azureFederatedTokenFileContent = value;\n        this.cacheDate = Date.now();\n      }\n    }\n    return this.azureFederatedTokenFileContent;\n  }\n}\n"]}