Azure Databricks · Networking & Security · Stage 3

Classic Compute Plane Networking

The one compute model where Spark runs on VMs in your subscription — so the customer's network team owns and hardens the pipes. Five decisions, mostly one-way doors: who owns the VNet, how big the subnets are, SCC, egress, and the path to your storage.
Azure-first 3.1 Managed vs Injection 3.2 Subnet Sizing 3.3 SCC / No Public IP 3.4 Egress 3.5 Compute → Storage

Build the building behind doors ② and ③

Stage 2 said there are only three doors: ① users in, ② compute ↔ control, ③ compute → your data. Stage 3 is the construction project for the building behind doors ② and ③ — the classic compute plane, where Databricks runs Spark on VMs in your Azure subscription.

🧠 Mental model — hold this in your head

Classic compute is a building you lease land for and fit out yourself. ① Pick the lot (managed VNet = locked apartment vs VNet injection = your plot — permanent). ② Pour the foundation (two equal address streets, sized for peak — you can't re-pave). ③ Wire the intercom (SCC: the building always dials out, so no inbound door). ④ Build the loading dock (NSG = if, UDR = which road, NAT = return address). ⑤ Run a private corridor to the shop (storage: public / Service Endpoint / Private Endpoint). SCC keeps clusters private in both VNet models; injection is what lets you own every other hop — and most of these are one-way doors.

Static topology (zoom-crisp, reusable in slides)

Stage 3 classic compute plane: VNet-injected host and container subnets (no public IP)
      delegated to Microsoft.Databricks/workspaces; container subnet dials outbound 443 to the SCC relay; egress chain of
      NSG, UDR and NAT gateway; storage firewall on ADLS Gen2 reached via Service Endpoint (backbone) or Private Endpoint
      (private IP); Service Endpoint Policy cannot attach to the delegated subnet.
The same map as the interactive diagrams — injected VNet, the two delegated subnets, SCC outbound to the relay, the NSG→UDR→NAT egress chain, and three storage routes to one ADLS account.

Where each subtopic sits on the three-path scaffold

PathWhat travelsStage-3 control
① User → DatabricksBrowser / BI / REST → workspace URLNot in Stage 3 — IP ACL / front-end PL (Stage 4)
② Compute ↔ ControlCluster phones home to be managed3.3 SCC (inbound) + 3.4 egress (outbound); back-end PL later
③ Compute → StorageCluster reads/writes your ADLS3.5 storage firewall + Service/Private Endpoint (via 3.4 plumbing)
(All)—3.1 injection owns the pipes; 3.2 sizing caps the node count

The line a security team wants to hear

"Clusters run in your VNet with no public IPs and no open inbound ports; they dial out to the control plane. Egress leaves on a stable NAT IP you can allowlist, and your data stays in your firewalled ADLS Gen2 reached over the Microsoft backbone."

Terms used here (full deep-dive in the tab noted)

VNet injection
Deploying clusters into your VNet so you control subnets/NSG/routing. → 3.1
Subnet delegation
Handing a subnet to Microsoft.Databricks/workspaces to auto-manage it. → 3.1
SCC / No Public IP
Clusters dial outbound to the SCC relay; no public IP, no inbound port. → 3.3
NSG / UDR / NAT
Egress: if a packet leaves · which road · what public IP. → 3.4
Service / Private Endpoint
Backbone+VNet-rule (free) vs a private IP NIC in your VNet (paid). → 3.5

3.1 · Default (managed) VNet vs VNet injection

The first decision: let Databricks run a locked managed VNet, or inject the workspace into a VNet you own. The choice is permanent and it gates every advanced control. Switch the diagram and click any box for the "what + why."

TipClick any component to see what it is and why it's there.

The choice is irreversible — and gates everything

You can't convert a managed-VNet workspace to injection later (that's a rebuild + migration). NSG egress rules, UDR→firewall, service/private endpoints, back-end Private Link, on-prem routing — all require injection. SCC / No Public IP works in both; injection adds the customization.

Managed VNet vs injection

DimensionManaged VNetVNet injection
Who owns itDatabricks, locked, managed RGYou, your subscription
CIDR / NSG Deny / UDR❌ none selectable✅ you control
Service/Private Endpoint, back-end PL, on-prem❌✅
SCC / No Public IP✅ default✅ default, recommended
Convert later❌ not convertiblen/a
Use forPOC / demo / trainingAny production / regulated

Illustrative config — the delegation + the one flag that declares injection

