Address bot review on #40654:
- SecretsMigrator now tries the previous key under both the column's
configured engine and the historical AES-CBC engine, so SECRET_KEY
rotation works for AES-GCM deployments (not just CBC) while still
reading CBC source data after an engine-flipped-first migration.
- re-encrypt-secrets --engine accepts case-insensitive engine names.
- Adapter logs a warning when SQLALCHEMY_ENCRYPTED_FIELD_ENGINE is
unrecognized before falling back to AES-CBC.
- config.py points operators at the SQLALCHEMY_ENCRYPTED_FIELD_ENGINE
knob as the preferred way to switch engines.
- Add unit test covering AES-GCM SECRET_KEY rotation.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Phase 2 of the authenticated-encryption-at-rest proposal. Teaches the
existing SecretsMigrator an engine-migration mode (decrypt with the source
engine under the current SECRET_KEY, re-encrypt with a target engine) and
exposes it via `superset re-encrypt-secrets --engine aes-gcm`. The run is
transactional and idempotent per column, so existing installs can move from
AES-CBC to authenticated AES-GCM without bricking stored secrets. Default
engine is unchanged ("aes"); behavior is opt-in. Adds UPDATING.md runbook and
updates the SIP to reflect Phases 1–2 shipping here.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
App-encrypted fields (DB passwords, SSH tunnel creds, OAuth tokens) use
sqlalchemy_utils EncryptedType, which defaults to AES-CBC — unauthenticated
encryption vulnerable to bit-flipping/tamper of ciphertext at rest. AES-GCM is
authenticated and fails closed on tampering.
Phase 1 (this change, backward compatible): add a configurable encryption
engine via SQLALCHEMY_ENCRYPTED_FIELD_ENGINE ("aes" | "aes-gcm"), defaulting to
"aes" so existing deployments are unchanged. The default SQLAlchemyUtilsAdapter
now honors it; an explicit engine kwarg still wins. New installs can opt into
AES-GCM with one line instead of writing a custom adapter.
Includes docs/sip/authenticated-encryption-at-rest.md describing the full
proposal: Phase 2 (a CBC->GCM re-encryption migrator built on SecretsMigrator)
and Phase 3 (flip default for fresh installs). The instance-wide re-encryption
migration is intentionally NOT included here — it is the subject of the SIP.
DRAFT: flipping the engine on a populated DB without the Phase 2 migrator makes
existing secrets undecryptable; this PR only adds the safe opt-in plumbing for
discussion.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>