botbook/node_modules/@azure/msal-node/dist/client/ManagedIdentitySources/AzureArc.cjs

174 lines
10 KiB
JavaScript
Raw Normal View History

2024-09-04 13:13:15 -03:00
/*! @azure/msal-node v2.13.1 2024-08-29 */
'use strict';
'use strict';
var msalCommon = require('@azure/msal-common');
var ManagedIdentityRequestParameters = require('../../config/ManagedIdentityRequestParameters.cjs');
var BaseManagedIdentitySource = require('./BaseManagedIdentitySource.cjs');
var ManagedIdentityError = require('../../error/ManagedIdentityError.cjs');
var Constants = require('../../utils/Constants.cjs');
var fs = require('fs');
var path = require('path');
var ManagedIdentityErrorCodes = require('../../error/ManagedIdentityErrorCodes.cjs');
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
const ARC_API_VERSION = "2019-11-01";
const DEFAULT_AZURE_ARC_IDENTITY_ENDPOINT = "http://127.0.0.1:40342/metadata/identity/oauth2/token";
const HIMDS_EXECUTABLE_HELPER_STRING = "N/A: himds executable exists";
const SUPPORTED_AZURE_ARC_PLATFORMS = {
win32: `${process.env["ProgramData"]}\\AzureConnectedMachineAgent\\Tokens\\`,
linux: "/var/opt/azcmagent/tokens/",
};
const AZURE_ARC_FILE_DETECTION = {
win32: `${process.env["ProgramFiles"]}\\AzureConnectedMachineAgent\\himds.exe`,
linux: "/opt/azcmagent/bin/himds",
};
/**
* Original source of code: https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/identity/Azure.Identity/src/AzureArcManagedIdentitySource.cs
*/
class AzureArc extends BaseManagedIdentitySource.BaseManagedIdentitySource {
constructor(logger, nodeStorage, networkClient, cryptoProvider, identityEndpoint) {
super(logger, nodeStorage, networkClient, cryptoProvider);
this.identityEndpoint = identityEndpoint;
}
static getEnvironmentVariables() {
let identityEndpoint = process.env[Constants.ManagedIdentityEnvironmentVariableNames.IDENTITY_ENDPOINT];
let imdsEndpoint = process.env[Constants.ManagedIdentityEnvironmentVariableNames.IMDS_ENDPOINT];
// if either of the identity or imds endpoints are undefined, check if the himds executable exists
if (!identityEndpoint || !imdsEndpoint) {
// get the expected Windows or Linux file path of the himds executable
const fileDetectionPath = AZURE_ARC_FILE_DETECTION[process.platform];
try {
/*
* check if the himds executable exists and its permissions allow it to be read
* returns undefined if true, throws an error otherwise
*/
fs.accessSync(fileDetectionPath, fs.constants.F_OK | fs.constants.R_OK);
identityEndpoint = DEFAULT_AZURE_ARC_IDENTITY_ENDPOINT;
imdsEndpoint = HIMDS_EXECUTABLE_HELPER_STRING;
}
catch (err) {
/*
* do nothing
* accessSync returns undefined on success, and throws an error on failure
*/
}
}
return [identityEndpoint, imdsEndpoint];
}
static tryCreate(logger, nodeStorage, networkClient, cryptoProvider, managedIdentityId) {
const [identityEndpoint, imdsEndpoint] = AzureArc.getEnvironmentVariables();
// if either of the identity or imds endpoints are undefined (even after himds file detection)
if (!identityEndpoint || !imdsEndpoint) {
logger.info(`[Managed Identity] ${Constants.ManagedIdentitySourceNames.AZURE_ARC} managed identity is unavailable through environment variables because one or both of '${Constants.ManagedIdentityEnvironmentVariableNames.IDENTITY_ENDPOINT}' and '${Constants.ManagedIdentityEnvironmentVariableNames.IMDS_ENDPOINT}' are not defined. ${Constants.ManagedIdentitySourceNames.AZURE_ARC} managed identity is also unavailable through file detection.`);
return null;
}
// check if the imds endpoint is set to the default for file detection
if (imdsEndpoint === HIMDS_EXECUTABLE_HELPER_STRING) {
logger.info(`[Managed Identity] ${Constants.ManagedIdentitySourceNames.AZURE_ARC} managed identity is available through file detection. Defaulting to known ${Constants.ManagedIdentitySourceNames.AZURE_ARC} endpoint: ${DEFAULT_AZURE_ARC_IDENTITY_ENDPOINT}. Creating ${Constants.ManagedIdentitySourceNames.AZURE_ARC} managed identity.`);
}
else {
// otherwise, both the identity and imds endpoints are defined without file detection; validate them
const validatedIdentityEndpoint = AzureArc.getValidatedEnvVariableUrlString(Constants.ManagedIdentityEnvironmentVariableNames.IDENTITY_ENDPOINT, identityEndpoint, Constants.ManagedIdentitySourceNames.AZURE_ARC, logger);
// remove trailing slash
validatedIdentityEndpoint.endsWith("/")
? validatedIdentityEndpoint.slice(0, -1)
: validatedIdentityEndpoint;
AzureArc.getValidatedEnvVariableUrlString(Constants.ManagedIdentityEnvironmentVariableNames.IMDS_ENDPOINT, imdsEndpoint, Constants.ManagedIdentitySourceNames.AZURE_ARC, logger);
logger.info(`[Managed Identity] Environment variables validation passed for ${Constants.ManagedIdentitySourceNames.AZURE_ARC} managed identity. Endpoint URI: ${validatedIdentityEndpoint}. Creating ${Constants.ManagedIdentitySourceNames.AZURE_ARC} managed identity.`);
}
if (managedIdentityId.idType !== Constants.ManagedIdentityIdType.SYSTEM_ASSIGNED) {
throw ManagedIdentityError.createManagedIdentityError(ManagedIdentityErrorCodes.unableToCreateAzureArc);
}
return new AzureArc(logger, nodeStorage, networkClient, cryptoProvider, identityEndpoint);
}
createRequest(resource) {
const request = new ManagedIdentityRequestParameters.ManagedIdentityRequestParameters(Constants.HttpMethod.GET, this.identityEndpoint.replace("localhost", "127.0.0.1"));
request.headers[Constants.METADATA_HEADER_NAME] = "true";
request.queryParameters[Constants.API_VERSION_QUERY_PARAMETER_NAME] =
ARC_API_VERSION;
request.queryParameters[Constants.RESOURCE_BODY_OR_QUERY_PARAMETER_NAME] =
resource;
// bodyParameters calculated in BaseManagedIdentity.acquireTokenWithManagedIdentity
return request;
}
async getServerTokenResponseAsync(originalResponse, networkClient, networkRequest, networkRequestOptions) {
let retryResponse;
if (originalResponse.status === msalCommon.HttpStatus.UNAUTHORIZED) {
const wwwAuthHeader = originalResponse.headers["www-authenticate"];
if (!wwwAuthHeader) {
throw ManagedIdentityError.createManagedIdentityError(ManagedIdentityErrorCodes.wwwAuthenticateHeaderMissing);
}
if (!wwwAuthHeader.includes("Basic realm=")) {
throw ManagedIdentityError.createManagedIdentityError(ManagedIdentityErrorCodes.wwwAuthenticateHeaderUnsupportedFormat);
}
const secretFilePath = wwwAuthHeader.split("Basic realm=")[1];
// throw an error if the managed identity application is not being run on Windows or Linux
if (!SUPPORTED_AZURE_ARC_PLATFORMS.hasOwnProperty(process.platform)) {
throw ManagedIdentityError.createManagedIdentityError(ManagedIdentityErrorCodes.platformNotSupported);
}
// get the expected Windows or Linux file path
const expectedSecretFilePath = SUPPORTED_AZURE_ARC_PLATFORMS[process.platform];
// throw an error if the file in the file path is not a .key file
const fileName = path.basename(secretFilePath);
if (!fileName.endsWith(".key")) {
throw ManagedIdentityError.createManagedIdentityError(ManagedIdentityErrorCodes.invalidFileExtension);
}
/*
* throw an error if the file path from the www-authenticate header does not match the
* expected file path for the platform (Windows or Linux) the managed identity application
* is running on
*/
if (expectedSecretFilePath + fileName !== secretFilePath) {
throw ManagedIdentityError.createManagedIdentityError(ManagedIdentityErrorCodes.invalidFilePath);
}
let secretFileSize;
// attempt to get the secret file's size, in bytes
try {
secretFileSize = await fs.statSync(secretFilePath).size;
}
catch (e) {
throw ManagedIdentityError.createManagedIdentityError(ManagedIdentityErrorCodes.unableToReadSecretFile);
}
// throw an error if the secret file's size is greater than 4096 bytes
if (secretFileSize > Constants.AZURE_ARC_SECRET_FILE_MAX_SIZE_BYTES) {
throw ManagedIdentityError.createManagedIdentityError(ManagedIdentityErrorCodes.invalidSecret);
}
// attempt to read the contents of the secret file
let secret;
try {
secret = fs.readFileSync(secretFilePath, "utf-8");
}
catch (e) {
throw ManagedIdentityError.createManagedIdentityError(ManagedIdentityErrorCodes.unableToReadSecretFile);
}
const authHeaderValue = `Basic ${secret}`;
this.logger.info(`[Managed Identity] Adding authorization header to the request.`);
networkRequest.headers[Constants.AUTHORIZATION_HEADER_NAME] = authHeaderValue;
try {
retryResponse =
await networkClient.sendGetRequestAsync(networkRequest.computeUri(), networkRequestOptions);
}
catch (error) {
if (error instanceof msalCommon.AuthError) {
throw error;
}
else {
throw msalCommon.createClientAuthError(msalCommon.ClientAuthErrorCodes.networkError);
}
}
}
return this.getServerTokenResponse(retryResponse || originalResponse);
}
}
exports.ARC_API_VERSION = ARC_API_VERSION;
exports.AZURE_ARC_FILE_DETECTION = AZURE_ARC_FILE_DETECTION;
exports.AzureArc = AzureArc;
exports.DEFAULT_AZURE_ARC_IDENTITY_ENDPOINT = DEFAULT_AZURE_ARC_IDENTITY_ENDPOINT;
exports.SUPPORTED_AZURE_ARC_PLATFORMS = SUPPORTED_AZURE_ARC_PLATFORMS;
//# sourceMappingURL=AzureArc.cjs.map