From 168a8c6ddf4e359a050b498b8fc045ed5e145ed3 Mon Sep 17 00:00:00 2001 From: AbhiMgowda Date: Mon, 30 Mar 2026 15:25:30 +0530 Subject: [PATCH] Wildcard API rate limit added --- .../daemon/controller/rate_limiter_test.go | 19 +++ internal/ratelimit/config.go | 6 +- internal/ratelimit/config_test.go | 155 ++++++++---------- 3 files changed, 95 insertions(+), 85 deletions(-) diff --git a/internal/daemon/controller/rate_limiter_test.go b/internal/daemon/controller/rate_limiter_test.go index 6a30bc808b..a6e83da53b 100644 --- a/internal/daemon/controller/rate_limiter_test.go +++ b/internal/daemon/controller/rate_limiter_test.go @@ -137,6 +137,25 @@ func TestController_initializeRateLimiter(t *testing.T) { false, nil, }, + { + "wildcardReadList", + &config.Config{ + Controller: &config.Controller{ + ApiRateLimits: ratelimit.Configs{ + { + Resources: []string{"*"}, + Actions: []string{"read", "list"}, + Per: "total", + Limit: 100, + Period: time.Minute, + }, + }, + ApiRateLimiterMaxQuotas: ratelimit.DefaultLimiterMaxQuotas(), + }, + }, + false, + nil, + }, { "invalid", &config.Config{ diff --git a/internal/ratelimit/config.go b/internal/ratelimit/config.go index a3eedee003..98c110e069 100644 --- a/internal/ratelimit/config.go +++ b/internal/ratelimit/config.go @@ -196,8 +196,9 @@ func (c Configs) Limits(ctx context.Context) ([]rate.Limit, error) { for _, cc := range c { var resourceSet []resource.Type + wildcardResources := len(cc.Resources) == 1 && cc.Resources[0] == resource.All.String() switch { - case len(cc.Resources) == 1 && cc.Resources[0] == resource.All.String(): + case wildcardResources: resourceSet = allResources default: for _, r := range cc.Resources { @@ -251,6 +252,9 @@ func (c Configs) Limits(ctx context.Context) ([]rate.Limit, error) { for _, aStr := range cc.Actions { a, ok := validActionMap[aStr] if !ok { + if wildcardResources { + continue + } return nil, errors.New(ctx, errors.InvalidConfiguration, op, "", errors.WithMsg("action %s not valid for resource %s", aStr, res.String())) } key := fmt.Sprintf("%s:%s:%s", res.String(), a.String(), rate.LimitPer(cc.Per)) diff --git a/internal/ratelimit/config_test.go b/internal/ratelimit/config_test.go index 1c3505be33..3a3fd5c30f 100644 --- a/internal/ratelimit/config_test.go +++ b/internal/ratelimit/config_test.go @@ -458,52 +458,16 @@ func TestConfigsLimits(t *testing.T) { case action.List, action.Read: limits = append( limits, - &rate.Limited{ - Resource: res.String(), - Action: a.String(), - Per: rate.LimitPerTotal, - MaxRequests: 10, - Period: time.Minute, - }, - &rate.Limited{ - Resource: res.String(), - Action: a.String(), - Per: rate.LimitPerIPAddress, - MaxRequests: 5, - Period: time.Minute, - }, - &rate.Limited{ - Resource: res.String(), - Action: a.String(), - Per: rate.LimitPerAuthToken, - MaxRequests: 1, - Period: time.Minute, - }, + &rate.Limited{Resource: res.String(), Action: a.String(), Per: rate.LimitPerTotal, MaxRequests: 10, Period: time.Minute}, + &rate.Limited{Resource: res.String(), Action: a.String(), Per: rate.LimitPerIPAddress, MaxRequests: 5, Period: time.Minute}, + &rate.Limited{Resource: res.String(), Action: a.String(), Per: rate.LimitPerAuthToken, MaxRequests: 1, Period: time.Minute}, ) default: limits = append( limits, - &rate.Limited{ - Resource: res.String(), - Action: a.String(), - Per: rate.LimitPerTotal, - MaxRequests: DefaultInTotalRequestLimit, - Period: DefaultPeriod, - }, - &rate.Limited{ - Resource: res.String(), - Action: a.String(), - Per: rate.LimitPerIPAddress, - MaxRequests: DefaultIpAddressRequestLimit, - Period: DefaultPeriod, - }, - &rate.Limited{ - Resource: res.String(), - Action: a.String(), - Per: rate.LimitPerAuthToken, - MaxRequests: DefaultAuthTokenRequestLimit, - Period: DefaultPeriod, - }, + &rate.Limited{Resource: res.String(), Action: a.String(), Per: rate.LimitPerTotal, MaxRequests: DefaultInTotalRequestLimit, Period: DefaultPeriod}, + &rate.Limited{Resource: res.String(), Action: a.String(), Per: rate.LimitPerIPAddress, MaxRequests: DefaultIpAddressRequestLimit, Period: DefaultPeriod}, + &rate.Limited{Resource: res.String(), Action: a.String(), Per: rate.LimitPerAuthToken, MaxRequests: DefaultAuthTokenRequestLimit, Period: DefaultPeriod}, ) } } @@ -517,52 +481,16 @@ func TestConfigsLimits(t *testing.T) { case action.List: limits = append( limits, - &rate.Limited{ - Resource: res.String(), - Action: a.String(), - Per: rate.LimitPerTotal, - MaxRequests: DefaultInTotalListRequestLimit, - Period: DefaultListPeriod, - }, - &rate.Limited{ - Resource: res.String(), - Action: a.String(), - Per: rate.LimitPerIPAddress, - MaxRequests: DefaultIpAddressListRequestLimit, - Period: DefaultListPeriod, - }, - &rate.Limited{ - Resource: res.String(), - Action: a.String(), - Per: rate.LimitPerAuthToken, - MaxRequests: DefaultAuthTokenListRequestLimit, - Period: DefaultListPeriod, - }, + &rate.Limited{Resource: res.String(), Action: a.String(), Per: rate.LimitPerTotal, MaxRequests: DefaultInTotalListRequestLimit, Period: DefaultListPeriod}, + &rate.Limited{Resource: res.String(), Action: a.String(), Per: rate.LimitPerIPAddress, MaxRequests: DefaultIpAddressListRequestLimit, Period: DefaultListPeriod}, + &rate.Limited{Resource: res.String(), Action: a.String(), Per: rate.LimitPerAuthToken, MaxRequests: DefaultAuthTokenListRequestLimit, Period: DefaultListPeriod}, ) default: limits = append( limits, - &rate.Limited{ - Resource: res.String(), - Action: a.String(), - Per: rate.LimitPerTotal, - MaxRequests: DefaultInTotalRequestLimit, - Period: DefaultPeriod, - }, - &rate.Limited{ - Resource: res.String(), - Action: a.String(), - Per: rate.LimitPerIPAddress, - MaxRequests: DefaultIpAddressRequestLimit, - Period: DefaultPeriod, - }, - &rate.Limited{ - Resource: res.String(), - Action: a.String(), - Per: rate.LimitPerAuthToken, - MaxRequests: DefaultAuthTokenRequestLimit, - Period: DefaultPeriod, - }, + &rate.Limited{Resource: res.String(), Action: a.String(), Per: rate.LimitPerTotal, MaxRequests: DefaultInTotalRequestLimit, Period: DefaultPeriod}, + &rate.Limited{Resource: res.String(), Action: a.String(), Per: rate.LimitPerIPAddress, MaxRequests: DefaultIpAddressRequestLimit, Period: DefaultPeriod}, + &rate.Limited{Resource: res.String(), Action: a.String(), Per: rate.LimitPerAuthToken, MaxRequests: DefaultAuthTokenRequestLimit, Period: DefaultPeriod}, ) } } @@ -572,6 +500,65 @@ func TestConfigsLimits(t *testing.T) { }(), nil, }, + { + "all-resources-multiple-actions", + Configs{ + { + Resources: []string{"*"}, + Actions: []string{"list", "read"}, + Per: "total", + Limit: 10, + Period: time.Minute, + }, + { + Resources: []string{"*"}, + Actions: []string{"list", "read"}, + Per: "ip-address", + Limit: 5, + Period: time.Minute, + }, + { + Resources: []string{"*"}, + Actions: []string{"list", "read"}, + Per: "auth-token", + Limit: 1, + Period: time.Minute, + }, + }, + func() []rate.Limit { + limits := make([]rate.Limit, 0, len(resource.Map)*len(action.Map)) + for _, res := range resource.Map { + switch res { + case resource.Unknown, resource.All, resource.Controller: + continue + } + validActions, err := action.ActionSetForResource(res) + require.NoError(t, err) + for a := range validActions { + switch a { + case action.Unknown, action.All: + continue + case action.List, action.Read: + limits = append( + limits, + &rate.Limited{Resource: res.String(), Action: a.String(), Per: rate.LimitPerTotal, MaxRequests: 10, Period: time.Minute}, + &rate.Limited{Resource: res.String(), Action: a.String(), Per: rate.LimitPerIPAddress, MaxRequests: 5, Period: time.Minute}, + &rate.Limited{Resource: res.String(), Action: a.String(), Per: rate.LimitPerAuthToken, MaxRequests: 1, Period: time.Minute}, + ) + default: + limits = append( + limits, + &rate.Limited{Resource: res.String(), Action: a.String(), Per: rate.LimitPerTotal, MaxRequests: DefaultInTotalRequestLimit, Period: DefaultPeriod}, + &rate.Limited{Resource: res.String(), Action: a.String(), Per: rate.LimitPerIPAddress, MaxRequests: DefaultIpAddressRequestLimit, Period: DefaultPeriod}, + &rate.Limited{Resource: res.String(), Action: a.String(), Per: rate.LimitPerAuthToken, MaxRequests: DefaultAuthTokenRequestLimit, Period: DefaultPeriod}, + ) + } + } + } + return limits + }(), + nil, + }, { "order-matters", Configs{