Skip to content

Latest commit

Β 

History

1 Commit

Folders and files

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

Repository files navigation

πŸ’™ Cisco ACI Cloud Application Container Terraform Module

Manage a Cisco ACI cloud application container β€” the cloud-policy grouping construct (class cloudApp, DN uni/tn-{name}/cloudapp-{name}) under a tenant on a Cisco Cloud APIC (Cloud Network Controller) that cloud EPGs compose under β€” as a typed, secure-by-default building block targeting CiscoDevNet/aci ~> 2.20.

Terraform Provider Module Version Type Resources

🧩 Overview

This module manages a single ACI cloud application container and its metadata tail as one coherent, secure-by-default unit:

  • ☁️ The cloud application container (aci_cloud_applicationcontainer.this) β€” the cloud-policy grouping construct on a Cisco Cloud APIC (Cloud Network Controller), addressed by the Distinguished Name uni/tn-{tenant}/cloudapp-{name}.
  • 🏷️ The ACI metadata tail this resource exposes β€” annotation (preserved as orchestrator:terraform so Terraform-managed objects are identifiable in APIC), name_alias, and description. This keystone's live schema has no annotations/tags lists and no typed relation_to_* relations.
  • πŸ”‘ Scope, not credentials β€” the container's only required scope is its parent tenant's DN; authentication and the APIC URL are the caller's provider concern and are never module variables.
  • 🌐 Cloud-only construct β€” this resource applies to a Cisco Cloud APIC (Cloud Network Controller) tenant, not an on-premises fabric.

πŸ’‘ Why it matters: the cloud application container is the anchor cloud EPGs nest under in a Cloud Network Controller tenant β€” the cloud analog of an on-premises application profile. A consistent, identifiable container is the foundation the cloud-EPG module wires into through its parent DN input.

❀️ 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 in the family

graph LR
  apic["Cisco Cloud APIC / Cloud Network Controller (provider auth, out of band)"]:::ext
  tenant["terraform-aci-tenant"]:::sib
  cac["terraform-aci-cloud-application-container (this module)"]:::this
  ca["aci_cloud_applicationcontainer - class cloudApp - DN uni/tn-{name}/cloudapp-{name}"]:::keystone
  cepg["terraform-aci-cloud-epg"]:::sib

  apic -->|"provider configured by caller"| cac
  tenant -->|"tenant_dn"| cac
  cac -->|"manages"| ca
  cac -->|"cloud application container DN"| cepg

  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;
Loading

The cloud application container sits directly under the tenant in the cloud-policy tree. It takes the tenant's DN as its only required parent input and emits an id (its own DN, uni/tn-{name}/cloudapp-{name}) that a cloud EPG module consumes as its parent DN.

🧬 What this module builds

graph TD
  n["cloud_application_container.name (required, immutable)"]:::in
  p["tenant_dn (required parent)"]:::in
  meta["annotation / name_alias / description"]:::in
  this["aci_cloud_applicationcontainer.this (keystone, cloudApp)"]:::this
  oid["output: id (DN uni/tn-{name}/cloudapp-{name})"]:::out
  onm["output: name"]:::out

  p --> this
  n --> this
  meta --> this
  this --> oid
  this --> onm

  classDef this fill:#00BCEB,color:#fff,stroke:#00BCEB;
  classDef in fill:#f5f5f5,color:#333,stroke:#cccccc;
  classDef out fill:#eeeeff,color:#333,stroke:#9999ff;
Loading

Resource inventory

Resource Name Cardinality Role
aci_cloud_applicationcontainer this 1 (keystone) The cloud application container / cloud-policy grouping construct (cloudApp).

βœ… Provider / Versions

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 Parent tenant DN only (tenant_dn) β€” no other scope inputs.

