Skip to content

Commit

Permalink
Fix quota enforcing old path issue (#10689) (#10872)
Browse files Browse the repository at this point in the history
* Fix db indexing issue

* Add CL update
  • Loading branch information
vishalnayak authored Feb 9, 2021
1 parent 698aa44 commit d0b731d
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 2 deletions.
3 changes: 3 additions & 0 deletions changelog/10689.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```changelog:bug
quotas/rate: Fix quotas enforcing old rate limit quota paths
```
8 changes: 6 additions & 2 deletions vault/logical_system_quotas.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import (
"strings"
"time"

"github.com/hashicorp/vault/helper/namespace"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/logical"

"github.com/hashicorp/vault/helper/namespace"
"github.com/hashicorp/vault/vault/quotas"
)

Expand Down Expand Up @@ -209,15 +210,18 @@ func (b *SystemBackend) handleRateLimitQuotasUpdate() framework.OperationFunc {

switch {
case quota == nil:

quota = quotas.NewRateLimitQuota(name, ns.Path, mountPath, rate, interval, blockInterval)
default:
rlq := quota.(*quotas.RateLimitQuota)
// Re-inserting the already indexed object in memdb might cause problems.
// So, clone the object. See https://github.com/hashicorp/go-memdb/issues/76.
rlq = rlq.Clone()
rlq.NamespacePath = ns.Path
rlq.MountPath = mountPath
rlq.Rate = rate
rlq.Interval = interval
rlq.BlockInterval = blockInterval
quota = rlq
}

entry, err := logical.StorageEntryJSON(quotas.QuotaStoragePath(qType, name), quota)
Expand Down
14 changes: 14 additions & 0 deletions vault/quotas/quotas_rate_limit.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,20 @@ func NewRateLimitQuota(name, nsPath, mountPath string, rate float64, interval, b
}
}

func (q *RateLimitQuota) Clone() *RateLimitQuota {
rlq := &RateLimitQuota{
ID: q.ID,
Name: q.Name,
MountPath: q.MountPath,
Type: q.Type,
NamespacePath: q.NamespacePath,
BlockInterval: q.BlockInterval,
Rate: q.Rate,
Interval: q.Interval,
}
return rlq
}

// initialize ensures the namespace and max requests are initialized, sets the ID
// if it's currently empty, sets the purge interval and stale age to default
// values, and finally starts the client purge go routine if it has been started
Expand Down
27 changes: 27 additions & 0 deletions vault/quotas/quotas_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,33 @@ import (
"github.com/stretchr/testify/require"
)

func TestQuotas_MountPathOverwrite(t *testing.T) {
qm, err := NewManager(logging.NewVaultLogger(log.Trace), nil, metricsutil.BlackholeSink())
require.NoError(t, err)

quota := NewRateLimitQuota("tq", "", "kv1/", 10, time.Second, 0)
require.NoError(t, qm.SetQuota(context.Background(), TypeRateLimit.String(), quota, false))
quota = quota.Clone()
quota.MountPath = "kv2/"
require.NoError(t, qm.SetQuota(context.Background(), TypeRateLimit.String(), quota, false))

q, err := qm.QueryQuota(&Request{
Type: TypeRateLimit,
MountPath: "kv1/",
})
require.NoError(t, err)
require.Nil(t, q)

require.NoError(t, qm.DeleteQuota(context.Background(), TypeRateLimit.String(), "tq"))

q, err = qm.QueryQuota(&Request{
Type: TypeRateLimit,
MountPath: "kv1/",
})
require.NoError(t, err)
require.Nil(t, q)
}

func TestQuotas_Precedence(t *testing.T) {
qm, err := NewManager(logging.NewVaultLogger(log.Trace), nil, metricsutil.BlackholeSink())
require.NoError(t, err)
Expand Down

0 comments on commit d0b731d

Please sign in to comment.