ENG-3566: Wire all DB connections through DBCredentialProvider#8176
Conversation
Add DBCredentialProvider class that sits between SQLAlchemy engine creators and the SecretProvider abstraction. Resolves credentials from static config or AWS Secrets Manager, retries once on auth failure during credential rotation, and sanitizes all connection exceptions to prevent credential leakage. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The build_field_documentation function assumed every anyOf entry has a "type" key, but Pydantic uses "$ref" for nested models. Skip $ref entries to avoid KeyError. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- aws_secrets_manager is None when provider is static - region is required (no default) when AWS is configured - Before-validator constructs from env vars when needed - Fix config doc generator for Optional nested model $ref Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace asserts with explicit raises for cases where upstream validators should prevent None but callers may bypass validation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Route all database engines, migrations, admin endpoints, and health checks through the credential provider so credentials always come from the SecretProvider. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #8176 +/- ##
==========================================
+ Coverage 85.59% 85.61% +0.01%
==========================================
Files 658 658
Lines 42847 42858 +11
Branches 5018 5016 -2
==========================================
+ Hits 36675 36691 +16
+ Misses 5064 5063 -1
+ Partials 1108 1104 -4 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
…URL constants Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
# Conflicts: # src/fides/common/db_credential_provider.py # src/fides/config/secrets/__init__.py # src/fides/config/secrets/aws_secrets_manager_provider.py # src/fides/config/secrets_settings.py # tests/common/test_db_credential_provider.py # tests/config/secrets/test_factory.py
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
|
||
| def get_db_session( | ||
| config: FidesConfig, | ||
| config: FidesConfig, # TODO: remove — no longer used, all callers pass CONFIG |
There was a problem hiding this comment.
I will address this in a follow-up PR -- I suspect I can also remove the sync_database_uri and async_database_uri builders in the db settings , but I want to make sure that wouldn't break anything before removing it.
- Resolve database URL once per request in admin.py - Include CONFIG.database.params in get_database_url() for SSL support - Rename _db_cred_provider to db_cred_provider (public API) - Add tests for get_database_url() with special characters - Extract shared self_signed_cert fixture for SSL tests Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
RDS Proxy may return non-standard error messages on auth failure that don't match SQLSTATE 28P01 or "password authentication failed". Retry on any OperationalError when using dynamic credentials. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Only thing I saw that we might want to document or something in case it ever becomes an issue is the catch-all isinstance(exc, Psycopg2OperationalError). The docstring explicitly acknowledges the tradeoff.
The concern for dynamic-credential deployments with this is: during a DB outage, every pool connection attempt across all workers will hammer Secrets Manager simultaneously (thundering herd). With n workers × m pool_size = many concurrent invalidation calls, this could hit AWS rate limits.
|
@JadeCara re the thundering-herd issue:
The thundering-herd protection in The circuit breaker pattern is built to mitigate this: after the first failed refresh (credentials are fine, DB is just down), subsequent |
…l_secret_name - Region defaults to None, letting boto3 discover it from the environment (AWS_DEFAULT_REGION, ~/.aws/config, instance metadata) - Rename credential_secret_id/readonly_credential_secret_id to credential_secret_name/readonly_credential_secret_name to match AWS Secrets Manager terminology Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Ticket ENG-3566
Description Of Changes
Wires the
DBCredentialProvider(from #8175) into all database connection paths so credentials always come from the provider — no hardcoded user/password in config required for AWS Secrets Manager deployments.Code Changes
engine_creators.py— module-level_db_cred_providerreplacesget_db_credentials()/get_readonly_db_credentials(); creator signatures unchanged (no call site changes to ctl_session, session_management, tasks)db_credential_provider.py— addedget_database_url()for callers that need a connection URIsession.py—get_db_session()defaults tomake_sync_creator()when no engine provided (fixes 6 callers that used URI-based path)env.py— alembic online migrations usemake_sync_creator(), offline usesget_database_url()app_setup.py— startupconfigure_dbuses provider URLadmin.py— migrate/reset/configure endpoints use provider URLhealth.py— health check uses provider URLtest_engine_creators.py— removed tests for deleted credential helpers, added SSL context integration testSteps to Confirm
GET /health/databasereturns healthyuser/passwordin confignox -s "pytest(lib)"andnox -s "pytest(misc-unit)"— all tests passPre-Merge Checklist
CHANGELOG.mdupdated