Skip to content

Latest commit

Β 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ“Š Microsoft Fabric Workspace Outbound Cloud Connection Rules Terraform Module

Manages a single fabric_workspace_outbound_cloud_connection_rules resource β€” the per-cloud-connection-type outbound allow/deny posture for one Fabric workspace β€” against the microsoft/fabric provider ~> 1.12.0.

Terraform Provider Module Version Module Type Resources Plan Only

🧩 Overview

  • 🌐 Sets a global fallback default_action (Allow | Deny) for every outbound cloud connection type not otherwise covered by a specific rule.
  • 🎯 Optionally defines per-connection-type rules (SQL, LakeHouse, MySQL, Web, etc.), each with its own default_action, an optional set of allowed hostname patterns, and an optional set of allowed target workspace GUIDs.
  • πŸ”€ Not a wrapper around terraform-fabric-connection β€” despite the module name, the confirmed schema has no field referencing a fabric_connection resource instance; connection_type is a category label, not a connection ID. See Β§ Architecture Notes.

πŸ’‘ Why it matters: this is a data-governance control restricting which external cloud connections a workspace's items can reach outbound. Combined with terraform-fabric-workspace-network-communication-policy (which must set outbound.default_action = "Deny" for this module's allow-list to matter at all), it lets a workspace block all outbound connectivity by default and then narrowly permit only named, reviewed connection categories and destinations.


❀️ Support this project

If these Terraform modules have been helpful to you or your organization, I'd appreciate your support in any of the following ways:

Whether it's a star, a professional connection, or a coffee, every gesture helps keep these modules actively maintained and continually improving. Thank you for being part of the community!


πŸ—ΊοΈ Where this fits

flowchart LR
 WS["terraform-fabric-workspace, this workspace"]:::keystone
 WS2["terraform-fabric-workspace, target workspace"]:::sibling
 THIS["terraform-fabric-workspace-outbound-cloud-connection-rules"]:::this
 WS -->|"workspace_id"| THIS
 WS2 -->|"id, into rules.allowed_workspaces"| THIS

 classDef keystone fill:#143551,color:#ffffff,stroke:#143551,stroke-width:2px;
 classDef this fill:#0F6CBD,color:#ffffff,stroke:#0F6CBD,stroke-width:2px;
 classDef sibling fill:#e8e8e8,color:#111111,stroke:#999999,stroke-width:1px;
Loading

