diff --git a/quickstart/201-machine-learning-moderately-secure/.gitignore b/quickstart/201-machine-learning-moderately-secure/.gitignore new file mode 100644 index 00000000..6f8b76c0 --- /dev/null +++ b/quickstart/201-machine-learning-moderately-secure/.gitignore @@ -0,0 +1,37 @@ +# Local .terraform directories +**/.terraform/* + +# .tfstate files +*.tfstate +*.tfstate.* + +# Crash log files +crash.log + +# Ignore any .tfvars files that are generated automatically for each Terraform run. Most +# .tfvars files are managed as part of configuration and so should be included in +# version control. +# +# example.tfvars + +# Ignore override files as they are usually used to override resources locally and so +# are not checked in +override.tf +override.tf.json +*_override.tf +*_override.tf.json +values.tfvars +*.tfvars +settings.tfvars +# Include override files you do wish to add to version control using negated pattern +# +# !example_override.tf + +# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan +# example: *tfplan* +terraform/.terraform.lock.hcl +.DS_Store +terraform/.terraform.lock.hcl +terraform/.terraform.lock.hcl +.terraform.lock.hcl +terraform/.terraform.lock.hcl \ No newline at end of file diff --git a/quickstart/201-machine-learning-moderately-secure/main.tf b/quickstart/201-machine-learning-moderately-secure/main.tf index b6b66a46..67dea407 100644 --- a/quickstart/201-machine-learning-moderately-secure/main.tf +++ b/quickstart/201-machine-learning-moderately-secure/main.tf @@ -4,7 +4,7 @@ terraform { required_providers { azurerm = { source = "hashicorp/azurerm" - version = "=2.72.0" + version = "=2.76.0" } } } diff --git a/quickstart/201-machine-learning-moderately-secure/network.tf b/quickstart/201-machine-learning-moderately-secure/network.tf index dbf1b6a6..b1fcb2e8 100644 --- a/quickstart/201-machine-learning-moderately-secure/network.tf +++ b/quickstart/201-machine-learning-moderately-secure/network.tf @@ -6,11 +6,27 @@ resource "azurerm_virtual_network" "default" { resource_group_name = azurerm_resource_group.default.name } -resource "azurerm_subnet" "mlsubnet" { - name = "mlsubnet" +resource "azurerm_subnet" "training-subnet" { + name = "training-subnet" resource_group_name = azurerm_resource_group.default.name virtual_network_name = azurerm_virtual_network.default.name - address_prefixes = var.subnet_address_space + address_prefixes = var.training_subnet_address_space + enforce_private_link_endpoint_network_policies = true +} + +resource "azurerm_subnet" "aks-subnet" { + name = "aks-subnet" + resource_group_name = azurerm_resource_group.default.name + virtual_network_name = azurerm_virtual_network.default.name + address_prefixes = var.aks_subnet_address_space + enforce_private_link_endpoint_network_policies = true +} + +resource "azurerm_subnet" "ml-subnet" { + name = "ml-subnet" + resource_group_name = azurerm_resource_group.default.name + virtual_network_name = azurerm_virtual_network.default.name + address_prefixes = var.ml_subnet_address_space enforce_private_link_endpoint_network_policies = true } @@ -87,3 +103,110 @@ resource "azurerm_private_dns_zone_virtual_network_link" "vnetlinknbs" { private_dns_zone_name = azurerm_private_dns_zone.dnsnotebooks.name virtual_network_id = azurerm_virtual_network.default.id } + +# Network Security Groups + +resource "azurerm_network_security_group" "training-NSG" { + name = "training-NSG" + location = azurerm_resource_group.default.location + resource_group_name = azurerm_resource_group.default.name + + security_rule { + name = "BatchNodeManagement" + priority = 100 + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_range = "*" + destination_port_range = "29876-29877" + source_address_prefix = "BatchNodeManagement" + destination_address_prefix = "*" + } + security_rule { + name = "AzureMachineLearning" + priority = 110 + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_range = "*" + destination_port_range = "44224" + source_address_prefix = "AzureMachineLearning" + destination_address_prefix = "*" + } +} + +resource "azurerm_subnet_network_security_group_association" "training-NSG-link" { + subnet_id = azurerm_subnet.training-subnet.id + network_security_group_id = azurerm_network_security_group.training-NSG.id +} + +resource "azurerm_network_security_group" "aks-NSG" { + name = "aks-NSG" + location = azurerm_resource_group.default.location + resource_group_name = azurerm_resource_group.default.name + + +} + +resource "azurerm_subnet_network_security_group_association" "aks-NSG-link" { + subnet_id = azurerm_subnet.aks-subnet.id + network_security_group_id = azurerm_network_security_group.aks-NSG.id +} + +# User Defined Routes + +#UDR for Compute instance and compute clusters +resource "azurerm_route_table" "training-UDR" { + name = "training-UDR" + location = azurerm_resource_group.default.location + resource_group_name = azurerm_resource_group.default.name +} + +resource "azurerm_route" "training-Internet-Route" { + name = "Internet" + resource_group_name = azurerm_resource_group.default.name + route_table_name = azurerm_route_table.training-UDR.name + address_prefix = "0.0.0.0/0" + next_hop_type = "Internet" +} + +resource "azurerm_route" "training-AzureMLRoute" { + name = "AzureMLRoute" + resource_group_name = azurerm_resource_group.default.name + route_table_name = azurerm_route_table.training-UDR.name + address_prefix = "AzureMachineLearning" + next_hop_type = "Internet" +} + +resource "azurerm_route" "training-BatchRoute" { + name = "BatchRoute" + resource_group_name = azurerm_resource_group.default.name + route_table_name = azurerm_route_table.training-UDR.name + address_prefix = "BatchNodeManagement" + next_hop_type = "Internet" +} + +resource "azurerm_subnet_route_table_association" "training-UDRlink" { + subnet_id = azurerm_subnet.training-subnet.id + route_table_id = azurerm_route_table.training-UDR.id +} +# Inferencing (AKS) Route + +resource "azurerm_route_table" "aks-UDR" { + name = "aks-UDR" + location = azurerm_resource_group.default.location + resource_group_name = azurerm_resource_group.default.name +} + +resource "azurerm_route" "aks-Internet-Route" { + name = "Internet" + resource_group_name = azurerm_resource_group.default.name + route_table_name = azurerm_route_table.aks-UDR.name + address_prefix = "0.0.0.0/0" + next_hop_type = "Internet" +} + +resource "azurerm_subnet_route_table_association" "aks-UDR-link" { + subnet_id = azurerm_subnet.aks-subnet.id + route_table_id = azurerm_route_table.aks-UDR.id +} \ No newline at end of file diff --git a/quickstart/201-machine-learning-moderately-secure/variables.tf b/quickstart/201-machine-learning-moderately-secure/variables.tf index ae58bfd1..bc226931 100644 --- a/quickstart/201-machine-learning-moderately-secure/variables.tf +++ b/quickstart/201-machine-learning-moderately-secure/variables.tf @@ -17,12 +17,30 @@ variable "location" { variable "vnet_address_space" { type = list(string) - description = "Address space of the subnet" + description = "Address space of the virtual network" default = ["10.0.0.0/16"] } -variable "subnet_address_space" { +variable "training_subnet_address_space" { type = list(string) - description = "Address space of the subnet" + description = "Address space of the training subnet" default = ["10.0.0.0/24"] +} + +variable "aks_subnet_address_space" { + type = list(string) + description = "Address space of the aks subnet" + default = ["10.0.1.0/24"] +} + +variable "ml_subnet_address_space" { + type = list(string) + description = "Address space of the ML workspace subnet" + default = ["10.0.2.0/24"] +} + +variable "image_build_compute_name" { + type = string + description = "Name of the compute cluster to be created and set to build docker images" + default = "image-builder" } \ No newline at end of file diff --git a/quickstart/201-machine-learning-moderately-secure/workspace.tf b/quickstart/201-machine-learning-moderately-secure/workspace.tf index da718bc2..dc4beb33 100644 --- a/quickstart/201-machine-learning-moderately-secure/workspace.tf +++ b/quickstart/201-machine-learning-moderately-secure/workspace.tf @@ -12,7 +12,7 @@ resource "azurerm_key_vault" "default" { resource_group_name = azurerm_resource_group.default.name tenant_id = data.azurerm_client_config.current.tenant_id sku_name = "premium" - purge_protection_enabled = false + purge_protection_enabled = true network_acls { default_action = "Deny" @@ -61,7 +61,7 @@ resource "azurerm_private_endpoint" "kv_ple" { name = "ple-${var.name}-${var.environment}-kv" location = azurerm_resource_group.default.location resource_group_name = azurerm_resource_group.default.name - subnet_id = azurerm_subnet.mlsubnet.id + subnet_id = azurerm_subnet.ml-subnet.id private_dns_zone_group { name = "private-dns-zone-group" @@ -80,7 +80,7 @@ resource "azurerm_private_endpoint" "st_ple_blob" { name = "ple-${var.name}-${var.environment}-st-blob" location = azurerm_resource_group.default.location resource_group_name = azurerm_resource_group.default.name - subnet_id = azurerm_subnet.mlsubnet.id + subnet_id = azurerm_subnet.ml-subnet.id private_dns_zone_group { name = "private-dns-zone-group" @@ -99,7 +99,7 @@ resource "azurerm_private_endpoint" "storage_ple_file" { name = "ple-${var.name}-${var.environment}-st-file" location = azurerm_resource_group.default.location resource_group_name = azurerm_resource_group.default.name - subnet_id = azurerm_subnet.mlsubnet.id + subnet_id = azurerm_subnet.ml-subnet.id private_dns_zone_group { name = "private-dns-zone-group" @@ -118,7 +118,7 @@ resource "azurerm_private_endpoint" "cr_ple" { name = "ple-${var.name}-${var.environment}-cr" location = azurerm_resource_group.default.location resource_group_name = azurerm_resource_group.default.name - subnet_id = azurerm_subnet.mlsubnet.id + subnet_id = azurerm_subnet.ml-subnet.id private_dns_zone_group { name = "private-dns-zone-group" @@ -137,7 +137,7 @@ resource "azurerm_private_endpoint" "mlw_ple" { name = "ple-${var.name}-${var.environment}-mlw" location = azurerm_resource_group.default.location resource_group_name = azurerm_resource_group.default.name - subnet_id = azurerm_subnet.mlsubnet.id + subnet_id = azurerm_subnet.ml-subnet.id private_dns_zone_group { name = "private-dns-zone-group" @@ -153,5 +153,36 @@ resource "azurerm_private_endpoint" "mlw_ple" { subresource_names = [ "amlworkspace" ] is_manual_connection = false } +} +#Compute cluster for image building https://docs.microsoft.com/en-us/azure/machine-learning/tutorial-create-secure-workspace#configure-image-builds -} \ No newline at end of file +resource "azurerm_machine_learning_compute_cluster" "image-builder" { + name = "${var.image_build_compute_name}" + location = azurerm_resource_group.default.location + vm_priority = "LowPriority" + vm_size = "Standard_DS2_v2" + machine_learning_workspace_id = azurerm_machine_learning_workspace.default.id + subnet_resource_id = azurerm_subnet.training-subnet.id + + scale_settings { + min_node_count = 0 + max_node_count = 1 + scale_down_nodes_after_idle_duration = "PT30S" # 30 seconds + } + + identity { + type = "SystemAssigned" + } +} + +# Update workspace for image-build-compute + +resource "null_resource" "ws_image_build_compute"{ + provisioner "local-exec" { + command = <