diff --git a/lib/tbot/service_workload_identity_api.go b/lib/tbot/service_workload_identity_api.go index f71e6cc940e5d..e469cf875b542 100644 --- a/lib/tbot/service_workload_identity_api.go +++ b/lib/tbot/service_workload_identity_api.go @@ -311,8 +311,13 @@ func (s *WorkloadIdentityAPIService) FetchX509SVID( if err != nil { return trace.Wrap(err, "fetching CRL set from cache") } + renewalInterval := cmp.Or( + s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime, + ).RenewalInterval var svids []*workloadpb.X509SVID + renewalTimer := time.NewTimer(renewalInterval) + defer renewalTimer.Stop() for { log.InfoContext(ctx, "Starting to issue X509 SVIDs to workload") @@ -322,6 +327,10 @@ func (s *WorkloadIdentityAPIService) FetchX509SVID( if err != nil { return trace.Wrap(err) } + // Reset our renewal timer to renew these freshly fetched SVIDs + // renewal_interval from now. + renewalTimer.Reset(renewalInterval) + // The SPIFFE Workload API (5.2.1): // // If the client is not entitled to receive any X509-SVIDs, then the @@ -336,7 +345,6 @@ func (s *WorkloadIdentityAPIService) FetchX509SVID( "workload did not pass attestation for any SVIDs", ) } - } resp := &workloadpb.X509SVIDResponse{ @@ -380,7 +388,7 @@ func (s *WorkloadIdentityAPIService) FetchX509SVID( log.DebugContext(ctx, "CRL set has been updated, distributing to client") crlSet = newCRLSet continue - case <-time.After(cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).RenewalInterval): + case <-renewalTimer.C: log.DebugContext(ctx, "Renewal interval reached, renewing SVIDs") svids = nil continue diff --git a/lib/tbot/service_workload_identity_x509.go b/lib/tbot/service_workload_identity_x509.go index 21c9ef024858e..be4e83e26d3cb 100644 --- a/lib/tbot/service_workload_identity_x509.go +++ b/lib/tbot/service_workload_identity_x509.go @@ -104,6 +104,9 @@ func (s *WorkloadIdentityX509Service) Run(ctx context.Context) error { if err != nil { return trace.Wrap(err, "getting CRL set from cache") } + renewalInterval := cmp.Or( + s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime, + ).RenewalInterval if s.statusReporter == nil { s.statusReporter = readyz.NoopReporter() @@ -115,6 +118,8 @@ func (s *WorkloadIdentityX509Service) Run(ctx context.Context) error { var failures int firstRun := make(chan struct{}, 1) firstRun <- struct{}{} + renewalTimer := time.NewTimer(renewalInterval) + defer renewalTimer.Stop() for { var retryAfter <-chan time.Time if failures > 0 { @@ -154,7 +159,7 @@ func (s *WorkloadIdentityX509Service) Run(ctx context.Context) error { } crlSet = newCRLSet s.log.DebugContext(ctx, "CRL set has been updated, will regenerate output") - case <-time.After(cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).RenewalInterval): + case <-renewalTimer.C: s.log.InfoContext(ctx, "Renewal interval reached, renewing SVIDs") x509Cred = nil privateKey = nil @@ -169,6 +174,8 @@ func (s *WorkloadIdentityX509Service) Run(ctx context.Context) error { failures++ continue } + // Reset the renewal timer to the configured interval. + renewalTimer.Reset(renewalInterval) } if err := s.render( ctx, bundleSet, x509Cred, privateKey, crlSet,