Manage a Cisco ACI FC domain — a fabric-scoped access-policy object (class
fcDomP, DNuni/fc-{name}) that binds a VSAN pool to a name every Fibre Channel connectivity binding references — as a typed, secure-by-default building block targetingCiscoDevNet/aci ~> 2.20.
This module manages a single ACI FC domain and its pool/attribute bindings as one coherent, secure-by-default unit:
- ⚓ The FC domain (
aci_fc_domain.this) — a fabric-scoped access-policy object in the ACI Management Information Tree (MIT), addressed by the Distinguished Nameuni/fc-{name}. - 🏷️ The ACI metadata tail —
annotation(preserved asorchestrator:terraformso Terraform-managed objects are identifiable in APIC) andname_alias. The live schema for this resource carries nodescription,owner_key/owner_tag, orannotations/tagslist. - 🔗 Classic flat pool/attribute relations — the VSAN pool binding that supplies this domain's Fibre Channel namespace and its resolved/definitive counterpart, an optional VSAN attribute policy binding and its resolved/definitive counterpart, an FCoE VLAN pool binding for FCoE deployments and its resolved/definitive counterpart, and the (rarely used outside GOLF/multi-pod) VIP address pool and VXLAN instance pool associations.
- 🔑 Scope, not credentials — the FC domain is a fabric-root object with no parent DN; authentication and the APIC URL are the caller's provider concern and are never module variables.
💡 Why it matters: the FC domain is the pivot between an access-policy VSAN pool and every downstream object that needs Fibre Channel connectivity — an Attachable Access Entity Profile's domain relation, or an application EPG's static/domain binding. A consistent, identifiable, correctly-bound FC domain keeps that storage-network plumbing auditable.
If these Terraform modules have been helpful to you or your organization, I'd appreciate your support in any of the following ways:
- ⭐ Star this repository to help others discover this Terraform module.
- 🤝 Connect with me on LinkedIn: linkedin.com/in/microsoftexpert
- ☕ Buy me a coffee: buymeacoffee.com/microsoftexpert
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!
graph LR
apic["Cisco APIC fabric (provider auth, out of band)"]:::ext
vsp["terraform-aci-vsan-pool"]:::sib
vp["terraform-aci-vlan-pool"]:::sib
fcd["terraform-aci-fc-domain (this module)"]:::this
fc["aci_fc_domain - class fcDomP - DN uni/fc-{name}"]:::keystone
aaep["terraform-aci-attachable-access-entity-profile"]:::sib
epg["terraform-aci-application-epg"]:::sib
apic -->|"provider configured by caller"| fcd
vsp -->|"vsan_pool_dn"| fcd
vp -->|"vlan_pool_dn (FCoE)"| fcd
fcd -->|"manages"| fc
fcd -->|"fc_domain_dn"| aaep
fcd -->|"fc_domain_dn (domain binding)"| epg
classDef this fill:#00BCEB,color:#fff,stroke:#00BCEB;
classDef keystone fill:#0D274D,color:#fff,stroke:#0D274D;
classDef sib fill:#f5f5f5,color:#333,stroke:#cccccc;
classDef ext fill:#eeeeff,color:#333,stroke:#9999ff;
The FC domain sits between an access-policy VSAN pool and every object that needs Fibre Channel connectivity. It takes no parent DN, consumes a VSAN pool's DN (and, for FCoE, a VLAN pool's DN) as optional relations, and emits an id (its DN, uni/fc-{name}) that Attachable Access Entity Profiles and application EPGs consume when binding Fibre Channel connectivity.
graph TD
n["fc_domain.name (required, immutable)"]:::in
meta["annotation / name_alias"]:::in
vsp["vsan_pool_dn / vsan_pool_definitive_dn"]:::in
vsa["vsan_attribute_dn / vsan_attribute_definitive_dn"]:::in
vp["vlan_pool_dn / vlan_pool_definitive_dn (FCoE)"]:::in
vip["vip_address_pool_dn / vxlan_pool_definitive_dn"]:::in
this["aci_fc_domain.this (keystone, fcDomP)"]:::this
oid["output: id (DN uni/fc-{name})"]:::out
onm["output: name"]:::out
orel["outputs: vsan_pool_dn / vsan_pool_definitive_dn / vsan_attribute_dn / vsan_attribute_definitive_dn / vlan_pool_dn / vlan_pool_definitive_dn / vip_address_pool_dn / vxlan_pool_definitive_dn"]:::out
n --> this
meta --> this
vsp --> this
vsa --> this
vp --> this
vip --> this
this --> oid
this --> onm
this --> orel
classDef this fill:#00BCEB,color:#fff,stroke:#00BCEB;
classDef in fill:#f5f5f5,color:#333,stroke:#cccccc;
classDef out fill:#eeeeff,color:#333,stroke:#9999ff;
Resource inventory
| Resource | Name | Cardinality | Role |
|---|---|---|---|
aci_fc_domain |
this |
1 (keystone) | The FC domain / access-policy VSAN binding (fcDomP). |
| Requirement | Value |
|---|---|
| Terraform | >= 1.3.0 (uses optional() object defaults) |
| Provider | CiscoDevNet/aci ~> 2.20 |
| Provider block | None in this module — the caller configures and authenticates the provider (username/password, X.509 signature, or login domain) out of band. |
| Scope | None — the FC domain is a fabric-root object (no parent DN). |
Schema notes that bite (verified against the live provider schema):
- 🔒
fc_domain.nameis immutable. Changing it forces replacement — a brand-new FC domain DN, breaking every binding (AAEP, EPG) that referenced the old one until re-pointed. - ℹ️
aci_fc_domainis a classic (SDKv2) resource. It has not migrated to the plugin-framework typedrelation_to_*shape — its pool/attribute bindings are flat string attributes (relation_fc_rs_vsan_ns,relation_fc_rs_vsan_ns_def,relation_fc_rs_vsan_attr,relation_fc_rs_vsan_attr_def,relation_infra_rs_vlan_ns,relation_infra_rs_vlan_ns_def,relation_infra_rs_vip_addr_ns,relation_infra_rs_dom_vxlan_ns_def), each holding a target DN directly. ⚠️ The live schema has nodescription,owner_key/owner_tag, orannotations/tagslist. Unlike migrated resources in this suite, the metadata tail here is limited toannotationandname_alias— nothing else is invented.- ℹ️
relation_fc_rs_vsan_ns_def,relation_fc_rs_vsan_attr_def,relation_infra_rs_vlan_ns_def, andrelation_infra_rs_dom_vxlan_ns_defareoptional, computed. The provider typically derives them once the corresponding primary relation is set; this module exposes them as inputs only for advanced migration/import scenarios — leave themnullin the common case. - ℹ️ The FCoE VLAN pool relation (
vlan_pool_dn) is only meaningful for FCoE deployments. A pure native Fibre Channel domain typically leaves itnull; native FC uses the VSAN pool relation exclusively. - ℹ️
idis the DN (uni/fc-{name}), computed by APIC at create. It is the value downstream modules consume when binding Fibre Channel connectivity to this domain. ⚠️ validate_relation_dn(provider defaulttrue) means avsan_pool_dn(or any other relation DN) pointing at an object that does not yet exist will fail at apply — create the object first, or wire it by reference.
Scope the caller's APIC login to the least privilege this module needs:
- Create / delete an FC domain: the
adminrole, or a custom role granted write privilege on fabric infrastructure/access-policy configuration (the APIC built-inaccess-adminrole covers this), scoped to theallsecurity domain — FC domains are fabric-wide objects, not tenant-scoped. - Referenced VSAN pool / VSAN attribute policy / VLAN pool / VIP address pool: read on any object targeted by the relation attributes.
The module never sees a credential — authentication is a provider/caller concern supplied out of band (e.g. ACI_USERNAME / ACI_PASSWORD, or ACI_PRIVATE_KEY / ACI_CERT_NAME for signature-based auth).
- A reachable Cisco APIC (
ACI_URL) whose version is compatible with the~> 2.20provider, with the provider configured and authenticated by the caller. - In production, the provider should be configured with
insecure = falseand proper CA trust — the provider's own default (insecure = true, skip TLS verification) is not a safe steady state. - If you set
vsan_pool_dn,vsan_attribute_dn,vlan_pool_dn, orvip_address_pool_dn, the referenced object must exist (or be created in the same configuration) so the provider's DN validation passes.
terraform-aci-fc-domain/
├── providers.tf # terraform{} + required_providers (aci ~> 2.20); no provider block
├── variables.tf # the fc_domain object — deeply typed, secure defaults, heredoc schema, validations
├── main.tf # aci_fc_domain.this (keystone) + metadata tail + classic pool/attribute relations
├── outputs.tf # id (the DN) first, then name and the resolved relations
├── README.md # this document
├── SCOPE.md # cross-module contract (scope, consumes/emits, roles, prerequisites)
├── LICENSE # MIT
└── .gitignore # canonical library ignore set
# The caller configures the provider (authentication is out of band).
provider "aci" {
# username / password, or private_key + cert_name for signature auth;
# url = "https://apic.example.com"; set insecure = false in production.
}
module "fc_domain" {
source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"
fc_domain = {
name = "storage-fc"
}
}
output "fc_domain_dn" {
value = module.fc_domain.id # pass this to AAEP / application-EPG domain bindings
}Consumes
| Input | Type | Typical source |
|---|---|---|
fc_domain |
object({...}) |
caller (name + metadata tail + optional pool/attribute relations) |
fc_domain.vsan_pool_dn |
string (DN) | terraform-aci-vsan-pool |
fc_domain.vlan_pool_dn |
string (DN) | terraform-aci-vlan-pool (FCoE only) |
Emits
| Output | Description | Consumed by |
|---|---|---|
id |
FC domain DN (uni/fc-{name}) — primary reference |
attachable-access-entity-profile, application-epg — any module binding Fibre Channel connectivity |
name |
FC domain name | composition / audit |
vsan_pool_dn |
DN of the bound VSAN pool, or null | audits / downstream reference |
vsan_pool_definitive_dn |
Resolved/definitive VSAN namespace association | audits |
vsan_attribute_dn |
DN of the bound VSAN attribute policy, or null | audits / downstream reference |
vsan_attribute_definitive_dn |
Resolved/definitive VSAN attribute policy association | audits |
vlan_pool_dn |
DN of the bound FCoE VLAN pool, or null | audits / downstream reference |
vlan_pool_definitive_dn |
Resolved/definitive VLAN namespace association | audits |
vip_address_pool_dn |
DN of the bound VIP address pool, or null | audits / downstream reference |
vxlan_pool_definitive_dn |
Resolved/definitive VXLAN instance pool association | audits |
1 · Minimal — an FC domain with secure defaults
module "fc_domain" {
source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"
fc_domain = {
name = "storage-fc"
}
}💡 The minimal call creates only the domain.
annotationis preserved asorchestrator:terraform, and no pool relation is forced — the domain is inert until deliberately bound.
2 · A GUI display alias
module "fc_domain" {
source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"
fc_domain = {
name = "storage-fc"
name_alias = "Storage-Fabric-A"
}
}ℹ️
name_aliasis a display alias shown in the APIC GUI;nameremains the immutable identity encoded in the DN.
3 · A custom annotation marker
module "fc_domain" {
source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"
fc_domain = {
name = "storage-fc"
annotation = "orchestrator:terraform:storage-team"
}
}🔒 Keep the
orchestrator:terraformprefix so Terraform-managed objects stay identifiable in APIC. This suite defaultsannotationtoorchestrator:terraform; override it only to extend, not to erase, that marker.
4 · Binding a VSAN pool by DN literal
module "fc_domain" {
source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"
fc_domain = {
name = "storage-fc"
vsan_pool_dn = "uni/infra/vsanns-[storage-vsans]-static"
}
}
⚠️ The referenced VSAN pool must exist. With the provider'svalidate_relation_dndefault oftrue, a dangling relation fails at apply — fix the missing pool rather than disabling validation.
5 · Binding a VSAN pool via module reference
module "vsan_pool" {
source = "git::https://github.com/microsoftexpert/terraform-aci-vsan-pool.git?ref=v1.0.0"
vsan_pool = { name = "storage-vsans", alloc_mode = "static" }
}
module "fc_domain" {
source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"
fc_domain = {
name = "storage-fc"
vsan_pool_dn = module.vsan_pool.id
}
}💡 Wiring the pool's
idoutput avoids hand-typing the pool's DN and keeps the dependency explicit for Terraform's graph.
6 · A VSAN attribute policy binding
module "fc_domain" {
source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"
fc_domain = {
name = "storage-fc"
vsan_pool_dn = "uni/infra/vsanns-[storage-vsans]-static"
vsan_attribute_dn = "uni/infra/vsanattrp-storage-loadbal"
}
}ℹ️ The VSAN attribute policy (
fcVsanAttrP) sets per-VSAN load-balancing/rewrite behavior for the domain — leave itnullto rely on switch defaults.
7 · An FCoE deployment — VSAN pool plus VLAN pool
module "fc_domain" {
source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"
fc_domain = {
name = "fcoe-storage"
vsan_pool_dn = "uni/infra/vsanns-[fcoe-vsans]-static"
vlan_pool_dn = "uni/infra/vlanns-[fcoe-vlans]-static"
}
}ℹ️
vlan_pool_dnis only relevant for FCoE — it supplies the Ethernet encapsulation namespace that carries FC traffic. A native (non-FCoE) FC domain leaves itnull.
8 · A VIP address pool relation (GOLF / multi-pod)
module "fc_domain" {
source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"
fc_domain = {
name = "golf-fc"
vsan_pool_dn = "uni/infra/vsanns-[golf-vsans]-static"
vip_address_pool_dn = "uni/infra/addrinst-[golf-vip-pool]"
}
}ℹ️
vip_address_pool_dnis rarely needed outside GOLF / multi-pod endpoint-tracking deployments — leave itnullfor a conventional FC domain.
9 · An explicit definitive VSAN namespace override (advanced)
module "fc_domain" {
source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"
fc_domain = {
name = "migrated-fc"
vsan_pool_dn = "uni/infra/vsanns-[storage-vsans]-static"
vsan_pool_definitive_dn = "uni/infra/vsanns-[storage-vsans]-static"
}
}
⚠️ Leavevsan_pool_definitive_dnunset (null) in the common case — the provider derives it fromvsan_pool_dn. Set it explicitly only when reconciling an imported or manually migrated domain.
10 · Full binding (all relations)
module "fc_domain" {
source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"
fc_domain = {
name = "full-bound-fc"
vsan_pool_dn = "uni/infra/vsanns-[storage-vsans]-static"
vsan_pool_definitive_dn = "uni/infra/vsanns-[storage-vsans]-static"
vsan_attribute_dn = "uni/infra/vsanattrp-storage-loadbal"
vsan_attribute_definitive_dn = "uni/infra/vsanattrp-storage-loadbal"
vlan_pool_dn = "uni/infra/vlanns-[fcoe-vlans]-static"
vlan_pool_definitive_dn = "uni/infra/vlanns-[fcoe-vlans]-static"
vip_address_pool_dn = "uni/infra/addrinst-[golf-vip-pool]"
vxlan_pool_definitive_dn = "uni/infra/vxlanns-default"
}
}11 · Least-privilege operating model (documentation variant)
# Configure the provider with a login scoped to access-policy management —
# not a full fabric admin — for day-2 changes to an existing domain.
provider "aci" {
# username = "svc-access-admin" # an access-admin role, write-scoped
# # to fabric access-policy configuration
# private_key = var.apic_private_key # signature auth avoids login-rate limits
# cert_name = "terraform-cert"
# url = "https://apic.example.com"
# insecure = false
}
module "fc_domain" {
source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"
fc_domain = { name = "storage-fc" }
}🔒 Creating an FC domain is a fabric-scoped action; delegate ongoing management to an
access-adminrole. Prefer signature-based (X.509) auth for automation to avoid APIC login-rate thresholds.
12 · Many FC domains from one definition (caller-side for_each)
locals {
fc_domains = {
"storage-fc-a" = { name = "storage-fc-a", vsan_pool_dn = "uni/infra/vsanns-[storage-vsans-a]-static" }
"storage-fc-b" = { name = "storage-fc-b", vsan_pool_dn = "uni/infra/vsanns-[storage-vsans-b]-static" }
"backup-fc" = { name = "backup-fc", vsan_pool_dn = "uni/infra/vsanns-[backup-vsans]-static" }
}
}
module "fc_domains" {
source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"
for_each = local.fc_domains
fc_domain = each.value
}
output "fc_domain_dns" {
value = { for k, m in module.fc_domains : k => m.id }
}💡 Instantiate the module with
for_eachto manage a fleet of FC domains from a single, auditable map.
13 · Reading outputs for downstream wiring
module "fc_domain" {
source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"
fc_domain = { name = "storage-fc", vsan_pool_dn = "uni/infra/vsanns-[storage-vsans]-static" }
}
output "fc_domain_dn" { value = module.fc_domain.id } # uni/fc-storage-fc
output "fc_domain_vsan_pool_dn" { value = module.fc_domain.vsan_pool_dn }14 · Wiring the domain DN into an Attachable Access Entity Profile
module "fc_domain" {
source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"
fc_domain = { name = "storage-fc", vsan_pool_dn = "uni/infra/vsanns-[storage-vsans]-static" }
}
module "aaep" {
source = "git::https://github.com/microsoftexpert/terraform-aci-attachable-access-entity-profile.git?ref=v1.0.0"
attachable_access_entity_profile = {
name = "storage-aaep"
fc_domain_dn = module.fc_domain.id # <-- the domain's DN becomes the AAEP's relation
}
}15 · 🏗️ End-to-end composition — VSAN pool → FC domain → AAEP → tenant → EPG
provider "aci" {
# configured + authenticated by the caller; insecure = false in production
}
# 1) A VSAN pool supplying the Fibre Channel namespace.
module "vsan_pool" {
source = "git::https://github.com/microsoftexpert/terraform-aci-vsan-pool.git?ref=v1.0.0"
vsan_pool = { name = "storage-vsans", alloc_mode = "static" }
}
# 2) The keystone FC domain, bound to that pool.
module "fc_domain" {
source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"
fc_domain = {
name = "storage-fc"
vsan_pool_dn = module.vsan_pool.id
}
}
# 3) An Attachable Access Entity Profile binding the domain to interface policy.
module "aaep" {
source = "git::https://github.com/microsoftexpert/terraform-aci-attachable-access-entity-profile.git?ref=v1.0.0"
attachable_access_entity_profile = {
name = "storage-aaep"
fc_domain_dn = module.fc_domain.id
}
}
# 4) A tenant + application EPG bound to the same FC domain.
module "tenant" {
source = "git::https://github.com/microsoftexpert/terraform-aci-tenant.git?ref=v1.0.0"
tenant = { name = "core-prod" }
}
module "ap" {
source = "git::https://github.com/microsoftexpert/terraform-aci-application-profile.git?ref=v1.0.0"
tenant_dn = module.tenant.id
application_profile = { name = "storage-apps" }
}
module "epg" {
source = "git::https://github.com/microsoftexpert/terraform-aci-application-epg.git?ref=v1.0.0"
application_profile_dn = module.ap.id
application_epg = { name = "storage-epg" }
fc_domain_dn = module.fc_domain.id
}
output "fc_domain_dn" { value = module.fc_domain.id }🏗️ One VSAN pool in; a fully-bound Fibre Channel connectivity path out. The FC domain is the pivot every access-policy and tenant-side binding wires into through
module.fc_domain.id.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
fc_domain |
object({...}) |
✅ | — | The FC domain: name (required, immutable) plus the metadata tail and the classic pool/attribute-relation attributes. |
Full input schema (from variables.tf)
variable "fc_domain" {
type = object({
name = string # REQUIRED, immutable (force-new), 1-64 chars
annotation = optional(string, "orchestrator:terraform") # ACI annotation marker (kept identifiable)
name_alias = optional(string, null) # GUI display alias
vsan_pool_dn = optional(string, null) # VSAN pool binding (fcRsVsanNs)
vsan_pool_definitive_dn = optional(string, null) # resolved/definitive VSAN namespace (fcRsVsanNsDef); provider-computed in the common case
vsan_attribute_dn = optional(string, null) # VSAN attribute policy binding (fcRsVsanAttr)
vsan_attribute_definitive_dn = optional(string, null) # resolved/definitive VSAN attribute policy (fcRsVsanAttrDef); provider-computed in the common case
vlan_pool_dn = optional(string, null) # FCoE VLAN pool binding (infraRsVlanNs); FCoE only
vlan_pool_definitive_dn = optional(string, null) # resolved/definitive VLAN namespace (infraRsVlanNsDef); provider-computed in the common case
vip_address_pool_dn = optional(string, null) # VIP address pool binding (infraRsVipAddrNs); GOLF / multi-pod
vxlan_pool_definitive_dn = optional(string, null) # resolved/definitive VXLAN instance pool (infraRsDomVxlanNsDef); provider-computed in the common case
})
# validation: name is 1-64 chars and matches ^[a-zA-Z0-9_.:-]+$ (ACI naming rules);
# each relation DN, if set, must begin with "uni/"
}| Output | Description | Notes |
|---|---|---|
id |
FC domain Distinguished Name (uni/fc-{name}) |
Primary cross-module reference. |
name |
FC domain name | For composition / audit. |
vsan_pool_dn |
DN of the bound VSAN pool, or null | Pass-through of the resolved relation. |
vsan_pool_definitive_dn |
Resolved/definitive VSAN namespace association | Provider-computed in the common case. |
vsan_attribute_dn |
DN of the bound VSAN attribute policy, or null | Pass-through of the resolved relation. |
vsan_attribute_definitive_dn |
Resolved/definitive VSAN attribute policy association | Provider-computed in the common case. |
vlan_pool_dn |
DN of the bound FCoE VLAN pool, or null | Pass-through of the resolved relation. |
vlan_pool_definitive_dn |
Resolved/definitive VLAN namespace association | Provider-computed in the common case. |
vip_address_pool_dn |
DN of the bound VIP address pool, or null | Pass-through of the resolved relation. |
vxlan_pool_definitive_dn |
Resolved/definitive VXLAN instance pool association | Provider-computed in the common case. |
- One keystone, no children.
aci_fc_domain.thisis the single resource. The domain is a fabric-scoped binding point; the objects that reference it (AAEPs, application EPGs) are owned by their own modules and consume this domain by DN — keeping this module small and composable. - Classic (SDKv2) shape. Unlike this suite's migrated modules, the pool/attribute relations here are flat string attributes, not typed
relation_to_*nested objects. The module surfaces each as a plainoptional(string, null)DN input and wires it directly to the matching provider attribute. - Minimal metadata tail. The live schema exposes only
annotationandname_alias— nodescription,owner_key/owner_tag, orannotations/tagslist exists on this resource, so none are modeled. - Computed relations left alone by default.
vsan_pool_definitive_dn,vsan_attribute_definitive_dn,vlan_pool_definitive_dn, andvxlan_pool_definitive_dnareoptional, computedin the schema; this module exposes them as inputs but defaults each tonullso the provider resolves them from the primary relation rather than fighting computed state. - FCoE is opt-in. The FCoE VLAN pool relation (
vlan_pool_dn) is only wired when set; a native Fibre Channel domain is fully described by the VSAN pool relation alone. - Immutable identity.
fc_domain.nameis force-new: a rename destroys and recreates the domain, breaking every DN-based binding that referenced it until re-pointed. The twovalidationblocks reject names that violate the ACI length/character rules at plan time. - Secure by omission. The minimal call preserves the
orchestrator:terraformannotation and binds no pool — nothing is wired by default.
| Concern | Secure default | How to opt out (deliberately) |
|---|---|---|
fc_domain.annotation |
orchestrator:terraform — Terraform-managed objects stay identifiable in APIC |
Extend the marker (e.g. add a team suffix); do not blank it. |
vsan_pool_dn |
null — no VSAN pool bound, domain is inert |
Set it to bind a VSAN pool by DN. |
vsan_pool_definitive_dn / vsan_attribute_definitive_dn / vlan_pool_definitive_dn / vxlan_pool_definitive_dn |
null — left to the provider to compute |
Set explicitly only for advanced migration/import scenarios. |
vlan_pool_dn |
null — no FCoE VLAN pool bound |
Set it only for an FCoE deployment. |
vip_address_pool_dn |
null — no VIP address pool bound |
Set it for GOLF / multi-pod endpoint-tracking deployments. |
| Transport (provider) | This suite instructs callers to set insecure = false with CA trust |
The provider default is insecure = true; do not keep it as a steady state. |
| Secrets | None accepted or emitted | n/a — the FC domain carries no secret material; credentials are provider config. |
# From the module directory (offline, no credentials, no backend):
terraform init -backend=false
terraform validate
terraform fmt -check- Pin the module by immutable tag:
?ref=v1.0.0— never a branch. - This module is plan-only from the library's perspective. A human runs
terraform plan/applyagainst a sub-production APIC from their own pipeline, with a login scoped to the permissions above. No cloud apply happens here.
The offline proof gate for this module:
- ✅
terraform validate— parses the module, resolves thefc_domainobject type, runs thenameand relation-DN validations, and confirms every argument exists in the provider schema. - ✅
terraform fmt -check— canonical formatting. - ⛔ Not exercised offline (only a real
plan/applyagainst an APIC covers these): DN validation of the pool/attribute relations (server-sidevalidate_relation_dn), APIC-side name-collision checks, resolution of the_defcomputed relations, and the computed DN returned asid.
$ terraform output
id = "uni/fc-storage-fc"
name = "storage-fc"
vsan_pool_dn = "uni/infra/vsanns-[storage-vsans]-static"
vsan_pool_definitive_dn = "uni/infra/vsanns-[storage-vsans]-static"
vsan_attribute_dn = null
vsan_attribute_definitive_dn = null
vlan_pool_dn = null
vlan_pool_definitive_dn = null
vip_address_pool_dn = null
vxlan_pool_definitive_dn = null
| Symptom | Cause | Fix |
|---|---|---|
fc_domain.name must be 1-64 characters |
Name is empty or too long | Use a 1-64 character name. |
fc_domain.name may contain only letters, digits, and the characters _ . : - |
Name has spaces or unsupported characters | Remove spaces/special characters (ACI naming rules). |
fc_domain.vsan_pool_dn must be a Distinguished Name beginning with "uni/" |
A relation DN was set to a bare name instead of a full DN | Pass the pool's id output (or its full uni/... DN), not just its name. |
Changing name wants to destroy/recreate the domain |
fc_domain.name is immutable (force-new) |
Treat a rename as a migration; expect every binding referencing the old DN to need re-pointing. |
| Apply fails validating the VSAN pool relation | vsan_pool_dn targets a pool that does not exist |
Create the VSAN pool first (or in the same apply); do not disable validate_relation_dn. |
| FCoE traffic not reaching leaf ports as expected | vlan_pool_dn left null in an FCoE deployment |
Set vlan_pool_dn to the VLAN pool supplying the FCoE encapsulation namespace. |
Post ... 401 / authentication error |
Provider not configured or wrong credentials | Configure the aci provider with valid credentials and url; prefer signature auth for automation. |
| TLS verification error against the APIC | insecure = false (correct) but no CA trust |
Install the APIC's CA chain in the caller's trust store rather than reverting to insecure = true. |
- Cisco ACI provider —
aci_fc_domain - Cisco ACI provider — provider configuration & authentication
- Cisco APIC object model — class
fcDomP(the FC domain access-policy object). - Sibling modules:
terraform-aci-vsan-pool,terraform-aci-vlan-pool,terraform-aci-attachable-access-entity-profile,terraform-aci-application-epg,terraform-aci-physical-domain,terraform-aci-l2-domain,terraform-aci-l3-domain. - This module's
SCOPE.md— the cross-module contract.
💙 "Infrastructure as Code should be standardized, consistent, and secure."