Terraform (azurerm) — the lines that teach the point. Full module is the Stage-3 hands-on artifact.

resource "azurerm_subnet" "host" {           # both subnets PRIVATE under SCC
  address_prefixes = ["10.179.0.0/18"]
  delegation {                               # REQUIRED: lets Databricks manage the subnet
    name = "databricks-del"
    service_delegation { name = "Microsoft.Databricks/workspaces" }
  }
}
resource "azurerm_databricks_workspace" "this" {
  sku = "premium"
  custom_parameters {
    virtual_network_id = azurerm_virtual_network.adb.id   # <-- THIS declares VNet injection
    no_public_ip       = true                             # SCC in either model
  }
}

Portal: Create → Azure Databricks → Networking → Deploy in your own VNet = Yes → pick the VNet + host/container subnets. Verify: VNet → Subnets → both show an NSG + Delegation = Microsoft.Databricks/workspaces.

Edge case — managed NSG rules & the SEP cutoff

Editing a Databricks-managed NSG rule is futile — the network intent policy reconciles it back; add your own Deny rules instead. And Service Endpoint Policies: workspaces created on/after 2025-07-14 support them by default; older ones need account-team enablement (injection + SCC + unlocked RG). Verify per workspace.

3.2 · Subnets & address-space sizing

A VNet-injected workspace needs two equal subnets — host + container. Every node is a duplex that burns one IP in each, and you can never re-pave the streets. Switch the diagram between the node-IP view and the sizing-math view.

TipClick any box to see what it is and why it's there.

Sizing is a one-way door

"Subnet CIDR ranges cannot be changed after deployment." A too-small subnet caps how many nodes the workspace can ever run. The only fixes — the Public-Preview Update workspace network configuration migration or an account-team CIDR increase — both involve downtime.

The numbers

SubnetUsable (total − 5 reserved)≈ Max nodes (all clusters)
/26 (recommended floor)59~59
/24251~251
/221,019~1,019
/204,091~4,091

VNet /16–/24; subnets up to /26 (min /28). Azure reserves 5 IPs/subnet. Max nodes ≈ 2^(32 − prefix) − 5, counted across all running clusters at once.

Illustrative config — sizing + delegation (the permanent part)

resource "azurerm_virtual_network" "adb" {
  address_space = ["10.179.0.0/16"]          # /16: room for big subnets + a future PL subnet
}
resource "azurerm_subnet" "host"      { address_prefixes = ["10.179.0.0/18"] }   # 16,379 usable
resource "azurerm_subnet" "container" { address_prefixes = ["10.179.64.0/18"] }  # MUST equal host, no overlap
# 10.179.128.0/18 left FREE -> headroom for a /27-/28 Private Link subnet (Stage 4).

Portal: VNet → IP addresses (set space a couple of bits larger than the subnets) → + Add subnet twice (equal, non-overlapping, leave a gap) → deploy the workspace into them.

Decision rule

Dev/small → /26; typical team → /24; large/concurrent → /22–/20. When peak is unknown, size up — IPs are free; a resize is a downtime outage. Always leave the VNet a couple of bits larger than the two subnets so a Private Link subnet fits later.

3.3 · Secure Cluster Connectivity (SCC) / No Public IP

SCC reverses the call direction: the cluster dials out to the SCC relay and the control plane talks back down that tunnel — so no public IP on the VM, no inbound port. Step the diagram through the SCC handshake and the egress; click any box for the "what + why."

TipClick any component to see what it is and why it's there.

The senior nuance — "No Public IP" ≠ no public addressing anywhere

SCC removes the public IP from your VM and the inbound port. But the cluster's outbound call still targets a public IP control-plane endpoint (that's why AzureDatabricks is in your egress allowlist) — over the Microsoft backbone. Back-end Private Link (Stage 4) makes that last outbound hop private.

SCC disabled vs enabled vs + Private Link

AspectDisabled (legacy)Enabled (default)+ back-end PL
Cluster VM public IPYesNoNo
Open inbound portsYesNoNo
Call directionCP inboundCluster outboundCluster → private relay
CP-side endpointPublic IPPublic IPPrivate IP
Needs AzureDatabricks egress tagYesYesNo

Illustrative config — the entire SCC switch

resource "azurerm_databricks_workspace" "this" {
  sku = "premium"
  custom_parameters {
    no_public_ip       = true     # <-- THIS is Secure Cluster Connectivity / No Public IP
    virtual_network_id = var.vnet_id
  }
}
# ARM: parameters.enableNoPublicIp.value = true  (defaults to true in API 2024-05-01+)

