Cisco firewalls look simple from the outside. You SSH in, type show running-config, and read the output. Anyone who has automated that process across a real estate knows how quickly the simplicity evaporates. The login lands in user EXEC mode, so you need enable privileges before the configuration is visible. A multiple-context ASA hides most of its configuration behind context switches. Secrets are masked in the default output. The running configuration can differ from the startup configuration. And on the Firepower side, the device you are logged into often is not the system that holds the policy at all.
Oxidized can handle all of this, but only if you design the backup around how these platforms actually behave. This guide walks through the full picture: how enable mode works with Oxidized, how to back up every security context on a multi-context ASA, what to do about Firepower Threat Defense and the Firepower Management Center, how to avoid the pitfalls that silently produce incomplete backups, and how to restore when something breaks. Along the way, it covers Docker deployment, Git versioning, syslog-triggered captures, hardening, and troubleshooting.
What Is Oxidized for Cisco ASA and Firepower?
Oxidized for Cisco ASA and Firepower is an automated backup workflow in which the Oxidized application connects to Cisco firewalls over SSH, enters privileged mode, runs configuration display commands defined in a model, and commits each changed result to a Git repository. For ASA appliances it captures the running configuration directly, while for Firepower Threat Defense it captures the device-level configuration and complements, rather than replaces, backups from the Firepower Management Center.
Key Takeaways
- Oxidized needs privileged EXEC access on an ASA, which you can provide through an enable password or, more cleanly, through automatic privilege assignment for the backup user.
- On a multi-context ASA, the system context and every user context are separate configurations, so each one needs its own capture.
- The default
show running-configoutput masks pre-shared keys and similar secrets, so a backup built from it is not a complete restore source. - Firepower Threat Defense policy lives in the Firepower Management Center or Firepower Device Manager, which means device CLI backups alone are insufficient.
- Timestamps and uptime lines create noisy diffs unless the model strips them.
- A syslog hook on configuration command messages captures changes within seconds.
- Every restore path needs rehearsal, because ASA, FTD, and FMC each restore differently.
Why Cisco Firewall Backups Are Trickier Than They Look
The phrase Cisco firewall covers several quite different products. Choosing the right backup method starts with knowing which one you actually run.
The Platform Landscape
| Platform | Where the Configuration Lives | What Oxidized Can Capture |
|---|---|---|
| ASA, single context | On the appliance | Full running configuration over SSH |
| ASA, multiple context | System context plus one config per user context | Each context, with context switching |
| ASA with FirePOWER module | ASA on the appliance, module policy in FMC or ASDM | ASA configuration only |
| FTD managed by FMC | Policy in FMC, deployed to the device | Device-level running configuration, not the policy source |
| FTD managed by FDM | Policy in the on-box manager | Limited CLI view, backup through the manager |
| Firepower chassis running FXOS | Chassis and logical device settings | Chassis configuration through the FXOS CLI |
In short, Oxidized is an excellent fit for ASA software and a useful partial tool for Firepower. For the Firepower family, treat it as one layer in a larger backup strategy.
Running Configuration Versus Startup Configuration
An ASA keeps its active configuration in memory and saves it to flash only when an administrator writes memory. Consequently, the running configuration can include changes that have never been saved, and a reload would discard them. Conversely, the startup configuration can be older than what the firewall currently enforces.
| Characteristic | Running Configuration | Startup Configuration |
|---|---|---|
| Location | Memory | Flash |
| Reflects enforced behavior | Yes | Only after a reload |
| Survives a reboot | Only if saved | Yes |
| Best backup source | Auditing what is enforced | Verifying what will survive a reload |
Because enforcement matters most, Oxidized captures the running configuration. Even so, a periodic comparison against the startup configuration is a worthwhile hygiene check, and a later section describes it.
What the Default Output Hides
By default, show running-config masks several sensitive values. Pre-shared keys in tunnel groups, SNMP community strings, and similar items appear as asterisks. In contrast, the more system:running-config command displays more of those values, and with password encryption enabled on newer releases, they appear in encrypted form rather than as plain text. Therefore, a backup assembled from the default command cannot restore VPN tunnels on its own, and an engineer must re-enter those secrets afterward.
How Oxidized Works with Cisco ASA
Oxidized organizes its work around sources, inputs, models, and outputs.
Architecture Components
| Layer | Component | Function in a Cisco Firewall Deployment |
|---|---|---|
| Source | CSV, SQL, HTTP, or NetBox | Lists firewalls, addresses, models, and groups |
| Input | SSH | Opens the CLI session |
| Model | asa, a Firepower model, or a custom model | Handles enable, paging, commands, and cleanup |
| Output | Git or gitcrypt | Stores each changed configuration as a commit |
| Hooks | githubrepo, exec, slackdiff | Reacts to stored changes |
| Interface | REST API and Oxidized Web | Shows node status and allows manual triggers |
The Backup Lifecycle
- Oxidized loads the node list from the source.
- A worker opens an SSH session to the firewall.
- The model logs in and escalates to privileged mode.
- The model disables the pager so long output is not interrupted.
- The model runs its display commands and collects the output.
- Volatile lines are stripped, and secrets are optionally removed.
- Oxidized compares the result to the last stored version.
- A changed result becomes a Git commit, and any hook fires.
The ASA Model
Oxidized ships with an asa model that handles enable mode, pager settings, and the display of the configuration and basic inventory. Model coverage and options evolve between releases, so confirm the variables supported by your installed version. Likewise, check which Firepower-related models your version provides, since naming and scope have changed over time.
Prerequisites and Planning
| Requirement | Recommendation | Why It Matters |
|---|---|---|
| Backup server | Linux VM with 2 vCPU and 2 GB RAM | Light workload, Git grows steadily |
| Container runtime | Docker Engine with Compose | Simple upgrades and rollbacks |
| SSH access | Enabled on a reachable interface | Oxidized uses SSH only |
| Service account | Dedicated local or AAA user | Limits blast radius |
| Source restriction | SSH allowed only from the Oxidized server | Makes stolen credentials less useful |
| Time sync | NTP on all devices | Reliable logs and commit times |
| Remote Git | Private repository on GitLab, GitHub, or Gitea | Protects history if the server fails |
| Platform inventory | Which ASA, FTD, FMC, and FXOS devices exist | Determines the backup method per device |
Management Reachability
SSH to an ASA is permitted only from addresses and interfaces you explicitly allow. If the Oxidized server sits behind a VPN or on a remote segment, the management-access feature may be needed so that the firewall accepts SSH on an interface other than the one the traffic arrives on. Decide this before building the account, since it is the most common reason a first test fails.
Preparing the ASA for Oxidized
The goal is a user that can log in over SSH from one address, reach privileged mode, and read the configuration.
Enable SSH on the ASA
If SSH is not yet configured, generate keys and allow the Oxidized server.
crypto key generate rsa modulus 2048 ssh version 2 ssh 10.10.50.25 255.255.255.255 inside ssh timeout 30 aaa authentication ssh console LOCAL These commands generate host keys, restrict SSH to version 2, permit the Oxidized server on the inside interface, extend the idle timeout so long configurations do not drop the session, and authenticate against the local user database. Cipher and key exchange options differ by release, so confirm available choices with ssh ? on your software version.
Create the Service Account
username oxidized password ChangeThisLongRandomPassword privilege 15 A privilege 15 user is the simplest approach, but it is also the most powerful, which is exactly what a read-only backup account should not be. The next section explains how enable mode works and how to narrow the account.
Enable Mode in Depth
An SSH session to an ASA begins in user EXEC mode, where the prompt ends with a greater-than sign. The configuration is visible only in privileged EXEC mode, where the prompt ends with a pound sign. Oxidized therefore needs a reliable way to cross that boundary.
Three Approaches Compared
| Approach | How It Works | Strengths | Limitations |
|---|---|---|---|
| Enable password | Oxidized sends enable and then the enable password | Simple, widely supported | Stores a second secret, high privilege |
| Automatic enable on login | AAA places the user directly in privileged mode | No enable secret in Oxidized | User keeps full privilege 15 |
| Command authorization with a limited level | User stays at a lower level with only chosen commands allowed | True least privilege | More complex, easy to misconfigure |
Approach One: The Enable Password
This is the default pattern. Define the enable secret on the ASA, then give Oxidized the same value through its variables.
vars: enable: ChangeThisEnablePassword The model sends the enable command, answers the password prompt, and continues. As a result, it works with nearly every ASA version. Nevertheless, the enable password is a shared secret that grants far more than reading, so protect the Oxidized configuration file accordingly.
Approach Two: Automatic Enable
An authorization setting can place the SSH user directly into privileged mode, which removes the need to store an enable password in Oxidized.
aaa authorization exec LOCAL auto-enable With this in place and the user at privilege 15, the session arrives at the pound-sign prompt immediately. When using this method, remove the enable variable from the Oxidized configuration, or confirm that the model tolerates a session that is already privileged.
Approach Three: Command Authorization for Least Privilege
For strict environments, local command authorization lets a lower-privilege user run only specific commands. The idea is to assign the user a custom level and raise just the needed show commands to that level.
username oxidized password ChangeThisLongRandomPassword privilege 5 aaa authorization command LOCAL privilege show level 5 mode exec command running-config privilege show level 5 mode exec command version privilege show level 5 mode exec command context This approach is powerful and fragile at the same time. The exact set of commands the model runs, including pager and context-switching commands, must all be permitted, and a missing one produces confusing authorization failures. Consequently, test it against the exact model you use, capture every command from a successful manual run, and only then roll it out. If your organization uses TACACS+ or RADIUS, the same idea is usually implemented with a command set on the AAA server, which is easier to maintain.
Failover Pairs
In an active-standby pair, the configuration is synchronized from the active unit. Backing up the shared management address captures the active unit. In addition, many teams register each unit’s management address separately, which confirms that both remain reachable and that the standby is in sync.
Installing Oxidized with Docker
Directory Layout
sudo mkdir -p /srv/oxidized/ssh /srv/oxidized/model sudo chown -R 30000:30000 /srv/oxidized The Core Configuration File
Save this as /srv/oxidized/config.
username: oxidized password: ChangeThisLongRandomPassword model: asa interval: 3600 use_syslog: false debug: false threads: 10 timeout: 45 retries: 3 rest: 127.0.0.1:8888 vars: enable: ChangeThisEnablePassword input: default: ssh ssh: secure: false output: default: git git: user: Oxidized email: oxidized@example.com repo: /home/oxidized/.config/oxidized/cisco-firewalls.git source: default: csv csv: file: /home/oxidized/.config/oxidized/router.db delimiter: !ruby/regexp /:/ map: name: 0 ip: 1 model: 2 group: 3 A 45-second timeout leaves room for large configurations, while ten threads keeps the load on firewall control planes modest. In production, switch secure to true after populating known hosts.
The Device Inventory
fw-asa-hq-01:10.10.1.2:asa:asa-single fw-asa-dc-02:10.30.1.2:asa:asa-single Start the Container
docker run -d --name oxidized \ --restart unless-stopped \ -p 127.0.0.1:8888:8888 \ -v /srv/oxidized:/home/oxidized/.config/oxidized \ oxidized/oxidized:latest oxidized Follow the first run with docker logs -f oxidized, then confirm with curl -s http://127.0.0.1:8888/nodes.json and git -C /srv/oxidized/cisco-firewalls.git log --oneline. If a node fails, jump to the troubleshooting section.
Handling Multiple Security Contexts
A multiple-context ASA behaves like several virtual firewalls on one chassis. Each context has its own configuration, interfaces, and policies. The system context controls resource allocation and context definitions, while the admin context provides management access. A backup that captures only the context you happened to log into is a partial backup, and partial backups are the most dangerous kind because they look complete.
What Each Context Contains
| Context | Contents | Why It Needs Its Own Backup |
|---|---|---|
| System | Context definitions, interface allocation, failover, resource classes | Controls how every other context exists |
| Admin | Management access, plus its own policies | Often the login target for SSH |
| User contexts | Interfaces, access lists, NAT, VPN, and policy per tenant | Hold the actual security policy |
Approaches to Backing Up Contexts
| Approach | How It Works | Best Fit |
|---|---|---|
| One node per context with its own management address | Each context has an SSH-reachable interface, and Oxidized logs into it directly | Contexts with dedicated management IPs |
| Login to admin context and switch | The model runs a context switch command before displaying the configuration | Contexts without separate management access |
| Combined capture | Separate nodes for the system context and every user context, all through custom models | Full coverage with clear history per context |
In practice, the second and third approaches are the most common, because few designs give every context its own management address.
Custom Models for System and Context Captures
The context-switch commands are the key. In the system context, the command changeto system moves the session there. For a user context, changeto context NAME does the same. Because the prompt changes to include the context name, the prompt pattern must allow slashes. Save the following as /srv/oxidized/model/asasystem.rb.
class ASASystem < Oxidized::Model comment '! ' prompt %r{^\r?[\w.@/()-]+[#>]\s?$} cmd :all do |cfg| cfg.each_line.to_a[1..-2].join end cmd 'show version' do |cfg| cfg.gsub!(/^\S+ up .*\n/, '') comment cfg end cmd 'show running-config' do |cfg| cfg.gsub!(/^: Written by .*\n/, '') cfg end cfg :ssh do post_login do if vars(:enable) cmd 'enable', /^[pP]assword:/ cmd vars(:enable) end end post_login 'terminal pager 0' post_login 'changeto system' pre_logout 'exit' end end A user-context model is almost identical, except that it reads the context name from a variable and switches to it. Save this as /srv/oxidized/model/asacontext.rb, changing only the class name and the switch step.
class ASAContext < Oxidized::Model comment '! ' prompt %r{^\r?[\w.@/()-]+[#>]\s?$} cmd :all do |cfg| cfg.each_line.to_a[1..-2].join end cmd 'show running-config' do |cfg| cfg.gsub!(/^: Written by .*\n/, '') cfg end cfg :ssh do post_login do if vars(:enable) cmd 'enable', /^[pP]assword:/ cmd vars(:enable) end end post_login 'terminal pager 0' post_login do cmd "changeto context #{vars(:asa_context)}" end pre_logout 'exit' end end These models are sketches built on the standard Oxidized model syntax, so test them on a lab ASA and adjust them to your software version. Models are plain Ruby, which means they belong in version control and deserve the same review as any other code.
Wiring Contexts into the Inventory
Assign each context to a group, and set the context name as a variable on that group.
groups: ctx-dmz: vars: asa_context: dmz ctx-partner: vars: asa_context: partner Then list one node per context, all pointing at the same management address.
fw-asa-mc-01-system:10.10.1.3:asasystem:system fw-asa-mc-01-dmz:10.10.1.3:asacontext:ctx-dmz fw-asa-mc-01-partner:10.10.1.3:asacontext:ctx-partner Because each node writes to its own file, Git history for the DMZ context is separate from the partner context. Importantly, when a new context is created on the ASA, nothing in Oxidized changes automatically, so the system-context history is your signal that a new node needs adding. Reviewing context definitions in the system backup each week prevents silent gaps.
Firepower: What Oxidized Covers and What It Does Not
Firepower Threat Defense combines the ASA data plane, known as LINA, with the Snort inspection engine, and a management plane that differs by deployment. This is where teams most often assume a backup exists and discover otherwise.
Where Firepower Configuration Actually Lives
| Management Model | Authoritative Source | Recommended Backup |
|---|---|---|
| FTD managed by FMC | Firepower Management Center | FMC backup, plus Oxidized for device-level configuration |
| FTD managed by FDM | The on-box Firepower Device Manager | Manager backup, plus exported configuration |
| ASA with FirePOWER module | FMC or ASDM for module policy | ASA configuration through Oxidized, module policy through its manager |
| FXOS chassis | Chassis manager and FXOS CLI | Chassis export, plus Oxidized for CLI configuration where supported |
What the Device CLI Shows
On an FTD managed by FMC, the device CLI can display parts of the running configuration, and an administrator can reach the underlying ASA-style prompt through the diagnostic CLI. That output reflects what FMC deployed, so it is useful as an independent record of the deployed state. However, it is not a source from which you can rebuild access control, intrusion, or SSL policy, because those policies are defined and stored in FMC.
Backing Up the Firepower Management Center
FMC provides its own backup and restore function, including scheduled backups to remote storage. For a production deployment, this is the primary protection for policy. In addition, FMC includes an import and export function for selected policies, and a REST API that can retrieve policy objects. Pairing scheduled FMC backups with Oxidized captures of each FTD device gives you two independent layers: the policy source, and the deployed result.
A Practical Firepower Backup Strategy
- Schedule FMC backups to a remote target and verify that the files are restorable on a lab FMC.
- Capture each FTD device’s running configuration with Oxidized to record what was actually deployed.
- Store FMC deployment history and audit logs in your log platform.
- For FDM-managed devices, schedule exports through the manager and archive them alongside Oxidized history.
- For FXOS chassis, export the chassis configuration after every significant change.
Because model names and support for Firepower platforms change between Oxidized releases, check the model list for your installed version, and test against a lab device before trusting the results. Where support is incomplete, a custom model following the patterns shown above is usually a small amount of work.
Git Versioning for Firewall Configurations
Why Git Fits
ASA configurations are line-oriented text where one added access list entry is one added line. Consequently, Git diffs show precisely what changed, and a one-line change inside a twelve-thousand-line configuration remains easy to find. Git also provides integrity, compact storage, and a toolset that auditors recognize.
Reading the History
git clone /srv/oxidized/cisco-firewalls.git ~/cisco-configs cd ~/cisco-configs # Last five changes to one firewall git log -5 --stat -- asa-single/fw-asa-hq-01 # What changed in the latest commit git show HEAD -- asa-single/fw-asa-hq-01 # Compare two points in time git diff HEAD~10 HEAD -- asa-single/fw-asa-hq-01 Because nodes are stored under their group directory, adjust the paths to match. Commit messages record the node, so git log --grep finds every change to a firewall quickly.
Push to a Remote Repository
hooks: push_to_remote: type: githubrepo events: [post_store] remote_repo: git@git.example.com:netops/cisco-firewall-configs.git publickey: /home/oxidized/.config/oxidized/ssh/deploy.pub privatekey: /home/oxidized/.config/oxidized/ssh/deploy The hook works with any SSH-reachable Git server. Use a deploy key limited to this repository and protect the main branch so history cannot be rewritten.
Taming Noise in Cisco Firewall Backups
A useful Git history contains commits that mean something. When every hourly run creates a commit, reviewers stop paying attention, and the one meaningful change gets lost. Fortunately, ASA noise comes from a short and predictable list.
| Noise Source | What Happens | Remedy |
|---|---|---|
| Written-by header | The comment line recording who saved the configuration and when changes with every write | Strip it in the model, as the custom models above do |
| Uptime in version output | Uptime increases constantly | Remove the uptime line from the captured version text |
| Timestamps in certificates and keys | Generated values shift after renewals | Accept as legitimate changes |
| Masked secrets | Asterisks appear identically, but a changed secret is invisible | Decide on a secrets policy, covered below |
| Failover state | Active and standby units show different transient lines | Keep each unit as its own node |
| Context churn | New contexts appear in the system configuration | Treat as a signal to add a node |
After changing any model, run two consecutive backups of a quiet lab firewall. If the second run produces a commit, noise remains. Repeat until two consecutive runs produce identical files, and only then deploy the model broadly.
The Secrets Decision
Because the default output masks keys, a quiet danger follows. If someone changes a tunnel group pre-shared key, the masked line looks identical before and after, and Git records no change. Consequently, your history is accurate about structure and silent about secrets.
| Policy | What You Gain | What You Risk |
|---|---|---|
| Default output with masked secrets | Safer repository, clean diffs | Cannot restore VPN keys, cannot detect key changes |
| More complete output with encrypted secrets | Better restore fidelity | Repository must be protected like a credential store |
| Default output plus a separate encrypted ASA backup | Clean diffs and full-fidelity recovery | Two artifacts to manage |
For most teams, the third policy is the best balance. Oxidized stores the readable, masked history for review, while a scheduled ASA backup, which includes certificates, keys, and related files, goes to encrypted storage.
The ASA Backup Command
Recent ASA software includes a backup command that bundles the configuration and related files into an archive. Its options let you protect the archive with a passphrase and choose a destination.
backup location tftp://10.10.50.25/asa-backups/fw-asa-hq-01.tar.gz passphrase ChangeThisBackupPassphrase Syntax and supported destinations differ between releases, so check backup ? on your version. In addition, restrict the destination server tightly and encrypt the passphrase’s storage, because an archive plus its passphrase is a complete copy of the firewall’s identity.
Checking Running Against Startup
Because an ASA can run with unsaved changes, a periodic comparison between running and startup is a valuable hygiene check. A difference means that a reload would roll back someone’s work.
- Retrieve the startup configuration with the same service account.
- Remove comment and header lines that legitimately differ.
- Compare the result against the latest Oxidized version.
- Investigate any remaining differences and decide whether to save or revert.
ssh oxidized@10.10.1.2 "show startup-config" | grep -v '^[:!]' > /tmp/startup.cfg grep -v '^[:!]' ~/cisco-configs/asa-single/fw-asa-hq-01 | diff - /tmp/startup.cfg | head -40 This example assumes the account lands in privileged mode automatically. If you use an enable password, add the enable step to the session. Any differences it prints are either saved-but-unreloaded changes or running changes that nobody saved, and both deserve a conversation.
Real-Time Backups with Syslog Triggers
Hourly polling leaves a gap between a change and its capture. ASA can announce configuration commands through syslog, which closes the gap.
How It Works
- An administrator executes a configuration command on the firewall.
- The ASA generates a command-execution message in the 1110xx range.
- The message is forwarded to the Oxidized server over syslog.
- rsyslog hands the sender address and message to a script.
- The script recognizes a configuration command and calls the Oxidized API.
- Oxidized fetches the running configuration and commits the diff.
Configure Logging on the ASA
logging enable logging timestamp logging trap notifications logging host inside 10.10.50.25 udp/514 These commands turn on logging, include timestamps, send messages at the notifications level and above, and forward them to the Oxidized host. Command-execution messages are generated at the notifications level, which is why that severity matters. If your ASA reaches the server through a different interface, change the interface name accordingly.
Configure rsyslog and the Script
template(name="ipmsg" type="string" string="%fromhost-ip% %msg%\n") module(load="imudp") input(type="imudp" port="514" ruleset="asa") ruleset(name="asa") { action(type="omprog" binary="/usr/local/bin/oxidized-trigger.sh" template="ipmsg") } #!/bin/bash while read -r ip msg; do case "$msg" in *"User 'oxidized'"*) ;; *"%ASA-5-111008"*|*"%ASA-5-111010"*|*"%FTD-5-111008"*) curl -s "http://127.0.0.1:8888/node/next/${ip}" > /dev/null ;; esac done Notice the first pattern. Oxidized’s own session runs commands on the firewall, and without an exclusion for the backup account those commands could trigger another backup, which would trigger another, and so on. Excluding the service account breaks that loop. Message wording varies slightly across releases, so capture samples from your own firewalls and adjust. Furthermore, a short debounce, such as processing each address at most once every thirty seconds, keeps busy change windows from flooding the queue.
Using the Oxidized REST API and Web Interface
| Endpoint | Purpose |
|---|---|
| /nodes | Lists nodes with status and last run time |
| /nodes.json | Same data in JSON for automation |
| /node/fetch/NAME | Returns the latest stored configuration |
| /node/next/NAME | Queues an immediate backup |
| /node/version?node_full=GROUP/NAME | Lists stored versions |
| /reload | Reloads the inventory |
The JSON node list is a convenient monitoring source. Alert on any node that remains in a failed state for more than two intervals, since that catches expired credentials, changed SSH access lists, and context nodes that no longer exist.
Securing the Backup Pipeline
Firewall configurations disclose address plans, NAT, VPN peers, and policy logic, so the repository deserves the same care as a credential store.
| Control | Recommendation |
|---|---|
| Service account | Dedicated user, SSH only from the Oxidized server, long random password or key |
| Privilege | Prefer automatic enable or command authorization over a shared enable password |
| SSH settings | Version 2 only, strong ciphers where supported, current Oxidized image |
| Host key checking | Enable in Oxidized after populating known hosts |
| API exposure | Bind to localhost, publish only through an authenticated TLS proxy |
| Repository | Private remote, deploy key, protected main branch |
| Encryption at rest | Use gitcrypt or disk encryption on the backup server |
| Archive passphrases | Store in a secrets manager, separate from the archives |
| Monitoring | Alert on failed nodes and unexpected commits |
These measures follow the same principles as CIS Controls for network device configuration and the configuration management controls in NIST SP 800-53. Moreover, an AAA server such as TACACS+ gives you per-command accounting for the service account, which makes misuse visible.
Restoring Cisco Firewalls from Backups
Restoration differs sharply across the platforms, and the most common error is assuming that loading a file replaces the configuration.
Restoring an ASA
Copying a configuration file to the running configuration merges it into whatever is already there. It does not replace it. Therefore, a clean restore either wipes the configuration first or loads the file as the startup configuration followed by a reload.
- Retrieve the target version from Git and confirm it with
git diffagainst the current state. - Review the file for masked secrets, which load literally as asterisks if you paste them back.
- Place the file on a TFTP, SCP, or flash location the ASA can reach.
- For a clean rebuild, copy the file to the startup configuration and reload.
- For a targeted rollback, paste only the affected sections into configuration mode.
- Save with write memory, then verify traffic, VPNs, NAT, and failover state.
copy tftp://10.10.50.25/fw-asa-hq-01.cfg startup-config reload After the reload, re-enter any secrets that the masked output could not preserve, and restore certificates and keys from the encrypted ASA backup. Importantly, rehearse this procedure on a spare unit, because the first restore attempt always reveals something that the runbook missed.
Restoring a Multi-Context ASA
Restore the system context first, since it defines the contexts and their configuration locations. Then restore each user context from its own history. The system configuration references a configuration URL for each context, so copying the context file to that location and reloading the context is one route, while pasting the content into the context after switching to it is another. Consult your software version’s documentation for the exact reload mechanism, and test it in a lab before relying on it.
Restoring Firepower Threat Defense
For an FTD managed by FMC, the device is largely disposable and the policy source is not. A failed device is typically re-imaged, registered to the FMC again, and then receives its policies through a deployment. Consequently, your most important restore asset is a verified FMC backup, not the device CLI output. FMC restores generally require a matching software version, so record versions alongside every backup.
| Platform | Primary Restore Path | Oxidized Output Role |
|---|---|---|
| ASA, single context | Startup configuration load and reload | Primary source |
| ASA, multiple contexts | System first, then each context | Primary source per context |
| FTD with FMC | Re-register, then deploy from FMC | Independent record of deployed state |
| FTD with FDM | Restore from the manager backup | Limited reference |
| FXOS chassis | Import chassis configuration | Reference where captured |
Change Auditing and Compliance Evidence
Because every commit records what changed and when, Git history combined with firewall command logs forms a complete audit trail.
| Framework | Relevant Area | How the Workflow Helps |
|---|---|---|
| NIST SP 800-53 | CM-2, CM-3, CM-6 | Baselines, tracked changes, documented settings |
| CIS Controls | Secure configuration of network devices | Versioned, reviewable firewall policy |
| ISO 27001:2022 | Configuration management | Retrievable configuration history |
| PCI DSS 4.0 | Network security control reviews and approved changes | Diffs that simplify periodic review |
| SOC 2 | Change management criteria | Timestamped records of production changes |
To put this to work, send a daily digest of commits to the network and security teams, and require that each commit correlate with an approved change ticket. As a result, undocumented changes surface within a day instead of at the next audit.
Scaling Across Many Firewalls
Groups for Roles and Credentials
Use groups to separate datacenter, branch, and customer firewalls, and to carry different credentials and variables. Git places each group in its own directory, which keeps large repositories navigable.
A Source of Truth for the Inventory
A CSV file is sufficient for a pilot, though it drifts from reality over time. Switching to NetBox or an HTTP source means the inventory follows your documentation, and retired firewalls leave the rotation automatically.
Timing and Load
Firewall control planes are modest, so keep thread counts conservative and timeouts generous. Meanwhile, stagger polling across groups if hundreds of devices share a management network, and rely on syslog triggers for timely capture instead of shortening the interval.
Troubleshooting Cisco Firewall Backups in Oxidized
| Symptom | Likely Cause | Fix |
|---|---|---|
| Node shows no_connection | SSH access list or interface blocks the server | Verify the ssh statement and management-access, then test manually |
| Authentication failed | Wrong password, user not in the local database, or AAA mismatch | Test the same login manually and review the aaa authentication ssh console setting |
| Enable password rejected | Wrong secret or auto-enable already applied | Match the method to the configuration and remove an unnecessary enable variable |
| Command authorization failed | A command the model runs is not permitted for the user | Capture the command list from a manual run and authorize each one |
| Output interrupted by more prompts | Pager not disabled | Confirm the pager command runs before the configuration display |
| Hang or timeout after context switch | Prompt pattern misses the context prompt | Allow slashes and context names in the prompt pattern |
| Only one context appears in Git | Model captured only the login context | Add system and per-context nodes as described |
| Key exchange or cipher error | Strict ASA SSH settings versus an outdated library | Update the Oxidized image and review cipher settings |
| Commit on every run | Written-by line or uptime changing | Strip volatile lines and verify two matching runs |
| Backup loop after syslog trigger | Oxidized’s own commands trigger messages | Exclude the service account in the trigger script |
Debugging a Single Node
Isolate the failing node, enable debug temporarily, and restart the container. Then run the same commands manually over SSH with the same account and compare the transcripts. If the manual session works and Oxidized does not, the culprit is nearly always the prompt pattern, the enable handshake, or a command that the account is not authorized to run.
After an ASA or FTD Upgrade
Major upgrades can alter banners, SSH algorithms, or command output. When backups begin failing afterward, update the Oxidized image, retest custom models, and compare a manual session with the model’s expectations. If the bundled model is at fault, report it to the project with the software version and a sanitized debug log.
Pitfalls Checklist
These are the mistakes that most often turn a working-looking backup into a hollow one.
- Capturing only the login context on a multi-context ASA and assuming it is the whole configuration.
- Trusting masked output as a complete restore source, then loading asterisks as real secrets.
- Pasting a full configuration into the running configuration and expecting it to replace rather than merge.
- Storing a shared enable password in Oxidized when automatic enable would avoid it.
- Granting privilege 15 to a backup account without source restrictions.
- Treating a device CLI capture of FTD as a substitute for FMC backups.
- Forgetting the standby unit, then discovering its configuration diverged.
- Allowing the backup account’s own commands to trigger syslog-driven backups in a loop.
- Letting the written-by header or uptime create a commit every hour.
- Never rehearsing a restore on a spare unit.
Oxidized Compared with Other Cisco Firewall Backup Options
| Method | Cost | Version Control | Multi-Vendor | Best Fit |
|---|---|---|---|---|
| Oxidized | Free | Native Git | Yes | Readable history and API across vendors |
| ASDM backup | Included | File-based | No | Occasional manual backups |
| ASA backup command with scheduling | Included | File-based | No | Full-fidelity archives with keys and certificates |
| FMC scheduled backup | Included | Backup sets | No | Firepower policy protection |
| Cisco Defense Orchestrator | Licensed | Change log | Cisco focused | Cloud-delivered policy management |
| Ansible with Cisco collections | Free | You build it | Yes | Teams invested in Ansible |
| Commercial NCM suites | Licensed | Yes | Yes | Vendor support and reporting |
In practice, these options layer rather than compete. Native backups provide full-fidelity recovery, FMC protects Firepower policy, and Oxidized provides the readable, multi-vendor history that sits next to your routers, switches, and other firewalls.
Real-World Scenarios
Scenario One: Tracing a Broken Partner VPN
A partner tunnel fails on Monday morning. The engineer opens the Git history for the partner context and finds a Friday commit that changed a crypto map entry and an access list. The diff shows the exact lines, the command log names the administrator, and the fix is a two-line revert instead of a day of packet captures.
Scenario Two: Discovering a Missing Context
During a quarterly review, the system context history shows a new context created three weeks earlier that was never added to Oxidized. Because the system backup recorded the definition, the team adds the node, captures its first backup, and closes a gap that had silently existed since the context was built.
Scenario Three: Replacing a Failed ASA
An ASA in a regional office fails. The replacement is staged with the same software version, loaded with the latest configuration as startup configuration, and reloaded. The engineer re-enters the VPN pre-shared keys from the secrets manager and restores certificates from the encrypted ASA backup. The office returns to service the same day, using a procedure the team had rehearsed.
Optimization Recommendations
| Area | Recommendation | Benefit |
|---|---|---|
| Enable handling | Automatic enable or command authorization | No shared enable secret in Oxidized |
| Contexts | Separate nodes for the system and every user context | Complete, separable history |
| Secrets | Masked history in Git plus encrypted native backups | Clean diffs and full-fidelity recovery |
| Firepower | FMC scheduled backups plus device captures | Policy source protected and deployed state recorded |
| Polling | Hourly interval plus syslog triggers | Fresh data, low load |
| Models | Keep custom models in version control | Reviewable, reproducible behavior |
| Repository | Off-site mirror and periodic garbage collection | Resilience and smaller storage |
| Documentation | README with restore steps and version notes | Faster recovery under pressure |
Frequently Asked Questions
Does Oxidized support Cisco ASA?
Yes. Oxidized includes an asa model that connects over SSH, handles enable mode, disables the pager, and stores the configuration in Git or another output.
How does Oxidized handle enable mode on an ASA?
The model sends the enable command and answers the password prompt using the enable variable. Alternatively, configure automatic enable on login so no enable secret is needed.
Can Oxidized back up every context on a multi-context ASA?
Yes, with separate nodes. Capture the system context and each user context by switching contexts in a model, or by logging in to a context’s own management address.
Does Oxidized back up Firepower Threat Defense?
It can capture device-level configuration, but FTD policy lives in the Firepower Management Center or Firepower Device Manager. Use FMC backups as the primary protection.
Why are pre-shared keys missing from my ASA backup?
The default show running-config output masks them. Use a separate encrypted ASA backup for full-fidelity recovery, or consider more complete output with strict repository protection.
Is the running configuration enough to restore an ASA?
It restores most structure, but masked secrets, certificates, and keys need separate recovery. Keep an encrypted native backup alongside Oxidized history.
Does copying a file to running-config replace the configuration?
No. It merges the file into the existing running configuration. For a clean restore, load the file as the startup configuration and reload.
What permissions does the Oxidized account need on an ASA?
Access to privileged mode and permission to run show commands, pager settings, and any context-switch commands the model uses. Restrict SSH to the Oxidized server’s address.
How do I trigger a backup after each ASA change?
Forward command-execution syslog messages to a receiver, and run a script that calls the Oxidized next-node endpoint, excluding the backup account to avoid loops.
Why does Oxidized commit every time it runs?
A volatile line, usually the written-by header or uptime, changes between runs. Strip those lines in the model and confirm that two consecutive runs match.
Conclusion
Backing up Cisco firewalls with Oxidized is straightforward once you respect how the platforms behave. Enable mode needs a deliberate, least-privilege answer. A multi-context ASA needs one capture per context, including the system context. Masked secrets need a complementary native backup. And Firepower needs its management center protected on its own terms, with Oxidized recording what was actually deployed. Furthermore, syslog triggers and a startup-versus-running check turn the repository from a periodic snapshot into a living, trustworthy record.
The practical next step is small. Pick one lab ASA, confirm that enable handling works, capture two consecutive backups with no noise, and rehearse one restore. After that, extend the pattern to contexts, add the encrypted native backups, and fold FMC backups into the same operational rhythm. Together, these pieces replace hope with evidence.

