diff --git a/changelog/10855.txt b/changelog/10855.txt new file mode 100644 index 000000000..19d4ba5c0 --- /dev/null +++ b/changelog/10855.txt @@ -0,0 +1,3 @@ +```release-note:bug +core: Fix duplicate quotas on performance standby nodes. +``` diff --git a/vault/quotas/quotas_rate_limit.go b/vault/quotas/quotas_rate_limit.go index 1899af6b0..8a7532e4b 100644 --- a/vault/quotas/quotas_rate_limit.go +++ b/vault/quotas/quotas_rate_limit.go @@ -1,6 +1,7 @@ package quotas import ( + "encoding/hex" "fmt" "math" "strconv" @@ -11,6 +12,7 @@ import ( log "github.com/hashicorp/go-hclog" "github.com/hashicorp/go-uuid" "github.com/hashicorp/vault/helper/metricsutil" + "github.com/hashicorp/vault/sdk/helper/cryptoutil" "github.com/sethvargo/go-limiter" "github.com/sethvargo/go-limiter/httplimit" "github.com/sethvargo/go-limiter/memorystore" @@ -79,8 +81,14 @@ type RateLimitQuota struct { // duration may be provided, where if set, when a client reaches the rate limit, // subsequent requests will fail until the block duration has passed. func NewRateLimitQuota(name, nsPath, mountPath string, rate float64, interval, block time.Duration) *RateLimitQuota { + id, err := uuid.GenerateUUID() + if err != nil { + // Fall back to generating with a hash of the name, later in initialize + id = "" + } return &RateLimitQuota{ Name: name, + ID: id, Type: TypeRateLimit, NamespacePath: nsPath, MountPath: mountPath, @@ -130,12 +138,13 @@ func (rlq *RateLimitQuota) initialize(logger log.Logger, ms *metricsutil.Cluster } if rlq.ID == "" { - id, err := uuid.GenerateUUID() - if err != nil { - return err - } - - rlq.ID = id + // A lease which was created with a blank ID may have been persisted + // to storage already (this is the case up to release 1.6.2.) + // So, performance standby nodes could call initialize() on their copy + // of the lease; for consistency we need to generate an ID that is + // deterministic. That ensures later invalidation removes the original + // lease from the memdb, instead of creating a duplicate. + rlq.ID = hex.EncodeToString(cryptoutil.Blake2b256Hash(rlq.Name)) } // Set purgeInterval if coming from a previous version where purgeInterval was