# Secrets are a Supply Chain

> Everyone rotates secrets.
> 
> Very few design **secret lifecycle risk** and that gap is where breaches live.

Most organizations believe secret rotation equals security. It doesn’t.

Rotation is a **maintenance activity**. Security is a **system design outcome**.

This article reframes secrets as **first-class supply-chain artifacts**; governed by contracts, events, blast radius, and standards, not cron jobs and hope.

---

# Why This Matters (The Reality)

In every serious breach review, the same pattern emerges:

* The secret *was* rotated
    
* The vault *did* exist
    
* Access *was* “restricted”
    

And yet:

* The secret lived longer than the risk window
    
* The blast radius was undefined
    
* Revocation depended on humans
    
* Audits validated screenshots, not behaviour
    

**The failure was architectural, not operational.**

---

# The Shift in Thinking: Secrets as a Supply Chain

Treat secrets like:

* TLS certificates
    
* IAM trust relationships
    
* API contracts
    

They have a lifecycle:

1. Creation
    
2. Distribution
    
3. Consumption
    
4. Expiration
    
5. Revocation
    
6. Forensics
    

If any of these are implicit, undocumented or manual, the system is fragile by design.

---

# Core Design Principles (Non-Negotiable)

### 1️⃣ Secrets Are Expiring Contracts

Every secret must explicitly define:

* **Owner**
    
* **Consumer**
    
* **Environment**
    
* **Maximum lifetime**
    
* **Invalidation triggers**
    

A secret without an expiry condition is a **latent incident**.

### 2️⃣ Rotation Must Be Event-Driven

Time-based rotation answers auditors. Event-based rotation answers attackers.

Rotation should be triggered by **risk**, not calendars:

| Event | Why |
| --- | --- |
| Auth code change | Exposure risk |
| Production deployment | Trust boundary reset |
| Incident/alert | Containment |
| Access policy change | Least privilege enforcement |

### 3️⃣ Blast Radius Is a First-Class Property

Every secret must answer one question clearly:

> *If this leaks, what breaks and what does not?*

If you can’t answer that in one sentence, the secret is already unsafe.

---

## Reference Architecture (End-to-End)

![Image](https://www.hashicorp.com/_next/image?q=75&url=https%3A%2F%2Fwww.datocms-assets.com%2F2885%2F1691011664-k8s-vault-sidecar-workflow-copy-2x.png&w=3840 align="left")

### Architectural Components

* **Secrets Authority** (Vault / Secrets Manager)
    
* **Contracts as Code** (YAML)
    
* **CI/CD Pipelines** (event triggers)
    
* **Policy Engine** (blast-radius enforcement)
    
* **Runtime Injection** (no persistence)
    
* **Audit Sink** (immutable evidence)
    

This architecture makes **compromise naturally expire**.

---

## Real-World Failure (Before)

A production API key leaked via application logs.

What actually happened:

* Rotated every 30 days
    
* Same key used across prod, staging, DR
    
* Incident response revoked prod only
    
* Staging continued leaking data silently
    

**Root cause:**

* No lifecycle ownership
    
* No blast-radius modelling
    
* No event-driven revocation
    

Rotation existed. Security did not.

---

# The Fix: Lifecycle-Aware Secret Design

![Integrate Terraform with Vault | HashiCorp Developer](https://developer.hashicorp.com/_next/image?dpl=dpl_DsRcgFnyFJztV9HKwqPqF6Ai7RGX&q=75&url=https%3A%2F%2Fcontent.hashicorp.com%2Fapi%2Fassets%3Fproduct%3Dtutorials%26version%3Dmain%26asset%3Dpublic%252Fimg%252Fvalidated-patterns%252Fterraform-better-together-vault%252Fterraform-secrets.png%26width%3D1560%26height%3D1427&w=3840 align="left")

## Implementation

### Step 1: Define Secret Contracts (Single Source of Truth)

`contracts/payment-api.yaml`

```yaml
name: payment-api-key
owner: payments-team
environment: prod
services:
  - billing-service
  - reconciliation-worker
ttl: 86400
rotate_on:
  - commit
  - deployment
  - incident
blast_radius: minimal
compliance:
  iso_27001: A.9.2
  pci_dss: 3.6
```

This file is simultaneously:

* Design documentation
    
* Security policy input
    
* Audit evidence
    

### Step 2: Provision Secrets via Terraform

```markdown
resource "random_password" "secret" {
  length  = 32
  special = false
}

resource "vault_generic_secret" "payment" {
  path = "secret/payment-api-key"

  data_json = jsonencode({
    value = random_password.secret.result
    owner = "payments-team"
    env   = "prod"
  })

  lifecycle {
    create_before_destroy = true
  }
}
```

✔ Immutable  
✔ Auditable  
✔ Automatically regenerated

### Step 3: Enforce Blast Radius with Policy

```markdown
path "secret/payment-api-key" {
  capabilities = ["read"]
  allowed_parameters = {
    env = ["prod"]
  }
}
```

A leaked secret **cannot escape its boundary** — even if exposed.

### Step 4: Rotate on Risky Commits

```yaml
on:
  push:
    paths:
      - "auth/**"
      - "security/**"

jobs:
  rotate:
    runs-on: ubuntu-latest
    steps:
      - run: |
          vault lease revoke -prefix secret/payment-api-key
```

Secrets die **before attackers finish reconnaissance**.

### Step 5: Rotate on Production Deployments

```yaml
on:
  deployment:
    environment: production

jobs:
  rotate:
    steps:
      - run: |
          vault lease revoke -prefix secret/payment-api-key
```

Every deploy = **fresh trust boundary**.

### Step 6: Incident-Triggered Revocation

```python
def handler(event, context):
    if event["severity"] == "CRITICAL":
        revoke("payment-api-key")
```

Connected to:

* SIEM
    
* PagerDuty
    
* Cloud alerts
    

Human response time → **zero**.

### Step 7: Runtime-Only Injection

```yaml
env:
  PAYMENT_API_KEY: "{{ vault.secret.payment-api-key }}"
```

* Never stored
    
* Never baked into images
    
* Auto-expires post-deploy
    

---

## Testing = Evidence (Not Optional)

### Blast Radius Test

```bash
SERVICE=analytics vault read secret/payment-api-key
# Permission denied
```

### Expiry Test

```bash
sleep 86400
vault read secret/payment-api-key
# Lease expired
```

Tests double as **audit artifacts**.

---

# ISO 27001 & PCI Mapping (By Design)

| Control | How It’s Satisfied |
| --- | --- |
| ISO A.9 Access Control | Policy-enforced blast radius |
| ISO A.12 Logging | Immutable pipeline + vault logs |
| ISO A.14 Secure SDLC | Event-driven rotation |
| PCI 3.6 | TTL, revocation, segregation |

Auditors don’t ask for screenshots. They inspect **system behaviour**.

---

# What Changes Organizationally

**Before**

* Manual rotations
    
* Jira tickets
    
* Screenshots
    
* High MTTR
    

**After**

* Zero tickets
    
* Zero screenshots
    
* Seconds to containment
    
* Compliance as a side effect
    

Security stops being a **department**. It becomes a **property of the system**.

---

# Final Takeaway

> Mature security isn’t about adding more tools.  
> It’s about designing systems where **trust naturally expires**.

Secrets are not configuration. They are **relationships,** and every relationship needs:

* boundaries
    
* ownership
    
* expiration
    
* accountability
