# Secrets are stored in a dedicated secrets manager with encryption at rest

- **Pattern:** `ab-001641` (`infrastructure-hardening.access-control-rbac.secrets-encrypted`)
- **Severity:** medium
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001641
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001641)

## Why it matters

Kubernetes Secrets stored without encryption at rest are base64-encoded plaintext in etcd — any operator with etcd access, a backup file, or an `etcd snapshot` command can decode every database password and API key in the cluster (CWE-312, OWASP A02). NIST 800-53 SC-28 requires encryption of data at rest. Secrets checked into ConfigMaps are worse — they appear in `kubectl get configmap -o yaml` with no access differentiation from application configuration. A hardcoded credential in a manifest that enters git history is exposed to every developer, CI system, and repository fork for the lifetime of the repo.

## Severity rationale

Medium because etcd encryption at rest is often disabled by default, making Kubernetes Secrets accessible to anyone with cluster backup or etcd read access without application-layer attack.

## Remediation

Enable etcd encryption at rest and reference secrets via `secretKeyRef` in all manifests. Configure etcd encryption in `/etc/kubernetes/encryption.yaml` on the control plane:

```yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
      - secrets
    providers:
      - aescbc:
          keys:
            - name: key1
              secret: <base64-encoded-32-byte-key>
      - identity: {}
```

Then reference secrets in Deployments:

```yaml
env:
  - name: DB_PASSWORD
    valueFrom:
      secretKeyRef:
        name: db-credentials
        key: password
```

For stronger guarantees, use HashiCorp Vault with the Vault Agent Injector or the Secrets Store CSI driver to mount secrets at runtime without storing them in etcd.

## Detection

- **ID:** `secrets-encrypted`
- **Severity:** `medium`
- **What to look for:** Enumerate every location where secrets are referenced across all manifests and configuration files. For each secret reference, classify it as: (a) dedicated secrets manager (Kubernetes Secrets, Vault, AWS Secrets Manager, Azure Key Vault, GCP Secret Manager), (b) ConfigMap or plaintext, or (c) hardcoded in manifest. Count the total secret references and how many use proper encryption at rest.
- **Pass criteria:** 100% of secrets are stored in a dedicated secrets manager (Kubernetes Secrets with encryption at rest, HashiCorp Vault, or cloud provider service) and referenced via `secretKeyRef` rather than inline values. No secrets appear in ConfigMaps, git history, or hardcoded in manifests. Report: "X secret references found, all Y use encrypted secret stores."
- **Fail criteria:** Any secret is stored in a ConfigMap, checked into git, hardcoded in manifests, or uses plaintext Kubernetes Secrets without encryption at rest.
- **Skip (N/A) when:** The application does not use secrets (extremely rare).
- **Cross-reference:** The `no-secrets-in-layers` check covers secrets leaked into Docker image layers specifically.
- **Detail on fail:** Quote the offending reference. Example: `"Kubernetes manifests reference secrets via ConfigMap instead of Secrets. Secrets are not encrypted at rest."` or `"Database password found in deployment environment variable as literal value instead of secret reference"`
- **Remediation:** Use Kubernetes Secrets with encryption at rest, or a dedicated secrets manager:

  ```yaml
  # Create secret from literal or file
  kubectl create secret generic db-secret \
    --from-literal=password=securepassword \
    --from-file=ca.crt=./ca.crt

  # Reference in Deployment
  env:
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: db-secret
          key: password
  ```

  Enable encryption at rest in etcd (Kubernetes secret storage):

  ```yaml
  # In kube-apiserver startup args
  --encryption-provider-config=/etc/kubernetes/encryption.yaml
  ```

---

## External references

- cwe CWE-312
- owasp A02
- nist SC-28
- external CIS-Kubernetes-5.4.1 — https://www.cisecurity.org/benchmark/kubernetes

Taxons: cryptography-and-secrets, operational-readiness

HTML version: https://auditbuffet.com/patterns/ab-001641