Schema notes that bite (verified against the live provider schema):

  • πŸ”’ cloud_application_container.name is immutable. Changing it forces replacement β€” a brand-new container, and any cloud EPGs created under its DN go with it. Treat renames as migrations.
  • ⚠️ This resource has not migrated to the plugin-framework shape. It is a classic (SDKv2) resource, and its live schema exposes the parent only through tenant_dn β€” there is no parent_dn alternative to prefer here, unlike migrated siblings in this suite (e.g. the bridge domain) that deprecate tenant_dn in favor of parent_dn. This module uses tenant_dn because it is the only attribute the live schema provides.
  • ℹ️ No annotations / tags lists, no relation_to_* relations. The live schema for this keystone exposes only annotation (singular), name_alias, and description beyond name and tenant_dn β€” this module models exactly that and nothing more.
  • ℹ️ id is the DN (uni/tn-{name}/cloudapp-{name}), computed by APIC at create. It is the value a cloud-EPG module consumes as its parent DN.
  • 🌐 Cloud Network Controller only. aci_cloud_applicationcontainer targets a Cisco Cloud APIC (Cloud Network Controller) tenant; it has no equivalent on an on-premises (classic) APIC fabric.

πŸ”‘ Required APIC Roles & Privileges

Scope the caller's APIC login to the least privilege this module needs:

  • Create / delete a cloud application container: the tenant-admin role (or a custom role with cloud-tenant-admin write privilege) scoped to the tenant's security domain on the Cloud Network Controller.
  • No additional read privileges are required β€” this keystone carries no relationships to objects outside its own tenant.

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).

Cisco ACI Prerequisites

  • A reachable Cisco Cloud APIC (Cloud Network Controller) (ACI_URL) whose version is compatible with the ~> 2.20 provider, with the provider configured and authenticated by the caller. This resource is not supported against an on-premises APIC fabric.
  • In production, the provider should be configured with insecure = false and proper CA trust β€” the provider's own default (insecure = true, skip TLS verification) is not a safe steady state.
  • The parent tenant must exist (e.g. via terraform-aci-tenant, or a tenant already onboarded to the Cloud Network Controller) so the provider's DN validation of tenant_dn passes.

πŸ“ Module Structure

terraform-aci-cloud-application-container/
β”œβ”€β”€ providers.tf     # terraform{} + required_providers (aci ~> 2.20); no provider block
β”œβ”€β”€ variables.tf     # tenant_dn + the cloud application container object β€” typed, secure defaults, heredoc schema, validations
β”œβ”€β”€ main.tf          # aci_cloud_applicationcontainer.this (keystone) + metadata tail
β”œβ”€β”€ outputs.tf       # id (the DN) first, then name
β”œβ”€β”€ README.md        # this document
β”œβ”€β”€ SCOPE.md         # cross-module contract (scope, consumes/emits, roles, prerequisites)
β”œβ”€β”€ LICENSE          # MIT
└── .gitignore       # canonical library ignore set

βš™οΈ Quick Start

# 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 "cloud_app_container" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-cloud-application-container.git?ref=v1.0.0"

  tenant_dn = "uni/tn-cloud-prod"

  cloud_application_container = {
    name = "web-tier"
  }
}

output "cloud_app_container_dn" {
  value = module.cloud_app_container.id # pass this as the parent DN to a cloud-epg module
}

πŸ”Œ Cross-Module Contract

Consumes

Input Type Typical source
tenant_dn string (DN) terraform-aci-tenant (or an existing Cloud Network Controller tenant)
cloud_application_container object({...}) caller (name + metadata tail)

Emits

Output Description Consumed by
id Cloud application container DN (uni/tn-{name}/cloudapp-{name}) β€” primary reference terraform-aci-cloud-epg (as the parent DN for cloud EPGs created here)
name Cloud application container name composition / audit

πŸ“š Example Library

1 Β· Minimal β€” a cloud application container with secure defaults
module "cloud_app_container" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-cloud-application-container.git?ref=v1.0.0"

  tenant_dn = module.tenant.id

  cloud_application_container = {
    name = "web-tier"
  }
}

πŸ’‘ The minimal call creates only the container. annotation is preserved as orchestrator:terraform, so the object is identifiable as Terraform-managed in APIC, and no permissive posture is introduced.

