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

Open
wants to merge 10 commits into
base: dev
Choose a base branch
from
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)
Robbie-Microsoft marked this conversation as resolved.
Show resolved Hide resolved

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
130 changes: 130 additions & 0 deletions lib/msal-node/src/client/ManagedIdentitySources/MachineLearning.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
* 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,
MACHINE_LEARNING_AND_SERVICE_FABRIC_SECRET_HEADER_NAME,
Robbie-Microsoft marked this conversation as resolved.
Show resolved Hide resolved
} 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 identityEndpoint: string;
private secret: string;

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

this.identityEndpoint = identityEndpoint;
this.secret = secret;
}

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

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

return [identityEndpoint, secret];
}

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

// if either of the identity endpoint or MSI secret variables are undefined, this MSI provider is unavailable.
if (!identityEndpoint || !secret) {
logger.info(
`[Managed Identity] ${ManagedIdentitySourceNames.MACHINE_LEARNING} managed identity is unavailable because one or both of the '${ManagedIdentityEnvironmentVariableNames.IDENTITY_HEADER}' and '${ManagedIdentityEnvironmentVariableNames.MSI_SECRET}' environment variables are not defined.`
Robbie-Microsoft marked this conversation as resolved.
Show resolved Hide resolved
);
return null;
}

const validatedIdentityEndpoint: string =
MachineLearning.getValidatedEnvVariableUrlString(
ManagedIdentityEnvironmentVariableNames.IDENTITY_ENDPOINT,
Robbie-Microsoft marked this conversation as resolved.
Show resolved Hide resolved
identityEndpoint,
ManagedIdentitySourceNames.MACHINE_LEARNING,
logger
);

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

return new MachineLearning(
logger,
nodeStorage,
networkClient,
cryptoProvider,
identityEndpoint,
Robbie-Microsoft marked this conversation as resolved.
Show resolved Hide resolved
secret
);
}

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

request.headers[METADATA_HEADER_NAME] = "true";
request.headers[
MACHINE_LEARNING_AND_SERVICE_FABRIC_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,
MACHINE_LEARNING_AND_SERVICE_FABRIC_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,9 @@ export class ServiceFabric extends BaseManagedIdentitySource {
this.identityEndpoint
);

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

request.queryParameters[API_VERSION_QUERY_PARAMETER_NAME] =
SERVICE_FABRIC_MSI_API_VERSION;
Expand Down
5 changes: 4 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,8 @@ 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 MACHINE_LEARNING_AND_SERVICE_FABRIC_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 +27,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 +42,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