Skip to content

Unavoidable Long-Lived Secrets — Inventory and Compensating Controls

Status: Living document — update on every new unavoidable credential Decision date: 2026-04-16 Decision owner: Rory Review cadence: Quarterly; also on every new integration evaluation SOC2 controls: CC6.1 Logical Access Security, CC6.3 Role-Based Access, CC7.2 Monitoring for Anomalies


Purpose

Cirius defaults to passwordless authentication wherever the downstream system supports it: managed identity for Azure-native, OIDC workload identity federation for GitHub Actions → Azure/AWS, certificate auth for Graph app registrations where federation is unavailable. This document lists the credentials that cannot be eliminated after all of those have been applied — credentials that remain long-lived because the downstream system does not accept any other form of authentication, or because the credential is a last-resort break-glass path that by definition must keep working when federated identity is broken.

Every item on this list is accompanied by:

  • Why it cannot be eliminated — the platform constraint or operational requirement.
  • Justification — the legitimate business / security reason the secret continues to exist.
  • Rotation schedule — concrete cadence.
  • Compensating controls — storage, access, logging, alerting, scoped privilege.

Auditors reading this should be able to answer "why does Cirius still have a long-lived X?" without asking a human.


Inventory

1. Cortex XDR API Key

  • Stored at: cirius-openai-kv-prod / secret cortex-api-key (value) and cortex-api-key-id (numeric key ID).
  • Why unavoidable: Palo Alto Cortex XDR SaaS public API accepts only its own HMAC-based API key scheme. No Entra federation, no OIDC exchange, no managed identity. Full analysis in security/secrets-managed-identity-eval.md.
  • Justification: Cortex XDR is the sole EDR for all Windows VMs and managed devices across PROD and DDE. The weekly audit (scripts/cortex-audit.py) and the CMDB upsert (scripts/cmdb-upsert-cortex.py) require read access to endpoints, incidents, alerts, and vulnerabilities. Removing this integration would blind the compliance pipeline.
  • Rotation schedule: Every 180 days. New key generated in Cortex XDR console (Settings → Configurations → Integrations → API Keys), stored to KV with a new version, old version disabled after one full weekly workflow cycle confirms success. Enforced by _THIRD_PARTY_POLICY["cortex-api-key"] = 180 in credential_expiry_findings_agent.py.
  • Compensating controls:
    • Storage: Key Vault, CMK, private endpoint, soft delete, 90-day recovery.
    • Access: Key Vault Secrets Usergithub-deploy-main SP (OIDC-only)
      • SecOps Container App managed identity. No human gets persistent read.
    • Scope: Advanced API key with read-only scopes on the four endpoints the agent actually calls. No write, no admin.
    • Logging: Every SecretGet against this secret goes to cirius-logging-law-central. Any caller identity other than the two approved identities triggers a HIGH finding.
    • Expiry: KV version has expires_on set to rotation date + 7 days (grace). credential_expiry_agent.py (SECRETS-033) flags 30/14/7 days out.
    • Incident path: revocation from Cortex console takes effect immediately; the same console is the rotation control plane, so revocation requires no additional path.