2 Β· Description and GUI alias
module "cloud_app_container" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-cloud-application-container.git?ref=v1.0.0"

  tenant_dn = module.tenant.id

  cloud_application_container = {
    name        = "web-tier"
    name_alias  = "Web Tier"
    description = "Cloud application container for the web tier β€” owned by the cloud platform team"
  }
}

ℹ️ name_alias is a display alias shown in the APIC GUI; name remains the immutable identity encoded in the DN.

3 Β· A custom annotation marker
module "cloud_app_container" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-cloud-application-container.git?ref=v1.0.0"

  tenant_dn = module.tenant.id

  cloud_application_container = {
    name       = "web-tier"
    annotation = "orchestrator:terraform:cloud-platform-team"
  }
}

πŸ”’ Keep the orchestrator:terraform prefix so Terraform-managed objects stay identifiable in APIC. This suite defaults annotation to orchestrator:terraform; override it only to extend, not to erase, that marker.

4 Β· Naming rule violation (rejected at plan time)
module "cloud_app_container" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-cloud-application-container.git?ref=v1.0.0"

  tenant_dn = module.tenant.id

  cloud_application_container = {
    name = "web tier!" # contains a space and "!" β€” rejected
  }
}

⚠️ cloud_application_container.name must match ^[a-zA-Z0-9_.:-]+$ and be 1-64 characters; this call fails plan-time validation rather than reaching APIC with an invalid name.

5 Β· Multiple cloud application containers per tenant
module "web_tier" {
  source                       = "git::https://github.com/microsoftexpert/terraform-aci-cloud-application-container.git?ref=v1.0.0"
  tenant_dn                    = module.tenant.id
  cloud_application_container  = { name = "web-tier" }
}

module "app_tier" {
  source                       = "git::https://github.com/microsoftexpert/terraform-aci-cloud-application-container.git?ref=v1.0.0"
  tenant_dn                    = module.tenant.id
  cloud_application_container  = { name = "app-tier" }
}

πŸ’‘ A tenant commonly hosts several cloud application containers, one per application tier or workload boundary. Each is an independent instance of this module.

6 Β· Many containers from one definition (caller-side for_each)
locals {
  cloud_app_containers = {
    "web-tier" = { name = "web-tier", description = "Public-facing web tier" }
    "app-tier" = { name = "app-tier", description = "Internal application tier" }
    "data-tier" = { name = "data-tier", description = "Data tier" }
  }
}

module "cloud_app_containers" {
  source   = "git::https://github.com/microsoftexpert/terraform-aci-cloud-application-container.git?ref=v1.0.0"
  for_each = local.cloud_app_containers

  tenant_dn                   = module.tenant.id
  cloud_application_container = each.value
}

output "cloud_app_container_dns" {
  value = { for k, m in module.cloud_app_containers : k => m.id }
}

πŸ’‘ Instantiate the module with for_each to manage a fleet of cloud application containers from a single, auditable map.

7 Β· Reading outputs for downstream wiring
module "cloud_app_container" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-cloud-application-container.git?ref=v1.0.0"

  tenant_dn                   = module.tenant.id
  cloud_application_container = { name = "web-tier" }
}

output "cloud_app_container_dn"   { value = module.cloud_app_container.id }   # uni/tn-cloud-prod/cloudapp-web-tier
output "cloud_app_container_name" { value = module.cloud_app_container.name }
8 Β· Wiring the tenant DN into this module
module "tenant" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-tenant.git?ref=v1.0.0"
  tenant = { name = "cloud-prod" }
}

module "cloud_app_container" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-cloud-application-container.git?ref=v1.0.0"

  tenant_dn                   = module.tenant.id # <-- the tenant's DN becomes the container's parent
  cloud_application_container = { name = "web-tier" }
}
9 Β· Least-privilege operating model (documentation variant)
# Configure the provider with a login scoped to cloud-tenant management only β€”
# not a fabric-wide admin β€” for day-2 changes to an existing cloud tenant.
provider "aci" {
  # username    = "svc-cloud-tenant-admin"   # a tenant-admin role, write-scoped to
  #                                           # this tenant's security domain
  # private_key = var.apic_private_key        # signature auth avoids login-rate limits
  # cert_name   = "terraform-cert"
  # url         = "https://cloudapic.example.com"
  # insecure    = false
}

