wangzhibo
2026-05-09 53418655c061ac26f66058253f39200aced1ab1d
1
{"version":3,"file":"imdsMsi.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/imdsMsi.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { PipelineRequestOptions, PipelineResponse } from \"@azure/core-rest-pipeline\";\nimport { createHttpHeaders, createPipelineRequest } from \"@azure/core-rest-pipeline\";\nimport { isError } from \"@azure/core-util\";\n\nimport type { GetTokenOptions } from \"@azure/core-auth\";\nimport { credentialLogger } from \"../../util/logging.js\";\nimport { mapScopesToResource } from \"./utils.js\";\nimport { tracingClient } from \"../../util/tracing.js\";\nimport type { IdentityClient } from \"../../client/identityClient.js\";\n\nconst msiName = \"ManagedIdentityCredential - IMDS\";\nconst logger = credentialLogger(msiName);\n\nconst imdsHost = \"http://169.254.169.254\";\nconst imdsEndpointPath = \"/metadata/identity/oauth2/token\";\n\n/**\n * Generates an invalid request options to get a response quickly from IMDS endpoint.\n * The response indicates the availability of IMSD service; otherwise the request would time out.\n */\nfunction prepareInvalidRequestOptions(scopes: string | string[]): PipelineRequestOptions {\n  const resource = mapScopesToResource(scopes);\n  if (!resource) {\n    throw new Error(`${msiName}: Multiple scopes are not supported.`);\n  }\n\n  // Pod Identity will try to process this request even if the Metadata header is missing.\n  // We can exclude the request query to ensure no IMDS endpoint tries to process the ping request.\n  const url = new URL(imdsEndpointPath, process.env.AZURE_POD_IDENTITY_AUTHORITY_HOST ?? imdsHost);\n\n  const rawHeaders: Record<string, string> = {\n    Accept: \"application/json\",\n    // intentionally leave out the Metadata header to invoke an error from IMDS endpoint.\n  };\n\n  return {\n    // intentionally not including any query\n    url: `${url}`,\n    method: \"GET\",\n    headers: createHttpHeaders(rawHeaders),\n  };\n}\n\n/**\n * Defines how to determine whether the Azure IMDS MSI is available.\n *\n * Actually getting the token once we determine IMDS is available is handled by MSAL.\n */\nexport const imdsMsi = {\n  name: \"imdsMsi\",\n  async isAvailable(options: {\n    scopes: string | string[];\n    identityClient?: IdentityClient;\n    clientId?: string;\n    resourceId?: string;\n    getTokenOptions?: GetTokenOptions;\n  }): Promise<boolean> {\n    const { scopes, identityClient, getTokenOptions } = options;\n    const resource = mapScopesToResource(scopes);\n    if (!resource) {\n      logger.info(`${msiName}: Unavailable. Multiple scopes are not supported.`);\n      return false;\n    }\n\n    // if the PodIdentityEndpoint environment variable was set no need to probe the endpoint, it can be assumed to exist\n    if (process.env.AZURE_POD_IDENTITY_AUTHORITY_HOST) {\n      return true;\n    }\n\n    if (!identityClient) {\n      throw new Error(\"Missing IdentityClient\");\n    }\n\n    const requestOptions = prepareInvalidRequestOptions(resource);\n\n    return tracingClient.withSpan(\n      \"ManagedIdentityCredential-pingImdsEndpoint\",\n      getTokenOptions ?? {},\n      async (updatedOptions) => {\n        requestOptions.tracingOptions = updatedOptions.tracingOptions;\n\n        // Create a request with a timeout since we expect that\n        // not having a \"Metadata\" header should cause an error to be\n        // returned quickly from the endpoint, proving its availability.\n        const request = createPipelineRequest(requestOptions);\n\n        // Default to 1000 if the default of 0 is used.\n        // Negative values can still be used to disable the timeout.\n        request.timeout = updatedOptions.requestOptions?.timeout || 1000;\n\n        // This MSI uses the imdsEndpoint to get the token, which only uses http://\n        request.allowInsecureConnection = true;\n        let response: PipelineResponse;\n        try {\n          logger.info(`${msiName}: Pinging the Azure IMDS endpoint`);\n          response = await identityClient.sendRequest(request);\n        } catch (err: unknown) {\n          // If the request failed, or Node.js was unable to establish a connection,\n          // or the host was down, we'll assume the IMDS endpoint isn't available.\n          if (isError(err)) {\n            logger.verbose(`${msiName}: Caught error ${err.name}: ${err.message}`);\n          }\n          // This is a special case for Docker Desktop which responds with a 403 with a message that contains \"A socket operation was attempted to an unreachable network\" or \"A socket operation was attempted to an unreachable host\"\n          // rather than just timing out, as expected.\n          logger.info(`${msiName}: The Azure IMDS endpoint is unavailable`);\n          return false;\n        }\n        if (response.status === 403) {\n          if (response.bodyAsText?.includes(\"unreachable\")) {\n            logger.info(`${msiName}: The Azure IMDS endpoint is unavailable`);\n            logger.info(`${msiName}: ${response.bodyAsText}`);\n            return false;\n          }\n        }\n        // If we received any response, the endpoint is available\n        logger.info(`${msiName}: The Azure IMDS endpoint is available`);\n        return true;\n      },\n    );\n  },\n};\n"]}