Portal: Create → Networking → Secure Cluster Connectivity (No Public IP) = Yes (default). Verify: Managed RG → cluster VM → Properties → Networking → Public IP is empty.

Egress is now what you manage

Because the cluster initiates everything outbound, attach an Azure NAT Gateway (Standard, static IP) to both subnets for a stable allowlist-able egress IP. Don't use an egress load balancer (SNAT exhaustion). After 2026-03-31 new Azure VNets have no implicit outbound — a NAT gateway is effectively mandatory or clusters won't start.

3.4 · Egress — NSG rules, UDRs, NAT gateway

Once the VMs are private, three primitives control the outbound door: NSG = allowed?, UDR = which path?, NAT = what public IP?. Switch the diagram between plain NAT egress and the firewall-UDR (DEP) pattern; click any box for the "what + why."

TipClick any component to see what it is and why it's there.

Routing precedence — the allowlist gotcha

A 0.0.0.0/0 UDR to a firewall/NVA overrides the NAT Gateway (order: UDR-to-NVA » NAT » instance IP » LB rules » default route). So if you route everything to the firewall, the firewall's IP is the egress source — allowlist that, not the NAT IP. Keep AzureDatabricks/Storage/ EventHub service-tag → Internet UDRs so the SCC relay skips the firewall hop.

What a cluster must reach (service tags, not raw IPs)

Service tagPort(s)For
AzureDatabricks443 · 3306 · 8443–8451SCC relay + web app/REST; legacy metastore; internal CP calls + UC lineage/logging
Storage443Artifact + log Blob storage
EventHub9093Telemetry / logging
(NFS)111 · 2049Library installs if you tighten egress

Illustrative config — NAT + firewall UDR (keep relay direct) + a neighbor deny

resource "azurerm_route" "to_firewall" {       # all other egress -> Azure Firewall
  address_prefix = "0.0.0.0/0"                 # NOTE: this UDR OVERRIDES the NAT gateway
  next_hop_type  = "VirtualAppliance"
  next_hop_in_ip_address = "10.10.0.4"
}
resource "azurerm_route" "databricks_direct" { # keep SCC relay DIRECT (skip firewall hop)
  address_prefix = "AzureDatabricks"           # service tag as route prefix (repeat: Storage, EventHub)
  next_hop_type  = "Internet"
}

Portal: NAT gateway → attach to both subnets; Route tables → 0.0.0.0/0 → Virtual appliance (firewall IP) + AzureDatabricks/Storage/EventHub → Internet → associate to both subnets. Never delete the managed NSG rules — add Deny rules on neighbor subnets instead.

NSGs are L4 only

An NSG filters by IP/port/service-tag — not by FQDN. "Allow only pypi.org" needs Azure Firewall application rules, not an NSG. NSG Deny rules cut lateral movement; the firewall does FQDN allowlisting (the Data Exfiltration Protection pattern, Stage 4).

3.5 · Compute → storage: public / service / private endpoints

Your cluster reads ADLS Gen2. By default that's a public endpoint; a storage firewall slams it shut and you re-open a controlled door via a Service Endpoint (free, backbone) or a Private Endpoint (paid, private IP). Switch the diagram between the three routes; click any box.

TipPick a route above, then click a box to see the "what + why."

The footgun — Service Endpoint Policies can't attach to the Databricks subnet

A SEP (allow-list of which storage accounts a subnet may reach) is unsupported on subnets delegated to a managed service — and because a SEP denies anything unlisted, it would block the managed-service infra storage and break the workspace. For exfiltration control use Azure Firewall + UDR FQDN allowlist (3.4) or a Private Endpoint + Public access Disabled.

Public vs Service vs Private Endpoint

DimensionPublicService EndpointPrivate Endpoint
PathNAT → public IPBackbone, private src IPPrivate Link, private IP
New private IP / DNS change?No / NoNo / NoYes / Yes
CostEgress onlyFreeHourly + per-GB
Reaches on-prem?Yes (public)NoYes
Public access can be Disabled?NoNoYes

Illustrative config — Service Endpoint path (free)

resource "azurerm_subnet" "container" {
  service_endpoints = ["Microsoft.Storage"]            # <-- the Service Endpoint switch
  delegation { service_delegation { name = "Microsoft.Databricks/workspaces" } }  # still required
}
resource "azurerm_storage_account_network_rules" "lake" {
  default_action             = "Deny"                   # <-- closes the public door
  virtual_network_subnet_ids = [azurerm_subnet.host.id, azurerm_subnet.container.id]  # the VNet rule
}
# DNS unchanged. For Private Endpoint: a /28 PE subnet + privatelink.dfs.core.windows.net + public access Disabled.