module "cloud_app_container" {
  source                       = "git::https://github.com/microsoftexpert/terraform-aci-cloud-application-container.git?ref=v1.0.0"
  tenant_dn                    = module.tenant.id
  cloud_application_container  = { name = "web-tier" }
}

πŸ”’ Prefer signature-based (X.509) auth for automation to avoid APIC login-rate thresholds.

10 Β· Wiring the container DN into a cloud EPG
module "cloud_app_container" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-cloud-application-container.git?ref=v1.0.0"

  tenant_dn                   = module.tenant.id
  cloud_application_container = { name = "web-tier" }
}

module "cloud_epg" {
  source                          = "git::https://github.com/microsoftexpert/terraform-aci-cloud-epg.git?ref=v1.0.0"
  cloud_application_container_dn  = module.cloud_app_container.id # <-- this module's output becomes the EPG's parent
  cloud_epg                       = { name = "web-epg" }
}
11 Β· Fully-annotated container (all available metadata)
module "cloud_app_container" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-cloud-application-container.git?ref=v1.0.0"

  tenant_dn = module.tenant.id

  cloud_application_container = {
    name        = "web-tier"
    name_alias  = "Web Tier"
    description = "Cloud application container for the web tier"
  }
}
12 Β· Separate containers per environment (dev / prod)
module "cloud_app_container_dev" {
  source                       = "git::https://github.com/microsoftexpert/terraform-aci-cloud-application-container.git?ref=v1.0.0"
  tenant_dn                    = module.tenant_dev.id
  cloud_application_container  = { name = "web-tier", description = "Development" }
}

module "cloud_app_container_prod" {
  source                       = "git::https://github.com/microsoftexpert/terraform-aci-cloud-application-container.git?ref=v1.0.0"
  tenant_dn                    = module.tenant_prod.id
  cloud_application_container  = { name = "web-tier", description = "Production" }
}

πŸ’‘ Because the container's identity is scoped by its parent tenant DN, the same name can be reused safely across tenants that represent different environments.

13 Β· πŸ—οΈ End-to-end composition β€” tenant β†’ cloud application container β†’ cloud EPG
provider "aci" {
  # configured + authenticated by the caller against a Cloud Network Controller;
  # insecure = false in production
}

# 1) The keystone tenant on the Cloud Network Controller.
module "tenant" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-tenant.git?ref=v1.0.0"
  tenant = { name = "cloud-prod", description = "Cloud production tenant" }
}

# 2) The cloud application container β€” this module.
module "cloud_app_container" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-cloud-application-container.git?ref=v1.0.0"

  tenant_dn = module.tenant.id
  cloud_application_container = {
    name        = "web-tier"
    description = "Public-facing web tier"
  }
}

# 3) A cloud EPG created within the container.
module "cloud_epg" {
  source                         = "git::https://github.com/microsoftexpert/terraform-aci-cloud-epg.git?ref=v1.0.0"
  cloud_application_container_dn = module.cloud_app_container.id
  cloud_epg                      = { name = "web-epg" }
}

output "cloud_app_container_dn" { value = module.cloud_app_container.id }

πŸ—οΈ One tenant in; a cloud application container and its cloud EPGs out. This module is the single grouping construct every cloud EPG in the tenant nests under, mirroring how an on-premises application profile anchors application EPGs.

πŸ“₯ Inputs

Name Type Required Default Description
tenant_dn string βœ… β€” DN of the parent tenant (e.g. module.tenant.id), format uni/tn-{name}.
cloud_application_container object({...}) βœ… β€” The container: name (required, immutable) plus the metadata tail this resource exposes.
Full input schema (from variables.tf)
variable "tenant_dn" {
  type = string
  # validation: must match ^uni/tn-
}

variable "cloud_application_container" {
  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
    description = optional(string, null)                     # free-form description
  })
  # validation: name is 1-64 chars and matches ^[a-zA-Z0-9_.:-]+$ (ACI naming rules)
}

🧾 Outputs

