# Bookstore — Part 11 ch.05 "Secrets at scale": DYNAMIC secrets — an ESO
# ExternalSecret that, instead of reading a STATIC value, makes Vault's
# DATABASE secrets engine GENERATE a fresh, short-lived Postgres role on
# demand (Vault creates the DB user, hands back creds with a LEASE, and
# DELETES the user when the lease expires).
#
# STATIC vs DYNAMIC (the core idea this file teaches)
#   20-externalsecret-db-credentials.yaml syncs a STATIC secret (one value in
#   Vault KV; rotation = you change it). DYNAMIC secrets have NO stored
#   password: Vault holds the privileged "create-a-role" credential, and on
#   each request mints a UNIQUE short-TTL Postgres user (e.g. valid 1h). A
#   leaked dynamic credential is useless after its lease; revocation is
#   instant (revoke the lease → Vault drops the DB user). This is the
#   strongest form of the Part 03 ch.02 / Part 05 ch.04 "short blast-radius
#   window" production note, made concrete.
#
# VAULT-SIDE SETUP (the `vault` CLI it assumes — NOT kubectl; dev-mode):
#   vault secrets enable database
#   vault write database/config/bookstore-pg \
#     plugin_name=postgresql-database-plugin \
#     allowed_roles="bookstore-app" \
#     connection_url="postgresql://{{username}}:{{password}}@postgres.bookstore.svc.cluster.local:5432/bookstore?sslmode=disable" \
#     username="bookstore" password="devpassword"   # the bootstrap admin (demo)
#   vault write database/roles/bookstore-app \
#     db_name=bookstore-pg \
#     creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
#     default_ttl="1h" max_ttl="24h"
#   (bookstore-ro policy in 00- already allows read on database/creds/bookstore-app.)
#
# NOTE — this is DEMONSTRATED but NOT wired into the running Bookstore by
# default: the app builds ONE DB_DSN at start (Part 03 ch.02) and would need a
# re-render/rollout (or a Vault Agent template sidecar) to consume rotating
# dynamic creds. Shown as the pattern + the production direction; the static
# 20- ExternalSecret is the drop-in 16- replacement. Honest about the gap.
#
# !!! CRD-INTRINSIC DRY-RUN (precedent: 18-/51-/70-/83-/argocd) !!!
#   `ExternalSecret` is external-secrets.io/v1 (ESO CRD). WITHOUT ESO a client
#   dry-run prints `no matches for kind "ExternalSecret" in version
#   "external-secrets.io/v1"` — EXPECTED, schema-correct; ESO must be
#   installed first. Whole-dir dry-run prints this for CRD files only and
#   continues. Schema verified against ESO external-secrets.io/v1.
#
# Requires: ESO installed; Vault database engine configured (above).
# Apply (illustrative — short-lived creds in a Secret you can inspect):
#   kubectl apply -f examples/bookstore/secrets/30-externalsecret-dynamic-db.yaml
#   kubectl get secret bookstore-db-dynamic -n bookstore -o jsonpath='{.data.username}' | base64 -d
#   # re-read after >1h: the username/password DIFFER — Vault minted new ones.
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
  name: bookstore-db-dynamic
  namespace: bookstore
  labels:
    app.kubernetes.io/part-of: bookstore
spec:
  # Short refresh so the demo shows rotation quickly; in production align it
  # to (well under) the Vault role's default_ttl so creds never expire in use.
  refreshInterval: "30m"
  secretStoreRef:
    name: vault-backend             # 10-secretstore-vault.yaml
    kind: SecretStore
  target:
    name: bookstore-db-dynamic      # a SEPARATE Secret (not db-credentials) —
    creationPolicy: Owner           # this is the dynamic-creds demo, additive
    template:
      type: Opaque
  data:
    # Vault's database/creds/<role> endpoint returns `username` + `password`
    # for a freshly-created, lease-bound Postgres role. ESO surfaces them and
    # re-generates on refresh (old lease/role revoked by Vault on expiry).
    - secretKey: username
      remoteRef:
        key: database/creds/bookstore-app
        property: username
    - secretKey: password
      remoteRef:
        key: database/creds/bookstore-app
        property: password
