spring-cloud / spring-cloud-vault

Configuration Integration with HashiCorp Vault
http://cloud.spring.io/spring-cloud-vault/
Apache License 2.0
270 stars 151 forks source link

Expiration ahead of maxTtl #632

Open nguchakov opened 2 years ago

nguchakov commented 2 years ago

Problem I'm trying to implement mongodb rotating secrets. While it's possible to achieve client lifecycle with more that one mongo-clients rolling up, it's hard to guarantee that new mongo client will be inicialised with new credentials before old credentials expires.

What I've tried I've tried to use a custom scope with delayed mongo client destroy. It works better, because it allows queries to start and shutdown gracefully. However, test fails randomly because sometimes expiration happens before queries started, but after old client was gotten from the scope.

class MyService(
 val template:MongoTemplate
){

fun run(){
    // What happens here:
   // _template_ is fetched from the scope ( 20 ms until maxTtl )
   // expiration event happens by spring cloud vault ( 20 ms until maxTtl )
   // real expiration happens by vault ( maxTtl )
   // query is executed and fails
    template.findAll();
}

}

Solution I think it's neccessary to be able to configure min time before maxTtl when expiration should happen. If we have it as an option "expire-ahead-of-max-ttl-ms" in the example above:

// What happens here:
// template is got from the scope ( "expire-ahead-of-max-ttl-ms" + 20 ms until maxTtl )
// expiration event happens by spring cloud vault ("expire-ahead-of-max-ttl-ms" ms until maxTtl )

// query is executed
template.findAll();

// real expiration happens by vault ( maxTtl after "expire-ahead-of-max-ttl-ms" pass )

While we would be still needed to control MongoClient lifecycle, it would be at least possible to do

Another problem here is that vault (as far as I know) doesn't provide maxTtl information for the Lease So we would need to have some approximate timer on an application side.

mp911de commented 2 years ago

SecretLeaseContainer allows configuring minRenewal for exactly such use cases where you want to spin up early on a new client instance or reconfigure credentials. You can either listen to SecretLeaseRotatedEvent or SecretLeaseExpiredEvent through LeaseListeners registered on the SecretLeaseContainer.

Spring Vault cannot know how long you're holding to a resource that was configured with details from a secret/lease so listening to events is the only viable option.

nguchakov commented 2 years ago

However, according to this it seems that following scenario may happen:

after a couple of renewing: renewed.getLeaseDuration().isZero() condition matches.

So vault may revoke user/password, but my application doesn't fetch new one yet

P.S. Sorry, I missed with the right project for the request

mp911de commented 2 years ago

No worries about the project, we can open a ticket in Spring Vault later on.

The zero-duration leads to immediate expiration. It's up to your configuration to pick a renewal period that doesn't fall exactly onto zero-slots. Also, the renewal happens in shorter intervals the shorter a lease is valid.

After all, it's timing and we do not have a real-time system that would allow us to cater for GC pauses. In the authentication support, we introduced a few years ago a RefreshTrigger abstraction to calculate the next time at which the lease is going to be renewed. That could be also a way out.

nguchakov commented 2 years ago

So, if I understand correct, the following configuration is the correct way to have a guaranteed 30m at least before of the real token expiration?

Vault:
maxTtl: 210m
ttl: 90m

Spring:
  minRenewal: 60m 

If I got you right, it's a bit hard to get it from documentation :)

Anyway, I'm going to test that after the weekends and check RefreshTrigger also.