Diagram validated for correct rendering before embedding. terraform-fabric-connection is deliberately absent from this diagram β€” the confirmed schema has no reference to it (see Β§ Architecture Notes for why this deviates from the module's original naming-derived hypothesis).

🧬 What this builds

flowchart TB
 subgraph Inputs
 A["workspace_id"]
 B["default_action"]
 C["rules, map keyed by caller-chosen name"]
 D["timeouts"]
 end
 R["fabric_workspace_outbound_cloud_connection_rules.this"]:::this
 A --> R
 B --> R
 C --> R
 D --> R
 R --> O1["workspace_id"]
 R --> O2["default_action"]
 R --> O3["rules"]

 classDef this fill:#0F6CBD,color:#ffffff,stroke:#0F6CBD,stroke-width:2px;
Loading

Resource inventory: 1 resource β€” fabric_workspace_outbound_cloud_connection_rules.this.

βœ… Provider / Versions

Terraform >= 1.12.0
Provider microsoft/fabric ~> 1.12.0
Provider block None β€” the caller configures provider "fabric" {} at the root

Schema notes that bite:

  • No id attribute β€” confirmed via terraform providers schema -json; workspace_id is the sole key. Outputs lead with workspace_id.
  • default_action is required with no documented provider-native default β€” modeled as a required module variable, not guessed, per this suite's secure-by-default convention.
  • rules[].connection_type has no documented closed enum. The provider's Example Usage shows only illustrative values (SQL, LakeHouse); this module cannot validate the string against a fixed list at terraform validate time β€” a typo'd connection_type is a real risk only caught at apply/runtime.
  • allowed_workspaces is honored only for Lakehouse, Warehouse, FabricSql, and PowerPlatformDataflows connection types per Microsoft's own docs; setting it elsewhere is accepted by validate but ignored by the API.
  • rules is an unordered Attributes Set, not a list or map at the API layer β€” this module renders a caller-keyed map(object({...})) into that Set shape via a for expression; the map key is a house-style convenience only, discarded before reaching the provider.
  • This resource had no prior internal house pattern β€” newly discovered and confirmed fresh this session against the live provider schema and the binary provider schema.
  • No delegated-auth requirement (provider doc: "This resource supports Service Principal authentication").

πŸ”‘ Required Fabric / Entra Permissions

  • Fabric: Workspace Admin role on the target workspace.
  • Entra: calling Service Principal (or Managed Identity) enabled under "Service principals can use Fabric APIs".
  • Fabric tenant administrator must have separately enabled the relevant tenant setting (see Prerequisites).

Microsoft Fabric Prerequisites

  • Tenant setting "Configure workspace-level outbound network rules" enabled by a Fabric tenant admin (off by default).
  • Workspace must reside on a Fabric (F SKU) capacity β€” no other capacity type is supported for outbound access protection.
  • This module's rules only matter if terraform-fabric-workspace-network-communication-policy's outbound.default_action is Deny for the same workspace.
  • Universal tenant-level SPN/MSI API access switch.
  • Deployment pipelines are not supported alongside workspace outbound access protection.

πŸ“ Module Structure

terraform-fabric-workspace-outbound-cloud-connection-rules/
β”œβ”€β”€ providers.tf # required_providers floor β€” no provider {} block
β”œβ”€β”€ variables.tf # workspace_id, default_action, rules, timeouts
β”œβ”€β”€ main.tf # fabric_workspace_outbound_cloud_connection_rules.this β€” thin renderer
β”œβ”€β”€ outputs.tf # workspace_id (primary), default_action, rules
β”œβ”€β”€ README.md # this file
β”œβ”€β”€ SCOPE.md # lightweight standalone scope
└── examples/
 β”œβ”€β”€ basic/ # global deny, no per-connection-type rules
 └── complete/ # global deny plus SQL endpoint + Lakehouse cross-workspace carve-outs

βš™οΈ Quick Start

module "outbound_cloud_connection_rules" {
  source = "git::https://github.com/microsoftexpert/terraform-fabric-workspace-outbound-cloud-connection-rules.git?ref=v1.0.0"

  workspace_id   = module.workspace.id
  default_action = "Deny"
}

πŸ”Œ Cross-Module Contract

Consumes

Input Type Source module
workspace_id string terraform-fabric-workspace's id output
rules[*].allowed_workspaces set(string) terraform-fabric-workspace's id output (target workspace)

Emits

Output Description Consumed by
workspace_id Primary output β€” the workspace GUID these rules govern Informational / cross-referencing
default_action Effective global fallback default_action Informational
rules Effective set of per-connection-type rule objects Informational

πŸ“š Example Library

1 Β· Basic β€” global deny, no exceptions
module "outbound_cloud_connection_rules" {
  source = "../../"

  workspace_id   = module.workspace.id # ws-core-bronze-prod
  default_action = "Deny"
}
2 Β· Global allow (permissive posture)
module "outbound_cloud_connection_rules" {
  source = "../../"

  workspace_id   = module.workspace.id # ws-core-sandbox-dev
  default_action = "Allow"
}

⚠️ Reserve for dev/sandbox workspaces β€” default_action = "Allow" is not the recommended posture for a regulated production workspace.

3 Β· Single SQL endpoint carve-out
module "outbound_cloud_connection_rules" {
  source = "../../"

  workspace_id   = module.workspace.id # ws-core-curated-prod
  default_action = "Deny"

  rules = {
    "sql-partner-endpoints" = {
      connection_type   = "SQL"
      default_action    = "Deny"
      allowed_endpoints = ["*.partner-bank.example.com"]
    }
  }
}

ℹ️ connection_type is a plain string with no closed-enum validation β€” double-check spelling against current Microsoft Fabric documentation before applying.

4 Β· Cross-workspace Lakehouse access
module "outbound_cloud_connection_rules" {
  source = "../../"

  workspace_id   = module.workspace.id # ws-core-silver-prod
  default_action = "Deny"

  rules = {
    "lakehouse-cross-workspace" = {
      connection_type    = "LakeHouse"
      default_action     = "Deny"
      allowed_workspaces = [module.gold_workspace.id]
    }
  }
}

πŸ’‘ allowed_workspaces is honored only for Lakehouse, Warehouse, FabricSql, and PowerPlatformDataflows connection types per Microsoft's documentation.

5 Β· Multiple connection types in one resource
module "outbound_cloud_connection_rules" {
  source = "../../"

  workspace_id   = module.workspace.id # ws-core-curated-prod
  default_action = "Deny"

  rules = {
    "sql-partner-endpoints" = {
      connection_type   = "SQL"
      default_action    = "Deny"
      allowed_endpoints = ["*.partner-bank.example.com"]
    }
    "web-vendor-api" = {
      connection_type   = "Web"
      default_action    = "Deny"
      allowed_endpoints = ["api.vendor.example.com"]
    }
  }
}
6 Β· Wildcard hostname patterns
module "outbound_cloud_connection_rules" {
  source = "../../"

  workspace_id   = module.workspace.id # ws-core-bronze-prod
  default_action = "Deny"

  rules = {
    "mysql-vendor-cluster" = {
      connection_type   = "MySQL"
      default_action    = "Deny"
      allowed_endpoints = ["*.vendor-mysql.example.com", "db-replica-*.vendor-mysql.example.com"]
    }
  }
}
7 Β· Multiple allowed target workspaces
module "outbound_cloud_connection_rules" {
  source = "../../"

  workspace_id   = module.workspace.id # ws-core-silver-prod
  default_action = "Deny"

  rules = {
    "warehouse-cross-workspace" = {
      connection_type = "Warehouse"
      default_action  = "Deny"
      allowed_workspaces = [
        module.gold_workspace.id,
        module.reporting_workspace.id,
      ]
    }
  }
}
8 Β· Environment-scoped naming convention
module "outbound_cloud_connection_rules" {
  source = "../../"

  workspace_id   = module.workspace.id # ws-core-bronze-dev
  default_action = "Deny"

  rules = {
    "sql-dev-sandbox-endpoints" = {
      connection_type   = "SQL"
      default_action    = "Deny"
      allowed_endpoints = ["*.dev-sandbox.example.com"]
    }
  }
}

πŸ’‘ The rule's caller-chosen map key (sql-dev-sandbox-endpoints) is a house-style readability aid β€” it is discarded before reaching the Fabric API, but encoding environment in it here helps a reviewer scan the diff.

9 Β· Custom timeouts
module "outbound_cloud_connection_rules" {
  source = "../../"

  workspace_id   = module.workspace.id # ws-core-bronze-prod
  default_action = "Deny"

  timeouts = {
    create = "30m"
  }
}
10 Β· Paired with the workspace-level outbound switch
module "network_communication_policy" {
  source = "git::https://github.com/microsoftexpert/terraform-fabric-workspace-network-communication-policy.git?ref=v1.0.0"

  workspace_id = module.workspace.id
  outbound = {
    public_access_rules = { default_action = "Deny" }
  }
}

module "outbound_cloud_connection_rules" {
  source = "../../"

  workspace_id   = module.workspace.id
  default_action = "Deny"

  rules = {
    "sql-partner-endpoints" = {
      connection_type   = "SQL"
      default_action    = "Deny"
      allowed_endpoints = ["*.partner-bank.example.com"]
    }
  }

  depends_on = [module.network_communication_policy]
}

⚠️ This module's rules have no effect unless the sibling network-communication-policy module's outbound.default_action is Deny for the same workspace β€” there is no Terraform attribute reference between the two, so the ordering is documented via depends_on.

11 Β· At scale β€” for_each over multiple workspaces
variable "curated_workspace_ids" {
  type = map(string)
}

module "outbound_cloud_connection_rules" {
  for_each = var.curated_workspace_ids
  source   = "../../"

  workspace_id   = each.value
  default_action = "Deny"
}

πŸ’‘ for_each over a caller-supplied map β€” adding a fifth workspace never threatens the first four.

12 Β· Guarding against a paused/wrong-SKU capacity
data "fabric_capacity" "target" {
  display_name = "cap-casey-fsku-prod"

  lifecycle {
    postcondition {
      condition     = self.state == "Active"
      error_message = "Target capacity must be Active for outbound access protection reads/writes to behave reliably."
    }
  }
}

module "outbound_cloud_connection_rules" {
  source = "../../"

  workspace_id   = module.workspace.id
  default_action = "Deny"

  depends_on = [data.fabric_capacity.target]
}

⚠️ Outbound access protection additionally requires an F-SKU capacity specifically β€” this postcondition only guards against a paused capacity, not the wrong SKU.

13 Β· Deliberately empty rules β€” deny everything, no exceptions
module "outbound_cloud_connection_rules" {
  source = "../../"

  workspace_id   = module.workspace.id # ws-core-locked-down-prod
  default_action = "Deny"
  rules          = {}
}

πŸ”’ Explicit rules = {} documents intent β€” identical in effect to omitting rules entirely, since {} is this module's own default.

14 Β· Real-Time Events cross-workspace consumption pattern
module "outbound_cloud_connection_rules" {
  source = "../../"

  workspace_id   = module.workspace.id # ws-core-events-consumer-prod
  default_action = "Deny"

  rules = {
    "realtime-events-cross-workspace" = {
      connection_type    = "RealTimeEvents"
      default_action     = "Deny"
      allowed_workspaces = [module.events_source_workspace.id]
    }
  }
}

ℹ️ "RealTimeEvents" is inferred from Microsoft Learn's Fabric-events outbound-protection material, not from the provider's own Example Usage β€” confirm exact spelling against current documentation before applying, since connection_type has no closed-enum validation in this module.

15 Β· πŸ—οΈ End-to-end composition
module "workspace" {
  source = "git::https://github.com/microsoftexpert/terraform-fabric-workspace.git?ref=v1.0.0"

  display_name = "ws-core-curated-prod"
  capacity_id  = data.fabric_capacity.core_fsku_prod.id
}

module "gold_workspace" {
  source = "git::https://github.com/microsoftexpert/terraform-fabric-workspace.git?ref=v1.0.0"

  display_name = "ws-core-gold-prod"
  capacity_id  = data.fabric_capacity.core_fsku_prod.id
}

data "fabric_capacity" "core_fsku_prod" {
  display_name = "cap-casey-fsku-core-prod"
}

module "network_communication_policy" {
  source = "git::https://github.com/microsoftexpert/terraform-fabric-workspace-network-communication-policy.git?ref=v1.0.0"

  workspace_id = module.workspace.id
  outbound = {
    public_access_rules = { default_action = "Deny" }
  }
}

module "outbound_cloud_connection_rules" {
  source = "git::https://github.com/microsoftexpert/terraform-fabric-workspace-outbound-cloud-connection-rules.git?ref=v1.0.0"

  workspace_id   = module.workspace.id
  default_action = "Deny"

  rules = {
    "lakehouse-cross-workspace" = {
      connection_type    = "LakeHouse"
      default_action     = "Deny"
      allowed_workspaces = [module.gold_workspace.id]
    }
  }

  depends_on = [module.network_communication_policy]
}

output "outbound_cloud_connection_rules" {
  value = module.outbound_cloud_connection_rules.rules
}

πŸ—οΈ Wires terraform-fabric-workspace's id output (both the primary and target workspace) into this module's workspace_id/rules.allowed_workspaces, layered on top of terraform-fabric-workspace-network-communication-policy for the top-level outbound switch.

πŸ“₯ Inputs

Variable Type Default Required
workspace_id string β€” βœ…
default_action string (Allow|Deny) β€” βœ…
rules map(object({ connection_type, default_action = string; allowed_endpoints, allowed_workspaces = optional(set(string), []) })) {} ❌
timeouts object({ create, read, update, delete = optional(string) }) null ❌
Full object schemas
variable "workspace_id" {
  type = string
}

variable "default_action" {
  type = string
}

variable "rules" {
  type = map(object({
    connection_type    = string
    default_action     = string
    allowed_endpoints  = optional(set(string), [])
    allowed_workspaces = optional(set(string), [])
  }))
  default = {}
}

variable "timeouts" {
  type = object({
    create = optional(string)
    read   = optional(string)
    update = optional(string)
    delete = optional(string)
  })
  default = null
}

🧾 Outputs

Output Description Sensitive
workspace_id Primary output β€” the workspace GUID (no id attribute exists) No
default_action Effective global fallback default_action No
rules Effective set of per-connection-type rule objects (unordered) No

🧠 Architecture Notes

  • rules is rendered from a caller-keyed map(object({...})) into the provider's unordered Attributes Set via [for _, rule in var.rules: {...}] in main.tf β€” the map key exists purely for readability in the caller's own .tf and is discarded at that boundary.
  • allowed_endpoints/allowed_workspaces are modeled as flat set(string) variables (not map(object({single_field}))) since each genuinely wraps a single scalar field in the provider schema β€” main.tf expands each string into the provider's { hostname_pattern =... } / { workspace_id =... } shape via a for expression.
  • This module does not reference terraform-fabric-connection at all, despite the "cloud connection" name β€” the confirmed schema's connection_type is a category string (SQL, LakeHouse, etc.), not a fabric_connection resource ID. Do not assume this module consumes that sibling's id output; it does not.
  • No id attribute exists on this resource β€” workspace_id is the primary output.

🧱 Design Principles

Concern Safe default Opt-out
Global fallback (default_action) No safe implicit default exists in the provider β€” required, not optional, per this suite's secure-by-default convention Caller must explicitly choose Allow or Deny
Per-connection-type rules (rules) Empty ({}) β€” no carve-outs unless explicitly added Caller supplies named rule entries

πŸš€ Runbook

cd C:\GitHubCode\newfabricmodules\terraform-fabric-workspace-outbound-cloud-connection-rules
terraform init -backend=false
terraform validate
terraform fmt -check

Pin ?ref=v1.0.0 β€” never a branch. Plan-only; a human applies from a reviewed pipeline.

πŸ§ͺ Testing

  • validate/fmt catch: missing workspace_id/default_action, an invalid top-level or per-rule default_action value, malformed rules object shape.
  • Only a live plan/apply exercises: whether connection_type strings are actually valid against the current Fabric API (no closed-enum validation exists in this module), whether the tenant/capacity prerequisites are met, and whether allowed_workspaces is honored for the chosen connection_type.

πŸ’¬ Example Output

workspace_id = "00000000-0000-0000-0000-000000000000"
default_action = "Deny"
rules = [
 {
 connection_type = "SQL"
 default_action = "Deny"
 allowed_endpoints = [{ hostname_pattern = "*.partner-bank.example.com" }]
 allowed_workspaces = []
 },
]

πŸ” Troubleshooting

Symptom Cause Fix
A rule's allowed_endpoints/allowed_workspaces appears to have no effect Field is not honored for the chosen connection_type (e.g. allowed_workspaces set on a SQL rule) Recheck Microsoft's connection-type-specific documentation; move the restriction to the field that type actually supports
apply succeeds but outbound traffic is not actually restricted The sibling terraform-fabric-workspace-network-communication-policy's outbound.default_action is still Allow Set that sibling module's outbound default_action to Deny β€” this module's rules only matter once the top-level switch is closed
A connection_type typo passes validate but fails silently at runtime connection_type has no closed-enum validation in this module Double-check spelling against current Microsoft Fabric documentation before applying
Terraform reports drift on every plan Workspace capacity is paused Resume the capacity before planning/applying (see this suite's region/instance/scope model convention)

πŸ”— Related Docs

About

Terraform module: terraform-fabric-workspace-outbound-cloud-connection-rules

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages