Skip to content

Commit 3ee9c68

Browse files
Implementation Based on Feature Request (#7151)
1 parent cc18b42 commit 3ee9c68

File tree

7 files changed

+246
-12
lines changed

7 files changed

+246
-12
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "patch",
3+
"comment": "Implementation Based on Feature Request #7151",
4+
"packageName": "@azure/msal-node",
5+
"email": "[email protected]",
6+
"dependentChangeType": "patch"
7+
}

lib/msal-node/src/client/ManagedIdentitySources/AzureArc.ts

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
import {
2525
API_VERSION_QUERY_PARAMETER_NAME,
2626
AUTHORIZATION_HEADER_NAME,
27+
AZURE_ARC_SECRET_FILE_MAX_SIZE_BYTES,
2728
HttpMethod,
2829
METADATA_HEADER_NAME,
2930
ManagedIdentityEnvironmentVariableNames,
@@ -32,12 +33,18 @@ import {
3233
RESOURCE_BODY_OR_QUERY_PARAMETER_NAME,
3334
} from "../../utils/Constants";
3435
import { NodeStorage } from "../../cache/NodeStorage";
35-
import { readFileSync } from "fs";
36+
import { readFileSync, statSync } from "fs";
3637
import { ManagedIdentityTokenResponse } from "../../response/ManagedIdentityTokenResponse";
3738
import { ManagedIdentityId } from "../../config/ManagedIdentityId";
39+
import path from "path";
3840

3941
export const ARC_API_VERSION: string = "2019-11-01";
4042

43+
export const SUPPORTED_AZURE_ARC_PLATFORMS = {
44+
win32: `${process.env["ProgramData"]}\\AzureConnectedMachineAgent\\Tokens\\`,
45+
linux: "/var/opt/azcmagent/tokens/",
46+
};
47+
4148
/**
4249
* Original source of code: https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/identity/Azure.Identity/src/AzureArcManagedIdentitySource.cs
4350
*/
@@ -168,10 +175,60 @@ export class AzureArc extends BaseManagedIdentitySource {
168175
);
169176
}
170177

171-
const secretFile = wwwAuthHeader.split("Basic realm=")[1];
178+
const secretFilePath = wwwAuthHeader.split("Basic realm=")[1];
179+
180+
// throw an error if the managed identity application is not being run on Windows or Linux
181+
if (
182+
!SUPPORTED_AZURE_ARC_PLATFORMS.hasOwnProperty(process.platform)
183+
) {
184+
throw createManagedIdentityError(
185+
ManagedIdentityErrorCodes.platformNotSupported
186+
);
187+
}
188+
189+
// get the expected Windows or Linux file path)
190+
const expectedSecretFilePath: string =
191+
SUPPORTED_AZURE_ARC_PLATFORMS[process.platform as string];
192+
193+
// throw an error if the file in the file path is not a .key file
194+
const fileName: string = path.basename(secretFilePath);
195+
if (!fileName.endsWith(".key")) {
196+
throw createManagedIdentityError(
197+
ManagedIdentityErrorCodes.invalidFileExtension
198+
);
199+
}
200+
201+
/*
202+
* throw an error if the file path from the www-authenticate header does not match the
203+
* expected file path for the platform (Windows or Linux) the managed identity application
204+
* is running on
205+
*/
206+
if (expectedSecretFilePath + fileName !== secretFilePath) {
207+
throw createManagedIdentityError(
208+
ManagedIdentityErrorCodes.invalidFilePath
209+
);
210+
}
211+
212+
let secretFileSize;
213+
// attempt to get the secret file's size, in bytes
214+
try {
215+
secretFileSize = await statSync(secretFilePath).size;
216+
} catch (e) {
217+
throw createManagedIdentityError(
218+
ManagedIdentityErrorCodes.unableToReadSecretFile
219+
);
220+
}
221+
// throw an error if the secret file's size is greater than 4096 bytes
222+
if (secretFileSize > AZURE_ARC_SECRET_FILE_MAX_SIZE_BYTES) {
223+
throw createManagedIdentityError(
224+
ManagedIdentityErrorCodes.invalidSecret
225+
);
226+
}
227+
228+
// attempt to read the contents of the secret file
172229
let secret;
173230
try {
174-
secret = readFileSync(secretFile, "utf-8");
231+
secret = readFileSync(secretFilePath, "utf-8");
175232
} catch (e) {
176233
throw createManagedIdentityError(
177234
ManagedIdentityErrorCodes.unableToReadSecretFile

lib/msal-node/src/error/ManagedIdentityError.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,16 @@ export { ManagedIdentityErrorCodes };
1212
* ManagedIdentityErrorMessage class containing string constants used by error codes and messages.
1313
*/
1414
export const ManagedIdentityErrorMessages = {
15+
[ManagedIdentityErrorCodes.invalidFileExtension]:
16+
"The file path in the WWW-Authenticate header does not contain a .key file.",
17+
[ManagedIdentityErrorCodes.invalidFilePath]:
18+
"The file path in the WWW-Authenticate header is not in a valid Windows or Linux Format.",
1519
[ManagedIdentityErrorCodes.invalidManagedIdentityIdType]:
1620
"More than one ManagedIdentityIdType was provided.",
21+
[ManagedIdentityErrorCodes.invalidSecret]:
22+
"The secret in the file on the file path in the WWW-Authenticate header is greater than 4096 bytes.",
23+
[ManagedIdentityErrorCodes.platformNotSupported]:
24+
"The platform is not supported by Azure Arc. Azure Arc only supports Windows and Linux.",
1725
[ManagedIdentityErrorCodes.missingId]:
1826
"A ManagedIdentityId id was not provided.",
1927
[ManagedIdentityErrorCodes.MsiEnvironmentVariableUrlMalformedErrorCodes

lib/msal-node/src/error/ManagedIdentityErrorCodes.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@
55

66
import { ManagedIdentityEnvironmentVariableNames } from "../utils/Constants";
77

8+
export const invalidFileExtension = "invalid_file_extension";
9+
export const invalidFilePath = "invalid_file_path";
810
export const invalidManagedIdentityIdType = "invalid_managed_identity_id_type";
11+
export const invalidSecret = "invalid_secret";
912
export const missingId = "missing_client_id";
1013
export const networkUnavailable = "network_unavailable";
14+
export const platformNotSupported = "platform_not_supported";
1115
export const unableToCreateAzureArc = "unable_to_create_azure_arc";
1216
export const unableToCreateCloudShell = "unable_to_create_cloud_shell";
1317
export const unableToCreateSource = "unable_to_create_source";

lib/msal-node/src/utils/Constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ export const LOOPBACK_SERVER_CONSTANTS = {
161161
TIMEOUT_MS: 5000,
162162
};
163163

164+
export const AZURE_ARC_SECRET_FILE_MAX_SIZE_BYTES = 4096; // 4 KB
165+
164166
export const MANAGED_IDENTITY_MAX_RETRIES = 3;
165167
export const MANAGED_IDENTITY_RETRY_DELAY = 1000;
166168
export const MANAGED_IDENTITY_HTTP_STATUS_CODES_TO_RETRY_ON = [

0 commit comments

Comments
 (0)