WorkCompliance engineering
Automating DISA STIG checks for Cisco ISE through a scanner with no ISE support
The 81 rules of the Cisco ISE NDM and NAC STIGs (V2R4): 24 checked automatically over SSH and a read-only API, 7 in part, and 50 kept visible as manual items, never counted as a pass.
The problem
Cisco Identity Services Engine has two DISA STIGs: one for the device itself (NDM, 51 rules) and one for its role as network access control (NAC, 30 rules). Release V2R4 carries 17 CAT I rules across the two.
The commercial compliance scanner this design targets has no Cisco ISE check type. A survey of public sources at the time of writing found no published automation of either ISE STIG: no SCAP benchmark, no scanner audit, no open-source profile, within the limits of public web and code search (one government tool’s current builds could not be inspected).
The aim was narrow: automate what documented interfaces can read, and make the rest impossible to mistake for a pass.
What was built
Three check mechanisms feed the same scanner console:
- SSH to each node. The scanner’s generic SSH command check runs six read-only
showcommands and matches the output against the patterns written for each rule. Two audit files, one per STIG. - A read-only API collector. A Python script reads the documented ISE REST APIs, masks any field whose name looks like a secret, and saves the answers.
- A facts file. An evaluator turns the collected answers into a plain
key = valuefile. A third audit file reads it on the collector host with the scanner’s file-content check, so API verdicts appear beside SSH ones.
The evaluator also writes two STIG Viewer 2 checklists (.ckl) and a results CSV covering all 81 rules. A per-rule coverage file records mechanism, command or endpoint, field, pass condition and, for manual rules, the reason.
Coverage
| Outcome | NDM | NAC | Total |
|---|---|---|---|
| Fully automated (CLI and/or API) | 14 | 10 | 24 |
| Partly automated, manual remainder | 6 | 1 | 7 |
| Manual: no documented interface | 29 | 19 | 48 |
| Manual: procedural (SSP review) | 2 | 0 | 2 |
The manual rules cluster in areas where the vendor documents no API, no CLI command and no read-only database view: logging configuration (26 rules), posture policy (8), FIPS mode (7), alarm settings (3), admin access settings (2) and TLS settings (2). None was guessed at.
Design decisions
- A WARNING is never a pass. Every manual rule is emitted as a WARNING with the full STIG check text and the reason it is manual, so it stays on the report.
- Missing data fails safe. A failed request, a missing site setting, an unexpected answer shape or an unknown status word yields “not evaluated”, never PASSED. A missing configuration line fails, so the likely error is a false FAILED rather than a false PASSED.
- Stale or untrusted facts are rejected. The collector-host audit reports WARNING for every rule if the facts file is missing, older than 26 hours, or produced by a dry run or with TLS verification off.
- Policy intent stays with the system security plan. Whether an authorization profile “restricts access” cannot be proven from an API. A rule passes only on a deny profile or a profile the site has listed; a permit-all result fails.
- Least privilege for the tooling. GET is the only data verb. The credential comes from the environment or a secret-store hook, never the command line, and is never written. Output files are owner-readable only.
- No added dependencies. The collector uses only the Python standard library. An optional, untested SSH capture uses a third-party SSH module only if one is already installed.
Evidence and limits
The offline suite, built on invented fixtures and fake HTTP layers, last passed 31 tests; the structural validator, including 76 CLI logic tests, passed all checks. The tests cover GET as the only data verb, credentials absent from every output, the expected status for every rule on compliant and non-compliant fixtures, and WARNING for every rule when the facts file is missing, stale or unverified.
Not yet done:
- Nothing has been run against a live ISE node or through the scanner. All 81 rules are marked unvalidated.
- Every API path, field name and answer shape comes from published documentation, some of it partial; the fixtures were written to match it.
- 17 rules rest on CLI facts either read from the previous release’s CLI reference or found in no reference; none is reconfirmed on the target release.
- The rule text came from public mirrors through a summarising page reader and was transcribed; it has not been compared with the official XCCDF, so wording may differ. The checklists have not yet been imported into STIG Viewer.
The first live run is planned on an isolated lab range. Its build scripts refuse to start the test node unless the lab’s isolation checks pass, and the node is rebuilt from a verified image for each run.
Where it applies
For an organization preparing an authorization package under NIST 800-53 or CMS ARS, the method answers a recurring question: how is configuration compliance (CM-6) shown for a platform the scanning tool does not support? The answer is a split a reviewer can follow: each automated rule traceable to a command or endpoint, each manual rule carrying its reason.
For a manufacturing supplier holding controlled data under NIST 800-171, the same split supports the requirement to establish and enforce security configuration settings and gives a defensible answer when a customer security questionnaire asks how network access control is hardened and checked.
For a fractional security leader, the transferable points are the failure rules: report what tooling cannot see, keep “not evaluated” distinct from “passed”, and validate on an isolated range before trusting a production scan.
Independent work by Wade Blackwell. Each write-up is written from scratch for this site, without client, employer or personal data. Names, hostnames, addresses and configuration detail are left out on purpose.