fix raft tls key rotation panic when rotation time in past (#15156)

* fix raft tls key rotation panic when rotation time in past

* add changelog entry

* push out next raft TLS rotation time in case close to elapsing

* consolidate tls key rotation duration calculation

* reduce raft getNextRotationTime padding to 10 seconds

* move tls rotation ticker reset to where its duration is calculated
This commit is contained in:
Chris Capurso 2022-04-25 21:48:34 -04:00 committed by GitHub
parent 2b5be0adec
commit cc531c793d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 23 additions and 13 deletions

3
changelog/15156.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:bug
rafft: fix Raft TLS key rotation panic that occurs if active key is more than 24 hours old
```

View File

@ -473,27 +473,33 @@ func (c *Core) raftTLSRotatePhased(ctx context.Context, logger hclog.Logger, raf
return errors.New("no active raft TLS key found") return errors.New("no active raft TLS key found")
} }
getNextRotationTime := func(next time.Time) time.Time {
now := time.Now()
// active key's CreatedTime + raftTLSRotationPeriod might be in
// the past (meaning it is ready to be rotated) which will cause
// NewTicker to panic when used with time.Until, prevent this by
// pushing out rotation time into very near future
if next.Before(now) {
return now.Add(1 * time.Minute)
}
// push out to ensure proposed time does not elapse
return next.Add(10 * time.Second)
}
// Start the process in a go routine // Start the process in a go routine
go func() { go func() {
nextRotationTime := activeKey.CreatedTime.Add(raftTLSRotationPeriod) nextRotationTime := getNextRotationTime(activeKey.CreatedTime.Add(raftTLSRotationPeriod))
keyCheckInterval := time.NewTicker(1 * time.Minute) keyCheckInterval := time.NewTicker(1 * time.Minute)
defer keyCheckInterval.Stop() defer keyCheckInterval.Stop()
var backoff bool
// ticker is used to prevent memory leak of using time.After in // ticker is used to prevent memory leak of using time.After in
// for - select pattern. // for - select pattern.
ticker := time.NewTicker(time.Until(nextRotationTime)) ticker := time.NewTicker(time.Until(nextRotationTime))
defer ticker.Stop() defer ticker.Stop()
for { for {
// If we encountered and error we should try to create the key
// again.
if backoff {
nextRotationTime = time.Now().Add(10 * time.Second)
backoff = false
}
ticker.Reset(time.Until(nextRotationTime))
select { select {
case <-keyCheckInterval.C: case <-keyCheckInterval.C:
err := checkCommitted() err := checkCommitted()
@ -505,11 +511,12 @@ func (c *Core) raftTLSRotatePhased(ctx context.Context, logger hclog.Logger, raf
next, err := rotateKeyring() next, err := rotateKeyring()
if err != nil { if err != nil {
logger.Error("failed to rotate TLS key", "error", err) logger.Error("failed to rotate TLS key", "error", err)
backoff = true nextRotationTime = time.Now().Add(10 * time.Second)
continue } else {
nextRotationTime = getNextRotationTime(next)
} }
nextRotationTime = next ticker.Reset(time.Until(nextRotationTime))
case <-stopCh: case <-stopCh:
return return