Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Support for Azure Machine Learning in Managed Identity #7512

Merged
merged 15 commits into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Added Machine Learning as a Managed Identity Source #7512",
"packageName": "@azure/msal-node",
"email": "[email protected]",
"dependentChangeType": "patch"
}
1 change: 1 addition & 0 deletions lib/msal-node/apiReview/msal-node.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,7 @@ export const ManagedIdentitySourceNames: {
readonly CLOUD_SHELL: "CloudShell";
readonly DEFAULT_TO_IMDS: "DefaultToImds";
readonly IMDS: "Imds";
readonly MACHINE_LEARNING: "MachineLearning";
readonly SERVICE_FABRIC: "ServiceFabric";
};

Expand Down
1 change: 1 addition & 0 deletions lib/msal-node/docs/managed-identity.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ A common challenge for developers is the management of secrets, credentials, cer
- [Azure Arc](https://learn.microsoft.com/en-us/azure/azure-arc/overview)
- [Azure Cloud Shell](https://learn.microsoft.com/en-us/azure/cloud-shell/overview)
- [Azure Service Fabric](https://learn.microsoft.com/en-us/azure/service-fabric/service-fabric-overview)
- [Azure Machine Learning](https://azure.microsoft.com/en-us/products/machine-learning)

For a complete list, refer to [Azure services that can use managed identities to access other services](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/managed-identities-status).

Expand Down
11 changes: 11 additions & 0 deletions lib/msal-node/src/client/ManagedIdentityClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { ManagedIdentityId } from "../config/ManagedIdentityId.js";
import { NodeStorage } from "../cache/NodeStorage.js";
import { BaseManagedIdentitySource } from "./ManagedIdentitySources/BaseManagedIdentitySource.js";
import { ManagedIdentitySourceNames } from "../utils/Constants.js";
import { MachineLearning } from "./ManagedIdentitySources/MachineLearning.js";

/*
* Class to initialize a managed identity and identify the service.
Expand Down Expand Up @@ -99,6 +100,10 @@ export class ManagedIdentityClient {
AppService.getEnvironmentVariables()
)
? ManagedIdentitySourceNames.APP_SERVICE
: this.allEnvironmentVariablesAreDefined(
MachineLearning.getEnvironmentVariables()
)
? ManagedIdentitySourceNames.MACHINE_LEARNING
: this.allEnvironmentVariablesAreDefined(
CloudShell.getEnvironmentVariables()
)
Expand Down Expand Up @@ -137,6 +142,12 @@ export class ManagedIdentityClient {
networkClient,
cryptoProvider
) ||
MachineLearning.tryCreate(
logger,
nodeStorage,
networkClient,
cryptoProvider
) ||
CloudShell.tryCreate(
logger,
nodeStorage,
Expand Down
125 changes: 125 additions & 0 deletions lib/msal-node/src/client/ManagedIdentitySources/MachineLearning.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/

import { INetworkModule, Logger } from "@azure/msal-common/node";
import { BaseManagedIdentitySource } from "./BaseManagedIdentitySource.js";
import {
HttpMethod,
API_VERSION_QUERY_PARAMETER_NAME,
RESOURCE_BODY_OR_QUERY_PARAMETER_NAME,
ManagedIdentityEnvironmentVariableNames,
ManagedIdentitySourceNames,
ManagedIdentityIdType,
METADATA_HEADER_NAME,
ML_AND_SF_SECRET_HEADER_NAME,
} from "../../utils/Constants.js";
import { CryptoProvider } from "../../crypto/CryptoProvider.js";
import { ManagedIdentityRequestParameters } from "../../config/ManagedIdentityRequestParameters.js";
import { ManagedIdentityId } from "../../config/ManagedIdentityId.js";
import { NodeStorage } from "../../cache/NodeStorage.js";

const MACHINE_LEARNING_MSI_API_VERSION: string = "2017-09-01";

// search for all App Service

export class MachineLearning extends BaseManagedIdentitySource {
private msiEndpoint: string;
private secret: string;

constructor(
logger: Logger,
nodeStorage: NodeStorage,
networkClient: INetworkModule,
cryptoProvider: CryptoProvider,
msiEndpoint: string,
secret: string
) {
super(logger, nodeStorage, networkClient, cryptoProvider);

this.msiEndpoint = msiEndpoint;
this.secret = secret;
}

public static getEnvironmentVariables(): Array<string | undefined> {
const msiEndpoint: string | undefined =
process.env[ManagedIdentityEnvironmentVariableNames.MSI_ENDPOINT];

const secret: string | undefined =
process.env[ManagedIdentityEnvironmentVariableNames.MSI_SECRET];

return [msiEndpoint, secret];
}

public static tryCreate(
logger: Logger,
nodeStorage: NodeStorage,
networkClient: INetworkModule,
cryptoProvider: CryptoProvider
): MachineLearning | null {
const [msiEndpoint, secret] = MachineLearning.getEnvironmentVariables();

// if either of the identity endpoint or MSI secret variables are undefined, this MSI provider is unavailable.
if (!msiEndpoint || !secret) {
logger.info(
`[Managed Identity] ${ManagedIdentitySourceNames.MACHINE_LEARNING} managed identity is unavailable because one or both of the '${ManagedIdentityEnvironmentVariableNames.MSI_ENDPOINT}' and '${ManagedIdentityEnvironmentVariableNames.MSI_SECRET}' environment variables are not defined.`
);
return null;
}

const validatedMsiEndpoint: string =
MachineLearning.getValidatedEnvVariableUrlString(
ManagedIdentityEnvironmentVariableNames.MSI_ENDPOINT,
msiEndpoint,
ManagedIdentitySourceNames.MACHINE_LEARNING,
logger
);

logger.info(
`[Managed Identity] Environment variables validation passed for ${ManagedIdentitySourceNames.MACHINE_LEARNING} managed identity. Endpoint URI: ${validatedMsiEndpoint}. Creating ${ManagedIdentitySourceNames.MACHINE_LEARNING} managed identity.`
);

return new MachineLearning(
logger,
nodeStorage,
networkClient,
cryptoProvider,
msiEndpoint,
secret
);
}

public createRequest(
resource: string,
managedIdentityId: ManagedIdentityId
): ManagedIdentityRequestParameters {
const request: ManagedIdentityRequestParameters =
new ManagedIdentityRequestParameters(
HttpMethod.GET,
this.msiEndpoint
);

request.headers[METADATA_HEADER_NAME] = "true";
request.headers[ML_AND_SF_SECRET_HEADER_NAME] = this.secret;

request.queryParameters[API_VERSION_QUERY_PARAMETER_NAME] =
MACHINE_LEARNING_MSI_API_VERSION;
request.queryParameters[RESOURCE_BODY_OR_QUERY_PARAMETER_NAME] =
resource;

if (
managedIdentityId.idType !== ManagedIdentityIdType.SYSTEM_ASSIGNED
) {
request.queryParameters[
this.getManagedIdentityUserAssignedIdQueryParameterKey(
managedIdentityId.idType
)
] = managedIdentityId.id;
}

// bodyParameters calculated in BaseManagedIdentity.acquireTokenWithManagedIdentity

return request;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
ManagedIdentityIdType,
ManagedIdentitySourceNames,
RESOURCE_BODY_OR_QUERY_PARAMETER_NAME,
SERVICE_FABRIC_SECRET_HEADER_NAME,
ML_AND_SF_SECRET_HEADER_NAME,
} from "../../utils/Constants.js";

// MSI Constants. Docs for MSI are available here https://docs.microsoft.com/azure/app-service/overview-managed-identity
Expand Down Expand Up @@ -122,8 +122,7 @@ export class ServiceFabric extends BaseManagedIdentitySource {
this.identityEndpoint
);

request.headers[SERVICE_FABRIC_SECRET_HEADER_NAME] =
this.identityHeader;
request.headers[ML_AND_SF_SECRET_HEADER_NAME] = this.identityHeader;

request.queryParameters[API_VERSION_QUERY_PARAMETER_NAME] =
SERVICE_FABRIC_MSI_API_VERSION;
Expand Down
4 changes: 3 additions & 1 deletion lib/msal-node/src/utils/Constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { HttpStatus } from "@azure/msal-common/node";
export const AUTHORIZATION_HEADER_NAME: string = "Authorization";
export const METADATA_HEADER_NAME: string = "Metadata";
export const APP_SERVICE_SECRET_HEADER_NAME: string = "X-IDENTITY-HEADER";
export const SERVICE_FABRIC_SECRET_HEADER_NAME: string = "secret";
export const ML_AND_SF_SECRET_HEADER_NAME: string = "secret";
export const API_VERSION_QUERY_PARAMETER_NAME: string = "api-version";
export const RESOURCE_BODY_OR_QUERY_PARAMETER_NAME: string = "resource";
export const DEFAULT_MANAGED_IDENTITY_ID = "system_assigned_managed_identity";
Expand All @@ -26,6 +26,7 @@ export const ManagedIdentityEnvironmentVariableNames = {
IDENTITY_SERVER_THUMBPRINT: "IDENTITY_SERVER_THUMBPRINT",
IMDS_ENDPOINT: "IMDS_ENDPOINT",
MSI_ENDPOINT: "MSI_ENDPOINT",
MSI_SECRET: "MSI_SECRET",
} as const;
export type ManagedIdentityEnvironmentVariableNames =
(typeof ManagedIdentityEnvironmentVariableNames)[keyof typeof ManagedIdentityEnvironmentVariableNames];
Expand All @@ -40,6 +41,7 @@ export const ManagedIdentitySourceNames = {
CLOUD_SHELL: "CloudShell",
DEFAULT_TO_IMDS: "DefaultToImds",
IMDS: "Imds",
MACHINE_LEARNING: "MachineLearning",
SERVICE_FABRIC: "ServiceFabric",
} as const;
/**
Expand Down
Loading
Loading