|
| 1 | +--- |
| 2 | +page_title: "Provisioning Databricks on Azure with Private Link - Simple deployment" |
| 3 | +--- |
| 4 | + |
| 5 | +# Deploying pre-requisite resources and enabling Private Link connections |
| 6 | + |
| 7 | +-> **Note** This guide assumes that connectivity from the on-premises user environment is already configured using ExpressRoute or a VPN gateway connection. |
| 8 | + |
| 9 | +Databricks Private Link support enables private connectivity between users and their Databricks workspaces and between clusters on the data plane and core services on the control plane within the Databricks workspace infrastructure. |
| 10 | + |
| 11 | +You can use Terraform to deploy the underlying cloud resources and the private access settings resources automatically, using a programmatic approach. |
| 12 | + |
| 13 | + |
| 14 | +This guide covers a [simple deployment](https://learn.microsoft.com/en-us/azure/databricks/administration-guide/cloud-configurations/azure/private-link-simplified) to configure Azure Databricks with Private Link: |
| 15 | +* No separate VNet separates user access from the VNet that you use for your compute resources in the Classic data plane |
| 16 | +* A transit subnet in the data plane VNet is used for user access |
| 17 | +* Only a single private endpoint is used for both front-end and back-end connectivity. |
| 18 | +* A separate private endpoint is used for web authentication |
| 19 | +* The same Databricks workspace is used for web authentication traffic but Databricks strongly recommends creating a separate workspace called a private web auth workspace for each region to host the web auth private network settings. |
| 20 | + |
| 21 | + |
| 22 | + |
| 23 | +This guide uses the following variables: |
| 24 | + |
| 25 | +- `cidr`: The CIDR for the Azure Vnet |
| 26 | +- `rg_name`: The name of the existing resource group |
| 27 | +- `location`: The location for Azure resources |
| 28 | + |
| 29 | +This guide is provided as-is and you can use it as the basis for your custom Terraform module. |
| 30 | + |
| 31 | +To get started with Azure Private Link integration, this guide takes you through the following high-level steps: |
| 32 | + |
| 33 | +- Initialize the required providers |
| 34 | +- Configure Azure objects |
| 35 | + - Deploy an Azure Vnet with the following subnets: |
| 36 | + - Public and private subnets for Azure Databricks workspace |
| 37 | + - Private Link subnet that will contain the following private endpoints: |
| 38 | + - Frontend / Backend private endpoint |
| 39 | + - Web_auth private endpoint |
| 40 | + - Configure the private DNS zone in order to add: |
| 41 | + - DNS A record to map connection for workspace access |
| 42 | + - DNS A record(s) for web_auth |
| 43 | +- Workspace Creation |
| 44 | + |
| 45 | +## Provider initialization |
| 46 | + |
| 47 | +Initialize provider |
| 48 | + |
| 49 | +```hcl |
| 50 | +terraform { |
| 51 | + required_providers { |
| 52 | + databricks = { |
| 53 | + source = "databricks/databricks" |
| 54 | + } |
| 55 | + azurerm = { |
| 56 | + source = "hashicorp/azurerm" |
| 57 | + version = ">=3.43.0" |
| 58 | + } |
| 59 | + } |
| 60 | +} |
| 61 | +
|
| 62 | +provider "azurerm" { |
| 63 | + features {} |
| 64 | +} |
| 65 | +``` |
| 66 | + |
| 67 | +Define the required variables |
| 68 | + |
| 69 | +```hcl |
| 70 | +variable "cidr" { |
| 71 | + type = string |
| 72 | +} |
| 73 | +
|
| 74 | +variable "rg_name" { |
| 75 | + type = string |
| 76 | +} |
| 77 | +
|
| 78 | +variable "location" { |
| 79 | + type = string |
| 80 | +} |
| 81 | +
|
| 82 | +data "azurerm_client_config" "current" { |
| 83 | +} |
| 84 | +
|
| 85 | +data "external" "me" { |
| 86 | + program = ["az", "account", "show", "--query", "user"] |
| 87 | +} |
| 88 | +
|
| 89 | +locals { |
| 90 | + prefix = "abd-pl" |
| 91 | + tags = { |
| 92 | + Environment = "Demo" |
| 93 | + Owner = lookup(data.external.me.result, "name") |
| 94 | + } |
| 95 | +} |
| 96 | +``` |
| 97 | + |
| 98 | +## Configure network |
| 99 | + |
| 100 | +### Deploy Azure vnet and subnets |
| 101 | + |
| 102 | +Create a new Azure VNet, the required subnets and associated security groups: |
| 103 | + |
| 104 | +```hcl |
| 105 | +resource "azurerm_virtual_network" "this" { |
| 106 | + name = "${local.prefix}-vnet" |
| 107 | + location = var.location |
| 108 | + resource_group_name = var.rg_name |
| 109 | + address_space = [var.cidr] |
| 110 | + tags = local.tags |
| 111 | +} |
| 112 | +
|
| 113 | +resource "azurerm_network_security_group" "this" { |
| 114 | + name = "${local.prefix}-nsg" |
| 115 | + location = var.location |
| 116 | + resource_group_name = var.rg_name |
| 117 | + tags = local.tags |
| 118 | +} |
| 119 | +
|
| 120 | +resource "azurerm_network_security_rule" "aad" { |
| 121 | + name = "AllowAAD" |
| 122 | + priority = 200 |
| 123 | + direction = "Outbound" |
| 124 | + access = "Allow" |
| 125 | + protocol = "Tcp" |
| 126 | + source_port_range = "*" |
| 127 | + destination_port_range = "443" |
| 128 | + source_address_prefix = "VirtualNetwork" |
| 129 | + destination_address_prefix = "AzureActiveDirectory" |
| 130 | + resource_group_name = var.rg_name |
| 131 | + network_security_group_name = azurerm_network_security_group.this.name |
| 132 | +} |
| 133 | +
|
| 134 | +resource "azurerm_network_security_rule" "azfrontdoor" { |
| 135 | + name = "AllowAzureFrontDoor" |
| 136 | + priority = 201 |
| 137 | + direction = "Outbound" |
| 138 | + access = "Allow" |
| 139 | + protocol = "Tcp" |
| 140 | + source_port_range = "*" |
| 141 | + destination_port_range = "443" |
| 142 | + source_address_prefix = "VirtualNetwork" |
| 143 | + destination_address_prefix = "AzureFrontDoor.Frontend" |
| 144 | + resource_group_name = var.rg_name |
| 145 | + network_security_group_name = azurerm_network_security_group.this.name |
| 146 | +} |
| 147 | +
|
| 148 | +resource "azurerm_subnet" "public" { |
| 149 | + name = "${local.prefix}-public" |
| 150 | + resource_group_name = var.rg_name |
| 151 | + virtual_network_name = azurerm_virtual_network.this.name |
| 152 | + address_prefixes = [cidrsubnet(var.cidr, 3, 0)] |
| 153 | +
|
| 154 | + delegation { |
| 155 | + name = "databricks" |
| 156 | + service_delegation { |
| 157 | + name = "Microsoft.Databricks/workspaces" |
| 158 | + actions = [ |
| 159 | + "Microsoft.Network/virtualNetworks/subnets/join/action", |
| 160 | + "Microsoft.Network/virtualNetworks/subnets/prepareNetworkPolicies/action", |
| 161 | + "Microsoft.Network/virtualNetworks/subnets/unprepareNetworkPolicies/action"] |
| 162 | + } |
| 163 | + } |
| 164 | +} |
| 165 | +
|
| 166 | +resource "azurerm_subnet_network_security_group_association" "public" { |
| 167 | + subnet_id = azurerm_subnet.public.id |
| 168 | + network_security_group_id = azurerm_network_security_group.this.id |
| 169 | +} |
| 170 | +
|
| 171 | +variable "private_subnet_endpoints" { |
| 172 | + default = [] |
| 173 | +} |
| 174 | +
|
| 175 | +resource "azurerm_subnet" "private" { |
| 176 | + name = "${local.prefix}-private" |
| 177 | + resource_group_name = var.rg_name |
| 178 | + virtual_network_name = azurerm_virtual_network.this.name |
| 179 | + address_prefixes = [cidrsubnet(var.cidr, 3, 1)] |
| 180 | +
|
| 181 | + enforce_private_link_endpoint_network_policies = true |
| 182 | + enforce_private_link_service_network_policies = true |
| 183 | +
|
| 184 | + delegation { |
| 185 | + name = "databricks" |
| 186 | + service_delegation { |
| 187 | + name = "Microsoft.Databricks/workspaces" |
| 188 | + actions = [ |
| 189 | + "Microsoft.Network/virtualNetworks/subnets/join/action", |
| 190 | + "Microsoft.Network/virtualNetworks/subnets/prepareNetworkPolicies/action", |
| 191 | + "Microsoft.Network/virtualNetworks/subnets/unprepareNetworkPolicies/action"] |
| 192 | + } |
| 193 | + } |
| 194 | +
|
| 195 | + service_endpoints = var.private_subnet_endpoints |
| 196 | +} |
| 197 | +
|
| 198 | +resource "azurerm_subnet_network_security_group_association" "private" { |
| 199 | + subnet_id = azurerm_subnet.private.id |
| 200 | + network_security_group_id = azurerm_network_security_group.this.id |
| 201 | +} |
| 202 | +
|
| 203 | +
|
| 204 | +resource "azurerm_subnet" "plsubnet" { |
| 205 | + name = "${local.prefix}-privatelink" |
| 206 | + resource_group_name = var.rg_name |
| 207 | + virtual_network_name = azurerm_virtual_network.this.name |
| 208 | + address_prefixes = [cidrsubnet(var.cidr, 3, 2)] |
| 209 | + enforce_private_link_endpoint_network_policies = true |
| 210 | +} |
| 211 | +
|
| 212 | +``` |
| 213 | + |
| 214 | +### Deploy Azure private endpoints |
| 215 | + |
| 216 | +#### Frontend / Backend private endpoint |
| 217 | + |
| 218 | +Create a private endpoint with sub resource **databricks_ui_api**: |
| 219 | + |
| 220 | + |
| 221 | +```hcl |
| 222 | +resource "azurerm_private_endpoint" "uiapi" { |
| 223 | + name = "uiapipvtendpoint" |
| 224 | + location = var.location |
| 225 | + resource_group_name = var.rg_name |
| 226 | + subnet_id = azurerm_subnet.plsubnet.id |
| 227 | +
|
| 228 | + private_service_connection { |
| 229 | + name = "ple-${var.workspace_prefix}-uiapi" |
| 230 | + private_connection_resource_id = azurerm_databricks_workspace.this.id |
| 231 | + is_manual_connection = false |
| 232 | + subresource_names = ["databricks_ui_api"] |
| 233 | + } |
| 234 | +
|
| 235 | + private_dns_zone_group { |
| 236 | + name = "private-dns-zone-uiapi" |
| 237 | + private_dns_zone_ids = [azurerm_private_dns_zone.dnsuiapi.id] |
| 238 | + } |
| 239 | +} |
| 240 | +
|
| 241 | +resource "azurerm_private_dns_zone" "dnsuiapi" { |
| 242 | + name = "privatelink.azuredatabricks.net" |
| 243 | + resource_group_name = var.rg_name |
| 244 | +} |
| 245 | +
|
| 246 | +resource "azurerm_private_dns_zone_virtual_network_link" "uiapidnszonevnetlink" { |
| 247 | + name = "uiapispokevnetconnection" |
| 248 | + resource_group_name = var.rg_name |
| 249 | + private_dns_zone_name = azurerm_private_dns_zone.dnsuiapi.name |
| 250 | + virtual_network_id = azurerm_virtual_network.this.id // connect to spoke vnet |
| 251 | +} |
| 252 | +``` |
| 253 | + |
| 254 | +#### Web auth private endpoint |
| 255 | + |
| 256 | +Create a private endpoint with sub resource **browser_authentication**: |
| 257 | + |
| 258 | +```hcl |
| 259 | +resource "azurerm_private_endpoint" "auth" { |
| 260 | + name = "aadauthpvtendpoint" |
| 261 | + location = var.location |
| 262 | + resource_group_name = var.rg_name |
| 263 | + subnet_id = azurerm_subnet.plsubnet.id |
| 264 | +
|
| 265 | + private_service_connection { |
| 266 | + name = "ple-${var.workspace_prefix}-auth" |
| 267 | + private_connection_resource_id = azurerm_databricks_workspace.this.id |
| 268 | + is_manual_connection = false |
| 269 | + subresource_names = ["browser_authentication"] |
| 270 | + } |
| 271 | +
|
| 272 | + private_dns_zone_group { |
| 273 | + name = "private-dns-zone-auth" |
| 274 | + private_dns_zone_ids = [azurerm_private_dns_zone.dnsdpcp.id] |
| 275 | + } |
| 276 | +} |
| 277 | +``` |
| 278 | + |
| 279 | +## Configure workspace |
| 280 | + |
| 281 | +Deploy an Azure Databricks workspace |
| 282 | + |
| 283 | +```hcl |
| 284 | +resource "azurerm_databricks_workspace" "this" { |
| 285 | + name = "${local.prefix}-workspace" |
| 286 | + resource_group_name = var.rg_name |
| 287 | + location = var.location |
| 288 | + sku = "premium" |
| 289 | + tags = local.tags |
| 290 | + public_network_access_enabled = false |
| 291 | + network_security_group_rules_required = "NoAzureDatabricksRules" |
| 292 | + customer_managed_key_enabled = true |
| 293 | + custom_parameters { |
| 294 | + no_public_ip = true |
| 295 | + virtual_network_id = azurerm_virtual_network.this.id |
| 296 | + private_subnet_name = azurerm_subnet.private.name |
| 297 | + public_subnet_name = azurerm_subnet.public.name |
| 298 | + public_subnet_network_security_group_association_id = azurerm_subnet_network_security_group_association.public.id |
| 299 | + private_subnet_network_security_group_association_id = azurerm_subnet_network_security_group_association.private.id |
| 300 | + storage_account_name = "dbfs" |
| 301 | + } |
| 302 | + |
| 303 | + depends_on = [ |
| 304 | + azurerm_subnet_network_security_group_association.public, |
| 305 | + azurerm_subnet_network_security_group_association.private |
| 306 | + ] |
| 307 | +} |
| 308 | +``` |
| 309 | + |
| 310 | +-> **Note** The public network access to the workspace is disabled. You can access the workspace only through the private connectivity to the on-premises user environment. For testing purposes, you can deploy an Azure VM in the same vnet in order to test the frontend connectivity. |
0 commit comments