Portal: Storage account → Networking → Enabled from selected VNets/IPs → add host + container subnets (auto-creates the SE) → Save. Add the VNet rule before setting Deny — the source-IP switch drops open connections.

Decision guide — what an architect recommends

VNet injection + SCC + NAT (the baseline)

  • Any production or regulated workload
  • Security team must own/inspect the network path
  • Size subnets for peak nodes; leave VNet room for a PL subnet
  • NAT gateway (Static Standard IP) on both subnets for a stable egress IP
  • Free, backbone-private; the floor for everything else

Managed VNet

  • Throwaway POC / demo / training only
  • Zero network customization needed
  • Still no public IPs (SCC by default)
  • Accept that it's locked and not convertible

Step up when mandated

  • "No CP traffic on a public IP" → back-end Private Link
  • FQDN egress allowlisting / exfiltration → UDR → Azure Firewall
  • "No public storage endpoint" / on-prem reach → Private Endpoint + Disabled
  • Serverless in scope → NCC (not SE/PE/NSG — no customer VNet)

Rule of thumb

Size for peak and inject on day one; start free, step up only when mandated. SCC + NAT-gateway egress and storage-firewall + Service Endpoint cost nothing and are backbone-private. Add Private Link / Private Endpoints only when a regulator demands no public-IP hop or on-prem reach. Premium tier is the non-negotiable baseline.

Customer Q&A — what the security team actually asks

The one-liner
"Clusters run in your VNet with no public IPs and no open inbound ports — they dial out to the control plane. Egress leaves on a stable NAT IP you can allowlist, and your data stays in your firewalled ADLS Gen2 reached over the Microsoft backbone. We inject and size on day one because most of these are one-way doors; we add Private Link / Private Endpoints only when a regulator demands no public-IP hop."

Common asks & the answer

Customer asks…Architect answers…
"Can we start managed and inject later?"No — the choice is permanent and not convertible; a managed workspace becomes a rebuild + migration. We inject from day one for anything prod-bound.
"Do cluster VMs have public IPs / open inbound ports?"No to both — SCC dials out to the relay; verify on the VM: Properties → Networking → Public IP is empty.
"Does management traffic hit the public internet?"The inbound path is gone; the outbound relay call still targets a public CP endpoint over the backbone — until back-end Private Link.
"Can we get one stable egress IP for our allowlist?"Yes — Azure NAT Gateway with a Static Standard IP on both subnets. (If you route 0.0.0.0/0 to a firewall, allowlist the firewall's IP instead.)
"How many nodes can this workspace ever run?"Usable IPs in one subnet (2^(32−prefix) − 5), across all running clusters. Subnets can't be resized without downtime.
"Does cluster→storage cross the public internet?"With a Service Endpoint, no — backbone with a private source IP. With a Private Endpoint, private end-to-end (and we can set Public access = Disabled).

What breaks in the field — and the FIRST check

Clusters stuck "Pending" on a fresh VNet

Post-2026-03-31 new VNets have no implicit outbound, so the cluster can't reach the relay.First check: NAT gateway attached to BOTH subnets — not a CP outage.

IaC deploy fails on the subnets

A subnet isn't delegated to the workspace service.First check: both subnets declare Microsoft.Databricks/workspaces delegation.

Cluster won't start / autoscale stalls (no IPs)

Subnet sized for today, not peak; 2 IPs/node + 5 reserved.First check: free IPs on BOTH subnets vs peak nodes × 2.

UC lineage/logging fails after hardening

The managed 8443–8451 outbound rule was deleted or shadowed.First check: that managed NSG rule + any higher-priority deny.

Partner allowlist rejects despite a NAT

A 0.0.0.0/0 → firewall UDR overrides the NAT.First check: the route table — allowlist the firewall's IP.

"PE created but reads still fail"

The VNet isn't linked to privatelink.dfs.core.windows.net.First check: nslookup the FQDN from a cluster — public IP = DNS.

Three questions to ask before recommending an architecture

  1. Is there a regulatory mandate for no public-IP hop (control plane and/or storage), or is backbone-private enough?
  2. What's the peak concurrent node count — and is there headroom in the VNet for a Private Link subnet later?
  3. Does anything on-prem need to reach the same storage (forces Private Endpoint), and are you on Premium?