Skip to content

Support credential rotation for database backends when max_ttl is reached #929

@laurentpellegrino

Description

@laurentpellegrino

Context

The documentation for spring.cloud.vault.config.lifecycle.enabled states:

"enabled controls whether leases associated with secrets are considered to be renewed and expired secrets are rotated."

However, the database backends documentation explicitly states the opposite:

"Spring Cloud Vault does not support getting new credentials and configuring your DataSource with them when the maximum lease time has been reached. That is, if max_ttl of the Database
role in Vault is set to 24h that means that 24 hours after your application has started it can no longer authenticate with the database."

This creates confusion and a significant operational limitation for long-running applications using dynamic database credentials.

Problem

When spring-cloud-vault-config-databases fetches credentials from database/creds/<role>, the Vault response includes renewable: true. Spring Cloud Vault then selects RENEW mode
for the lease lifecycle:

DEBUG LeaseAwareVaultPropertySource : Requesting secrets from Vault at database/creds/my-role using RENEW

In RENEW mode:

  • The lease TTL is periodically extended (same credentials)
  • When max_ttl is reached, renewal fails
  • The credentials are revoked by Vault
  • No new credentials are fetched — the application loses database connectivity

The rotation mechanism ("expired secrets are rotated") exists in SecretLeaseContainer for non-renewable secrets (ROTATE mode), but database credentials are excluded because the
renewable flag in the Vault response drives the mode selection.

Prior issues

This has been reported multiple times and closed as "invalid" or redirected to StackOverflow:

In #152, the response was:

"Credentials obtained via Spring Cloud Vault are renewed until their terminal TTL expires but they are not rotated."

Why this matters

The renewable: true flag in Vault's response means the lease TTL can be extended, not that renewal is the only appropriate strategy. For database dynamic credentials, max_ttl is an
absolute ceiling. After it's reached:

  • The credentials are revoked regardless of renewal attempts
  • The application must read database/creds/<role> again to get new credentials
  • This is exactly what ROTATE mode does — but it's not used because renewable: true

Proposed solution

One or more of:

  1. Allow configuring the lifecycle mode per backend, e.g.:
    spring.cloud.vault:
      mongodb:
        lifecycle-mode: rotate
    
  2. Default to ROTATE for database backends — the spring-cloud-vault-config-databases module knows it's a database backend, so it could override the mode regardless of the renewable flag.
  3. Fall back to ROTATE when RENEW fails — when a renewable lease reaches max_ttl and renewal fails, automatically re-read the secret (effectively switching from RENEW to ROTATE) instead of
    giving up.
  4. Fire SecretLeaseCreatedEvent with new credentials on rotation so applications can react (e.g., recreate MongoClient/DataSource).

Current workaround

Applications must implement custom credential rotation: manually read new credentials from Vault via VaultOperations, create a new database client, and schedule the next rotation based on
the lease duration. This bypasses Spring Cloud Vault's lifecycle management entirely.

Versions

  • Spring Cloud Vault: 5.0.1
  • Spring Boot: 4.0.3
  • Vault server: OpenBao 2.5.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions