PassCycler detects break-glass credential exposure in Cisco IOS XE and NX-OS environments and drives safe password rotation workflows through Vault and Ansible.
PassCycler is a three-container workflow:
vault: stores group-based break-glass credentials and password policiessyslog: receives network syslog telemetry from IOS XE and NX-OSorchestrator: correlates Vault exposure with syslog login usage and triggers Ansible rotation
For live log viewing, the runtime stack also includes a lightweight browser viewer on port 8228 that exposes tailed network.log and vault.log streams.
Vault also exposes a small access model for the demo:
Administrator: manages PassCycler policies, auth bindings, and secretsAnsible Password Reader: reads the initial bootstrap password byusernameAnsible Password Cycler: reads and rotates group secrets plus device aliasesOperator 1: reads only the Vault device path fordevnet-cat8kvOperator 2: reads only the Vault device path fordevnet-n9k
The approved trigger model is:
- a secret read in Vault moves the group into
armedstate, - each successful local login seen in syslog extends the
login timeout, - rotation happens when the
login timeoutexpires after the last observed login, or - if no login ever appears, rotation happens on the
dead timeout.
The current default timeouts are 5 min after the last observed login and 10 min after disclosure when no login is observed.
Rotation success is confirmed only after a post-change verification login:
- PassCycler reads the current password from Vault.
- It uses that current password to log in to the device and apply the new password.
- It opens a fresh session with the new password to verify that the change really worked.
- Only after that verification succeeds does it write the new password back to Vault, where the old value remains in KV version history.
- If post-change verification fails, the incident is marked failed and the orchestrator emits a failure event to syslog.
docs/ARCHITECTURE.mdexplains the system boundaries and runtime shape.DEVELOPMENT.mdcovers local setup and test execution.OPERATIONS.mdcovers day-to-day operation and failure handling.docs/DEPLOYMENT_VARIANTS.mddefines the supported deployment models.docs/DEVBOX_DEPLOYMENT.mdcaptures the preferred DevNet sandbox deployment model on10.10.20.50.docs/DEVBOX_RUNBOOK.mdis the exact bootstrap and runtime procedure for the DevNet sandbox on theDevBox.docs/OWN_INFRA_RUNBOOK.mdis the exact bootstrap and runtime procedure for the own-infrastructure variant.AGENTS.mddocuments collaboration rules for automated workers.docs/superpowers/specs/2026-04-20-passcycler-design.mdis the current approved design basis.
This repository is being scaffolded in stages. The current foundation includes:
- standard project documentation,
- packaging metadata and test scaffolding,
- Docker Compose runtime skeleton,
- file-backed runtime configuration in
config/passcycler.yml, - Vault bootstrap assets,
- IOS XE and NX-OS Ansible bootstrap and rotation playbooks,
- a tested Python incident/state foundation,
- a polling orchestrator loop that tails Vault audit and syslog files,
- seeded Vault paths for canonical group secrets, bootstrap lookup by
username, and per-device operator aliases.
Current local verification:
python3 -m pytest tests/test_docs_structure.py tests/test_stack_layout.py tests/test_ansible_files.py tests/test_passwords.py tests/test_events.py tests/test_incident_engine.py -vpython3 -m pytest tests/test_rotation.py -vpython3 -m ruff check src testspython3 -m mypy src/passcyclerPYTHONPYCACHEPREFIX=/tmp/passcycler-pyc python3 -m compileall src
The primary demo target is a mixed Cisco DevNet Sandbox lab:
devnet-cat8kvon10.10.20.48forIOS XEdevnet-n9kon10.10.20.40forNX-OS
Connectivity prerequisites for the published demo are:
- reserve the sandbox via Cisco DevNet Sandbox; Cisco DevNet login supports GitHub, Cisco ID, Google, and Webex accounts
- use the specific sandbox
IOS XE on Cat8kv: IOS XE on Cat8kv - connect with
Cisco Secure Client 5orOpenConnect - use ansible/inventory.devnet.bootstrap.yml as a template for sandbox bootstrap usernames and passwords from your reservation
- use ansible/inventory.devnet.yml as a template for steady-state rotation with your current break-glass accounts
- for the sandbox deployment model, prefer running
vault + syslog + orchestratordirectly on the reachableDevBoxat10.10.20.50; this DevBox-oriented configuration was prepared for theIOS XE on Cat8kvsandbox; see docs/DEVBOX_DEPLOYMENT.md - for the sandbox workflow, clone the repository directly on the
DevBoxand run both switch bootstrap and Docker deployment there; see docs/DEVBOX_RUNBOOK.md - for the initial break-glass password on the devices, use
PASSCYCLER_INITIAL_IOSXE_PASSWORDandPASSCYCLER_INITIAL_NXOS_PASSWORDin.env.devbox; the DevBox bootstrap helper applies those same values to the devices and Vault - for easy repeatable updates on the
DevBox, use scripts/deploy_devbox.sh - use scripts/devnet_syslog_relay.py only as a local fallback diagnostic helper when the stack is still running on the laptop
This public release ships placeholder DevNet inventory files in ansible/inventory.devnet.bootstrap.yml and ansible/inventory.devnet.yml. Replace those placeholders with the credentials from your current reservation or lab before testing. Vault tokens and any non-public credentials must stay out of git.
For the exact sandbox procedure, use docs/DEVBOX_RUNBOOK.md.
Important bootstrap constraint:
- PassCycler must preserve the published static sandbox usernames already present on the devices.
- The bootstrap playbooks only add and maintain the PassCycler break-glass account plus related logging and AAA settings.
PassCycler maintains two supported deployment variants:
Cisco DevNet sandbox: deploy the full stack on the sandboxDevBox; see docs/DEVBOX_DEPLOYMENT.mdOwn infrastructure: deploy locally with direct bidirectional reachability between the Docker host and the managed devices; see docs/DEPLOYMENT_VARIANTS.md and ansible/inventory.local.example.yml
Compose entrypoints:
DevNet sandbox / DevBox:docker compose --env-file .env.devbox.example -f docker-compose.yml -f docker-compose.devbox.yml up -dOwn infrastructure:docker compose --env-file .env.local.example -f docker-compose.yml -f docker-compose.local.yml up -d
Published UI ports:
Vault UI/API:8200/tcpSyslog viewer:8228/tcp
Easy update helpers:
DevNet sandbox / DevBox: scripts/deploy_devbox.shOwn infrastructure: scripts/deploy_local.sh
The DevBox helper prints the Vault URI, the Syslog viewer URI, and the current bootstrap Vault root token after a successful update.
Exact runbooks:
DevNet sandbox / DevBox: docs/DEVBOX_RUNBOOK.mdOwn infrastructure: docs/OWN_INFRA_RUNBOOK.md
- The DevNet sandbox is not exercised automatically from this local scaffold.
- Real Vault tokens and other non-sandbox secrets must stay out of git.
- Cisco IOS XE and NX-OS bootstrap currently use
network_cliover SSH for reliability during first-device setup. - The current
NX-OS 9.3(5)sandbox image does not expose local-userpassword 6syntax even withfeature password encryption aesenabled. PassCycler enables the AES feature but uses the strongest local-user storage that the platform CLI actually supports. - The DevNet demo bootstrap also disables NX-OS
password strength-checkso the seeded break-glass password from.env.devboxcan be applied deterministically during the sandbox baseline. - Per-device Vault aliases do not change the fact that a shared group password grants access to the whole group. Strong isolation requires per-device passwords, which remain out of scope for v1.
