Terraform automation for configuring Cisco Firepower Management Center (FMC) lab environments. Targets a cloud-delivered FMC (cdFMC) instance managed through Cisco Defense Orchestrator (CDO/SCC).
The automation handles the full lifecycle of a lab pod:
- Device onboarding: Registers the FTD with CDO, imports base configuration from
.sfobackup - Interface configuration: 7 physical interfaces + 2 VTI tunnel interfaces with security zones
- Network objects and static routes: Branch EVPN networks, host objects, 8 static routes
- Policy assignments: Access control policy + platform policy assigned to the device
- OSPF: Process 1 / Area 0 via Python REST API
- BGP: AS 65532, neighbors via Tunnel1/Tunnel2 to Secure Access
- VPN: Single IKEv2 site-to-site tunnel (SecureAccess)
| Provider | Version |
|---|---|
CiscoDevNet/fmc |
2.0.1 |
CiscoDevnet/cdo |
latest |
fmc-devices → fmc-vti-discovery → fmc-interfaces → fmc-interface-groups
→ fmc-networking → fmc-network-objects → fmc-policies → fmc-ospf → fmc-bgp → fmc-vpn
VPN module always runs last. Never reorder without understanding the full depends_on chain.
| Module | Purpose |
|---|---|
fmc-devices |
.sfo config import, CDO device registration, SSH onboarding |
fmc-vti-discovery |
Data sources — discovers Tunnel1 and Tunnel2 interface IDs |
fmc-interfaces |
Physical (G0/0–G0/6) and VTI interface config with zone assignment |
fmc-interface-groups |
Manages pre-existing NetFlowGrp (imported by deploy) |
fmc-networking |
Network objects, host objects, 8 static routes |
fmc-network-objects |
OSPF-specific network objects |
fmc-policies |
ACP + platform policy assignments (native fmc_policy_assignment) |
fmc-ospf |
OSPF Process 1 / Area 0 via Python REST API |
fmc-bgp |
BGP AS 65532 via Python REST API |
fmc-vpn |
IKEv2 site-to-site: SecureAccess |
| Interface | Logical Name | IP | Zone |
|---|---|---|---|
| G0/0 | Main-WAN | 198.18.8.1/31 | WAN |
| G0/1 | DMZ | 198.18.9.1/24 | DMZ |
| G0/2 | INTERNET | 198.18.3.2/24 | INTERNET |
| G0/3 | DATA-CENTER | 198.18.5.1/24 | DATA-CENTER |
| G0/4 | PROD-WAN | 198.18.8.3/31 | WAN |
| G0/5 | IOT-WAN | 198.18.8.5/31 | WAN |
| G0/6 | APP | 198.18.11.1/24 | — |
| Tunnel1 | WAN_static_vti_1 | 169.254.6.2/30 | SecureAccess |
| Tunnel2 | WAN_static_vti_2 | 169.254.6.6/30 | SecureAccess |
VTI interfaces (Tunnel1, Tunnel2) are imported into state by the deploy script — not created fresh.
- Terraform >= 1.0
- Python 3 with
pip - Access to a cdFMC tenant and CDO/SCC API token
Copy terraform.tfvars.ignore to terraform.tfvars and fill in:
scc_token = "your-scc-api-token"
scc_host = "https://eu.manage.security.cisco.com" # match your region
cdfmc_host = "your-cdfmc-hostname.cisco.com"
# Pre-configured for lab — change only if your pod differs
ftd_ips = ["198.18.133.39"]
device_name = ["hqftdv"]
policies = ["HQ Firewall Policy"]terraform.tfvars and *.tfstate are gitignored — never commit them.
./cli.py deployThe deploy script is fully automated and self-bootstrapping (creates the Python venv automatically). It runs 11 steps:
terraform init- Python venv ready
- FTD device registration (
module.fmc_devices) - VTI discovery (
module.fmc_vti_discovery) - ID extraction (device ID, VTI IDs, NetFlowGrp ID)
- VTI interface import into state (always rm-then-import for idempotency)
- NetFlowGrp import into state
- Core configuration (interfaces, networking, objects, groups, policies)
- OSPF configuration
- BGP configuration
- VPN configuration
Progress is cached in .pod_prepare_progress and .vti_ids_cache. Delete these files to force a full re-run.
./cli.py resetCleans the cdFMC tenant and Terraform state so the next ./cli.py deploy runs cleanly against a fresh pod. Sequence:
- Deletes the
SecureAccessS2S VPN topology from FMC - Deregisters the FTD from CDO and polls until gone
- Deletes the
HQ Firewall PolicyACP (re-imported from.sfoon next deploy) - Clears all device-scoped Terraform state
- Clears deploy cache files
./cli.py destroyRemoves OSPF-managed network objects and pre-imported resources from state first, then runs terraform destroy.
# Deploy a specific module
terraform apply -target=module.fmc_interfaces
# View current state
terraform state list
# Remove a resource from state before re-importing
terraform state rm module.fmc_interface_groups.fmc_interface_group.netflow_managed
# Force re-run of deploy from scratch
rm -f .pod_prepare_progress .vti_ids_cache
./cli.py deploy
# Enable debug logging
export TF_LOG=DEBUG
terraform applyDevice registration fails / ACP not found
The deploy script expects the .sfo import to complete and the ACP to exist before registering the device. If the previous session's ACP is missing, run ./cli.py reset first to ensure a clean state.
VTI import fails
VTI IDs are tied to the device. After a reset, the old IDs are stale. The deploy script always removes stale VTI state before importing (rm-then-import pattern). If it fails, delete .vti_ids_cache and re-run.
OSPF/BGP not applying These are Python null_resource triggers. If the device ID changed (after a reset), they will re-run automatically on the next deploy.
State out of sync after manual operations
terraform state list # see what's in state
terraform state rm <addr> # remove a stale entryAll scripts share a single venv at scripts/.venv/ (created automatically by cli.py).
| Script | Purpose |
|---|---|
scripts/config-import/main.py |
Imports .sfo config backup to cdFMC via REST API |
scripts/device-onboarding/cdo.py |
SSH automation for CDO registration command |
scripts/ospf/cdfmc_ospf_automation.py |
Configures OSPF via FMC REST API |
scripts/bgp/bgp_routing.py |
Configures BGP via FMC REST API |
scripts/reset/reset.py |
Tenant cleanup between sessions |
- CiscoDevNet/fmc Terraform provider
- CiscoDevnet/cdo Terraform provider
- FMC REST API reference
- CDO API reference
FMC Provider: 2.0.1 | Terraform: >= 1.0