Add Redis rate limiter

This commit is contained in:
longquan0104 2025-03-10 17:02:05 +07:00 committed by GitHub
parent c166a41c99
commit 550d96ea67
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 2268 additions and 69 deletions

View file

@ -266,7 +266,7 @@ func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client)
continue
}
rateLimit, err := createRateLimitMiddleware(middleware.Spec.RateLimit)
rateLimit, err := createRateLimitMiddleware(client, middleware.Namespace, middleware.Spec.RateLimit)
if err != nil {
logger.Error().Err(err).Msg("Error while reading rateLimit middleware")
continue
@ -686,7 +686,7 @@ func createCompressMiddleware(compress *traefikv1alpha1.Compress) *dynamic.Compr
return c
}
func createRateLimitMiddleware(rateLimit *traefikv1alpha1.RateLimit) (*dynamic.RateLimit, error) {
func createRateLimitMiddleware(client Client, namespace string, rateLimit *traefikv1alpha1.RateLimit) (*dynamic.RateLimit, error) {
if rateLimit == nil {
return nil, nil
}
@ -713,9 +713,97 @@ func createRateLimitMiddleware(rateLimit *traefikv1alpha1.RateLimit) (*dynamic.R
rl.SourceCriterion = rateLimit.SourceCriterion
}
if rateLimit.Redis != nil {
rl.Redis = &dynamic.Redis{
DB: rateLimit.Redis.DB,
PoolSize: rateLimit.Redis.PoolSize,
MinIdleConns: rateLimit.Redis.MinIdleConns,
MaxActiveConns: rateLimit.Redis.MaxActiveConns,
}
rl.Redis.SetDefaults()
if len(rateLimit.Redis.Endpoints) > 0 {
rl.Redis.Endpoints = rateLimit.Redis.Endpoints
}
if rateLimit.Redis.TLS != nil {
rl.Redis.TLS = &types.ClientTLS{
InsecureSkipVerify: rateLimit.Redis.TLS.InsecureSkipVerify,
}
if len(rateLimit.Redis.TLS.CASecret) > 0 {
caSecret, err := loadCASecret(namespace, rateLimit.Redis.TLS.CASecret, client)
if err != nil {
return nil, fmt.Errorf("failed to load auth ca secret: %w", err)
}
rl.Redis.TLS.CA = caSecret
}
if len(rateLimit.Redis.TLS.CertSecret) > 0 {
authSecretCert, authSecretKey, err := loadAuthTLSSecret(namespace, rateLimit.Redis.TLS.CertSecret, client)
if err != nil {
return nil, fmt.Errorf("failed to load auth secret: %w", err)
}
rl.Redis.TLS.Cert = authSecretCert
rl.Redis.TLS.Key = authSecretKey
}
}
if rateLimit.Redis.DialTimeout != nil {
err := rl.Redis.DialTimeout.Set(rateLimit.Redis.DialTimeout.String())
if err != nil {
return nil, err
}
}
if rateLimit.Redis.ReadTimeout != nil {
err := rl.Redis.ReadTimeout.Set(rateLimit.Redis.ReadTimeout.String())
if err != nil {
return nil, err
}
}
if rateLimit.Redis.WriteTimeout != nil {
err := rl.Redis.WriteTimeout.Set(rateLimit.Redis.WriteTimeout.String())
if err != nil {
return nil, err
}
}
if rateLimit.Redis.Secret != "" {
var err error
rl.Redis.Username, rl.Redis.Password, err = loadRedisCredentials(namespace, rateLimit.Redis.Secret, client)
if err != nil {
return nil, err
}
}
}
return rl, nil
}
func loadRedisCredentials(namespace, secretName string, k8sClient Client) (string, string, error) {
secret, exists, err := k8sClient.GetSecret(namespace, secretName)
if err != nil {
return "", "", fmt.Errorf("failed to fetch secret '%s/%s': %w", namespace, secretName, err)
}
if !exists {
return "", "", fmt.Errorf("secret '%s/%s' not found", namespace, secretName)
}
if secret == nil {
return "", "", fmt.Errorf("data for secret '%s/%s' must not be nil", namespace, secretName)
}
username, usernameExists := secret.Data["username"]
password, passwordExists := secret.Data["password"]
if !usernameExists || !passwordExists {
return "", "", fmt.Errorf("secret '%s/%s' must contain both username and password keys", secret.Namespace, secret.Name)
}
return string(username), string(password), nil
}
func createRetryMiddleware(retry *traefikv1alpha1.Retry) (*dynamic.Retry, error) {
if retry == nil {
return nil, nil