diff --git a/CHANGELOG.md b/CHANGELOG.md index c760a5c850..743f246adf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ FEATURES: ENHANCEMENTS: * Add support for referencing IP Groups from the Core Resource Group in firewall rules created via the pipeline [#3089](https://github.com/microsoft/AzureTRE/pull/3089) +* Update Azure Machine Learning Workspace Service to support "no public IP" compute. This is a full rework so upgrades of existing Azure ML Workspace Service deployments are not supported. Requires `v0.8.0` or later of the TRE project. [#3052](https://github.com/microsoft/AzureTRE/pull/3052) BUG FIXES: diff --git a/Makefile b/Makefile index 405a3978f3..fdded1aea5 100644 --- a/Makefile +++ b/Makefile @@ -134,6 +134,7 @@ terraform-deploy: $(call target_title, "Deploying ${DIR} with Terraform") \ && . ${MAKEFILE_DIR}/devops/scripts/check_dependencies.sh env \ && . ${MAKEFILE_DIR}/devops/scripts/load_and_validate_env.sh \ + && . ${MAKEFILE_DIR}/devops/scripts/load_env.sh ${DIR}/.env \ && cd ${DIR}/terraform/ && ./deploy.sh terraform-import: diff --git a/docs/tre-templates/workspace-services/azure-ml.md b/docs/tre-templates/workspace-services/azure-ml.md index 7a8ef5412d..d356de507a 100644 --- a/docs/tre-templates/workspace-services/azure-ml.md +++ b/docs/tre-templates/workspace-services/azure-ml.md @@ -6,30 +6,11 @@ This service installs the following resources into an existing virtual network w ![Azure Machine Learning Service](images/aml_service.png) -Any users with the role of `Workspace Researcher` will be assigned the `AzureML Data Scientist` role within the AML workspace. - -## Properties - -- `display_name` - The name of the Azure Machine Learning workspace. -- `description` - The description of the Azure Machine Learning workspace. -- `is_exposed_externally` - If `True`, the Azure Machine Learning workspace is accessible from outside of the worksapce virtual network. - +When deploying the service the Azure ML workspace can be exposed publicly or access restricted to the virtual network. Depending on the choice appropriate network security rules are added. This also means that in the public configuration compute instances can be deployed with public IPs, and in the private configuration they must be deployed with no public IP. -## Firewall Rules - -Please be aware that the following outbound Firewall rules are opened for the workspace when this service is deployed, including to Azure Storage. This does open the possibility to extract data from a workspace if the user is determined to do so. Work is ongoing to remove some of these requirements: - -Service Tags: -- AzureActiveDirectory -- AzureResourceManager -- AzureMachineLearning" -- Storage.`{AzureRegion}` -- MicrosoftContainerRegistry - -URLs: -- aadcdn.msftauth.net -- ml.azure.com +Any users with the role of `Workspace Researcher` will be assigned the `AzureML Data Scientist` role within the AML workspace. +To ensure AML compute instances are deployed with the appropriate configuration we suggest they are deployed using an Compute Instance User Resource. ## Prerequisites diff --git a/docs/tre-templates/workspace-services/images/aml_service.png b/docs/tre-templates/workspace-services/images/aml_service.png index 31b5c1c292..7baaf75233 100644 Binary files a/docs/tre-templates/workspace-services/images/aml_service.png and b/docs/tre-templates/workspace-services/images/aml_service.png differ diff --git a/e2e_tests/test_workspace_services.py b/e2e_tests/test_workspace_services.py index a3b993511c..9739bd4090 100644 --- a/e2e_tests/test_workspace_services.py +++ b/e2e_tests/test_workspace_services.py @@ -8,7 +8,7 @@ pytestmark = pytest.mark.asyncio workspace_services = [ - # strings.AZUREML_SERVICE, + strings.AZUREML_SERVICE, # strings.INNEREYE_SERVICE, strings.GITEA_SERVICE, strings.MLFLOW_SERVICE, diff --git a/templates/workspace_services/azureml/.env.sample b/templates/workspace_services/azureml/.env.sample index ee8cbc0d41..497bce4cc6 100644 --- a/templates/workspace_services/azureml/.env.sample +++ b/templates/workspace_services/azureml/.env.sample @@ -8,3 +8,5 @@ WORKSPACE_ID="__CHANGE_ME__" DISPLAY_NAME="__CHANGE_ME__" DESCRIPTION="__CHANGE_ME__" IS_EXPOSED_EXTERNALLY="false" + +ADDRESS_SAPCE="__CHANGE_ME__" diff --git a/templates/workspace_services/azureml/parameters.json b/templates/workspace_services/azureml/parameters.json index 0e77f0980d..8482f49d68 100755 --- a/templates/workspace_services/azureml/parameters.json +++ b/templates/workspace_services/azureml/parameters.json @@ -34,6 +34,12 @@ "env": "DESCRIPTION" } }, + { + "name": "address_space", + "source": { + "env": "ADDRESS_SPACE" + } + }, { "name": "is_exposed_externally", "source": { diff --git a/templates/workspace_services/azureml/porter.yaml b/templates/workspace_services/azureml/porter.yaml index ab6acfe35c..6bc6d81247 100644 --- a/templates/workspace_services/azureml/porter.yaml +++ b/templates/workspace_services/azureml/porter.yaml @@ -1,7 +1,7 @@ --- schemaVersion: 1.0.0 name: tre-service-azureml -version: 0.6.0 +version: 0.7.25 description: "An Azure TRE service for Azure Machine Learning" registry: azuretre dockerfile: Dockerfile.tmpl @@ -41,6 +41,9 @@ parameters: default: false env: IS_EXPOSED_EXTERNALLY description: "Determines if the AML workspace will be available over public/internet" + - name: address_space + type: string + description: "Address space for the AML subnets" - name: tfstate_resource_group_name type: string description: "Resource group containing the Terraform state storage account" @@ -83,7 +86,12 @@ outputs: applyTo: - install - upgrade - - name: workspace_services_subnet_address_prefix + - name: workspace_address_spaces + type: string + applyTo: + - install + - upgrade + - name: aml_subnet_address_prefixes type: string applyTo: - install @@ -93,14 +101,22 @@ outputs: applyTo: - install - upgrade + - name: batch_tag + type: string + applyTo: + - install + - upgrade + - name: mcr_tag + type: string + applyTo: + - install + - upgrade mixins: - terraform: clientVersion: 1.3.6 - az: clientVersion: 2.37.0 - extensions: - - azure-firewall install: - terraform: @@ -111,11 +127,9 @@ install: tre_resource_id: ${ bundle.parameters.id } display_name: ${ bundle.parameters.display_name } description: ${ bundle.parameters.description } + address_space: ${ bundle.parameters.address_space } is_exposed_externally: ${ bundle.parameters.is_exposed_externally } arm_tenant_id: ${ bundle.credentials.azure_tenant_id } - arm_client_id: ${ bundle.credentials.azure_client_id } - arm_client_secret: ${ bundle.credentials.azure_client_secret } - arm_use_msi: ${ bundle.parameters.arm_use_msi } auth_client_id: ${ bundle.credentials.auth_client_id } auth_client_secret: ${ bundle.credentials.auth_client_secret } auth_tenant_id: ${ bundle.credentials.auth_tenant_id } @@ -130,8 +144,11 @@ install: - name: azureml_storage_account_id - name: connection_uri - name: internal_connection_uri - - name: workspace_services_subnet_address_prefix + - name: workspace_address_spaces + - name: aml_subnet_address_prefixes - name: storage_tag + - name: batch_tag + - name: mcr_tag upgrade: - terraform: @@ -142,11 +159,9 @@ upgrade: tre_resource_id: ${ bundle.parameters.id } display_name: ${ bundle.parameters.display_name } description: ${ bundle.parameters.description } + address_space: ${ bundle.parameters.address_space } is_exposed_externally: ${ bundle.parameters.is_exposed_externally } arm_tenant_id: ${ bundle.credentials.azure_tenant_id } - arm_client_id: ${ bundle.credentials.azure_client_id } - arm_client_secret: ${ bundle.credentials.azure_client_secret } - arm_use_msi: ${ bundle.parameters.arm_use_msi } auth_client_id: ${ bundle.credentials.auth_client_id } auth_client_secret: ${ bundle.credentials.auth_client_secret } auth_tenant_id: ${ bundle.credentials.auth_tenant_id } @@ -161,8 +176,11 @@ upgrade: - name: azureml_storage_account_id - name: connection_uri - name: internal_connection_uri - - name: workspace_services_subnet_address_prefix + - name: workspace_address_spaces + - name: aml_subnet_address_prefixes - name: storage_tag + - name: batch_tag + - name: mcr_tag uninstall: - terraform: @@ -173,11 +191,9 @@ uninstall: tre_resource_id: ${ bundle.parameters.id } display_name: ${ bundle.parameters.display_name } description: ${ bundle.parameters.description } + address_space: ${ bundle.parameters.address_space } is_exposed_externally: ${ bundle.parameters.is_exposed_externally } - arm_use_msi: ${ bundle.parameters.arm_use_msi } arm_tenant_id: ${ bundle.credentials.azure_tenant_id } - arm_client_id: ${ bundle.credentials.azure_client_id } - arm_client_secret: ${ bundle.credentials.azure_client_secret } auth_client_id: ${ bundle.credentials.auth_client_id } auth_client_secret: ${ bundle.credentials.auth_client_secret } auth_tenant_id: ${ bundle.credentials.auth_tenant_id } diff --git a/templates/workspace_services/azureml/template_schema.json b/templates/workspace_services/azureml/template_schema.json index 5465be0fda..769c8360b9 100644 --- a/templates/workspace_services/azureml/template_schema.json +++ b/templates/workspace_services/azureml/template_schema.json @@ -3,19 +3,59 @@ "$id": "https://github.com/microsoft/AzureTRE/templates/workspace_services/azureml/template_schema.json", "type": "object", "title": "Azure Machine Learning", - "description": "Installs Azure Machine Learning. Please be aware this template opens up additional firewall rules to enable Azure ML to function.", + "description": "Azure Machine Learning", "required": [], "properties": { + "display_name": { + "type": "string", + "title": "Name for the workspace service", + "description": "The name of the workspace service to be displayed to users", + "default": "Azure Machine Learning", + "updateable": true + }, + "description": { + "type": "string", + "title": "Description of the workspace service", + "description": "Description of the workspace service", + "default": "Azure Machine Learning empowers data scientists and developers to build, deploy, and manage high-quality models faster and with confidence.", + "updateable": true + }, + "overview": { + "type": "string", + "title": "Workspace Service Overview", + "description": "Long form description of the workspace service, in markdown syntax", + "default": "Azure Machine Learning is a cloud service for accelerating and managing the machine learning project lifecycle. Machine learning professionals, data scientists, and engineers can use it in their day-to-day workflows: Train and deploy models, and manage MLOps. \nYou can create a model in Azure Machine Learning or use a model built from an open-source platform, such as Pytorch, TensorFlow, or scikit-learn. MLOps tools help you monitor, retrain, and redeploy models.\n- [Azure Machine Learning Documentation](https://learn.microsoft.com/en-us/azure/machine-learning/)\n- [Azure Machine Learning Python SDK](https://docs.microsoft.com/en-us/python/api/overview/azure/ml/intro?view=azure-ml-py)", + "updateable": true + }, "is_exposed_externally": { "$id": "#/properties/is_exposed_externally", "type": "boolean", "title": "Expose externally", - "description": "Is the Azure ML workspace accessible from outside of the workspace network", + "description": "Is the Azure ML workspace accessible from outside of the workspace network. Also opens firewall rules to allow compute instances with public IP addresses.", "default": false + }, + "address_space": { + "$id": "#/properties/address_space", + "type": "string", + "title": "Address space", + "description": "The address space for use by AML subnets" + } + }, + "uiSchema": { + "address_space": { + "classNames": "tre-hidden" } }, "pipeline": { "install": [ + { + "stepId": "12ba0dad-ea6c-4d0d-9255-d316212f5ffa", + "stepTitle": "Upgrade to ensure aware of address space", + "resourceType": "workspace", + "resourceAction": "upgrade", + "properties": [ + ] + }, { "stepId": "main" }, @@ -38,9 +78,7 @@ { "name": "AzureMachineLearning", "description": "Azure Machine Learning rules", - "source_addresses": [ - "{{ resource.properties.workspace_services_subnet_address_prefix }}" - ], + "source_addresses": "{{ resource.properties.aml_subnet_address_prefixes }}", "destination_addresses": [ "AzureMachineLearning" ], @@ -54,32 +92,59 @@ ] }, { - "name": "AzureActiveDirectory", - "description": "Azure Active Directory", - "source_addresses": [ - "{{ resource.properties.workspace_services_subnet_address_prefix }}" - ], + "name": "BatchNodeManagement", + "description": "Batch Node Management", + "source_addresses": "{{ resource.properties.aml_subnet_address_prefixes }}", "destination_addresses": [ - "AzureActiveDirectory" + "{{ resource.properties.batch_tag }}" ], "destination_ports": [ - "443", - "80" + "443" ], "protocols": [ "TCP" ] }, + { + "name": "AzureMachineLearningUdp", + "description": "Azure Machine Learning UDP", + "source_addresses": "{{ resource.properties.aml_subnet_address_prefixes }}", + "destination_addresses": [ + "AzureMachineLearning" + ], + "destination_ports": [ + "5831" + ], + "protocols": [ + "UDP" + ] + }, { "name": "AzureML_Dependancies", "description": "AzureML Dependancies", - "source_addresses": [ - "{{ resource.properties.workspace_services_subnet_address_prefix }}" + "source_addresses": "{{ resource.properties.aml_subnet_address_prefixes }}", + "destination_addresses": [ + "AzureActiveDirectory", + "AzureResourceManager", + "{{ resource.properties.mcr_tag }}", + "AzureFrontDoor.FirstParty" + ], + "destination_ports": [ + "443" + ], + "protocols": [ + "TCP" + ] + }, + { + "name": "AzureML_Client", + "description": "AzureML Client", + "source_addresses": "{{ resource.properties.workspace_address_spaces }}", "destination_addresses": [ "AzureActiveDirectory", "AzureResourceManager", - "MicrosoftContainerRegistry" + "AzureMachineLearning" ], "destination_ports": [ "443" @@ -91,9 +156,7 @@ { "name": "AzureML_Storage", "description": "AzureML Storage", - "source_addresses": [ - "{{ resource.properties.workspace_services_subnet_address_prefix }}" - ], + "source_addresses": "{{ resource.properties.aml_subnet_address_prefixes }}", "destination_addresses": [ "{{ resource.properties.storage_tag }}" ], @@ -114,18 +177,17 @@ "arraySubstitutionAction": "replace", "arrayMatchField": "name", "value": { - "name": "arc_svc_{{ resource.id }}_azureml", + "name": "arc_svc_{{ resource.id }}_azureml_client", "action": "Allow", "rules": [ { - "name": "AzureML", + "name": "AzureML_client", "description": "AzureML rules", - "source_addresses": [ - "{{ resource.properties.workspace_services_subnet_address_prefix }}" - ], + "source_addresses": "{{ resource.properties.workspace_address_spaces }}", "target_fqdns": [ - "aadcdn.msftauth.net", - "ml.azure.com" + "aadcdn.msauth.net", + "ml.azure.com", + "automlresources-prod.azureedge.net" ], "protocols": [ { @@ -163,9 +225,7 @@ { "name": "AzureMachineLearning", "description": "Azure Machine Learning rules", - "source_addresses": [ - "{{ resource.properties.workspace_services_subnet_address_prefix }}" - ], + "source_addresses": "{{ resource.properties.aml_subnet_address_prefixes }}", "destination_addresses": [ "AzureMachineLearning" ], @@ -179,32 +239,59 @@ ] }, { - "name": "AzureActiveDirectory", - "description": "Azure Active Directory", - "source_addresses": [ - "{{ resource.properties.workspace_services_subnet_address_prefix }}" - ], + "name": "BatchNodeManagement", + "description": "Batch Node Management", + "source_addresses": "{{ resource.properties.aml_subnet_address_prefixes }}", "destination_addresses": [ - "AzureActiveDirectory" + "{{ resource.properties.batch_tag }}" ], "destination_ports": [ - "443", - "80" + "443" ], "protocols": [ "TCP" ] }, + { + "name": "AzureMachineLearningUdp", + "description": "Azure Machine Learning UDP", + "source_addresses": "{{ resource.properties.aml_subnet_address_prefixes }}", + "destination_addresses": [ + "AzureMachineLearning" + ], + "destination_ports": [ + "5831" + ], + "protocols": [ + "UDP" + ] + }, { "name": "AzureML_Dependancies", "description": "AzureML Dependancies", - "source_addresses": [ - "{{ resource.properties.workspace_services_subnet_address_prefix }}" + "source_addresses": "{{ resource.properties.aml_subnet_address_prefixes }}", + "destination_addresses": [ + "AzureActiveDirectory", + "AzureResourceManager", + "{{ resource.properties.mcr_tag }}", + "AzureFrontDoor.FirstParty" + ], + "destination_ports": [ + "443" + ], + "protocols": [ + "TCP" + ] + }, + { + "name": "AzureML_Client", + "description": "AzureML Client", + "source_addresses": "{{ resource.properties.workspace_address_spaces }}", "destination_addresses": [ "AzureActiveDirectory", "AzureResourceManager", - "MicrosoftContainerRegistry" + "AzureMachineLearning" ], "destination_ports": [ "443" @@ -216,9 +303,7 @@ { "name": "AzureML_Storage", "description": "AzureML Storage", - "source_addresses": [ - "{{ resource.properties.workspace_services_subnet_address_prefix }}" - ], + "source_addresses": "{{ resource.properties.aml_subnet_address_prefixes }}", "destination_addresses": [ "{{ resource.properties.storage_tag }}" ], @@ -239,18 +324,17 @@ "arraySubstitutionAction": "replace", "arrayMatchField": "name", "value": { - "name": "arc_svc_{{ resource.id }}_azureml", + "name": "arc_svc_{{ resource.id }}_azureml_client", "action": "Allow", "rules": [ { - "name": "AzureML", + "name": "AzureML_client", "description": "AzureML rules", - "source_addresses": [ - "{{ resource.properties.workspace_services_subnet_address_prefix }}" - ], + "source_addresses": "{{ resource.properties.workspace_address_spaces }}", "target_fqdns": [ - "aadcdn.msftauth.net", - "ml.azure.com" + "aadcdn.msauth.net", + "ml.azure.com", + "automlresources-prod.azureedge.net" ], "protocols": [ { diff --git a/templates/workspace_services/azureml/terraform/.terraform.lock.hcl b/templates/workspace_services/azureml/terraform/.terraform.lock.hcl index 8dac16d816..11412f37a1 100644 --- a/templates/workspace_services/azureml/terraform/.terraform.lock.hcl +++ b/templates/workspace_services/azureml/terraform/.terraform.lock.hcl @@ -2,42 +2,42 @@ # Manual edits may be lost in future updates. provider "registry.terraform.io/azure/azapi" { - version = "1.0.0" - constraints = "1.0.0" + version = "1.1.0" + constraints = "1.1.0" hashes = [ - "h1:OsBIUCGM+lcmbEJqfHeY9ScQoWU5Ir/MdAUU4+lNNI0=", - "zh:01a33aaefe4d185e70d926103eeb0ac9fefeadf750f69c5977ead2ae02e0b038", - "zh:1ce767851be07e432b4cdde91b40beef84f030432bb7b431ffda85b89305414d", - "zh:1cf15bc8430377091c06373c74a68ce61a9f36dd1455929a64e8083332f2c291", - "zh:4372f59b2761b3ae4b59d59f978af547cd8fae44d2b2e5baa91735b0ea3b16e2", - "zh:6602e2aae7937456418f53372d7139d2f56aea5e46dfd46634f9b202988178c0", - "zh:6f0945ee6ae05cbd708c10ee7b0f8c987032e35122a01d661188538f7548e59f", - "zh:6fc5e5017b8f87aff48732cc619f1295175913e3c1c039a170e8f0100a8233a2", - "zh:740f6c339f28406988204af6fadc9e58c754a22f234902b34c1f6d54421476c2", - "zh:7f003da3b64cb5129627b96a5eb0a03113853a0b17fd4cb77bd505fd27a8ca0b", - "zh:a1ed7aa209cdee91b013691ddb61d77eb3d840f9cba2f4c8b923ba80823c5912", - "zh:d6dad27af147a127027a8aa08a259f6dc418b09f842620e56e5db85547b1b090", - "zh:e67ddb150ff40cf9453fd56f47c2ac657ede1c1861b4d2f9009e98bddfc345b2", + "h1:IR+AHCwfjl1c0baWwfOwZ6QZtHj41H2syTgHkJtAr/M=", + "zh:2a25df6325a49f9e821f0b02c7da86167fc19a3bac647cd1edf231300f29d077", + "zh:2b443a836a39724663fe455d4deee408ff3a2d9a8b86f8408aa7db2e8aa743f8", + "zh:364ed09ddfc50d9bed8d930f7de489cb654a9908feb139413a097823a50075fd", + "zh:523bc005f56ae785867d230d55c29f59db4b599dbc6c38b4d03ea55a79458916", + "zh:60ded375fdb305b60bcb4d9e596dbb222cab166bad1b4958199b05a72aaeacfd", + "zh:61e69c58642fead6814e511c872b7c0a6478ec6af4ab758b4512607d910ac078", + "zh:823b2154ae2262dabcbd11aac992e3cc29eae0f7baa96bee1e3e2fe1ece8730b", + "zh:870ea9cc24807ef5142e4cad0281dac7173f7b6bf818a79762b6c690d12d4c4b", + "zh:9094ae76ed66cb328a4f35bd18b9140fb6fc6859c2e46431ec73c018bcb58d96", + "zh:d89149cfd01cb70012459536b4d36490b58e43312440562e5910bd5160537858", + "zh:dba7ec06171ca062fc423ba5b4776a5600444e45e57f4d1cb043bdc3eee538b7", + "zh:ff5bd6883d9ac8334e043434246357a55107411e9a962856c1d17e47ee15ac37", ] } provider "registry.terraform.io/hashicorp/azurerm" { - version = "3.27.0" - constraints = "3.27.0" + version = "3.37.0" + constraints = "3.37.0" hashes = [ - "h1:0CrzPeSTqt0Q1i9HymfWMovS2/2omGYS//cFYkDU0So=", - "zh:02e014e70113c321aca49e76c4c39e7d7ca0f45763f095a063d523f0af1a9327", - "zh:17457072dbc2e0cb112dcc246173895f873c5d7d907e2f6883c19a104e053e66", - "zh:2f38a5326dbadeba80da45c1c6f4eabe207a7672d3e7c9056df1861433148790", - "zh:63f608417196fd88d3a5a20b037de0064302985414f49ff494aa65e00dc5d218", - "zh:705d67e00c77181bcc6c50613bb8aa2c77988f86534bc240a300a1826efbc24c", - "zh:72f7eca9bd3b7b1e6fffb5bc7b11a9281c1f34319b2073b2c7db1b08b558b2f8", - "zh:7579eef7a029f0bb8440f161afd53e59859541a4aa05008d0d88c5ecf2d81c23", - "zh:78429d5602a356acadc3c4b2d19bbed3e1a373f8c89e2bb9871527a1c56f51cb", - "zh:e0eb79998b61d7d2a4be05cc28f7c2caa8bc50edddd2f0e0bfb99a833982ae6b", - "zh:e6b3d8da3e75d6793a21f318937ce3ba81d6267c18cc058a9366ba35d37cf3be", + "h1:83XTgyPKUKt706IjTLHo9HL0KN5m+DwmSKuVQv6dNb4=", + "zh:2a7bda0b7679d1c791c762103a22f333b544b6e6776c4177f33bafc9cc28c919", + "zh:49ff49670c349f918017315838a43ece09bf6f1bf7721b992f1cadbceb273c62", + "zh:55c9346d03380585e17616b79c4233b726d6fb9efa1921848834fc881e5d7d54", + "zh:5ab117b56a4236ea29926e9d95c27d7bf8ae6706d0fffb76c0b1bfe67bf3a78e", + "zh:5cfc086d5d56308edb3e68aac5f8a448ddc6e56541be7b152ae886399e9b2c69", + "zh:7a8929ed38152aac6652711f32193c8582bc996f8fa73879a3ac7a9bf88d2460", + "zh:895294e90a37f719975fcd2269b95e973147e48ec0ebb9c2fe472bc93531b49c", + "zh:8baa5e2b6e5b02df5b45d253a3aea93f22619920cf9577290d682b59a6d5664b", + "zh:b146a732c7909238c10d216b92a35092be4f72a0509a4c6742cc3245bf3b3bf3", + "zh:cedef898ccd512a6519eae3dff7eb0d581d2c3dad8e0001992da16ad1d7fded8", + "zh:f016d9ba94ea88476883b4d63cff88a0225974e0a8b8c3e8555f73c5de6f7119", "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", - "zh:f7905b2ac7e3a71ebbdc6846bbbc417df4be5690e7afd74d2aba48828a21398e", ] } @@ -80,3 +80,22 @@ provider "registry.terraform.io/hashicorp/null" { "zh:eff8872458806499889f6927b5d954560f3d74bf20b6043409edf94d26cd906f", ] } + +provider "registry.terraform.io/hashicorp/random" { + version = "3.4.3" + hashes = [ + "h1:xZGZf18JjMS06pFa4NErzANI98qi59SEcBsOcS2P2yQ=", + "zh:41c53ba47085d8261590990f8633c8906696fa0a3c4b384ff6a7ecbf84339752", + "zh:59d98081c4475f2ad77d881c4412c5129c56214892f490adf11c7e7a5a47de9b", + "zh:686ad1ee40b812b9e016317e7f34c0d63ef837e084dea4a1f578f64a6314ad53", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:84103eae7251384c0d995f5a257c72b0096605048f757b749b7b62107a5dccb3", + "zh:8ee974b110adb78c7cd18aae82b2729e5124d8f115d484215fd5199451053de5", + "zh:9dd4561e3c847e45de603f17fa0c01ae14cae8c4b7b4e6423c9ef3904b308dda", + "zh:bb07bb3c2c0296beba0beec629ebc6474c70732387477a65966483b5efabdbc6", + "zh:e891339e96c9e5a888727b45b2e1bb3fcbdfe0fd7c5b4396e4695459b38c8cb1", + "zh:ea4739860c24dfeaac6c100b2a2e357106a89d18751f7693f3c31ecf6a996f8d", + "zh:f0c76ac303fd0ab59146c39bc121c5d7d86f878e9a69294e29444d4c653786f8", + "zh:f143a9a5af42b38fed328a161279906759ff39ac428ebcfe55606e05e1518b93", + ] +} diff --git a/templates/workspace_services/azureml/terraform/acr.tf b/templates/workspace_services/azureml/terraform/acr.tf index 7dc8eab27f..33b4ae315f 100644 --- a/templates/workspace_services/azureml/terraform/acr.tf +++ b/templates/workspace_services/azureml/terraform/acr.tf @@ -1,12 +1,13 @@ resource "azurerm_container_registry" "acr" { - name = local.acr_name - location = data.azurerm_resource_group.ws.location - resource_group_name = data.azurerm_resource_group.ws.name - sku = "Premium" - admin_enabled = false - tags = local.tre_workspace_service_tags + name = local.acr_name + location = data.azurerm_resource_group.ws.location + resource_group_name = data.azurerm_resource_group.ws.name + sku = "Premium" + admin_enabled = false + public_network_access_enabled = false + tags = local.tre_workspace_service_tags lifecycle { ignore_changes = [tags] } } @@ -20,7 +21,7 @@ resource "azurerm_private_endpoint" "acrpe" { name = "acrpe-${local.service_resource_name_suffix}" location = data.azurerm_resource_group.ws.location resource_group_name = data.azurerm_resource_group.ws.name - subnet_id = data.azurerm_subnet.services.id + subnet_id = azurerm_subnet.aml.id tags = local.tre_workspace_service_tags lifecycle { ignore_changes = [tags] } @@ -36,4 +37,6 @@ resource "azurerm_private_endpoint" "acrpe" { is_manual_connection = false subresource_names = ["registry"] } + } + diff --git a/templates/workspace_services/azureml/terraform/compute.tf b/templates/workspace_services/azureml/terraform/compute.tf new file mode 100644 index 0000000000..a0e7a26da2 --- /dev/null +++ b/templates/workspace_services/azureml/terraform/compute.tf @@ -0,0 +1,93 @@ +resource "random_password" "password" { + length = 16 + lower = true + min_lower = 1 + upper = true + min_upper = 1 + numeric = true + min_numeric = 1 + special = true + min_special = 1 + override_special = "_%@" +} + +resource "azurerm_key_vault_secret" "aml_password" { + name = "cp-${local.short_service_id}" + value = random_password.password.result + key_vault_id = data.azurerm_key_vault.ws.id + tags = local.tre_workspace_service_tags +} + + +resource "azapi_resource" "compute_cluster" { + type = "Microsoft.MachineLearningServices/workspaces/computes@2022-10-01" + name = "cp-${local.short_service_id}" + location = data.azurerm_resource_group.ws.location + parent_id = azurerm_machine_learning_workspace.aml_workspace.id + tags = local.tre_workspace_service_tags + + lifecycle { ignore_changes = [tags] } + + identity { + type = "SystemAssigned" + } + + body = jsonencode({ + properties = { + computeLocation = data.azurerm_resource_group.ws.location + description = "Default Compute Cluster" + disableLocalAuth = true + computeType = "AmlCompute" + properties = { + enableNodePublicIp = false + isolatedNetwork = true + osType = "Linux" + remoteLoginPortPublicAccess = "Disabled" + scaleSettings = { + maxNodeCount = 1 + minNodeCount = 0 + nodeIdleTimeBeforeScaleDown = "PT10M" + } + subnet = { + id = azurerm_subnet.aml.id + } + vmPriority = "Dedicated" + vmSize = "Standard_DS2_v2" + } + } + }) + + depends_on = [ + azurerm_private_endpoint.mlpe, + azurerm_private_endpoint.blobpe, + azurerm_private_endpoint.filepe + ] + + response_export_values = ["*"] + +} + +# This seems to be added automatically +# resource "azurerm_role_assignment" "compute_cluster_acr_pull" { +# scope = azurerm_container_registry.acr.id +# role_definition_name = "AcrPull" +# principal_id = jsondecode(azapi_resource.compute_cluster.output).identity.principalId +# } + +resource "azapi_update_resource" "set_image_build_compute" { + type = "Microsoft.MachineLearningServices/workspaces@2022-10-01" + name = azurerm_machine_learning_workspace.aml_workspace.name + parent_id = data.azurerm_resource_group.ws.id + + body = jsonencode({ + properties = { + imageBuildCompute = jsondecode(azapi_resource.compute_cluster.output).name + } + }) + + depends_on = [ + azapi_resource.compute_cluster + #, + #azurerm_role_assignment.compute_cluster_acr_pull + ] +} diff --git a/templates/workspace_services/azureml/terraform/data.tf b/templates/workspace_services/azureml/terraform/data.tf new file mode 100644 index 0000000000..63cf294ad7 --- /dev/null +++ b/templates/workspace_services/azureml/terraform/data.tf @@ -0,0 +1,49 @@ +data "azurerm_resource_group" "ws" { + name = "rg-${var.tre_id}-ws-${local.short_workspace_id}" +} + +data "azurerm_virtual_network" "ws" { + name = "vnet-${var.tre_id}-ws-${local.short_workspace_id}" + resource_group_name = data.azurerm_resource_group.ws.name +} + +resource "azurerm_application_insights" "ai" { + name = "ai-${local.service_resource_name_suffix}" + location = data.azurerm_resource_group.ws.location + resource_group_name = data.azurerm_resource_group.ws.name + application_type = "web" + tags = local.tre_workspace_service_tags + + lifecycle { ignore_changes = [tags] } +} + +data "azurerm_key_vault" "ws" { + name = local.keyvault_name + resource_group_name = data.azurerm_resource_group.ws.name +} + +data "azurerm_subnet" "shared" { + resource_group_name = local.core_resource_group_name + virtual_network_name = local.core_vnet + name = "SharedSubnet" +} + +data "azurerm_route_table" "rt" { + name = "rt-${var.tre_id}" + resource_group_name = local.core_resource_group_name +} + +data "azurerm_private_dns_zone" "azureml" { + name = "privatelink.api.azureml.ms" + resource_group_name = local.core_resource_group_name +} + +data "azurerm_private_dns_zone" "azuremlcert" { + name = "privatelink.cert.api.azureml.ms" + resource_group_name = local.core_resource_group_name +} + +data "azurerm_private_dns_zone" "notebooks" { + name = "privatelink.notebooks.azure.net" + resource_group_name = local.core_resource_group_name +} diff --git a/templates/workspace_services/azureml/terraform/get_nsg_priorities.sh b/templates/workspace_services/azureml/terraform/get_nsg_priorities.sh deleted file mode 100755 index 1a1d8aa510..0000000000 --- a/templates/workspace_services/azureml/terraform/get_nsg_priorities.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -set -o pipefail -set -o nounset - - -eval "$(jq -r '@sh "nsg_name=\(.nsg_name) resource_group_name=\(.resource_group_name) nsg_rule_name=\(.nsg_rule_name) direction=\(.direction)"')" - -# These variables are loaded in for us -if NSG_RULE=$(az network nsg rule show -g "${resource_group_name?}" --nsg-name "${nsg_name?}" --name "${nsg_rule_name?}" -o json); then - NSG_RULE_PRIORITY=$(echo "$NSG_RULE" | jq '.priority') -else - NSG_RULE_MAX_PRIORITY=$(az network nsg rule list -g "${resource_group_name?}" --nsg-name "${nsg_name?}" --query "not_null(max_by([?direction=='${direction?}' && access=='Allow'],&priority).priority) || '100'" -o json) - # without $(()) command fails - # shellcheck disable=SC2004 - NSG_RULE_PRIORITY=$(($NSG_RULE_MAX_PRIORITY + 1)) -fi - -# Safely produce a JSON object containing the result value. -jq -n --arg nsg_rule_priority "$NSG_RULE_PRIORITY" '{ "nsg_rule_priority":$nsg_rule_priority }' diff --git a/templates/workspace_services/azureml/terraform/locals.tf b/templates/workspace_services/azureml/terraform/locals.tf index c99f98d5eb..ac11d6c921 100644 --- a/templates/workspace_services/azureml/terraform/locals.tf +++ b/templates/workspace_services/azureml/terraform/locals.tf @@ -1,6 +1,7 @@ locals { short_service_id = substr(var.tre_resource_id, -4, -1) short_workspace_id = substr(var.workspace_id, -4, -1) + core_vnet = "vnet-${var.tre_id}" core_resource_group_name = "rg-${var.tre_id}" workspace_resource_name_suffix = "${var.tre_id}-ws-${local.short_workspace_id}" service_resource_name_suffix = "${var.tre_id}-ws-${local.short_workspace_id}-svc-${local.short_service_id}" diff --git a/templates/workspace_services/azureml/terraform/main.tf b/templates/workspace_services/azureml/terraform/main.tf index 9435b37e43..d1cf6b14ad 100644 --- a/templates/workspace_services/azureml/terraform/main.tf +++ b/templates/workspace_services/azureml/terraform/main.tf @@ -1,83 +1,27 @@ -data "azurerm_resource_group" "ws" { - name = "rg-${var.tre_id}-ws-${local.short_workspace_id}" -} - -data "azurerm_virtual_network" "ws" { - name = "vnet-${var.tre_id}-ws-${local.short_workspace_id}" - resource_group_name = data.azurerm_resource_group.ws.name -} - -data "azurerm_subnet" "services" { - name = "ServicesSubnet" - virtual_network_name = data.azurerm_virtual_network.ws.name - resource_group_name = data.azurerm_virtual_network.ws.resource_group_name -} - -resource "azurerm_application_insights" "ai" { - name = "ai-${local.service_resource_name_suffix}" - location = data.azurerm_resource_group.ws.location - resource_group_name = data.azurerm_resource_group.ws.name - application_type = "web" - tags = local.tre_workspace_service_tags - - lifecycle { ignore_changes = [tags] } -} - -data "azurerm_key_vault" "ws" { - name = local.keyvault_name - resource_group_name = data.azurerm_resource_group.ws.name -} - -# Using AzAPI due to https://github.com/hashicorp/terraform-provider-azurerm/issues/16177 -resource "azapi_resource" "aml_workspace" { - name = local.workspace_name - parent_id = data.azurerm_resource_group.ws.id - type = "Microsoft.MachineLearningServices/workspaces@2022-05-01" - schema_validation_enabled = false - location = data.azurerm_resource_group.ws.location - - body = jsonencode({ - properties = { - allowRecoverSoftDeletedWorkspace = "True" - applicationInsights = azurerm_application_insights.ai.id - containerRegistry = azurerm_container_registry.acr.id - friendlyName = var.display_name - description = var.description - hbiWorkspace = true - keyVault = data.azurerm_key_vault.ws.id - publicNetworkAccess = var.is_exposed_externally ? "Enabled" : "Disabled" - storageAccount = azurerm_storage_account.aml.id - v1LegacyMode = false - } - identity = { - type = "SystemAssigned" - } - }) - - response_export_values = ["*"] - -} - -data "azurerm_private_dns_zone" "azureml" { - name = "privatelink.api.azureml.ms" - resource_group_name = local.core_resource_group_name -} - -data "azurerm_private_dns_zone" "azuremlcert" { - name = "privatelink.cert.api.azureml.ms" - resource_group_name = local.core_resource_group_name +resource "azurerm_machine_learning_workspace" "aml_workspace" { + name = local.workspace_name + resource_group_name = data.azurerm_resource_group.ws.name + location = data.azurerm_resource_group.ws.location + application_insights_id = azurerm_application_insights.ai.id + container_registry_id = azurerm_container_registry.acr.id + friendly_name = var.display_name + description = var.description + high_business_impact = true + key_vault_id = data.azurerm_key_vault.ws.id + public_network_access_enabled = var.is_exposed_externally ? true : false + storage_account_id = azurerm_storage_account.aml.id + tags = local.tre_workspace_service_tags + + identity { + type = "SystemAssigned" + } } - -data "azurerm_private_dns_zone" "notebooks" { - name = "privatelink.notebooks.azure.net" - resource_group_name = local.core_resource_group_name -} resource "azurerm_private_endpoint" "mlpe" { name = "mlpe-${local.service_resource_name_suffix}" location = data.azurerm_resource_group.ws.location resource_group_name = data.azurerm_resource_group.ws.name - subnet_id = data.azurerm_subnet.services.id + subnet_id = azurerm_subnet.aml.id tags = local.tre_workspace_service_tags lifecycle { ignore_changes = [tags] } @@ -89,8 +33,14 @@ resource "azurerm_private_endpoint" "mlpe" { private_service_connection { name = "mlpesc-${local.service_resource_name_suffix}" - private_connection_resource_id = azapi_resource.aml_workspace.id + private_connection_resource_id = azurerm_machine_learning_workspace.aml_workspace.id is_manual_connection = false subresource_names = ["amlworkspace"] } + + depends_on = [ + azurerm_subnet_network_security_group_association.aml, + azapi_resource.aml_service_endpoint_policy + ] + } diff --git a/templates/workspace_services/azureml/terraform/network.tf b/templates/workspace_services/azureml/terraform/network.tf index 06805ad39d..5aba3d18b5 100644 --- a/templates/workspace_services/azureml/terraform/network.tf +++ b/templates/workspace_services/azureml/terraform/network.tf @@ -1,92 +1,109 @@ +resource "azurerm_network_security_group" "aml" { + location = data.azurerm_virtual_network.ws.location + name = "nsg-aml-${local.short_service_id}" + resource_group_name = data.azurerm_virtual_network.ws.resource_group_name + tags = local.tre_workspace_service_tags -data "azurerm_network_security_group" "ws" { - name = "nsg-ws" - resource_group_name = data.azurerm_resource_group.ws.name + lifecycle { ignore_changes = [tags] } } +# Using AzApi due to https://github.com/hashicorp/terraform-provider-azurerm/issues/14852 +# resource "azurerm_subnet_service_endpoint_storage_policy" "aml" { +# name = "aml-service-endpoint-policy" +# resource_group_name = data.azurerm_virtual_network.ws.resource_group_name +# location = data.azurerm_virtual_network.ws.location +# +# definition { +# name = "aml-service-endpoint-policy" +# service_resources = [ +# azurerm_storage_account.aml.id, +# "/services/Azure/MachineLearning" +# ] +# } +# +# tags = local.tre_workspace_service_tags +# } -resource "null_resource" "az_login_sp" { - - count = var.arm_use_msi == true ? 0 : 1 - provisioner "local-exec" { - command = "az login --service-principal --username ${var.arm_client_id} --password ${var.arm_client_secret} --tenant ${var.arm_tenant_id}" - } - - triggers = { - timestamp = timestamp() - } - +resource "azapi_resource" "aml_service_endpoint_policy" { + type = "Microsoft.Network/serviceEndpointPolicies@2022-05-01" + name = "aml-service-endpoint-policy-${local.short_service_id}" + location = data.azurerm_virtual_network.ws.location + parent_id = data.azurerm_resource_group.ws.id + tags = local.tre_workspace_service_tags + body = jsonencode({ + properties = { + serviceEndpointPolicyDefinitions = [ + { + name = "aml-service-endpoint-policy-definition-storage-${local.short_service_id}" + properties = { + service = "Microsoft.Storage" + serviceResources = [ + azurerm_storage_account.aml.id + ] + } + type = "Microsoft.Network/serviceEndpointPolicies/serviceEndpointPolicyDefinitions" + }, + { + name = "aml-service-endpoint-policy-definition-azureml-${local.short_service_id}" + properties = { + service = "Global" + serviceResources = [ + "/services/Azure/MachineLearning" + ] + } + type = "Microsoft.Network/serviceEndpointPolicies/serviceEndpointPolicyDefinitions" + } + ] + } + }) } -resource "null_resource" "az_login_msi" { - - count = var.arm_use_msi == true ? 1 : 0 - provisioner "local-exec" { - command = "az login --identity -u '${data.azurerm_client_config.current.client_id}'" - } - - triggers = { - timestamp = timestamp() - } -} +resource "azurerm_subnet" "aml" { + name = "AMLSubnet${local.short_service_id}" + virtual_network_name = data.azurerm_virtual_network.ws.name + resource_group_name = data.azurerm_virtual_network.ws.resource_group_name + address_prefixes = [var.address_space] -data "external" "nsg_rule_priorities_inbound" { - program = ["bash", "-c", "./get_nsg_priorities.sh"] + # need to be disabled for AML private compute + private_endpoint_network_policies_enabled = false + private_link_service_network_policies_enabled = false - query = { - nsg_name = data.azurerm_network_security_group.ws.name - resource_group_name = data.azurerm_resource_group.ws.name - nsg_rule_name = "${local.short_service_id}-aml-inbound" - direction = "Inbound" - } - depends_on = [ - null_resource.az_login_sp, - null_resource.az_login_msi + service_endpoints = [ + "Microsoft.Storage" ] + service_endpoint_policy_ids = [azapi_resource.aml_service_endpoint_policy.id] } - - -data "external" "nsg_rule_priorities_outbound" { - program = ["bash", "-c", "./get_nsg_priorities.sh"] - - query = { - nsg_name = data.azurerm_network_security_group.ws.name - nsg_rule_name = "${local.short_service_id}-allow-Outbound_Storage_445" - resource_group_name = data.azurerm_resource_group.ws.name - direction = "Outbound" - } - depends_on = [ - null_resource.az_login_sp, - null_resource.az_login_msi - ] +resource "azurerm_subnet_network_security_group_association" "aml" { + network_security_group_id = azurerm_network_security_group.aml.id + subnet_id = azurerm_subnet.aml.id } -resource "azurerm_network_security_rule" "allow_batch_inbound" { - access = "Allow" - destination_port_ranges = ["29876"] - destination_address_prefix = "VirtualNetwork" - source_address_prefix = "BatchNodeManagement" - direction = "Inbound" - name = "${local.short_service_id}-batch-inbound-29876" - network_security_group_name = data.azurerm_network_security_group.ws.name - priority = tonumber(data.external.nsg_rule_priorities_inbound.result.nsg_rule_priority) - protocol = "Tcp" - resource_group_name = data.azurerm_resource_group.ws.name - source_port_range = "*" +resource "azurerm_network_security_rule" "allow_inbound_within_workspace_vnet" { + access = "Allow" + destination_port_range = "*" + destination_address_prefixes = data.azurerm_virtual_network.ws.address_space + source_address_prefixes = data.azurerm_virtual_network.ws.address_space + direction = "Inbound" + name = "inbound-within-workspace-vnet" + network_security_group_name = azurerm_network_security_group.aml.name + priority = 100 + protocol = "*" + resource_group_name = data.azurerm_resource_group.ws.name + source_port_range = "*" } -resource "azurerm_network_security_rule" "allow_batch_inbound_29877" { +resource "azurerm_network_security_rule" "allow_batch_inbound" { count = var.is_exposed_externally ? 1 : 0 access = "Allow" - destination_port_ranges = ["29877"] + destination_port_ranges = ["29876", "29877"] destination_address_prefix = "VirtualNetwork" source_address_prefix = "BatchNodeManagement" direction = "Inbound" - name = "${local.short_service_id}-batch-inbound-29877" - network_security_group_name = data.azurerm_network_security_group.ws.name - priority = tonumber(data.external.nsg_rule_priorities_inbound.result.nsg_rule_priority) + 1 + name = "${local.short_service_id}-batch-inbound-29876" + network_security_group_name = azurerm_network_security_group.aml.name + priority = 101 protocol = "Tcp" resource_group_name = data.azurerm_resource_group.ws.name source_port_range = "*" @@ -100,8 +117,8 @@ resource "azurerm_network_security_rule" "allow_aml_inbound" { source_address_prefix = "AzureMachineLearning" direction = "Inbound" name = "${local.short_service_id}-aml-inbound" - network_security_group_name = data.azurerm_network_security_group.ws.name - priority = tonumber(data.external.nsg_rule_priorities_inbound.result.nsg_rule_priority) + 2 + network_security_group_name = azurerm_network_security_group.aml.name + priority = 102 protocol = "Tcp" resource_group_name = data.azurerm_resource_group.ws.name source_port_range = "*" @@ -115,9 +132,191 @@ resource "azurerm_network_security_rule" "allow_outbound_storage_445" { source_address_prefix = "VirtualNetwork" direction = "Outbound" name = "${local.short_service_id}-allow-Outbound_Storage_445" - network_security_group_name = data.azurerm_network_security_group.ws.name - priority = tonumber(data.external.nsg_rule_priorities_outbound.result.nsg_rule_priority) + network_security_group_name = azurerm_network_security_group.aml.name + priority = 103 + protocol = "Tcp" + resource_group_name = data.azurerm_resource_group.ws.name + source_port_range = "*" +} + +resource "azurerm_network_security_rule" "allow_outbound_to_shared_services" { + access = "Allow" + destination_address_prefixes = data.azurerm_subnet.shared.address_prefixes + destination_port_range = "*" + direction = "Outbound" + name = "to-shared-services" + network_security_group_name = azurerm_network_security_group.aml.name + priority = 104 + protocol = "*" + resource_group_name = data.azurerm_resource_group.ws.name + source_address_prefix = "*" + source_port_range = "*" +} + + +resource "azurerm_network_security_rule" "allow_outbound_to_internet" { + access = "Allow" + destination_address_prefix = "INTERNET" + destination_port_range = "443" + direction = "Outbound" + name = "to-internet" + network_security_group_name = azurerm_network_security_group.aml.name + priority = 105 + protocol = "Tcp" + resource_group_name = data.azurerm_resource_group.ws.name + source_address_prefix = "*" + source_port_range = "*" +} + +resource "azurerm_network_security_rule" "allow_outbound_to_aml_udp_5831" { + access = "Allow" + destination_address_prefix = "AzureMachineLearning" + destination_port_range = "5831" + direction = "Outbound" + name = "to-aml-udp" + network_security_group_name = azurerm_network_security_group.aml.name + priority = 106 + protocol = "Udp" + resource_group_name = data.azurerm_resource_group.ws.name + source_address_prefix = "*" + source_port_range = "*" +} + +resource "azurerm_network_security_rule" "allow_outbound_to_aml_tcp_443" { + access = "Allow" + destination_address_prefix = "AzureMachineLearning" + destination_port_range = "443" + direction = "Outbound" + name = "to-aml-tcp-443" + network_security_group_name = azurerm_network_security_group.aml.name + priority = 107 protocol = "Tcp" resource_group_name = data.azurerm_resource_group.ws.name + source_address_prefix = "*" source_port_range = "*" } + +resource "azurerm_network_security_rule" "allow_outbound_to_aml_tcp_8787" { + access = "Allow" + destination_address_prefix = "AzureMachineLearning" + destination_port_range = "8787" + direction = "Outbound" + name = "to-aml-tcp-8787-rstudio" + network_security_group_name = azurerm_network_security_group.aml.name + priority = 108 + protocol = "Tcp" + resource_group_name = data.azurerm_resource_group.ws.name + source_address_prefix = "*" + source_port_range = "*" +} + +resource "azurerm_network_security_rule" "allow_outbound_to_aml_tcp_18881" { + access = "Allow" + destination_address_prefix = "AzureMachineLearning" + destination_port_range = "18881" + direction = "Outbound" + name = "to-aml-tcp-18881-language-server" + network_security_group_name = azurerm_network_security_group.aml.name + priority = 109 + protocol = "Tcp" + resource_group_name = data.azurerm_resource_group.ws.name + source_address_prefix = "*" + source_port_range = "*" +} + +resource "azurerm_network_security_rule" "allow_outbound_within_workspace_vnet" { + access = "Allow" + destination_port_range = "*" + destination_address_prefixes = data.azurerm_virtual_network.ws.address_space + source_address_prefixes = data.azurerm_virtual_network.ws.address_space + direction = "Outbound" + name = "outbound-within-workspace-subnet" + network_security_group_name = azurerm_network_security_group.aml.name + priority = 100 + protocol = "*" + resource_group_name = data.azurerm_resource_group.ws.name + source_port_range = "*" +} + +resource "azurerm_network_security_rule" "deny_outbound_override" { + access = "Deny" + destination_address_prefix = "*" + destination_port_range = "*" + direction = "Outbound" + name = "deny-outbound-override" + network_security_group_name = azurerm_network_security_group.aml.name + priority = 4096 + protocol = "*" + resource_group_name = data.azurerm_resource_group.ws.name + source_address_prefix = "*" + source_port_range = "*" +} + + + +resource "azurerm_network_security_rule" "deny_all_inbound_override" { + access = "Deny" + destination_address_prefix = "*" + destination_port_range = "*" + direction = "Inbound" + name = "deny-inbound-override" + network_security_group_name = azurerm_network_security_group.aml.name + priority = 4096 + protocol = "*" + resource_group_name = data.azurerm_resource_group.ws.name + source_address_prefix = "*" + source_port_range = "*" +} + +resource "azurerm_route_table" "aml" { + count = var.is_exposed_externally ? 1 : 0 + name = "rt-aml-${var.tre_id}-${local.short_service_id}" + resource_group_name = data.azurerm_resource_group.ws.name + location = data.azurerm_resource_group.ws.location + disable_bgp_route_propagation = false + tags = local.tre_workspace_service_tags + + lifecycle { ignore_changes = [tags] } + +} + +resource "azurerm_route" "firewall" { + count = var.is_exposed_externally ? 1 : 0 + name = "rt-aml-${var.tre_id}-${local.short_service_id}" + resource_group_name = data.azurerm_resource_group.ws.name + route_table_name = azurerm_route_table.aml[count.index].name + address_prefix = data.azurerm_route_table.rt.route[0].address_prefix + next_hop_type = data.azurerm_route_table.rt.route[0].next_hop_type + next_hop_in_ip_address = data.azurerm_route_table.rt.route[0].next_hop_in_ip_address +} + +resource "azurerm_route" "aml" { + count = var.is_exposed_externally ? 1 : 0 + name = "rt-aml-${var.tre_id}-${local.short_service_id}" + resource_group_name = data.azurerm_resource_group.ws.name + route_table_name = azurerm_route_table.aml[count.index].name + address_prefix = "AzureMachineLearning" + next_hop_type = "Internet" +} + +resource "azurerm_route" "batch" { + count = var.is_exposed_externally ? 1 : 0 + name = "rt-aml-${var.tre_id}-${local.short_service_id}" + resource_group_name = data.azurerm_resource_group.ws.name + route_table_name = azurerm_route_table.aml[count.index].name + address_prefix = "BatchNodeManagement" + next_hop_type = "Internet" +} + + +resource "azurerm_subnet_route_table_association" "rt_aml_subnet_association" { + count = var.is_exposed_externally ? 1 : 0 + route_table_id = azurerm_route_table.aml[count.index].id + subnet_id = azurerm_subnet.aml.id +} + +resource "azurerm_subnet_route_table_association" "rt_core_aml_subnet_association" { + count = var.is_exposed_externally ? 0 : 1 + route_table_id = data.azurerm_route_table.rt.id + subnet_id = azurerm_subnet.aml.id +} diff --git a/templates/workspace_services/azureml/terraform/outputs.tf b/templates/workspace_services/azureml/terraform/outputs.tf index e9bb0f2a56..427828e4ab 100644 --- a/templates/workspace_services/azureml/terraform/outputs.tf +++ b/templates/workspace_services/azureml/terraform/outputs.tf @@ -1,5 +1,5 @@ output "azureml_workspace_name" { - value = azapi_resource.aml_workspace.name + value = azurerm_machine_learning_workspace.aml_workspace.name } output "azureml_acr_id" { @@ -11,15 +11,19 @@ output "azureml_storage_account_id" { } output "connection_uri" { - value = var.is_exposed_externally ? "https://ml.azure.com/?wsid=${azapi_resource.aml_workspace.id}&tid=${var.arm_tenant_id}" : "" + value = var.is_exposed_externally ? "https://ml.azure.com/?wsid=${azurerm_machine_learning_workspace.aml_workspace.id}&tid=${var.arm_tenant_id}" : "" } output "internal_connection_uri" { - value = var.is_exposed_externally ? "" : "https://ml.azure.com/?wsid=${azapi_resource.aml_workspace.id}&tid=${var.arm_tenant_id}" + value = var.is_exposed_externally ? "" : "https://ml.azure.com/?wsid=${azurerm_machine_learning_workspace.aml_workspace.id}&tid=${var.arm_tenant_id}" } -output "workspace_services_subnet_address_prefix" { - value = data.azurerm_subnet.services.address_prefix +output "workspace_address_spaces" { + value = data.azurerm_virtual_network.ws.address_space +} + +output "aml_subnet_address_prefixes" { + value = azurerm_subnet.aml.address_prefixes } data "azurerm_network_service_tags" "storage_tag" { @@ -28,6 +32,26 @@ data "azurerm_network_service_tags" "storage_tag" { location_filter = azurerm_storage_account.aml.location } +data "azurerm_network_service_tags" "mcr_tag" { + location = azurerm_storage_account.aml.location + service = "MicrosoftContainerRegistry" + location_filter = azurerm_storage_account.aml.location +} + +data "azurerm_network_service_tags" "batch_tag" { + location = azurerm_storage_account.aml.location + service = "BatchNodeManagement" + location_filter = azurerm_storage_account.aml.location +} + output "storage_tag" { value = data.azurerm_network_service_tags.storage_tag.id } + +output "mcr_tag" { + value = data.azurerm_network_service_tags.mcr_tag.id +} + +output "batch_tag" { + value = data.azurerm_network_service_tags.batch_tag.id +} diff --git a/templates/workspace_services/azureml/terraform/providers.tf b/templates/workspace_services/azureml/terraform/providers.tf index 740de5ea42..67cf34f0af 100644 --- a/templates/workspace_services/azureml/terraform/providers.tf +++ b/templates/workspace_services/azureml/terraform/providers.tf @@ -2,21 +2,20 @@ terraform { required_providers { azurerm = { source = "hashicorp/azurerm" - version = "=3.27.0" + version = "=3.37.0" } azapi = { source = "Azure/azapi" - version = "=1.0.0" + version = "=1.1.0" } external = { source = "hashicorp/external" version = "=2.2.2" } - null = { - source = "hashicorp/null" - version = "=3.1.1" + random = { + source = "hashicorp/random" + version = "3.4.3" } - } backend "azurerm" {} @@ -39,7 +38,4 @@ provider "azurerm" { } } -provider "azapi" { -} - -data "azurerm_client_config" "current" {} +provider "azapi" {} diff --git a/templates/workspace_services/azureml/terraform/roles.tf b/templates/workspace_services/azureml/terraform/roles.tf index 9a791fb743..a3c5d445a8 100644 --- a/templates/workspace_services/azureml/terraform/roles.tf +++ b/templates/workspace_services/azureml/terraform/roles.tf @@ -21,7 +21,7 @@ data "azurerm_role_definition" "azure_ml_data_scientist" { resource "azurerm_role_assignment" "app_role_members_aml_data_scientist" { for_each = (data.external.app_role_members.result.principals == "") ? [] : toset(split("\n", data.external.app_role_members.result.principals)) - scope = azapi_resource.aml_workspace.id + scope = azurerm_machine_learning_workspace.aml_workspace.id role_definition_id = data.azurerm_role_definition.azure_ml_data_scientist.id principal_id = each.value } diff --git a/templates/workspace_services/azureml/terraform/storage.tf b/templates/workspace_services/azureml/terraform/storage.tf index a244c82c29..fd23106a9c 100644 --- a/templates/workspace_services/azureml/terraform/storage.tf +++ b/templates/workspace_services/azureml/terraform/storage.tf @@ -4,6 +4,12 @@ resource "azurerm_storage_account" "aml" { resource_group_name = data.azurerm_resource_group.ws.name account_tier = "Standard" account_replication_type = "GRS" + tags = local.tre_workspace_service_tags + network_rules { + default_action = "Deny" + } + + } data "azurerm_private_dns_zone" "blobcore" { @@ -11,12 +17,17 @@ data "azurerm_private_dns_zone" "blobcore" { resource_group_name = local.core_resource_group_name } -resource "azurerm_private_endpoint" "stgblobpe" { +data "azurerm_private_dns_zone" "filecore" { + name = "privatelink.file.core.windows.net" + resource_group_name = local.core_resource_group_name +} + +resource "azurerm_private_endpoint" "blobpe" { name = "pe-${local.storage_name}" location = data.azurerm_resource_group.ws.location resource_group_name = data.azurerm_resource_group.ws.name - subnet_id = data.azurerm_subnet.services.id - + subnet_id = azurerm_subnet.aml.id + tags = local.tre_workspace_service_tags lifecycle { ignore_changes = [tags] } private_dns_zone_group { @@ -25,9 +36,39 @@ resource "azurerm_private_endpoint" "stgblobpe" { } private_service_connection { - name = "pesc-${local.storage_name}" + name = "dnsgroup-blob${local.storage_name}" private_connection_resource_id = azurerm_storage_account.aml.id is_manual_connection = false subresource_names = ["Blob"] } + + +} + + +resource "azurerm_private_endpoint" "filepe" { + name = "pe-file-${local.storage_name}" + location = data.azurerm_resource_group.ws.location + resource_group_name = data.azurerm_resource_group.ws.name + subnet_id = azurerm_subnet.aml.id + tags = local.tre_workspace_service_tags + + lifecycle { ignore_changes = [tags] } + + private_dns_zone_group { + name = "dnsgroup-files-${local.storage_name}" + private_dns_zone_ids = [data.azurerm_private_dns_zone.filecore.id] + } + + private_service_connection { + name = "dnsgroup-file-${var.tre_id}" + private_connection_resource_id = azurerm_storage_account.aml.id + is_manual_connection = false + subresource_names = ["file"] + } + + depends_on = [ + azurerm_private_endpoint.blobpe + ] + } diff --git a/templates/workspace_services/azureml/terraform/variables.tf b/templates/workspace_services/azureml/terraform/variables.tf index 4cc3dca6ae..ca61e4c792 100644 --- a/templates/workspace_services/azureml/terraform/variables.tf +++ b/templates/workspace_services/azureml/terraform/variables.tf @@ -1,17 +1,27 @@ -variable "workspace_id" {} -variable "tre_id" {} -variable "tre_resource_id" {} -variable "arm_use_msi" { - type = bool +variable "workspace_id" { + type = string +} +variable "tre_id" { + type = string +} +variable "tre_resource_id" { + type = string +} +variable "display_name" { + type = string +} +variable "description" { + type = string } -variable "arm_tenant_id" {} -variable "arm_client_id" {} -variable "arm_client_secret" {} -variable "display_name" {} -variable "description" {} variable "is_exposed_externally" { type = bool } +variable "address_space" { + type = string +} +variable "arm_tenant_id" { + type = string +} variable "auth_tenant_id" { type = string description = "Used to authenticate into the AAD Tenant to get app role members" @@ -22,5 +32,6 @@ variable "auth_client_id" { } variable "auth_client_secret" { type = string + sensitive = true description = "Used to authenticate into the AAD Tenant to get app role members" } diff --git a/templates/workspace_services/azureml/user_resources/aml_compute/parameters.json b/templates/workspace_services/azureml/user_resources/aml_compute/parameters.json index afa9df266a..f863764854 100644 --- a/templates/workspace_services/azureml/user_resources/aml_compute/parameters.json +++ b/templates/workspace_services/azureml/user_resources/aml_compute/parameters.json @@ -34,12 +34,6 @@ "env": "VM_SIZE" } }, - { - "name": "auth_tenant_id", - "source": { - "env": "AAD_TENANT_ID" - } - }, { "name": "user_object_id", "source": { diff --git a/templates/workspace_services/azureml/user_resources/aml_compute/porter.yaml b/templates/workspace_services/azureml/user_resources/aml_compute/porter.yaml index 7729c4e290..64ba3f5ad1 100644 --- a/templates/workspace_services/azureml/user_resources/aml_compute/porter.yaml +++ b/templates/workspace_services/azureml/user_resources/aml_compute/porter.yaml @@ -1,12 +1,14 @@ --- schemaVersion: 1.0.0 name: tre-user-resource-aml-compute-instance -version: 0.5.0 +version: 0.5.3 description: "Azure Machine Learning Compute Instance" registry: azuretre dockerfile: Dockerfile.tmpl credentials: + - name: auth_tenant_id + env: AUTH_TENANT_ID - name: azure_tenant_id env: ARM_TENANT_ID - name: azure_subscription_id @@ -28,8 +30,6 @@ parameters: - name: vm_size type: string default: "Standard_DS2_v3" - - name: auth_tenant_id - type: string - name: user_object_id type: string - name: tfstate_resource_group_name @@ -66,12 +66,8 @@ install: tre_resource_id: ${ bundle.parameters.id } parent_service_id: ${ bundle.parameters.parent_service_id } vm_size_sku: ${ bundle.parameters.vm_size } - auth_tenant_id: ${ bundle.parameters.auth_tenant_id } + auth_tenant_id: ${ bundle.credentials.auth_tenant_id } user_object_id: ${ bundle.parameters.user_object_id } - arm_tenant_id: ${ bundle.credentials.azure_tenant_id } - arm_client_id: ${ bundle.credentials.azure_client_id } - arm_client_secret: ${ bundle.credentials.azure_client_secret } - arm_use_msi: ${ bundle.parameters.arm_use_msi } backendConfig: resource_group_name: ${ bundle.parameters.tfstate_resource_group_name } storage_account_name: ${ bundle.parameters.tfstate_storage_account_name } @@ -79,11 +75,21 @@ install: key: tre-user-resource-aml-compute-instance-${ bundle.parameters.id } upgrade: - - exec: - description: "Upgrade shared service" - command: echo - arguments: - - "This shared service does not implement upgrade action" + - terraform: + description: "Deploy service" + vars: + workspace_id: ${ bundle.parameters.workspace_id } + tre_id: ${ bundle.parameters.tre_id } + tre_resource_id: ${ bundle.parameters.id } + parent_service_id: ${ bundle.parameters.parent_service_id } + vm_size_sku: ${ bundle.parameters.vm_size } + auth_tenant_id: ${ bundle.credentials.auth_tenant_id } + user_object_id: ${ bundle.parameters.user_object_id } + backendConfig: + resource_group_name: ${ bundle.parameters.tfstate_resource_group_name } + storage_account_name: ${ bundle.parameters.tfstate_storage_account_name } + container_name: ${ bundle.parameters.tfstate_container_name } + key: tre-user-resource-aml-compute-instance-${ bundle.parameters.id } uninstall: - terraform: @@ -94,12 +100,8 @@ uninstall: tre_resource_id: ${ bundle.parameters.id } parent_service_id: ${ bundle.parameters.parent_service_id } vm_size_sku: ${ bundle.parameters.vm_size } - auth_tenant_id: ${ bundle.parameters.auth_tenant_id } + auth_tenant_id: ${ bundle.credentials.auth_tenant_id } user_object_id: ${ bundle.parameters.user_object_id } - arm_tenant_id: ${ bundle.credentials.azure_tenant_id } - arm_client_id: ${ bundle.credentials.azure_client_id } - arm_client_secret: ${ bundle.credentials.azure_client_secret } - arm_use_msi: ${ bundle.parameters.arm_use_msi } backendConfig: resource_group_name: ${ bundle.parameters.tfstate_resource_group_name } storage_account_name: ${ bundle.parameters.tfstate_storage_account_name } diff --git a/templates/workspace_services/azureml/user_resources/aml_compute/template_schema.json b/templates/workspace_services/azureml/user_resources/aml_compute/template_schema.json index f963259de2..044dfa5ee1 100644 --- a/templates/workspace_services/azureml/user_resources/aml_compute/template_schema.json +++ b/templates/workspace_services/azureml/user_resources/aml_compute/template_schema.json @@ -1,37 +1,50 @@ { - "$schema": "http://json-schema.org/draft-07/schema", - "$id": "https://github.com/microsoft/AzureTRE/templates/workspace_services/azureml/user_resources/aml_compute/custom_parameters.json", - "type": "object", - "title": "Azure Machine Learning Compute Instance", - "description": "Create an Azure Machine Learning compute instance.", - "required": [ - ], - "properties": { - "vm_size": { - "type": "string", - "title": "Virtual Machine Size", - "description": "The size of the virtual machine to be created.", - "enum": [ - "Standard_D2_v3", - "Standard_D4_v3", - "Standard_D8_v3", - "Standard_D16_v3" - ], - "default": "Standard_D2_v3" - }, - "auth_tenant_id": { - "type": "string", - "title": "Azure Active Directory Tenant ID", - "description": "The Azure Active Directory tenant ID of User who will be using the compute instance", - "default": "", - "minLength": 1 - }, - "user_object_id": { - "type": "string", - "title": "Azure Active Directory User Object ID", - "description": "The Azure Active Directory user object ID of User who will be using the compute instance", - "default": "", - "minLength": 1 - } + "$schema": "http://json-schema.org/draft-07/schema", + "$id": "https://github.com/microsoft/AzureTRE/templates/workspace_services/azureml/user_resources/aml_compute/custom_parameters.json", + "type": "object", + "title": "Azure Machine Learning Compute Instance", + "description": "An Azure Machine Learning compute instance is a managed cloud-based workstation for data scientists. Each compute instance has only one owner, although you can share files between multiple compute instances.", + "required": [], + "properties": { + "display_name": { + "type": "string", + "title": "Name for the user resource", + "description": "The name of the user resource to be displayed to users", + "default": "Compute Instance", + "updateable": true + }, + "description": { + "type": "string", + "title": "Description of the user resource", + "description": "Description of the user resource", + "default": "AML Compute Instance", + "updateable": true + }, + "overview": { + "type": "string", + "title": "User Resource Overview", + "description": "Long form description of the user resource, in markdown syntax", + "default": "An Azure Machine Learning compute instance is a managed cloud-based workstation for data scientists. Each compute instance has only one owner, although you can share files between multiple compute instances.\n- [Azure Machine Learning Compute Instance](https://docs.microsoft.com/en-us/azure/machine-learning/concept-compute-instance)", + "updateable": true + }, + "vm_size": { + "type": "string", + "title": "Virtual Machine Size", + "description": "The size of the virtual machine to be created.", + "enum": [ + "Standard_D2_v3", + "Standard_D4_v3", + "Standard_D8_v3", + "Standard_D16_v3" + ], + "default": "Standard_D2_v3" + }, + "user_object_id": { + "type": "string", + "title": "Azure Active Directory User Object ID", + "description": "The Azure Active Directory user object ID of User who will be using the compute instance", + "default": "", + "minLength": 1 } + } } diff --git a/templates/workspace_services/azureml/user_resources/aml_compute/terraform/.terraform.lock.hcl b/templates/workspace_services/azureml/user_resources/aml_compute/terraform/.terraform.lock.hcl index e9fa0d994d..2d50ab9ef5 100644 --- a/templates/workspace_services/azureml/user_resources/aml_compute/terraform/.terraform.lock.hcl +++ b/templates/workspace_services/azureml/user_resources/aml_compute/terraform/.terraform.lock.hcl @@ -2,41 +2,41 @@ # Manual edits may be lost in future updates. provider "registry.terraform.io/azure/azapi" { - version = "0.3.0" - constraints = "0.3.0" + version = "1.1.0" + constraints = "1.1.0" hashes = [ - "h1:KGHPwnrVw1R7UZjCJUwD2ncSR59Evj/woOXq6kMokI0=", - "zh:2d6e75d48f649498982aa0405161f18715ce61f651e3bfb798d5eca19241e450", - "zh:472f93b81b30e07afcea8b56048847f80bc10237a74f75f178a69072a74109ca", - "zh:4b949da7e9c3f98a27a43e579e801e5878d33e9602272c1e79989b7b197db7d4", - "zh:63a5e9f037158dbf9676d7918ff5136cb006e6e44d05518732a1caef76f19032", - "zh:8552d620c2d5af9b947286ea1224642f507e103b542dde66a263bdd401672db4", - "zh:8636c942a64665a7a68b7d8eb8d30b535fe8c3bd5d8b28133b092416006693a3", - "zh:8ab0534b571335b17504a15c697ed71c80b63e78bf265f836bac778efc4b2f2e", - "zh:8f290f233240b4e2771e7a678186033c86b9b30dfcc86b52ee7b8d4552766fb3", - "zh:a425eb1a5d5bd17f5a2398c7efae1de89c09927f4c923da3ab9a6615725e1375", - "zh:c30d4577d22ef1bdf850c70c34be66066ada20739923cfced805a67bd5c0cbb1", - "zh:f5ffb5eb96ffaa4e039569cf4d620dbfce1d68c65b6199b6d057556cadb7fe8f", - "zh:fd6e626c32e8c10edae52e89aac13d43936522d1debe4a60acb8227a562c8173", + "h1:IR+AHCwfjl1c0baWwfOwZ6QZtHj41H2syTgHkJtAr/M=", + "zh:2a25df6325a49f9e821f0b02c7da86167fc19a3bac647cd1edf231300f29d077", + "zh:2b443a836a39724663fe455d4deee408ff3a2d9a8b86f8408aa7db2e8aa743f8", + "zh:364ed09ddfc50d9bed8d930f7de489cb654a9908feb139413a097823a50075fd", + "zh:523bc005f56ae785867d230d55c29f59db4b599dbc6c38b4d03ea55a79458916", + "zh:60ded375fdb305b60bcb4d9e596dbb222cab166bad1b4958199b05a72aaeacfd", + "zh:61e69c58642fead6814e511c872b7c0a6478ec6af4ab758b4512607d910ac078", + "zh:823b2154ae2262dabcbd11aac992e3cc29eae0f7baa96bee1e3e2fe1ece8730b", + "zh:870ea9cc24807ef5142e4cad0281dac7173f7b6bf818a79762b6c690d12d4c4b", + "zh:9094ae76ed66cb328a4f35bd18b9140fb6fc6859c2e46431ec73c018bcb58d96", + "zh:d89149cfd01cb70012459536b4d36490b58e43312440562e5910bd5160537858", + "zh:dba7ec06171ca062fc423ba5b4776a5600444e45e57f4d1cb043bdc3eee538b7", + "zh:ff5bd6883d9ac8334e043434246357a55107411e9a962856c1d17e47ee15ac37", ] } provider "registry.terraform.io/hashicorp/azurerm" { - version = "3.5.0" - constraints = "3.5.0" + version = "3.37.0" + constraints = "3.37.0" hashes = [ - "h1:T4XsCHDT839VehWKdxbVsLn0ECjcQaUTzbSGW055pgM=", - "zh:0d8ae6d6e87f44ed4a178be03d6466339b0bb578ab54c2677e365a8281b0bb7d", - "zh:29d250d1a18d49652b28f234ecd17687b36c875dc47877a678e587d5d136b054", - "zh:2e69ba373cf009e8a60b36d04f3dbc4638708d1bf88be9f96b3e52cbf8f47f31", - "zh:53d525dd84ac63b5f749bfbc6b70a202dacf29597664d2ab1165efea6f24f630", - "zh:a25024d574ccd5ae6c2962f3bb71d510f62899f493b1ed096f2f7f0e2b18f975", - "zh:aabc64fe64319b95aaba1d1866f87abc7b10adae37d2eafa2f85f37317fdd49f", - "zh:acc6a977814897cb23d3b3753213281334238f8bce6d2b21e9f04fc4087ee980", - "zh:b24987e9416c39cd59c0fa41c139a97406b9955f0607fcafbf3315014456338a", - "zh:c550eae45fd32acdbe32b4e5c450ae95df6cb18903ac7216b1b07b23a16ce045", - "zh:c8f83b763b643893dcb6933a6bcee824cb514e06e7e5c5f5ac4ba187e66d7e22", - "zh:dcdac07e7ea18464dea729717870c275de9453775243c231e1fb305cad0ee597", + "h1:83XTgyPKUKt706IjTLHo9HL0KN5m+DwmSKuVQv6dNb4=", + "zh:2a7bda0b7679d1c791c762103a22f333b544b6e6776c4177f33bafc9cc28c919", + "zh:49ff49670c349f918017315838a43ece09bf6f1bf7721b992f1cadbceb273c62", + "zh:55c9346d03380585e17616b79c4233b726d6fb9efa1921848834fc881e5d7d54", + "zh:5ab117b56a4236ea29926e9d95c27d7bf8ae6706d0fffb76c0b1bfe67bf3a78e", + "zh:5cfc086d5d56308edb3e68aac5f8a448ddc6e56541be7b152ae886399e9b2c69", + "zh:7a8929ed38152aac6652711f32193c8582bc996f8fa73879a3ac7a9bf88d2460", + "zh:895294e90a37f719975fcd2269b95e973147e48ec0ebb9c2fe472bc93531b49c", + "zh:8baa5e2b6e5b02df5b45d253a3aea93f22619920cf9577290d682b59a6d5664b", + "zh:b146a732c7909238c10d216b92a35092be4f72a0509a4c6742cc3245bf3b3bf3", + "zh:cedef898ccd512a6519eae3dff7eb0d581d2c3dad8e0001992da16ad1d7fded8", + "zh:f016d9ba94ea88476883b4d63cff88a0225974e0a8b8c3e8555f73c5de6f7119", "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", ] } diff --git a/templates/workspace_services/azureml/user_resources/aml_compute/terraform/compute.tf b/templates/workspace_services/azureml/user_resources/aml_compute/terraform/compute.tf index 554921a0c7..5ff10ccdfe 100644 --- a/templates/workspace_services/azureml/user_resources/aml_compute/terraform/compute.tf +++ b/templates/workspace_services/azureml/user_resources/aml_compute/terraform/compute.tf @@ -1,3 +1,4 @@ +# Using AzApi due to https://github.com/hashicorp/terraform-provider-azurerm/issues/15362 resource "azapi_resource" "compute_instance" { type = "Microsoft.MachineLearningServices/workspaces/computes@2022-06-01-preview" name = local.aml_compute_instance_name @@ -20,7 +21,7 @@ resource "azapi_resource" "compute_instance" { } } subnet = { - id = data.azurerm_subnet.services.id + id = data.azurerm_subnet.aml.id } } } diff --git a/templates/workspace_services/azureml/user_resources/aml_compute/terraform/data.tf b/templates/workspace_services/azureml/user_resources/aml_compute/terraform/data.tf index bed90ff9d4..2c69844b09 100644 --- a/templates/workspace_services/azureml/user_resources/aml_compute/terraform/data.tf +++ b/templates/workspace_services/azureml/user_resources/aml_compute/terraform/data.tf @@ -7,8 +7,8 @@ data "azurerm_virtual_network" "ws" { resource_group_name = data.azurerm_resource_group.ws.name } -data "azurerm_subnet" "services" { - name = "ServicesSubnet" +data "azurerm_subnet" "aml" { + name = "AMLSubnet${local.short_service_id}" virtual_network_name = data.azurerm_virtual_network.ws.name resource_group_name = data.azurerm_virtual_network.ws.resource_group_name } diff --git a/templates/workspace_services/azureml/user_resources/aml_compute/terraform/providers.tf b/templates/workspace_services/azureml/user_resources/aml_compute/terraform/providers.tf index bc6bfbdf3e..ae58c6f613 100644 --- a/templates/workspace_services/azureml/user_resources/aml_compute/terraform/providers.tf +++ b/templates/workspace_services/azureml/user_resources/aml_compute/terraform/providers.tf @@ -1,20 +1,21 @@ -# Azure Provider source and version being used terraform { required_providers { azurerm = { source = "hashicorp/azurerm" - version = "=3.5.0" + version = "=3.37.0" } azapi = { source = "Azure/azapi" - version = "=0.3.0" + version = "=1.1.0" } } - backend "azurerm" { - } -} + backend "azurerm" {} +} provider "azurerm" { - features {} + features { + } } + +provider "azapi" {}