diff --git a/.azuredevops/modulePipelines/ms.machinelearningservices.workspaces.yml b/.azuredevops/modulePipelines/ms.machinelearningservices.workspaces.yml index 8571b04a75..9005efae93 100644 --- a/.azuredevops/modulePipelines/ms.machinelearningservices.workspaces.yml +++ b/.azuredevops/modulePipelines/ms.machinelearningservices.workspaces.yml @@ -49,6 +49,7 @@ stages: deploymentBlocks: - path: $(modulePath)/.test/min.parameters.json - path: $(modulePath)/.test/parameters.json + - path: $(modulePath)/.test/encr.parameters.json - stage: Publishing displayName: Publishing diff --git a/modules/Microsoft.MachineLearningServices/workspaces/.test/encr.parameters.json b/modules/Microsoft.MachineLearningServices/workspaces/.test/encr.parameters.json new file mode 100644 index 0000000000..b98a6f241d --- /dev/null +++ b/modules/Microsoft.MachineLearningServices/workspaces/.test/encr.parameters.json @@ -0,0 +1,49 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "name": { + "value": "<>-az-mls-encr-001" + }, + "sku": { + "value": "Basic" + }, + "associatedStorageAccountResourceId": { + "value": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Storage/storageAccounts/adp<>azsax001" + }, + "associatedKeyVaultResourceId": { + "value": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.KeyVault/vaults/adp-<>-az-kv-x-001" + }, + "associatedApplicationInsightsResourceId": { + "value": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Insights/components/adp-<>-az-appi-x-001" + }, + "cMKUserAssignedIdentityResourceId": { + "value": "/subscriptions/<>/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-<>-az-msi-x-001" + }, + "cMKKeyName": { + "value": "keyEncryptionKey" + }, + "cMKKeyVaultResourceId": { + "value": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.KeyVault/vaults/adp-<>-az-kv-nopr-002" + }, + "systemAssignedIdentity": { + "value": false // Must be false if `primaryUserAssignedIdentity` is provided + }, + "userAssignedIdentities": { + "value": { + "/subscriptions/<>/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-<>-az-msi-x-001": {} + } + }, + "primaryUserAssignedIdentity": { + "value": "/subscriptions/<>/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-<>-az-msi-x-001" + }, + "privateEndpoints": { + "value": [ + { + "subnetResourceId": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Network/virtualNetworks/adp-<>-az-vnet-x-001/subnets/<>-az-subnet-x-005-privateEndpoints", + "service": "amlworkspace" + } + ] + } + } +} diff --git a/modules/Microsoft.MachineLearningServices/workspaces/.test/parameters.json b/modules/Microsoft.MachineLearningServices/workspaces/.test/parameters.json index d8058a2616..ae1a639a13 100644 --- a/modules/Microsoft.MachineLearningServices/workspaces/.test/parameters.json +++ b/modules/Microsoft.MachineLearningServices/workspaces/.test/parameters.json @@ -34,15 +34,6 @@ "discoveryUrl": { "value": "http://example.com" }, - "encryptionIdentity": { - "value": "/subscriptions/<>/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-<>-az-msi-x-001" - }, - "encryptionKeyIdentifier": { - "value": "https://adp-carml-az-kv-nopr-002.vault.azure.net/keys/keyEncryptionKey/5263fcde203347baa7cda35d074073b2" // ID must be updated for new keys - }, - "encryptionKeyVaultResourceId": { - "value": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.KeyVault/vaults/adp-carml-az-kv-nopr-002" - }, "imageBuildCompute": { "value": "testcompute" }, diff --git a/modules/Microsoft.MachineLearningServices/workspaces/deploy.bicep b/modules/Microsoft.MachineLearningServices/workspaces/deploy.bicep index 86afd9df48..c3c63ac945 100644 --- a/modules/Microsoft.MachineLearningServices/workspaces/deploy.bicep +++ b/modules/Microsoft.MachineLearningServices/workspaces/deploy.bicep @@ -113,14 +113,17 @@ param description string = '' @sys.description('Optional. URL for the discovery service to identify regional endpoints for machine learning experimentation services.') param discoveryUrl string = '' -@sys.description('Optional. The Resource ID of the user assigned identity that will be used to access the customer managed key vault.') -param encryptionIdentity string = '' +@sys.description('Optional. The resource ID of a key vault to reference a customer managed key for encryption from.') +param cMKKeyVaultResourceId string = '' -@sys.description('Conditional. Key vault URI to access the encryption key. Required if an \'encryptionIdentity\' was provided.') -param encryptionKeyIdentifier string = '' +@sys.description('Optional. The name of the customer managed key to use for encryption.') +param cMKKeyName string = '' -@sys.description('Conditional. The ResourceID of the keyVault where the customer owned encryption key is present. Required if an \'encryptionIdentity\' was provided.') -param encryptionKeyVaultResourceId string = '' +@sys.description('Optional. The version of the customer managed key to reference for encryption. If not provided, the latest key version is used.') +param cMKKeyVersion string = '' + +@sys.description('Optional. User assigned identity to use when fetching the customer managed key. If not provided, a system-assigned identity can be used - but must be given access to the referenced key vault first.') +param cMKUserAssignedIdentityResourceId string = '' @sys.description('Optional. The compute name for image build.') param imageBuildCompute string = '' @@ -181,6 +184,11 @@ resource defaultTelemetry 'Microsoft.Resources/deployments@2021-04-01' = if (ena } } +resource cMKKeyVaultKey 'Microsoft.KeyVault/vaults/keys@2021-10-01' existing = if (!empty(cMKKeyVaultResourceId) && !empty(cMKKeyName)) { + name: '${last(split(cMKKeyVaultResourceId, '/'))}/${cMKKeyName}' + scope: resourceGroup(split(cMKKeyVaultResourceId, '/')[2], split(cMKKeyVaultResourceId, '/')[4]) +} + resource workspace 'Microsoft.MachineLearningServices/workspaces@2021-07-01' = { name: name location: location @@ -200,15 +208,16 @@ resource workspace 'Microsoft.MachineLearningServices/workspaces@2021-07-01' = { allowPublicAccessWhenBehindVnet: allowPublicAccessWhenBehindVnet description: description discoveryUrl: discoveryUrl - encryption: any({ - identity: !empty(encryptionIdentity) ? { - userAssignedIdentity: encryptionIdentity - } : null - keyVaultProperties: !empty(encryptionIdentity) ? { - keyIdentifier: encryptionKeyIdentifier - keyVaultArmId: encryptionKeyVaultResourceId + encryption: !empty(cMKKeyName) ? { + status: 'Enabled' + identity: !empty(cMKUserAssignedIdentityResourceId) ? { + userAssignedIdentity: cMKUserAssignedIdentityResourceId } : null - }) + keyVaultProperties: { + keyVaultArmId: cMKKeyVaultResourceId + keyIdentifier: !empty(cMKKeyVersion) ? '${cMKKeyVaultKey.properties.keyUri}/${cMKKeyVersion}' : cMKKeyVaultKey.properties.keyUriWithVersion + } + } : null imageBuildCompute: imageBuildCompute primaryUserAssignedIdentity: primaryUserAssignedIdentity publicNetworkAccess: publicNetworkAccess diff --git a/modules/Microsoft.MachineLearningServices/workspaces/readme.md b/modules/Microsoft.MachineLearningServices/workspaces/readme.md index 1243209479..80c6dc976e 100644 --- a/modules/Microsoft.MachineLearningServices/workspaces/readme.md +++ b/modules/Microsoft.MachineLearningServices/workspaces/readme.md @@ -35,8 +35,6 @@ This module deploys a Machine Learning Services Workspace. **Conditional parameters** | Parameter Name | Type | Default Value | Description | | :-- | :-- | :-- | :-- | -| `encryptionKeyIdentifier` | string | `''` | Key vault URI to access the encryption key. Required if an 'encryptionIdentity' was provided. | -| `encryptionKeyVaultResourceId` | string | `''` | The ResourceID of the keyVault where the customer owned encryption key is present. Required if an 'encryptionIdentity' was provided. | | `primaryUserAssignedIdentity` | string | `''` | 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. | | `systemAssignedIdentity` | bool | `False` | Enables system assigned managed identity on the resource. Required if `userAssignedIdentities` is not provided. | | `userAssignedIdentities` | object | `{object}` | The ID(s) to assign to the resource. Required if `systemAssignedIdentity` is set to false. | @@ -46,6 +44,10 @@ This module deploys a Machine Learning Services Workspace. | :-- | :-- | :-- | :-- | :-- | | `allowPublicAccessWhenBehindVnet` | bool | `False` | | The flag to indicate whether to allow public access when behind VNet. | | `associatedContainerRegistryResourceId` | string | `''` | | The resource ID of the associated Container Registry. | +| `cMKKeyName` | string | `''` | | The name of the customer managed key to use for encryption. | +| `cMKKeyVaultResourceId` | string | `''` | | The resource ID of a key vault to reference a customer managed key for encryption from. | +| `cMKKeyVersion` | string | `''` | | The version of the customer managed key to reference for encryption. If not provided, the latest key version is used. | +| `cMKUserAssignedIdentityResourceId` | string | `''` | | User assigned identity to use when fetching the customer managed key. If not provided, a system-assigned identity can be used - but must be given access to the referenced key vault first. | | `computes` | _[computes](computes/readme.md)_ array | `[]` | | Computes to create respectively attach to the workspace. | | `description` | string | `''` | | The description of this workspace. | | `diagnosticEventHubAuthorizationRuleId` | string | `''` | | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | @@ -58,7 +60,6 @@ This module deploys a Machine Learning Services Workspace. | `diagnosticWorkspaceId` | string | `''` | | Resource ID of the diagnostic log analytics workspace. | | `discoveryUrl` | string | `''` | | URL for the discovery service to identify regional endpoints for machine learning experimentation services. | | `enableDefaultTelemetry` | bool | `True` | | Enable telemetry via the Customer Usage Attribution ID (GUID). | -| `encryptionIdentity` | string | `''` | | The Resource ID of the user assigned identity that will be used to access the customer managed key vault. | | `hbiWorkspace` | bool | `False` | | The flag to signal HBI data in the workspace and reduce diagnostic data collected by the service. | | `imageBuildCompute` | string | `''` | | The compute name for image build. | | `location` | string | `[resourceGroup().location]` | | Location for all resources. | @@ -403,6 +404,100 @@ userAssignedIdentities: { via JSON Parameter file +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "name": { + "value": "<>-az-mls-encr-001" + }, + "sku": { + "value": "Basic" + }, + "associatedStorageAccountResourceId": { + "value": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Storage/storageAccounts/adp<>azsax001" + }, + "associatedKeyVaultResourceId": { + "value": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.KeyVault/vaults/adp-<>-az-kv-x-001" + }, + "associatedApplicationInsightsResourceId": { + "value": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Insights/components/adp-<>-az-appi-x-001" + }, + "cMKUserAssignedIdentityResourceId": { + "value": "/subscriptions/<>/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-<>-az-msi-x-001" + }, + "cMKKeyName": { + "value": "keyEncryptionKey" + }, + "cMKKeyVaultResourceId": { + "value": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.KeyVault/vaults/adp-<>-az-kv-nopr-002" + }, + "systemAssignedIdentity": { + "value": false // Must be false if `primaryUserAssignedIdentity` is provided + }, + "userAssignedIdentities": { + "value": { + "/subscriptions/<>/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-<>-az-msi-x-001": {} + } + }, + "primaryUserAssignedIdentity": { + "value": "/subscriptions/<>/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-<>-az-msi-x-001" + }, + "privateEndpoints": { + "value": [ + { + "subnetResourceId": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Network/virtualNetworks/adp-<>-az-vnet-x-001/subnets/<>-az-subnet-x-005-privateEndpoints", + "service": "amlworkspace" + } + ] + } + } +} +``` + + + +
+ +via Bicep module + +```bicep +module workspaces './Microsoft.MachineLearningServices/workspaces/deploy.bicep' = { + name: '${uniqueString(deployment().name)}-workspaces' + params: { + name: '<>-az-mls-encr-001' + sku: 'Basic' + associatedStorageAccountResourceId: '/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Storage/storageAccounts/adp<>azsax001' + associatedKeyVaultResourceId: '/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.KeyVault/vaults/adp-<>-az-kv-x-001' + associatedApplicationInsightsResourceId: '/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Insights/components/adp-<>-az-appi-x-001' + cMKUserAssignedIdentityResourceId: '/subscriptions/<>/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-<>-az-msi-x-001' + cMKKeyName: 'keyEncryptionKey' + cMKKeyVaultResourceId: '/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.KeyVault/vaults/adp-<>-az-kv-nopr-002' + systemAssignedIdentity: false + userAssignedIdentities: { + '/subscriptions/<>/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-<>-az-msi-x-001': {} + } + primaryUserAssignedIdentity: '/subscriptions/<>/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-<>-az-msi-x-001' + privateEndpoints: [ + { + subnetResourceId: '/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.Network/virtualNetworks/adp-<>-az-vnet-x-001/subnets/<>-az-subnet-x-005-privateEndpoints' + service: 'amlworkspace' + } + ] + } +} +``` + +
+

+ +

Example 2

+ +
+ +via JSON Parameter file + ```json { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", @@ -453,7 +548,7 @@ module workspaces './Microsoft.MachineLearningServices/workspaces/deploy.bicep'

-

Example 2

+

Example 3

@@ -496,15 +591,6 @@ module workspaces './Microsoft.MachineLearningServices/workspaces/deploy.bicep' "discoveryUrl": { "value": "http://example.com" }, - "encryptionIdentity": { - "value": "/subscriptions/<>/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-<>-az-msi-x-001" - }, - "encryptionKeyIdentifier": { - "value": "https://adp-carml-az-kv-nopr-002.vault.azure.net/keys/keyEncryptionKey/5263fcde203347baa7cda35d074073b2" // ID must be updated for new keys - }, - "encryptionKeyVaultResourceId": { - "value": "/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.KeyVault/vaults/adp-carml-az-kv-nopr-002" - }, "imageBuildCompute": { "value": "testcompute" }, @@ -603,9 +689,6 @@ module workspaces './Microsoft.MachineLearningServices/workspaces/deploy.bicep' } description: 'The cake is a lie.' discoveryUrl: 'http://example.com' - encryptionIdentity: '/subscriptions/<>/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-<>-az-msi-x-001' - encryptionKeyIdentifier: 'https://adp-carml-az-kv-nopr-002.vault.azure.net/keys/keyEncryptionKey/5263fcde203347baa7cda35d074073b2' - encryptionKeyVaultResourceId: '/subscriptions/<>/resourceGroups/validation-rg/providers/Microsoft.KeyVault/vaults/adp-carml-az-kv-nopr-002' imageBuildCompute: 'testcompute' publicNetworkAccess: 'Enabled' primaryUserAssignedIdentity: '/subscriptions/<>/resourcegroups/validation-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adp-<>-az-msi-x-001'