Manage a Cisco ACI access (leaf) switch policy group (class
infraAccNodePGrp, DNuni/infra/funcprof/accnodepgrp-{name}) and its companion spine switch policy groups (classinfraSpineAccNodePGrp, DNuni/infra/funcprof/spaccnodepgrp-{name}) as a typed, secure-by-default building block targetingCiscoDevNet/aci ~> 2.20.
This module manages leaf and spine switch policy groups β the node-level policy bundles fabric access-policy selectors apply to switches β as one coherent, secure-by-default unit:
- π§ The access switch policy group (
aci_access_switch_policy_group.this) β the keystone: a reusable bundle of leaf-node policies (BFD, Fibre Channel, inbound ACL profile, CoPP, CDP/LLDP, monitoring, MST, NetFlow, PoE, forwarding-scale) addressed by the Distinguished Nameuni/infra/funcprof/accnodepgrp-{name}. - π Companion spine switch policy groups (
aci_spine_switch_policy_group.this) β the spine-node counterpart, managed withfor_eachover a keyed map since it is an independent object, not a child, of the keystone. - π·οΈ The ACI metadata tail β
annotation(preserved asorchestrator:terraformso Terraform-managed objects are identifiable in APIC),name_alias, anddescriptionon every managed object. - π Flat, classic policy relations β every
relation_infra_rs_*attribute the live provider schema exposes for both resources, surfaced as descriptively named, independently settable DN inputs. - π Scope, not credentials β both resources are fabric access-policy singletons with no parent DN; authentication and the APIC URL are the caller's provider concern and are never module variables.
π‘ Why it matters: a switch policy group is the reusable unit that a leaf or spine switch profile's node-block selector applies to physical switches. Bundling node-level policies here β rather than scattering them across individual switch configurations β keeps fabric access policy auditable, versioned, and consistent across the fabric.
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
aspg["terraform-aci-access-switch-policy-group (this module)"]:::this
fv["aci_access_switch_policy_group - class infraAccNodePGrp - DN uni/infra/funcprof/accnodepgrp-{name}"]:::keystone
sp["aci_spine_switch_policy_group - class infraSpineAccNodePGrp - DN uni/infra/funcprof/spaccnodepgrp-{name}"]:::keystone
lsp["terraform-aci-leaf-switch-profile"]:::sib
ssp["terraform-aci-spine-switch-profile"]:::sib
cdp["terraform-aci-cdp-interface-policy"]:::sib
lldp["terraform-aci-lldp-interface-policy"]:::sib
copp["terraform-aci-copp-interface-policy"]:::sib
mon["terraform-aci-monitoring-policy"]:::sib
apic -->|"provider configured by caller"| aspg
aspg -->|"manages"| fv
aspg -->|"manages"| sp
fv -->|"id (selected by node-block)"| lsp
sp -->|"id (selected by node-block)"| ssp
cdp -->|"relation_to_cdp_interface_policy"| aspg
lldp -->|"relation_to_lldp_interface_policy"| aspg
copp -->|"relation_to_leaf_copp_profile / relation_to_spine_copp_profile"| aspg
mon -->|"relation_to_monitoring_policy"| aspg
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;
Both objects are fabric access-policy singletons living directly under the fixed uni/infra/funcprof container. They take no parent DN and emit their own DNs for leaf/spine switch profile node-block selectors to bind; the individual node policies they reference (CDP, LLDP, CoPP, monitoring, and so on) are owned by their own sibling modules and consumed here by DN.
graph TD
n["access_switch_policy_group.name (required, immutable)"]:::in
meta["annotation / name_alias / description"]:::in
rel["18 relation_to_* policy relation DNs"]:::in
this["aci_access_switch_policy_group.this (keystone, infraAccNodePGrp)"]:::this
oid["output: id (DN uni/infra/funcprof/accnodepgrp-{name})"]:::out
onm["output: name"]:::out
sn["spine_switch_policy_groups (map, keyed by name)"]:::in
srel["6 relation_to_* policy relation DNs per entry"]:::in
spine["aci_spine_switch_policy_group.this[for_each] (infraSpineAccNodePGrp)"]:::this
osp["output: spine_switch_policy_group_dns (map)"]:::out
n --> this
meta --> this
rel --> this
this --> oid
this --> onm
sn --> spine
srel --> spine
spine --> osp
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_access_switch_policy_group |
this |
1 (keystone) | The leaf-node switch policy group (infraAccNodePGrp). |
aci_spine_switch_policy_group |
this |
0..N (for_each) |
Companion spine-node switch policy groups (infraSpineAccNodePGrp), keyed by name. |
| 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 β both resources are fabric access-policy objects living directly under the fixed uni/infra/funcprof container (no parent DN). |
Schema notes that bite (verified against the live provider schema):
- π
nameis expected immutable on both resources (it is a DN component). The provider's documentation for the siblingaci_leaf_access_bundle_policy_groupresource states explicitly that its name cannot be changed after creation; treat a rename here the same way, as a replacement. - βΉοΈ Both resources are classic (SDKv2) in this provider line: every policy relation is a flat
relation_infra_rs_*attribute (a single target DN string) β there is no typedrelation_to_*nested object and no protocol-v6 migration banner for either resource. β οΈ The two resources are siblings, not parent-child. A spine switch policy group's DN (uni/infra/funcprof/spaccnodepgrp-{name}) does not nest under an access switch policy group's DN (uni/infra/funcprof/accnodepgrp-{name}) β both sit directly underuni/infra/funcprof.spine_switch_policy_groupsis afor_eachcollection wired independently of the keystone'sid, never through it.- βΉοΈ Most relations are
optional,computed. Passingnullleaves a relation at the provider's default rather than forcing an empty value. β οΈ validate_relation_dn(provider defaulttrue) fails apply if any referenced policy DN (BFD, CoPP, CDP/LLDP, monitoring, MST, NetFlow, PoE, forwarding-scale, inbound control profile) does not exist β fix the missing object rather than disabling validation.- βΉοΈ Neither policy group has any effect on its own. Each only takes effect once selected by a leaf or spine switch profile's node-block selector.
- Create / modify either policy group: the
adminrole, or a custom role with fabric access-policy (infra) write privilege β access policies are fabric-scoped, not tenant-scoped, so this typically requires a broader security-domain grant than a tenant-admin role. - Referenced node policies (BFD, Fibre Channel, CoPP, CDP/LLDP, monitoring, MST, NetFlow, PoE, forwarding-scale, inbound control profiles): read, scoped to the fabric access-policy security domain.
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. - Any node policy referenced by a relation must exist (or be created in the same apply) so the provider's DN validation passes.
- A leaf switch profile (to select the access switch policy group) and/or a spine switch profile (to select a spine switch policy group) β neither policy group takes effect until a node-block selector references it.
terraform-aci-access-switch-policy-group/
βββ providers.tf # terraform{} + required_providers (aci ~> 2.20); no provider block
βββ variables.tf # access_switch_policy_group object + spine_switch_policy_groups map β typed, secure defaults
βββ main.tf # aci_access_switch_policy_group.this (keystone) + aci_spine_switch_policy_group.this[for_each]
βββ outputs.tf # id (the DN) first, then name, then the spine DN map
βββ 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 "access_switch_pg" {
source = "git::https://github.com/microsoftexpert/terraform-aci-access-switch-policy-group.git?ref=v1.0.0"
access_switch_policy_group = {
name = "leaf-standard"
}
}
output "access_switch_policy_group_dn" {
value = module.access_switch_pg.id # select this from a leaf switch profile node-block
}Consumes
| Input | Type | Typical source |
|---|---|---|
access_switch_policy_group |
object({...}) |
caller (name + metadata tail + policy relation DNs) |
spine_switch_policy_groups |
map(object({...})) |
caller (keyed by name; metadata tail + policy relation DNs) |
Emits
| Output | Description | Consumed by |
|---|---|---|
id |
Access switch policy group DN (uni/infra/funcprof/accnodepgrp-{name}) β primary reference |
leaf switch profile node-block selectors |
name |
Access switch policy group name | composition / audit |
spine_switch_policy_group_dns |
Map of spine switch policy group key (name) β DN | spine switch profile node-block selectors |
1 Β· Minimal β an access switch policy group with secure defaults
module "access_switch_pg" {
source = "git::https://github.com/microsoftexpert/terraform-aci-access-switch-policy-group.git?ref=v1.0.0"
access_switch_policy_group = {
name = "leaf-standard"
}
}π‘ The minimal call creates only the access switch policy group. No node policy is force-attached, and
annotationis preserved asorchestrator:terraform, so the object is identifiable as Terraform-managed in APIC.
2 Β· Description and GUI alias
module "access_switch_pg" {
source = "git::https://github.com/microsoftexpert/terraform-aci-access-switch-policy-group.git?ref=v1.0.0"
access_switch_policy_group = {
name = "leaf-standard"
name_alias = "Standard Leaf Group"
description = "Standard leaf node policy bundle for production racks"
}
}βΉοΈ
name_aliasis a display alias shown in the APIC GUI;nameremains the immutable identity encoded in the DN.
3 Β· Binding CDP and LLDP interface policies
module "access_switch_pg" {
source = "git::https://github.com/microsoftexpert/terraform-aci-access-switch-policy-group.git?ref=v1.0.0"
access_switch_policy_group = {
name = "leaf-standard"
relation_to_cdp_interface_policy = "uni/infra/cdpIfP-cdp-enabled"
relation_to_lldp_interface_policy = "uni/infra/lldpIfP-lldp-enabled"
}
}
β οΈ Each relation takes the target policy's DN. With the provider'svalidate_relation_dndefault oftrue, a dangling DN fails at apply β create the referenced policy first, or wire it from a sibling module'sid.
4 Β· Binding a CoPP leaf profile and a monitoring policy
module "access_switch_pg" {
source = "git::https://github.com/microsoftexpert/terraform-aci-access-switch-policy-group.git?ref=v1.0.0"
access_switch_policy_group = {
name = "leaf-standard"
relation_to_leaf_copp_profile = "uni/infra/coppprof-leaf-strict"
relation_to_monitoring_policy = "uni/fabric/moninfra-default"
}
}βΉοΈ
relation_to_leaf_copp_profileprotects the leaf CPU from control-plane traffic floods;relation_to_monitoring_policyattaches fabric-wide monitoring/faults/stats policy to this node group.
5 Β· Binding BFD instance policies (single-hop and multihop)
module "access_switch_pg" {
source = "git::https://github.com/microsoftexpert/terraform-aci-access-switch-policy-group.git?ref=v1.0.0"
access_switch_policy_group = {
name = "leaf-standard"
relation_to_bfd_ipv4_policy = "uni/tn-infra/bfdIpv4InstPol-default"
relation_to_bfd_multihop_ipv4_policy = "uni/tn-infra/bfdMhIpv4InstPol-default"
}
}βΉοΈ Single-hop and multihop BFD instance policies are independent relations β set only the ones relevant to the leaf's routing design.
6 Β· Binding Fibre Channel fabric and instance policies
module "access_switch_pg" {
source = "git::https://github.com/microsoftexpert/terraform-aci-access-switch-policy-group.git?ref=v1.0.0"
access_switch_policy_group = {
name = "fcoe-leaf-pg"
relation_to_fc_fabric_policy = "uni/infra/fcfabricpol-default"
relation_to_fc_instance_policy = "uni/infra/fcinstpol-default"
}
}βΉοΈ Relevant only to leaf switches carrying FCoE/native Fibre Channel uplinks.
7 Β· Binding the inbound control (ACL) leaf profile
module "access_switch_pg" {
source = "git::https://github.com/microsoftexpert/terraform-aci-access-switch-policy-group.git?ref=v1.0.0"
access_switch_policy_group = {
name = "leaf-standard"
relation_to_inbound_control_leaf_profile = "uni/tn-infra/laclprof-leaf-baseline"
}
}π The inbound (ingress) control ACL profile restricts control-plane-directed traffic to the leaf's CPU β a hardening measure worth pairing with
relation_to_leaf_copp_profile.
8 Β· Binding NetFlow, PoE, and forwarding-scale policies
module "access_switch_pg" {
source = "git::https://github.com/microsoftexpert/terraform-aci-access-switch-policy-group.git?ref=v1.0.0"
access_switch_policy_group = {
name = "leaf-standard"
relation_to_netflow_node_policy = "uni/infra/netflownodepol-default"
relation_to_poe_instance_policy = "uni/infra/poeInstP-default"
relation_to_forwarding_scale_profile_policy = "uni/fabric/topoctrlfwdscaleprofpol-default"
}
}βΉοΈ
relation_to_poe_instance_policyonly applies to PoE-capable leaf hardware;relation_to_forwarding_scale_profile_policycontrols hardware forwarding-table scale profiles.
9 Β· A single companion spine switch policy group
module "access_switch_pg" {
source = "git::https://github.com/microsoftexpert/terraform-aci-access-switch-policy-group.git?ref=v1.0.0"
access_switch_policy_group = {
name = "leaf-standard"
}
spine_switch_policy_groups = {
"spine-standard" = {
description = "Standard spine node policy bundle"
}
}
}π‘
spine_switch_policy_groupsis keyed by name; the map key becomes the spine switch policy group'sname. Leave it empty (the default) to manage only the leaf-side keystone.
10 Β· Multiple spine switch policy groups with policy relations
module "access_switch_pg" {
source = "git::https://github.com/microsoftexpert/terraform-aci-access-switch-policy-group.git?ref=v1.0.0"
access_switch_policy_group = {
name = "leaf-standard"
}
spine_switch_policy_groups = {
"spine-standard" = {
relation_to_spine_copp_profile = "uni/infra/coppprof-spine-strict"
relation_to_cdp_interface_policy = "uni/infra/cdpIfP-cdp-enabled"
}
"spine-strict" = {
relation_to_inbound_control_spine_profile = "uni/tn-infra/laclprof-spine-strict"
relation_to_bfd_ipv4_policy = "uni/tn-infra/bfdIpv4InstPol-default"
}
}
}βΉοΈ Each map entry is an independent
aci_spine_switch_policy_group, iterated withfor_eachβ adding or removing an entry never churns the others.
11 Β· A fully-annotated access switch policy group (metadata + several relations)
module "access_switch_pg" {
source = "git::https://github.com/microsoftexpert/terraform-aci-access-switch-policy-group.git?ref=v1.0.0"
access_switch_policy_group = {
name = "leaf-standard"
name_alias = "Standard Leaf Group"
description = "Standard leaf node policy bundle for production racks"
relation_to_cdp_interface_policy = "uni/infra/cdpIfP-cdp-enabled"
relation_to_lldp_interface_policy = "uni/infra/lldpIfP-lldp-enabled"
relation_to_leaf_copp_profile = "uni/infra/coppprof-leaf-strict"
relation_to_monitoring_policy = "uni/fabric/moninfra-default"
}
}12 Β· Least-privilege operating model (documentation variant)
# Configure the provider with a login scoped to fabric access-policy
# management only β not a fabric-wide admin β for day-2 changes.
provider "aci" {
# username = "svc-fabric-access-admin" # write-scoped to the fabric
# # access-policy security domain
# private_key = var.apic_private_key # signature auth avoids login-rate limits
# cert_name = "terraform-cert"
# url = "https://apic.example.com"
# insecure = false
}
module "access_switch_pg" {
source = "git::https://github.com/microsoftexpert/terraform-aci-access-switch-policy-group.git?ref=v1.0.0"
access_switch_policy_group = { name = "leaf-standard" }
}π Fabric access-policy objects require a broader grant than a tenant-scoped role. Prefer signature-based (X.509) auth for automation to avoid APIC login-rate thresholds.
13 Β· Many policy groups from one definition (caller-side for_each)
locals {
leaf_groups = {
"leaf-standard" = { name = "leaf-standard" }
"leaf-fcoe" = { name = "leaf-fcoe", description = "FCoE-capable leaf racks" }
}
}
module "access_switch_pgs" {
source = "git::https://github.com/microsoftexpert/terraform-aci-access-switch-policy-group.git?ref=v1.0.0"
for_each = local.leaf_groups
access_switch_policy_group = each.value
}
output "access_switch_policy_group_dns" {
value = { for k, m in module.access_switch_pgs : k => m.id }
}π‘ Instantiate the module with
for_eachto manage a fleet of access switch policy groups from a single, auditable map. Each instance can still carry its ownspine_switch_policy_groups.
14 Β· Reading outputs for downstream wiring
module "access_switch_pg" {
source = "git::https://github.com/microsoftexpert/terraform-aci-access-switch-policy-group.git?ref=v1.0.0"
access_switch_policy_group = { name = "leaf-standard" }
spine_switch_policy_groups = {
"spine-standard" = {}
}
}
output "access_switch_policy_group_dn" { value = module.access_switch_pg.id }
output "access_switch_policy_group_name" { value = module.access_switch_pg.name }
output "spine_switch_policy_group_dns" { value = module.access_switch_pg.spine_switch_policy_group_dns }15 Β· ποΈ End-to-end composition β policy modules β switch policy groups β switch profiles
provider "aci" {
# configured + authenticated by the caller; insecure = false in production
}
# 1) Node-level policies referenced by the switch policy groups.
module "cdp_policy" {
source = "git::https://github.com/microsoftexpert/terraform-aci-cdp-interface-policy.git?ref=v1.0.0"
cdp_interface_policy = { name = "cdp-enabled", admin_state = true }
}
module "lldp_policy" {
source = "git::https://github.com/microsoftexpert/terraform-aci-lldp-interface-policy.git?ref=v1.0.0"
lldp_interface_policy = { name = "lldp-enabled" }
}
module "monitoring_policy" {
source = "git::https://github.com/microsoftexpert/terraform-aci-monitoring-policy.git?ref=v1.0.0"
monitoring_policy = { name = "fabric-default" }
}
# 2) The access switch policy group + companion spine switch policy group,
# wiring the sibling policies above by DN.
module "switch_policy_groups" {
source = "git::https://github.com/microsoftexpert/terraform-aci-access-switch-policy-group.git?ref=v1.0.0"
access_switch_policy_group = {
name = "leaf-standard"
relation_to_cdp_interface_policy = module.cdp_policy.id
relation_to_lldp_interface_policy = module.lldp_policy.id
relation_to_monitoring_policy = module.monitoring_policy.id
}
spine_switch_policy_groups = {
"spine-standard" = {
relation_to_cdp_interface_policy = module.cdp_policy.id
relation_to_lldp_interface_policy = module.lldp_policy.id
}
}
}
# 3) Leaf/spine switch profiles select the policy groups by DN onto real switches.
module "leaf_switch_profile" {
source = "git::https://github.com/microsoftexpert/terraform-aci-leaf-switch-profile.git?ref=v1.0.0"
leaf_switch_profile = { name = "leaf-profile-101-102" }
access_switch_policy_group_dn = module.switch_policy_groups.id
}
module "spine_switch_profile" {
source = "git::https://github.com/microsoftexpert/terraform-aci-spine-switch-profile.git?ref=v1.0.0"
spine_switch_profile = { name = "spine-profile-201-202" }
spine_switch_policy_group_dn = module.switch_policy_groups.spine_switch_policy_group_dns["spine-standard"]
}
output "access_switch_policy_group_dn" { value = module.switch_policy_groups.id }ποΈ Node-level policies in; leaf and spine switch profiles bind their respective node-block selectors to the policy groups this module manages β completing the fabric access-policy chain from individual policies to switches in the field.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
access_switch_policy_group |
object({...}) |
β | β | The access switch policy group: name (required, immutable) plus the metadata tail and the 18 classic policy relations. |
spine_switch_policy_groups |
map(object({...})) |
β | {} |
Companion spine switch policy groups, keyed by name. Empty manages none. |
Full input schema (from variables.tf)
variable "access_switch_policy_group" {
type = object({
name = string # REQUIRED, expected immutable (DN component), 1-64 chars
annotation = optional(string, "orchestrator:terraform") # ACI annotation marker (kept identifiable)
name_alias = optional(string, null) # GUI display alias
description = optional(string, null) # free-form description
relation_to_bfd_ipv4_policy = optional(string, null) # -> bfdIpv4InstPol DN
relation_to_bfd_ipv6_policy = optional(string, null) # -> bfdIpv6InstPol DN
relation_to_bfd_multihop_ipv4_policy = optional(string, null) # -> bfdMhIpv4InstPol DN
relation_to_bfd_multihop_ipv6_policy = optional(string, null) # -> bfdMhIpv6InstPol DN
relation_to_flash_config_policy = optional(string, null) # -> equipmentFlashConfigPol DN
relation_to_fc_fabric_policy = optional(string, null) # -> fcFabricPol DN
relation_to_fc_instance_policy = optional(string, null) # -> fcInstPol DN
relation_to_inbound_control_leaf_profile = optional(string, null) # -> iaclLeafProfile DN
relation_to_l2_node_auth_policy = optional(string, null) # -> l2NodeAuthPol DN
relation_to_leaf_copp_profile = optional(string, null) # -> coppLeafProfile DN
relation_to_cdp_interface_policy = optional(string, null) # -> cdpIfPol DN
relation_to_lldp_interface_policy = optional(string, null) # -> lldpIfPol DN
relation_to_monitoring_policy = optional(string, null) # -> monInfraPol DN
relation_to_stp_instance_policy = optional(string, null) # -> stpInstPol DN
relation_to_netflow_node_policy = optional(string, null) # -> netflowNodePol DN
relation_to_poe_instance_policy = optional(string, null) # -> poeInstPol DN
relation_to_fast_link_failover_policy = optional(string, null) # -> topoctrlFastLinkFailoverInstPol DN
relation_to_forwarding_scale_profile_policy = optional(string, null) # -> topoctrlFwdScaleProfilePol DN
})
# validation: name is 1-64 chars and matches ^[a-zA-Z0-9_.:-]+$ (ACI naming rules)
}
variable "spine_switch_policy_groups" {
type = map(object({
annotation = optional(string, "orchestrator:terraform")
name_alias = optional(string, null)
description = optional(string, null)
relation_to_inbound_control_spine_profile = optional(string, null) # -> iaclSpineProfile DN
relation_to_bfd_ipv4_policy = optional(string, null) # -> bfdIpv4InstPol DN
relation_to_bfd_ipv6_policy = optional(string, null) # -> bfdIpv6InstPol DN
relation_to_spine_copp_profile = optional(string, null) # -> coppSpineProfile DN
relation_to_cdp_interface_policy = optional(string, null) # -> cdpIfPol DN
relation_to_lldp_interface_policy = optional(string, null) # -> lldpIfPol DN
}))
default = {}
# validation: every map key (name) is 1-64 chars and matches ^[a-zA-Z0-9_.:-]+$
}| Output | Description | Notes |
|---|---|---|
id |
Access switch policy group Distinguished Name (uni/infra/funcprof/accnodepgrp-{name}) |
Primary cross-module reference. |
name |
Access switch policy group name | For composition / audit. |
spine_switch_policy_group_dns |
Map of spine switch policy group key (name) β DN | Empty map if spine_switch_policy_groups is empty. |
- One keystone, one independent sibling collection.
aci_access_switch_policy_group.thisis the single keystone resource.aci_spine_switch_policy_group.thisis iterated withfor_eachalongside it β deliberately not wired through the keystone'sid, because the two objects share no DN nesting in the ACI object model. Modeling it as a fabricated parent-child relationship would misrepresent the schema. - Classic (SDKv2) flat relations. Neither resource has been migrated to the plugin-framework in this provider line; every policy relation is a flat
relation_infra_rs_*string attribute (a target DN), surfaced here under a descriptiverelation_to_*name rather than the raw provider attribute name. for_eachkey stability.spine_switch_policy_groupsis keyed by policy group name β the map key becomesnameinmain.tf(name = each.key), so the map has no redundantnamefield and inserting/removing an entry never churns the others.- Immutable identity.
nameon both resources is expected immutable (a DN component); thevalidationblocks reject names that violate the ACI length/character rules at plan time, not apply time. - Secure by omission. The minimal call attaches no policy relations on either resource β nothing is force-applied to leaf or spine ports by default, and the
orchestrator:terraformannotation is preserved on every managed object.
| Concern | Secure default | How to opt out (deliberately) |
|---|---|---|
access_switch_policy_group.annotation / each spine entry's annotation |
orchestrator:terraform β Terraform-managed objects stay identifiable in APIC |
Extend the marker (e.g. add a team suffix); do not blank it. |
Every relation_to_* (both resources) |
null β no policy relation forced |
Set the relevant relation to the target policy's DN. |
spine_switch_policy_groups |
{} β no spine switch policy groups managed |
Add entries keyed by name. |
| 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 β neither resource carries 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 theaccess_switch_policy_groupobject andspine_switch_policy_groupsmap types, runs everynamevalidation, 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 everyrelation_to_*(server-sidevalidate_relation_dn), APIC-side name-collision checks, the computed DNs returned asid/spine_switch_policy_group_dns, and whether either policy group is actually selected by a switch profile node block.
$ terraform output
id = "uni/infra/funcprof/accnodepgrp-leaf-standard"
name = "leaf-standard"
spine_switch_policy_group_dns = {
"spine-standard" = "uni/infra/funcprof/spaccnodepgrp-spine-standard"
}
| Symptom | Cause | Fix |
|---|---|---|
access_switch_policy_group.name must be 1-64 characters |
Name is empty or too long | Use a 1-64 character name. |
access_switch_policy_group.name may contain only letters, digits, and the characters _ . : - |
Name has spaces or unsupported characters | Remove spaces/special characters (ACI naming rules). |
Every spine_switch_policy_groups map key ... must be 1-64 characters |
A spine_switch_policy_groups key violates the naming rule |
Use a 1-64 character key matching ^[a-zA-Z0-9_.:-]+$. |
Changing name wants to destroy/recreate a policy group |
name is a DN component and expected immutable |
Treat a rename as a migration; expect the policy group (and its selection by a switch profile) to be replaced. |
Apply fails validating a relation_to_* DN |
The referenced policy (BFD, CoPP, CDP/LLDP, monitoring, MST, NetFlow, PoE, forwarding-scale, inbound control profile) does not exist | Create the referenced policy first (or in the same apply); do not disable validate_relation_dn. |
| Policy group exists but has no visible effect | Neither policy group takes effect until selected | Bind the policy group's id (or the relevant spine_switch_policy_group_dns entry) from a leaf/spine switch profile node-block selector. |
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_access_switch_policy_group - Cisco ACI provider β
aci_spine_switch_policy_group - Cisco ACI provider β provider configuration & authentication
- Cisco APIC object model β classes
infraAccNodePGrp(leaf switch policy group) andinfraSpineAccNodePGrp(spine switch policy group). - Sibling modules:
terraform-aci-leaf-switch-profile,terraform-aci-spine-switch-profile,terraform-aci-cdp-interface-policy,terraform-aci-lldp-interface-policy,terraform-aci-copp-interface-policy,terraform-aci-monitoring-policy,terraform-aci-leaf-access-port-policy-group. - This module's
SCOPE.mdβ the cross-module contract.
π "Infrastructure as Code should be standardized, consistent, and secure."