Output Description Notes
id Cloud application container Distinguished Name (uni/tn-{name}/cloudapp-{name}) Primary cross-module reference β€” pass as the parent DN to a cloud-epg module.
name Cloud application container name For composition / audit.

🧠 Architecture Notes

  • One keystone, no children. aci_cloud_applicationcontainer.this is the single resource. Cloud EPGs that live under it are owned by their own module and reference this container by DN β€” keeping this module small and composable along the cloud MIT.
  • Classic (SDKv2) shape, not migrated. Unlike migrated siblings in this suite, this resource has no typed relation_to_* attributes and no annotations/tags lists β€” it exposes only name, tenant_dn, annotation, name_alias, and description. The module models exactly that surface; nothing is invented.
  • Parent wiring uses tenant_dn deliberately. This suite's general convention prefers a resource's current parent_dn over a deprecated tenant_dn where both exist; here the live schema exposes only tenant_dn, so that is the correct β€” and only β€” choice.
  • Immutable identity. cloud_application_container.name is force-new: a rename destroys and recreates the container (and, server-side, any cloud EPGs under its DN). The two validation blocks reject names that violate the ACI length/character rules at plan time, not apply time.
  • Secure by omission. The minimal call preserves the orchestrator:terraform annotation and sets no additional posture β€” there is no permissive knob on this keystone to loosen.

🧱 Design Principles

Concern Secure default How to opt out (deliberately)
cloud_application_container.annotation orchestrator:terraform β€” Terraform-managed objects stay identifiable in APIC Extend the marker (e.g. add a team suffix); do not blank it.
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 β€” this keystone carries no secret material; credentials are provider config.
Scope Only the parent tenant DN is required; no fabric-wide or cross-tenant reach n/a β€” this resource has no relation attributes to widen.

πŸš€ Runbook

# 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 / apply against a Cloud Network Controller from their own pipeline, with a login scoped to the permissions above. No cloud apply happens here.

πŸ§ͺ Testing

The offline proof gate for this module:

  • βœ… terraform validate β€” parses the module, resolves the cloud_application_container object type, runs the name validations, and confirms every argument exists in the provider schema.
  • βœ… terraform fmt -check β€” canonical formatting.
  • β›” Not exercised offline (only a real plan / apply against a Cloud Network Controller covers these): DN validation of tenant_dn, APIC-side name-collision checks within the tenant, and the computed DN returned as id.

πŸ’¬ Example Output

$ terraform output
id   = "uni/tn-cloud-prod/cloudapp-web-tier"
name = "web-tier"

πŸ” Troubleshooting

Symptom Cause Fix
cloud_application_container.name must be 1-64 characters Name is empty or too long Use a 1-64 character name.
cloud_application_container.name may contain only letters, digits, and the characters _ . : - Name has spaces or unsupported characters Remove spaces/special characters (ACI naming rules).
tenant_dn must be a tenant DN of the form uni/tn-{name} tenant_dn was not a valid tenant DN Pass the tenant module's id output (or a valid uni/tn-{name} DN).
Changing name wants to destroy/recreate the container cloud_application_container.name is immutable (force-new) Treat a rename as a migration; expect the container and its cloud EPGs to be replaced.
Apply fails with a resource-not-found / unsupported-controller error Applied against an on-premises APIC instead of a Cloud Network Controller Point the provider at a Cisco Cloud APIC (Cloud Network Controller); this resource is cloud-only.
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 controller insecure = false (correct) but no CA trust Install the controller's CA chain in the caller's trust store rather than reverting to insecure = true.

πŸ”— Related Docs

  • Cisco ACI provider β€” aci_cloud_applicationcontainer
  • Cisco ACI provider β€” provider configuration & authentication
  • Cisco Cloud APIC object model β€” class cloudApp (the cloud application container).
  • Sibling modules: terraform-aci-tenant, terraform-aci-cloud-epg, terraform-aci-cloud-context-profile, terraform-aci-cloud-external-epg.
  • This module's SCOPE.md β€” the cross-module contract.

πŸ’™ "Infrastructure as Code should be standardized, consistent, and secure."

About

Terraform module: terraform-aci-cloud-application-container

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages