Documentation
¶
Overview ¶
Package ratelimit provides HTTP rate limiting middleware with support for per-principal and per-application rate limits.
The package supports multiple storage backends (in-memory, Redis) and integrates with Cedar policies for dynamic tier-based rate limiting.
Index ¶
- Constants
- Variables
- func ForwardedClientIP(trustedProxies ...string) (func(*http.Request) string, error)
- func NewRedisClient(cfg *RedisConfig) redis.UniversalClient
- func PeerIP(r *http.Request) string
- type CoreAPIResolver
- type CoreAPIResolverOption
- type KeyFunc
- type Limit
- type LimitResolver
- type Limiter
- type MemoryOption
- type MemoryStorage
- type Option
- type RedisConfig
- type RedisOption
- type RedisStorage
- type Result
- type StaticResolver
- type Storage
- type TieredResolver
Constants ¶
const DefaultMaxKeys = 100_000
DefaultMaxKeys is the number of keys MemoryStorage tracks by default.
Variables ¶
var ( ErrRateLimitExceeded = errors.New("rate limit exceeded") ErrStorageFailure = errors.New("rate limit storage failure") )
Common errors returned by the rate limiter.
var ErrClosed = errors.New("ratelimit: storage closed")
ErrClosed is returned by a closed storage.
var ErrTooManyKeys = errors.New("ratelimit: too many tracked keys")
ErrTooManyKeys is returned when a new key arrives while the storage is tracking its maximum number of live keys. Callers should treat it as a refusal: keys are attacker-influenced on pre-authentication endpoints, and admitting them without bound would exhaust memory.
Functions ¶
func ForwardedClientIP ¶ added in v0.14.0
ForwardedClientIP returns a function that finds the client's address behind reverse proxies. When the direct peer is one of the trusted proxy networks, it reads X-Forwarded-For from the right, skipping addresses that are themselves trusted proxies, and returns the first address a trusted proxy did not vouch for: a client can put anything at the left of the header, but not past the proxy that appends to it. Requests whose peer is not a trusted proxy, or whose header holds nothing usable, are attributed to the peer itself.
func NewRedisClient ¶
func NewRedisClient(cfg *RedisConfig) redis.UniversalClient
NewRedisClient creates a Redis client from configuration.
Types ¶
type CoreAPIResolver ¶
type CoreAPIResolver struct {
// contains filtered or unexported fields
}
CoreAPIResolver adapts coreapi.PolicyStore to the LimitResolver interface. It looks up rate limit policies based on the OAuth client ID from JWT claims.
func NewCoreAPIResolver ¶
func NewCoreAPIResolver(store coreapi.PolicyStore, opts ...CoreAPIResolverOption) *CoreAPIResolver
NewCoreAPIResolver creates a LimitResolver that uses coreapi.PolicyStore.
func (*CoreAPIResolver) GetPolicyForRequest ¶
func (r *CoreAPIResolver) GetPolicyForRequest(ctx context.Context, req *http.Request) *coreapi.RateLimitPolicy
GetPolicyForRequest returns the policy that would be applied to a request. Useful for debugging and displaying policy info in responses.
func (*CoreAPIResolver) InvalidateCache ¶
func (r *CoreAPIResolver) InvalidateCache(clientID string)
InvalidateCache clears the policy cache.
type CoreAPIResolverOption ¶
type CoreAPIResolverOption func(*CoreAPIResolver)
CoreAPIResolverOption configures a CoreAPIResolver.
func WithResolverCache ¶
func WithResolverCache(ttl time.Duration) CoreAPIResolverOption
WithResolverCache enables caching of policy lookups.
type KeyFunc ¶
KeyFunc extracts the rate limit key from a request. Common implementations include extracting principal ID or client ID from JWT.
func ClientEndpointKey ¶
func ClientEndpointKey() KeyFunc
ClientEndpointKey is a convenience function combining ClientKey with EndpointKey.
func ClientKey ¶
func ClientKey() KeyFunc
ClientKey returns a KeyFunc that extracts the OAuth client ID (azp) from JWT claims. Falls back to IP address if no client ID is present.
func CompositeKey ¶
func CompositeKey() KeyFunc
CompositeKey returns a KeyFunc that combines principal and client IDs. Format: "pid:{principal_id}:client:{client_id}" or fallback to IP.
func EndpointKey ¶
EndpointKey wraps another KeyFunc to add endpoint-specific rate limiting. Format: "{inner_key}:path:{path}:method:{method}"
func ForwardedIPKey ¶ added in v0.14.0
ForwardedIPKey is IPKey for a server behind reverse proxies: it takes the client address from X-Forwarded-For when the request arrives from one of the trusted proxy networks (see ForwardedClientIP).
func IPKey ¶
func IPKey() KeyFunc
IPKey returns a KeyFunc that keys on the IP address of the direct peer (see PeerIP). Behind a reverse proxy every client would share the proxy's address; use ForwardedIPKey there. Forwarding headers are never believed unless a trusted proxy is configured, because any client can send them.
func PrincipalEndpointKey ¶
func PrincipalEndpointKey() KeyFunc
PrincipalEndpointKey is a convenience function combining PrincipalKey with EndpointKey.
func PrincipalKey ¶
func PrincipalKey() KeyFunc
PrincipalKey returns a KeyFunc that extracts the principal ID from JWT claims. Falls back to IP address if no principal is authenticated.
type Limit ¶
type Limit struct {
// Rate is the number of requests allowed per Period.
Rate int
// Period is the time window for the rate limit (e.g., time.Minute).
Period time.Duration
// Burst is the maximum number of requests allowed in a single burst.
// If zero, defaults to Rate.
Burst int
}
Limit defines rate limit parameters.
func DefaultLimit ¶
func DefaultLimit() Limit
DefaultLimit returns a sensible default rate limit (100 requests per minute).
type LimitResolver ¶
type LimitResolver interface {
// Resolve returns the rate limit for the given key and context.
// The key is typically derived from the principal ID or client ID.
Resolve(ctx context.Context, key string, r *http.Request) Limit
}
LimitResolver determines the rate limit for a given request. This allows dynamic rate limiting based on user tier, endpoint, etc.
type Limiter ¶
type Limiter struct {
// contains filtered or unexported fields
}
Limiter is the main rate limiter type.
type MemoryOption ¶
type MemoryOption func(*MemoryStorage)
MemoryOption configures MemoryStorage.
func WithCleanupInterval ¶
func WithCleanupInterval(d time.Duration) MemoryOption
WithCleanupInterval sets the interval for cleaning up expired windows.
func WithMaxKeys ¶ added in v0.14.0
func WithMaxKeys(n int) MemoryOption
WithMaxKeys sets the number of keys the storage tracks at once (default DefaultMaxKeys). Expired windows are discarded to make room first.
type MemoryStorage ¶
type MemoryStorage struct {
// contains filtered or unexported fields
}
MemoryStorage is an in-memory rate limit storage using sliding window algorithm. Suitable for single-instance deployments and development/testing.
func NewMemoryStorage ¶
func NewMemoryStorage(opts ...MemoryOption) *MemoryStorage
NewMemoryStorage creates a new in-memory rate limit storage.
type Option ¶
type Option func(*Limiter)
Option configures a Limiter.
func WithFailOpen ¶ added in v0.14.0
func WithFailOpen() Option
WithFailOpen lets requests through when the storage fails. By default the middleware fails closed, answering 503, because a storage outage otherwise switches off the limits that protect authentication endpoints at the moment an attacker may be causing it.
func WithKeyFunc ¶
WithKeyFunc sets the function to extract rate limit keys from requests.
func WithLogger ¶ added in v0.14.0
WithLogger sets the logger for storage failures.
func WithObservability ¶
func WithObservability(obs *observability.Observability) Option
WithObservability sets the observability provider for metrics and tracing.
func WithResolver ¶
func WithResolver(resolver LimitResolver) Option
WithResolver sets a custom limit resolver.
type RedisConfig ¶
type RedisConfig struct {
// Addr is the Redis server address (e.g., "localhost:6379").
Addr string
// Password is the Redis password (optional).
Password string
// DB is the Redis database number (default 0).
DB int
// PoolSize is the maximum number of connections (default 10).
PoolSize int
// Cluster enables Redis Cluster mode.
Cluster bool
// ClusterAddrs are the cluster node addresses (used when Cluster is true).
ClusterAddrs []string
}
RedisConfig contains configuration for connecting to Redis.
type RedisOption ¶
type RedisOption func(*RedisStorage)
RedisOption configures RedisStorage.
func WithKeyPrefix ¶
func WithKeyPrefix(prefix string) RedisOption
WithKeyPrefix sets a prefix for all rate limit keys in Redis.
type RedisStorage ¶
type RedisStorage struct {
// contains filtered or unexported fields
}
RedisStorage is a Redis-backed rate limit storage using sliding window algorithm. Suitable for distributed deployments where multiple instances share rate limit state.
func NewRedisStorage ¶
func NewRedisStorage(client redis.UniversalClient, opts ...RedisOption) *RedisStorage
NewRedisStorage creates a new Redis-backed rate limit storage. The client can be *redis.Client, *redis.ClusterClient, or any UniversalClient.
func (*RedisStorage) Allow ¶
Allow implements Storage.Allow using a sliding window algorithm with Redis.
func (*RedisStorage) Close ¶
func (r *RedisStorage) Close() error
Close implements Storage.Close. Note: This does NOT close the Redis client since it may be shared.
type Result ¶
type Result struct {
// Allowed is true if the request should be permitted.
Allowed bool
// Remaining is the number of requests remaining in the current window.
Remaining int
// ResetAt is when the rate limit window resets.
ResetAt time.Time
// RetryAfter is the duration to wait before retrying (only set if not allowed).
RetryAfter time.Duration
}
Result contains the outcome of a rate limit check.
type StaticResolver ¶
type StaticResolver struct {
Limit Limit
}
StaticResolver always returns the same limit.
type Storage ¶
type Storage interface {
// Allow checks if a request should be allowed and updates the counter.
// Returns the result of the check and any error.
Allow(ctx context.Context, key string, limit Limit) (Result, error)
// Reset clears the rate limit state for a key.
Reset(ctx context.Context, key string) error
// Close releases any resources held by the storage.
Close() error
}
Storage defines the interface for rate limit state storage.