diff --git a/infra/main.bicep b/infra/main.bicep index 7d671be83..2bd4fb6d9 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -623,7 +623,6 @@ var privateDnsZones = [ 'privatelink.cognitiveservices.azure.com' 'privatelink.openai.azure.com' 'privatelink.vaultcore.azure.net' - 'privatelink.api.azureml.ms' ] // DNS Zone Index Constants @@ -637,7 +636,6 @@ var dnsZoneIndex = { cognitiveServices: 6 openAI: 7 keyVault: 8 - machinelearning: 9 } // =================================================== diff --git a/infra/main.json b/infra/main.json index 690c7c884..b77a30260 100644 --- a/infra/main.json +++ b/infra/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.42.1.51946", - "templateHash": "16421140691716802279" + "templateHash": "3757241389066518547" } }, "parameters": { @@ -634,8 +634,7 @@ "privatelink.search.windows.net", "privatelink.cognitiveservices.azure.com", "privatelink.openai.azure.com", - "privatelink.vaultcore.azure.net", - "privatelink.api.azureml.ms" + "privatelink.vaultcore.azure.net" ], "dnsZoneIndex": { "cosmosDB": 0, @@ -646,8 +645,7 @@ "searchService": 5, "cognitiveServices": 6, "openAI": 7, - "keyVault": 8, - "machinelearning": 9 + "keyVault": 8 }, "cosmosDbName": "db_conversation_history", "cosmosDbContainerName": "conversations", diff --git a/infra/modules/machine-learning-services/workspace/compute/compute.bicep b/infra/modules/machine-learning-services/workspace/compute/compute.bicep deleted file mode 100644 index 751e95ffe..000000000 --- a/infra/modules/machine-learning-services/workspace/compute/compute.bicep +++ /dev/null @@ -1,147 +0,0 @@ -metadata name = 'Machine Learning Services Workspaces Computes' -metadata description = '''This module deploys a Machine Learning Services Workspaces Compute. - -Attaching a compute is not idempotent and will fail in case you try to redeploy over an existing compute in AML (see parameter `deployCompute`).''' - -// ================ // -// Parameters // -// ================ // - -@sys.description('Conditional. The name of the parent Machine Learning Workspace. Required if the template is used in a standalone deployment.') -param machineLearningWorkspaceName string - -@sys.description('Required. Name of the compute.') -@minLength(2) -@maxLength(16) -param name string - -@sys.description('Optional. Specifies the location of the resource.') -param location string = resourceGroup().location - -@sys.description('Optional. Specifies the sku, also referred as "edition". Required for creating a compute resource.') -@allowed([ - 'Basic' - 'Free' - 'Premium' - 'Standard' -]) -param sku string? - -@sys.description('Optional. Contains resource tags defined as key-value pairs. Ignored when attaching a compute resource, i.e. when you provide a resource ID.') -param tags object? - -@sys.description('Optional. Flag to specify whether to deploy the compute. Required only for attach (i.e. providing a resource ID), as in this case the operation is not idempotent, i.e. a second deployment will fail. Therefore, this flag needs to be set to "false" as long as the compute resource exists.') -param deployCompute bool = true - -@sys.description('Optional. Location for the underlying compute. Ignored when attaching a compute resource, i.e. when you provide a resource ID.') -param computeLocation string = resourceGroup().location - -@sys.description('Optional. The description of the Machine Learning compute.') -param description string? - -@sys.description('Optional. Opt-out of local authentication and ensure customers can use only MSI and AAD exclusively for authentication.') -param disableLocalAuth bool = false - -@sys.description('Optional. ARM resource ID of the underlying compute.') -param resourceId string? - -@sys.description('Required. Set the object type.') -@allowed([ - 'AKS' - 'AmlCompute' - 'ComputeInstance' - 'Databricks' - 'DataFactory' - 'DataLakeAnalytics' - 'HDInsight' - 'Kubernetes' - 'SynapseSpark' - 'VirtualMachine' -]) -param computeType string - -@sys.description('Optional. The properties of the compute. Will be ignored in case "resourceId" is set.') -param properties object? - -import { managedIdentityAllType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@sys.description('Optional. The managed identity definition for this resource.') -param managedIdentities managedIdentityAllType? - -// ================// -// Variables // -// ================// - -var formattedUserAssignedIdentities = reduce( - map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), - {}, - (cur, next) => union(cur, next) -) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } - -var identity = !empty(managedIdentities) - ? { - type: (managedIdentities.?systemAssigned ?? false) - ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') - : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : null) - userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null - } - : null - -// ============================= // -// Existing resources references // -// ============================= // - -resource machineLearningWorkspace 'Microsoft.MachineLearningServices/workspaces@2025-12-01' existing = { - name: machineLearningWorkspaceName -} - -// ============ // -// Deployments // -// ============ // - -resource compute 'Microsoft.MachineLearningServices/workspaces/computes@2025-12-01' = if (deployCompute == true) { - name: name - location: location - tags: empty(resourceId) ? tags : any(null) - sku: empty(resourceId) - ? { - name: sku - tier: sku - } - : any(null) - parent: machineLearningWorkspace - identity: empty(resourceId) ? identity : any(null) - properties: union( - { - description: description - disableLocalAuth: disableLocalAuth - computeType: computeType - }, - (!empty(resourceId) - ? { - resourceId: resourceId - } - : { - computeLocation: computeLocation - properties: properties - }) - ) -} - -// =========== // -// Outputs // -// =========== // - -@sys.description('The name of the compute.') -output name string = compute.name - -@sys.description('The resource ID of the compute.') -output resourceId string = compute.id - -@sys.description('The resource group the compute was deployed into.') -output resourceGroupName string = resourceGroup().name - -@sys.description('The principal ID of the system assigned identity.') -output systemAssignedMIPrincipalId string? = compute.?identity.?principalId - -@sys.description('The location the resource was deployed into.') -output location string = compute.?location ?? location diff --git a/infra/modules/machine-learning-services/workspace/connection/connection.bicep b/infra/modules/machine-learning-services/workspace/connection/connection.bicep deleted file mode 100644 index 48ee4bcd3..000000000 --- a/infra/modules/machine-learning-services/workspace/connection/connection.bicep +++ /dev/null @@ -1,334 +0,0 @@ -metadata name = 'Machine Learning Services Workspaces Connections' -metadata description = 'This module creates a connection in a Machine Learning Services workspace.' - -// ================ // -// Parameters // -// ================ // - -@description('Required. Name of the connection to create.') -param name string - -@description('Required. The name of the parent Machine Learning Workspace. Required if the template is used in a standalone deployment.') -param machineLearningWorkspaceName string - -@description('Required. Category of the connection.') -param category categoryType - -@description('Optional. The expiry time of the connection.') -param expiryTime string? - -@description('Optional. Indicates whether the connection is shared to all users in the workspace.') -param isSharedToAll bool? - -@description('Optional. User metadata for the connection.') -param metadata metadataType = {} - -@description('Optional. The shared user list of the connection.') -param sharedUserList string[]? - -@description('Required. The target of the connection.') -param target string - -@description('Optional. Value details of the workspace connection.') -param value string? - -@description('Required. The properties of the connection, specific to the auth type.') -param connectionProperties connectionPropertyType - -// ============================= // -// Existing resources references // -// ============================= // - -resource machineLearningWorkspace 'Microsoft.MachineLearningServices/workspaces@2025-12-01' existing = { - name: machineLearningWorkspaceName -} - -// ============== // -// Resources // -// ============== // - -resource connection 'Microsoft.MachineLearningServices/workspaces/connections@2025-12-01' = { - name: name - parent: machineLearningWorkspace - properties: union( - { - category: category - expiryTime: expiryTime - isSharedToAll: isSharedToAll - metadata: metadata - sharedUserList: sharedUserList - target: target - value: value - }, - connectionProperties - ) -} - -// ============ // -// Outputs // -// ============ // - -@description('The resource ID of the connection.') -output resourceId string = connection.id - -@description('The name of the connection.') -output name string = connection.name - -@description('The name of the resource group the connection was created in.') -output resourceGroupName string = resourceGroup().name - -// ================ // -// Definitions // -// ================ // - -@description('The tpe for the metadata.') -type metadataType = { - @description('Required. The metadata key-value pairs.') - *: string -} - -@export() -@description('The type of the connection category.') -type categoryType = - | 'ADLSGen2' - | 'AIServices' - | 'AmazonMws' - | 'AmazonRdsForOracle' - | 'AmazonRdsForSqlServer' - | 'AmazonRedshift' - | 'AmazonS3Compatible' - | 'ApiKey' - | 'AzureBlob' - | 'AzureDataExplorer' - | 'AzureDatabricksDeltaLake' - | 'AzureMariaDb' - | 'AzureMySqlDb' - | 'AzureOneLake' - | 'AzureOpenAI' - | 'AzurePostgresDb' - | 'AzureSqlDb' - | 'AzureSqlMi' - | 'AzureSynapseAnalytics' - | 'AzureTableStorage' - | 'BingLLMSearch' - | 'Cassandra' - | 'CognitiveSearch' - | 'CognitiveService' - | 'Concur' - | 'ContainerRegistry' - | 'CosmosDb' - | 'CosmosDbMongoDbApi' - | 'Couchbase' - | 'CustomKeys' - | 'Db2' - | 'Drill' - | 'Dynamics' - | 'DynamicsAx' - | 'DynamicsCrm' - | 'Elasticsearch' - | 'Eloqua' - | 'FileServer' - | 'FtpServer' - | 'GenericContainerRegistry' - | 'GenericHttp' - | 'GenericRest' - | 'Git' - | 'GoogleAdWords' - | 'GoogleBigQuery' - | 'GoogleCloudStorage' - | 'Greenplum' - | 'Hbase' - | 'Hdfs' - | 'Hive' - | 'Hubspot' - | 'Impala' - | 'Informix' - | 'Jira' - | 'Magento' - | 'ManagedOnlineEndpoint' - | 'MariaDb' - | 'Marketo' - | 'MicrosoftAccess' - | 'MongoDbAtlas' - | 'MongoDbV2' - | 'MySql' - | 'Netezza' - | 'ODataRest' - | 'Odbc' - | 'Office365' - | 'OpenAI' - | 'Oracle' - | 'OracleCloudStorage' - | 'OracleServiceCloud' - | 'PayPal' - | 'Phoenix' - | 'Pinecone' - | 'PostgreSql' - | 'Presto' - | 'PythonFeed' - | 'QuickBooks' - | 'Redis' - | 'Responsys' - | 'S3' - | 'Salesforce' - | 'SalesforceMarketingCloud' - | 'SalesforceServiceCloud' - | 'SapBw' - | 'SapCloudForCustomer' - | 'SapEcc' - | 'SapHana' - | 'SapOpenHub' - | 'SapTable' - | 'Serp' - | 'Serverless' - | 'ServiceNow' - | 'Sftp' - | 'SharePointOnlineList' - | 'Shopify' - | 'Snowflake' - | 'Spark' - | 'SqlServer' - | 'Square' - | 'Sybase' - | 'Teradata' - | 'Vertica' - | 'WebTable' - | 'Xero' - | 'Zoho' - -@description('The connection properties when the auth type is AAD.') -type aadAuthTypeWorkspaceConnectionPropertyType = { - @description('Required. The authentication type of the connection target.') - authType: 'AAD' -} - -@description('The connection properties when the auth type is AccessKey.') -type accessKeyAuthTypeWorkspaceConnectionPropertyType = { - @description('Required. The authentication type of the connection target.') - authType: 'AccessKey' - - @description('Required. The credentials for the connection.') - credentials: workspaceConnectionAccessKeyType -} - -@description('The connection properties when the auth type is ApiKey.') -type apiKeyAuthWorkspaceConnectionPropertyType = { - @description('Required. The authentication type of the connection target.') - authType: 'ApiKey' - - @description('Required. The credentials for the connection.') - credentials: workspaceConnectionApiKeyType -} - -@description('The connection properties when the auth type is ManagedIdentity.') -type managedIdentityAuthTypeWorkspaceConnectionPropertyType = { - @description('Required. The authentication type of the connection target.') - authType: 'ManagedIdentity' - - @description('Required. The credentials for the connection.') - credentials: workspaceConnectionManagedIdentityType -} - -@description('The type for the workspace connection access key.') -type workspaceConnectionAccessKeyType = { - @description('Required. The connection access key ID.') - accessKeyId: string - - @description('Required. The connection secret access key.') - secretAccessKey: string -} - -@description('The type for the workspace connection account key.') -type workspaceConnectionAccountKeyType = { - @description('Required. The connection key.') - key: string -} - -@description('The type for the workspace connection API key.') -type workspaceConnectionApiKeyType = { - @description('Required. The connection API key.') - key: string -} - -@description('The type for the workspace connection managed identity.') -type workspaceConnectionManagedIdentityType = { - @description('Required. The connection managed identity ID.') - clientId: string - - @description('Required. The connection managed identity resource ID.') - resourceId: string -} - -type workspaceConnectionOAuth2Type = { - @description('Conditional. The connection auth URL. Required if connection category is Concur.') - authUrl: string? - - @minLength(36) - @maxLength(36) - @description('Required. The connection client ID in the format of UUID.') - clientId: string - - @description('Required. The connection client secret.') - clientSecret: string - - @description('Conditional. The connection developer token. Required if connection category is GoogleAdWords.') - developerToken: string? - - @description('Conditional. The connection password. Required if connection category is Concur or ServiceNow where AccessToken grant type is \'Password\'.') - password: string? - - @description('Conditional. The connection refresh token. Required if connection category is GoogleBigQuery, GoogleAdWords, Hubspot, QuickBooks, Square, Xero or Zoho.') - refreshToken: string? - - @description('Conditional. The connection tenant ID. Required if connection category is QuickBooks or Xero.') - tenantId: string? - - @description('Conditional. The connection username. Required if connection category is Concur or ServiceNow where AccessToken grant type is \'Password\'.') - username: string? -} - -@description('The type for the workspace connection personal access token.') -type workspaceConnectionPersonalAccessTokenType = { - @description('Required. The connection personal access token.') - pat: string -} - -@description('The type for the workspace connection shared access signature.') -type workspaceConnectionSharedAccessSignatureType = { - @description('Required. The connection SAS token.') - sas: string -} - -@description('The type for the workspace connection service principal.') -type workspaceConnectionServicePrincipalType = { - @description('Required. The connection client ID.') - clientId: string - - @description('Required. The connection client secret.') - clientSecret: string - - @description('Required. The connection tenant ID.') - tenantId: string -} - -@description('The type for the workspace connection username and password.') -type workspaceConnectionUsernamePasswordType = { - @description('Required. The connection password.') - password: string - - @description('Conditional. The connection security token. Required if connection is like SalesForce for extra security in addition to \'UsernamePassword\'.') - securityToken: string? - - @description('Required. The connection username.') - username: string -} - -@secure() -@export() -@description('The type of the connection properties.') -@discriminator('authType') -type connectionPropertyType = - | aadAuthTypeWorkspaceConnectionPropertyType - | accessKeyAuthTypeWorkspaceConnectionPropertyType - | apiKeyAuthWorkspaceConnectionPropertyType - | managedIdentityAuthTypeWorkspaceConnectionPropertyType diff --git a/infra/modules/machine-learning-services/workspace/ml_workspace.bicep b/infra/modules/machine-learning-services/workspace/ml_workspace.bicep deleted file mode 100644 index 8948acaae..000000000 --- a/infra/modules/machine-learning-services/workspace/ml_workspace.bicep +++ /dev/null @@ -1,627 +0,0 @@ -metadata name = 'Machine Learning Services Workspaces' -metadata description = 'This module deploys a Machine Learning Services Workspace.' - -// ================ // -// Parameters // -// ================ // -@sys.description('Required. The name of the machine learning workspace.') -param name string - -@sys.description('Optional. The friendly name of the machine learning workspace.') -param friendlyName string? - -@sys.description('Optional. Location for all resources.') -param location string = resourceGroup().location - -@sys.description('Required. Specifies the SKU, also referred as \'edition\' of the Azure Machine Learning workspace.') -@allowed([ - 'Free' - 'Basic' - 'Standard' - 'Premium' -]) -param sku string - -@sys.description('Optional. The type of Azure Machine Learning workspace to create.') -@allowed([ - 'Default' - 'Project' - 'Hub' - 'FeatureStore' -]) -param kind string = 'Default' - -@sys.description('Conditional. The resource ID of the associated Storage Account. Required if \'kind\' is \'Default\', \'FeatureStore\' or \'Hub\'.') -param associatedStorageAccountResourceId string? - -@sys.description('Conditional. The resource ID of the associated Key Vault. Required if \'kind\' is \'Default\' or \'FeatureStore\'. If not provided, the key vault will be managed by Microsoft.') -param associatedKeyVaultResourceId string? - -@sys.description('Conditional. The resource ID of the associated Application Insights. Required if \'kind\' is \'Default\' or \'FeatureStore\'.') -param associatedApplicationInsightsResourceId string? - -@sys.description('Optional. The resource ID of the associated Container Registry.') -param associatedContainerRegistryResourceId string? - -@sys.description('Optional. Enable service-side encryption.') -param enableServiceSideCMKEncryption bool? - -import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@sys.description('Optional. The lock settings of the service.') -param lock lockType? - -@sys.description('Optional. The flag to signal HBI data in the workspace and reduce diagnostic data collected by the service.') -param hbiWorkspace bool = false - -@sys.description('Conditional. The resource ID of the hub to associate with the workspace. Required if \'kind\' is set to \'Project\'.') -param hubResourceId string? - -import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@sys.description('Optional. Array of role assignments to create.') -param roleAssignments roleAssignmentType[]? - -import { privateEndpointSingleServiceType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@sys.description('Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') -param privateEndpoints privateEndpointSingleServiceType[]? - -@sys.description('Optional. Connections to create in the workspace.') -param connections connectionType[]? - -@sys.description('Optional. Resource tags.') -param tags object? - -@sys.description('Optional. Enable/Disable usage telemetry for module.') -param enableTelemetry bool = true - -import { managedIdentityAllType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@sys.description('Optional. The managed identity definition for this resource. At least one identity type is required.') -param managedIdentities managedIdentityAllType = { - systemAssigned: true -} - -// @sys.description('Conditional. Settings for feature store type workspaces. Required if \'kind\' is set to \'FeatureStore\'.') -// param featureStoreSettings featureStoreSettingType? - -@sys.description('Optional. List of IPv4 addresse ranges that are allowed to access the workspace.') -param ipAllowlist string[]? - -// @sys.description('Optional. Managed Network settings for a machine learning workspace.') -// param managedNetworkSettings managedNetworkSettingType? - -@sys.description('Optional. Trigger the provisioning of the managed virtual network when creating the workspace.') -param provisionNetworkNow bool? - -// @sys.description('Optional. Settings for serverless compute created in the workspace.') -// param serverlessComputeSettings serverlessComputeSettingType? - -@sys.description('Optional. The authentication mode used by the workspace when connecting to the default storage account.') -@allowed([ - 'AccessKey' - 'Identity' - 'UserDelegationSAS' -]) -param systemDatastoresAuthMode string? - -//@sys.description('Optional. Configuration for workspace hub settings.') -//param workspaceHubConfig workspaceHubConfigType? - -// Diagnostic Settings -import { diagnosticSettingFullType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@sys.description('Optional. The diagnostic settings of the service.') -param diagnosticSettings diagnosticSettingFullType[]? - -@sys.description('Optional. The description of this workspace.') -param description string? - -@sys.description('Optional. URL for the discovery service to identify regional endpoints for machine learning experimentation services.') -param discoveryUrl string? - -import { customerManagedKeyType } from 'br/public:avm/utl/types/avm-common-types:0.7.0' -@sys.description('Optional. The customer managed key definition.') -param customerManagedKey customerManagedKeyType? - -@sys.description('Optional. The compute name for image build.') -param imageBuildCompute string? - -@sys.description('Conditional. The user assigned identity resource ID that represents the workspace identity. Required if \'userAssignedIdentities\' is not empty and may not be used if \'systemAssignedIdentity\' is enabled.') -param primaryUserAssignedIdentity string? - -@sys.description('Optional. The service managed resource settings.') -param serviceManagedResourcesSettings object? - -@sys.description('Optional. The list of shared private link resources in this workspace. Note: This property is not idempotent.') -param sharedPrivateLinkResources array? - -@sys.description('Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled.') -@allowed([ - 'Enabled' - 'Disabled' -]) -param publicNetworkAccess string = 'Disabled' - -// ================// -// Variables // -// ================// - -var enableReferencedModulesTelemetry = false - -var formattedUserAssignedIdentities = reduce( - map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), - {}, - (cur, next) => union(cur, next) -) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } - -var identity = !empty(managedIdentities) - ? { - type: (managedIdentities.?systemAssigned ?? false) - ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') - : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : 'None') - userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null - } - : null - -// ================// -// Deployments // -// ================// -var builtInRoleNames = { - 'AzureML Compute Operator': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'e503ece1-11d0-4e8e-8e2c-7a6c3bf38815' - ) - 'AzureML Data Scientist': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'f6c7c914-8db3-469d-8ca1-694a8f32e121' - ) - 'AzureML Metrics Writer (preview)': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '635dd51f-9968-44d3-b7fb-6d9a6bd613ae' - ) - 'AzureML Registry User': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '1823dd4f-9b8c-4ab6-ab4e-7397a3684615' - ) - Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') - Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') - Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') - 'Role Based Access Control Administrator': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' - ) - 'User Access Administrator': subscriptionResourceId( - 'Microsoft.Authorization/roleDefinitions', - '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' - ) -} - -var formattedRoleAssignments = [ - for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { - roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( - roleAssignment.roleDefinitionIdOrName, - '/providers/Microsoft.Authorization/roleDefinitions/' - ) - ? roleAssignment.roleDefinitionIdOrName - : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) - }) -] - -#disable-next-line no-deployments-resources -resource avmTelemetry 'Microsoft.Resources/deployments@2025-04-01' = if (enableTelemetry) { - name: '46d3xbcp.res.machinelearningservices-workspace.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' - properties: { - mode: 'Incremental' - template: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: '1.0.0.0' - resources: [] - outputs: { - telemetry: { - type: 'String' - value: 'For more information, see https://aka.ms/avm/TelemetryInfo' - } - } - } - } -} - -resource cMKKeyVault 'Microsoft.KeyVault/vaults@2026-02-01' existing = if (!empty(customerManagedKey.?keyVaultResourceId)) { - name: last(split((customerManagedKey.?keyVaultResourceId!), '/')) - scope: resourceGroup( - split(customerManagedKey.?keyVaultResourceId!, '/')[2], - split(customerManagedKey.?keyVaultResourceId!, '/')[4] - ) - - resource cMKKey 'keys@2023-02-01' existing = if (!empty(customerManagedKey.?keyVaultResourceId) && !empty(customerManagedKey.?keyName)) { - name: customerManagedKey.?keyName! - } -} - -resource cMKUserAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30' existing = if (!empty(customerManagedKey.?userAssignedIdentityResourceId)) { - name: last(split(customerManagedKey.?userAssignedIdentityResourceId!, '/')) - scope: resourceGroup( - split(customerManagedKey.?userAssignedIdentityResourceId!, '/')[2], - split(customerManagedKey.?userAssignedIdentityResourceId!, '/')[4] - ) -} - -resource workspace 'Microsoft.MachineLearningServices/workspaces@2025-12-01' = { - name: name - location: location - tags: tags - sku: { - name: sku - tier: sku - } - identity: identity - properties: { - friendlyName: friendlyName ?? name - storageAccount: associatedStorageAccountResourceId - keyVault: associatedKeyVaultResourceId - applicationInsights: associatedApplicationInsightsResourceId - containerRegistry: associatedContainerRegistryResourceId - hbiWorkspace: hbiWorkspace - description: description - discoveryUrl: discoveryUrl - encryption: !empty(customerManagedKey) - ? { - status: 'Enabled' - identity: !empty(customerManagedKey.?userAssignedIdentityResourceId) - ? { - userAssignedIdentity: cMKUserAssignedIdentity.id - } - : null - keyVaultProperties: { - keyVaultArmId: cMKKeyVault.id - keyIdentifier: !empty(customerManagedKey.?keyVersion ?? '') - ? '${cMKKeyVault::cMKKey!.properties.?keyUri}/${customerManagedKey.?keyVersion}' - : cMKKeyVault::cMKKey!.properties.?keyUriWithVersion - } - } - : null - enableServiceSideCMKEncryption: enableServiceSideCMKEncryption - imageBuildCompute: imageBuildCompute - primaryUserAssignedIdentity: primaryUserAssignedIdentity - systemDatastoresAuthMode: systemDatastoresAuthMode - publicNetworkAccess: publicNetworkAccess - ipAllowlist: ipAllowlist - serviceManagedResourcesSettings: serviceManagedResourcesSettings - // featureStoreSettings: featureStoreSettings - hubResourceId: hubResourceId - // managedNetwork: managedNetworkSettings - provisionNetworkNow: provisionNetworkNow - // serverlessComputeSettings: serverlessComputeSettings - // workspaceHubConfig: workspaceHubConfig - // Parameters only added if not empty - ...(!empty(sharedPrivateLinkResources) - ? { - sharedPrivateLinkResources: sharedPrivateLinkResources - } - : {}) - } - kind: kind -} - -module workspace_connections 'connection/connection.bicep' = [ - for connection in (connections ?? []): { - name: '${workspace.name}-${connection.name}-connection' - params: { - machineLearningWorkspaceName: workspace.name - name: connection.name - category: connection.category - expiryTime: connection.?expiryTime - isSharedToAll: connection.?isSharedToAll - metadata: connection.?metadata - sharedUserList: connection.?sharedUserList - target: connection.target - value: connection.?value - connectionProperties: connection.connectionProperties - } - } -] - -resource workspace_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ - for (diagnosticSetting, index) in (diagnosticSettings ?? []): { - name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' - properties: { - storageAccountId: diagnosticSetting.?storageAccountResourceId - workspaceId: diagnosticSetting.?workspaceResourceId - eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId - eventHubName: diagnosticSetting.?eventHubName - metrics: [ - for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { - category: group.category - enabled: group.?enabled ?? true - timeGrain: null - } - ] - logs: [ - for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { - categoryGroup: group.?categoryGroup - category: group.?category - enabled: group.?enabled ?? true - } - ] - marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId - logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType - } - scope: workspace - } -] - -module workspace_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.12.0' = [ - for (privateEndpoint, index) in (privateEndpoints ?? []): { - name: '${uniqueString(deployment().name, location)}-workspace-PrivateEndpoint-${index}' - scope: resourceGroup( - split(privateEndpoint.?resourceGroupResourceId ?? resourceGroup().id, '/')[2], - split(privateEndpoint.?resourceGroupResourceId ?? resourceGroup().id, '/')[4] - ) - params: { - name: privateEndpoint.?name ?? 'pep-${last(split(workspace.id, '/'))}-${privateEndpoint.?service ?? 'amlworkspace'}-${index}' - privateLinkServiceConnections: privateEndpoint.?isManualConnection != true - ? [ - { - name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(workspace.id, '/'))}-${privateEndpoint.?service ?? 'amlworkspace'}-${index}' - properties: { - privateLinkServiceId: workspace.id - groupIds: [ - privateEndpoint.?service ?? 'amlworkspace' - ] - } - } - ] - : null - manualPrivateLinkServiceConnections: privateEndpoint.?isManualConnection == true - ? [ - { - name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(workspace.id, '/'))}-${privateEndpoint.?service ?? 'amlworkspace'}-${index}' - properties: { - privateLinkServiceId: workspace.id - groupIds: [ - privateEndpoint.?service ?? 'amlworkspace' - ] - requestMessage: privateEndpoint.?manualConnectionRequestMessage ?? 'Manual approval required.' - } - } - ] - : null - subnetResourceId: privateEndpoint.subnetResourceId - enableTelemetry: enableReferencedModulesTelemetry - location: privateEndpoint.?location ?? reference( - split(privateEndpoint.subnetResourceId, '/subnets/')[0], - '2020-06-01', - 'Full' - ).location - lock: privateEndpoint.?lock ?? lock - privateDnsZoneGroup: privateEndpoint.?privateDnsZoneGroup - roleAssignments: privateEndpoint.?roleAssignments - tags: privateEndpoint.?tags ?? tags - customDnsConfigs: privateEndpoint.?customDnsConfigs - ipConfigurations: privateEndpoint.?ipConfigurations - applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds - customNetworkInterfaceName: privateEndpoint.?customNetworkInterfaceName - } - } -] - -resource workspace_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ - for (roleAssignment, index) in (formattedRoleAssignments ?? []): { - name: roleAssignment.?name ?? guid(workspace.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) - properties: { - roleDefinitionId: roleAssignment.roleDefinitionId - principalId: roleAssignment.principalId - description: roleAssignment.?description - principalType: roleAssignment.?principalType - condition: roleAssignment.?condition - conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set - delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId - } - scope: workspace - } -] - -// ================// -// Outputs // -// ================// - -@sys.description('The resource ID of the machine learning service.') -output resourceId string = workspace.id - -@sys.description('The resource group the machine learning service was deployed into.') -output resourceGroupName string = resourceGroup().name - -@sys.description('The name of the machine learning service.') -output name string = workspace.name - -@sys.description('The principal ID of the system assigned identity.') -output systemAssignedMIPrincipalId string? = workspace.?identity.?principalId - -@sys.description('The location the resource was deployed into.') -output location string = workspace.location - -// =============== // -// Definitions // -// =============== // - -// @export() -// @sys.description('The type for the private endpoint output.') -// type privateEndpointOutputType = { -// @sys.description('The name of the private endpoint.') -// name: string - -// @sys.description('The resource ID of the private endpoint.') -// resourceId: string - -// @sys.description('The group Id for the private endpoint Group.') -// groupId: string? - -// @sys.description('The custom DNS configurations of the private endpoint.') -// customDnsConfigs: { -// @sys.description('FQDN that resolves to private endpoint IP address.') -// fqdn: string? - -// @sys.description('A list of private IP addresses of the private endpoint.') -// ipAddresses: string[] -// }[] - -// @sys.description('The IDs of the network interfaces associated with the private endpoint.') -// networkInterfaceResourceIds: string[] -// } - -// @export() -// @sys.description('The type for the feature store setting.') -// type featureStoreSettingType = { -// @sys.description('Optional. Compute runtime config for feature store type workspace.') -// computeRuntime: { -// @sys.description('Optional. The spark runtime version.') -// sparkRuntimeVersion: string? -// }? - -// @sys.description('Optional. The offline store connection name.') -// offlineStoreConnectionName: string? - -// @sys.description('Optional. The online store connection name.') -// onlineStoreConnectionName: string? -// } - -// @export() -// @discriminator('type') -// @sys.description('The type for the outbound rule.') -// type outboundRuleType = fqdnoutboundRuleType | privateEndpointoutboundRuleType | serviceTagoutboundRuleType - -// @export() -// @sys.description('The type for the FQDN outbound rule.') -// type fqdnoutboundRuleType = { -// @sys.description('Required. Type of a managed network Outbound Rule of a machine learning workspace. Only supported when \'isolationMode\' is \'AllowOnlyApprovedOutbound\'.') -// type: 'FQDN' - -// @sys.description('Required. Fully Qualified Domain Name to allow for outbound traffic.') -// destination: string - -// @sys.description('Optional. Category of a managed network Outbound Rule of a machine learning workspace.') -// category: 'Dependency' | 'Recommended' | 'Required' | 'UserDefined'? -// } - -// @export() -// @sys.description('The type for the private endpoint outbound rule.') -// type privateEndpointoutboundRuleType = { -// @sys.description('Required. Type of a managed network Outbound Rule of a machine learning workspace. Only supported when \'isolationMode\' is \'AllowOnlyApprovedOutbound\' or \'AllowInternetOutbound\'.') -// type: 'PrivateEndpoint' - -// @sys.description('Required. Service Tag destination for a Service Tag Outbound Rule for the managed network of a machine learning workspace.') -// destination: { -// @sys.description('Required. The resource ID of the target resource for the private endpoint.') -// serviceResourceId: string - -// @sys.description('Optional. Whether the private endpoint can be used by jobs running on Spark.') -// sparkEnabled: bool? - -// @sys.description('Required. The sub resource to connect for the private endpoint.') -// subresourceTarget: string -// } - -// @sys.description('Optional. Category of a managed network Outbound Rule of a machine learning workspace.') -// category: 'Dependency' | 'Recommended' | 'Required' | 'UserDefined'? -// } - -// @export() -// @sys.description('The type for the service tag outbound rule.') -// type serviceTagoutboundRuleType = { -// @sys.description('Required. Type of a managed network Outbound Rule of a machine learning workspace. Only supported when \'isolationMode\' is \'AllowOnlyApprovedOutbound\'.') -// type: 'ServiceTag' - -// @sys.description('Required. Service Tag destination for a Service Tag Outbound Rule for the managed network of a machine learning workspace.') -// destination: { -// @sys.description('Required. The name of the service tag to allow.') -// portRanges: string - -// @sys.description('Required. The protocol to allow. Provide an asterisk(*) to allow any protocol.') -// protocol: 'TCP' | 'UDP' | 'ICMP' | '*' - -// @sys.description('Required. Which ports will be allow traffic by this rule. Provide an asterisk(*) to allow any port.') -// serviceTag: string -// } - -// @sys.description('Optional. Category of a managed network Outbound Rule of a machine learning workspace.') -// category: 'Dependency' | 'Recommended' | 'Required' | 'UserDefined'? -// } - -// @export() -// @sys.description('The type for the managed network setting.') -// type managedNetworkSettingType = { -// @sys.description('Required. Isolation mode for the managed network of a machine learning workspace.') -// isolationMode: 'AllowInternetOutbound' | 'AllowOnlyApprovedOutbound' | 'Disabled' - -// @sys.description('Optional. Outbound rules for the managed network of a machine learning workspace.') -// outboundRules: { -// @sys.description('Required. The outbound rule. The name of the rule is the object key.') -// *: outboundRuleType -// }? - -// @sys.description('Optional. The firewall SKU used for FQDN rules.') -// firewallSku: 'Basic' | 'Standard'? -// } - -// @export() -// @sys.description('The type for the serverless compute setting.') -// type serverlessComputeSettingType = { -// @sys.description('Optional. The resource ID of an existing virtual network subnet in which serverless compute nodes should be deployed.') -// serverlessComputeCustomSubnet: string? - -// @sys.description('Optional. The flag to signal if serverless compute nodes deployed in custom vNet would have no public IP addresses for a workspace with private endpoint.') -// serverlessComputeNoPublicIP: bool? -// } - -// @export() -// @sys.description('The type for the workspace hub configuration.') -// type workspaceHubConfigType = { -// @sys.description('Optional. The resource IDs of additional storage accounts to attach to the workspace.') -// additionalWorkspaceStorageAccounts: string[]? - -// @sys.description('Optional. The resource ID of the default resource group for projects created in the workspace hub.') -// defaultWorkspaceResourceGroup: string? -// } - -import { categoryType, connectionPropertyType } from 'connection/connection.bicep' - -@export() -@sys.description('The type for the workspace connection.') -type connectionType = { - @sys.description('Required. Name of the connection to create.') - name: string - - @sys.description('Required. Category of the connection.') - category: categoryType - - @sys.description('Optional. The expiry time of the connection.') - expiryTime: string? - - @sys.description('Optional. Indicates whether the connection is shared to all users in the workspace.') - isSharedToAll: bool? - - @sys.description('Optional. User metadata for the connection.') - metadata: { - @sys.description('Required. The metadata key-value pairs.') - *: string - }? - - @sys.description('Optional. The shared user list of the connection.') - sharedUserList: string[]? - - @sys.description('Required. The target of the connection.') - target: string - - @sys.description('Optional. Value details of the workspace connection.') - value: string? - - @sys.description('Required. The properties of the connection, specific to the auth type.') - connectionProperties: connectionPropertyType -} - -// @export() -// @sys.description('The type for the workspace connection.') -// type datastoreType = { -// @sys.description('Required. Name of the datastore to create.') -// name: string - -// @sys.description('Required. The properties of the datastore.') -// properties: resourceInput<'Microsoft.MachineLearningServices/workspaces/datastores@2025-12-01'>.properties -// }