2. Palo Alto Firewall Local Admin Passwords (4 firewalls)

  • Stored at: Key Vault cirius-openai-kv-prod / pa-localadmin-<device-name> for each of: azure-prod-panorama, azure-prod-firewall, azure-dde-firewall, aws-networking-firewall.
  • Why unavoidable: PAN-OS local admin is the break-glass path. When Entra (used for PAN-OS admin SSO) is unreachable, the local account is the only way to recover the firewall. PAN-OS does not federate the local account — by design it cannot depend on any external system.
  • Justification: These firewalls stand between the internet and all Azure VNets and AWS VPCs in our environment. If Entra is down and the firewall needs emergency configuration (block a live attack, restore a rule set, unbrick after a failed deploy), no other path exists.
  • Rotation schedule: Annual — full password rotation on all four firewalls during the annual break-glass kit verification runbook (runbooks/annual-bgkit-verification.md). Also rotated immediately on any event that might have compromised the current password (e.g., printout handed to someone who has left, console screen share logged incorrectly).
  • Compensating controls:
    • Storage: Key Vault, CMK, private endpoint.
    • Access: No service principal has Key Vault Secrets User on these secrets. Rory alone has Key Vault Secrets Officer via PIM with approval + justification. Retrieval requires a PIM elevation event that is logged to SecOps.
    • Usage monitoring: Any activity by a Palo Alto local admin account is CRITICAL by permanent rule — hard-blocked from suppression at the SecOps API layer, same as all 18 break-glass accounts.
    • Physical: One offline printed copy per firewall in the break-glass kit (sealed envelope, tamper-evident, stored in Kevin and Greg's physical possession for DR scenarios). Verified intact in annual runbook. Re-sealed after any use.
    • Length/complexity: 32 random characters, Entra-unknown, never reused.

3. Break-Glass Cloud Account Passwords

  • Accounts:
    • cirius-breakglass@ciriusgroup.com (Entra PROD)
    • cirius-breakglass@ciriusdde.com (Entra DDE)
    • On-prem AD break-glass (3 accounts on the DR domain)
    • AWS root accounts — all 7 accounts in the organization (Management, Backup, Dev, Identity, Logging, Networking, Prod)
  • Stored at: Offline — printed, sealed envelopes in physical break-glass kit. Not in Key Vault. This is intentional: if Entra or the KV access path is compromised, the break-glass credential must still work.
  • Why unavoidable: Break-glass is the last resort when the primary identity plane (Entra + PIM + Conditional Access) is unavailable or compromised. By definition it cannot depend on the plane it is breaking glass around. AWS root in particular is a hard AWS constraint — root is the only account that can perform a handful of recovery operations (e.g., change the account's support plan, close the account).
  • Justification: HIPAA business continuity requirement. Our runbooks assume these credentials continue to exist and work; eliminating them would cause a DR scenario to fail.
  • Rotation schedule: Annual — verified + rotated during the annual break-glass kit verification runbook. Also on any of:
    • Departure of anyone who ever held physical custody of the kit.
    • Any use of the credential (rotated within 24 hours of use).
    • Any suspected physical tampering of the sealed envelopes.
  • Compensating controls:
    • Storage: Offline-only. Sealed tamper-evident envelopes. Kevin and Greg maintain geographically separated copies.
    • MFA: FIDO2 hardware keys for Entra break-glass (stored with the password envelopes). AWS root requires virtual MFA backed by a hardware key recorded as a second factor.
    • Activity monitoring: Every sign-in or API call by any break-glass identity fires a CRITICAL SecOps finding. Permanently unsuppressible at the SecOps API layer — hard-coded blocklist prevents any known-good rule from matching these accounts.
    • Scope: Break-glass accounts hold Global Administrator / AWS root by necessity. They are excluded from Conditional Access MFA policies (since Entra/MFA might be the thing that's broken) but never from logging or monitoring.
    • Use-then-rotate: SOP requires rotation within 24 hours of any actual use. SecOps alert includes "rotation due by <timestamp>" language to force the follow-up.

4. SecOps Platform INGEST_API_KEY and SECOPS_API_KEY

  • Stored at: Key Vault cirius-openai-kv-prod / ingest-api-key and secops-api-key.
  • Why long-lived: The SecOps platform (ca-secops-prod) exposes X-API-Key for machine-to-machine callers from other clouds (GitHub Actions running in AWS, AWS Lambda, the on-prem syslog VM). Browser users authenticate via Entra SSO and do not touch this key. Entra federation for non-Azure callers is implemented wherever possible (GitHub Actions → Azure → then calls SecOps), but some callers live in environments where we cannot chain through Entra without excessive complexity (e.g., AWS Lambda → SecOps).
  • Justification: SecOps is the control plane for incident suppression, CM ticket creation, and evidence registration. Every automation that feeds SecOps is part of the compliance pipeline.
  • Rotation schedule: Semi-annual — every 6 months. Can be accelerated at any time by rotating the KV secret; consumers reload on next workflow run.
  • Compensating controls:
    • Storage: Key Vault, CMK, private endpoint.
    • Access: GitHub Actions OIDC only; no long-lived consumer stores this key at rest outside KV.
    • Scope: The ingest key is authorised only for POST /api/ingest/findings and POST /api/changes. It cannot suppress incidents, cannot create known-good rules, cannot read the incidents table. The operational key (secops-api-key) has broader read access but still no suppression authority.
    • Transport: HTTPS with HSTS. Key Vault access over private endpoint only.
    • Fail-open: If the key is revoked mid-operation, agents degrade to "raise alerts, skip suppression checks" rather than failing closed (by design — we prefer noisy to blind).
    • Logging: Every API call logs the key ID used and caller IP; any unexpected caller IP fires a finding.

5. Azure OpenAI API Key (cirius-openai-prod)

  • Stored at: Key Vault cirius-openai-kv-prod / openai-api-key.
  • Why long-lived: Some consumers of Azure OpenAI in our environment use the Python SDK in ways that do not yet support DefaultAzureCredential token auth cleanly. Specifically, older versions of the LLM client libraries embedded in the SecurityAgent require a static API key.
  • Justification: Azure OpenAI is the GPT-4o backend for the SecurityAgent triage pipeline. Without it, the detection agent cannot enrich OPEN tickets with LLM triage.
  • Rotation schedule: Quarterly — every 90 days. Also on any library upgrade that promises full Entra auth support (trigger the migration at that point).
  • Compensating controls:
    • Storage: Key Vault, CMK, private endpoint.
    • Access: SecOps Container App managed identity only.
    • Scope: Read-only against the specific gpt-4o deployment. No quota admin, no deployment management.
    • Logging: All Azure OpenAI calls logged via diagnostic settings; unusual volume (DoS / exfiltration attempt) fires a HIGH finding.
    • Migration target: Once the SDK path cleanly supports Entra auth, remove this key and authenticate using the Container App managed identity.

6. Arctic Wolf MDR API Credentials

  • Stored at: Key Vault cirius-openai-kv-prod / arctic-wolf-api-key.
  • Why long-lived: Arctic Wolf's portal API accepts only its own vendor-issued API key. Arctic Wolf does not offer Entra federation or OIDC exchange for machine-to-machine callers.
  • Justification: Arctic Wolf is the MDR for all managed devices. Integration with SecOps (pulling investigation status and posting acknowledgements) requires this API key.
  • Rotation schedule: Semi-annual — every 6 months, coordinated with the Arctic Wolf account manager. Rotation procedure involves raising a ticket with Arctic Wolf.
  • Compensating controls:
    • Storage: Key Vault, CMK, private endpoint.
    • Access: SecOps Container App managed identity only.
    • Scope: Read-only scopes for investigations and findings. No configuration-change permissions.
    • Logging: Every API call logged; any non-SecOps caller IP fires a HIGH finding.

What Is Not on This List

For reference, the following were evaluated for inclusion and rejected because they are either eliminated or on an active migration path:

  • GitHub Actions → Azure / AWS auth — fully OIDC federated, no stored credentials.
  • SecOps → PostgreSQL psql-secops-prod — managed identity (AAD-only auth on the PostgreSQL flexible server).
  • SecOps → Key Vault — managed identity.
  • Graph API app registrations — migrating to certificate auth (see security/graph-api-cert-auth-eval.md). Once the migration completes, none of those app regs will hold a long-lived client secret.
  • Azure VM → Key Vault / Storage — system-assigned managed identity on each VM.

Governance

  • This document is the definitive inventory. No credential may be introduced into the environment without either: (a) being impossible to eliminate via managed identity / OIDC / cert auth (in which case it is added to this inventory with the same rigor), or (b) being eliminated by the end of the implementation sprint.
  • New integrations undergo the "managed identity eval" pattern from security/secrets-managed-identity-eval.md before any key or secret is introduced.
  • The quarterly review compares this inventory against Key Vault contents. Any KV secret not listed here is a finding — either it should be added (with justification) or it should be migrated away.

  • security/secrets-managed-identity-eval.md — managed identity evaluation (Cortex XDR case study)
  • security/graph-api-cert-auth-eval.md — Graph app reg certificate auth migration plan
  • runbooks/annual-bgkit-verification.md — break-glass kit annual verification procedure
  • compliance/ — SOC2 evidence binders for CC6.1, CC6.3, CC7.2

Internal use only — Cirius Group