Commit 40fbc768 authored by ale's avatar ale

Show ratelimit / blacklist names in output logs

Meant to simplify debugging.
parent e517e314
Pipeline #5908 passed with stages
in 1 minute and 33 seconds
......@@ -51,18 +51,18 @@ type service struct {
aspService string
}
func (s *service) checkRateLimits(user *backend.User, req *auth.Request) bool {
func (s *service) checkRateLimits(user *backend.User, req *auth.Request) (bool, string) {
for _, rl := range s.rl {
if !rl.AllowIncr(user, req) {
return false
return false, rl.rl.name
}
}
for _, bl := range s.bl {
if !bl.Allow(user, req) {
return false
return false, bl.bl.name
}
}
return true
return true, ""
}
func (s *service) notifyBlacklists(user *backend.User, req *auth.Request, resp *auth.Response) {
......@@ -210,7 +210,7 @@ func createRatelimiters(config *Config) (map[string]*authRatelimiter, map[string
}
blacklists[name] = bl
} else {
rl, err := newAuthRatelimiter(params)
rl, err := newAuthRatelimiter(name, params)
if err != nil {
return nil, nil, err
}
......@@ -324,7 +324,6 @@ func (s *Server) Authenticate(ctx context.Context, req *auth.Request) *auth.Resp
var (
errServiceUnknown = errors.New("unknown service")
errUserUnknown = errors.New("unknown user")
errRatelimited = errors.New("ratelimited")
)
// Function with the actual authentication API logic - we return either a
......@@ -347,11 +346,11 @@ func (s *Server) doAuthenticate(ctx context.Context, req *auth.Request) (*auth.R
// Apply rate limiting and blacklisting _before_ invoking the
// authentication handlers, as they may be CPU intensive.
if allowed := svc.checkRateLimits(user, req); !allowed {
if allowed, blockedBy := svc.checkRateLimits(user, req); !allowed {
ratelimitCounter.With(prometheus.Labels{
"service": req.Service,
}).Inc()
return nil, errRatelimited
return nil, fmt.Errorf("ratelimited (%s)", blockedBy)
}
resp, err := s.authenticateUser(req, svc, user)
......
......@@ -105,6 +105,7 @@ services:
src: users.yml
rate_limits:
- failed_login_bl
- failed_ip_bl
rate_limits:
failed_login_bl:
limit: 10
......@@ -112,6 +113,13 @@ rate_limits:
blacklist_for: 3600
on_failure: true
keys: [user]
# Meant not to trigger:
failed_ip_bl:
limit: 10000
period: 3600
blacklist_for: 3600
on_failure: true
keys: [ip]
`
)
......
......@@ -12,12 +12,9 @@ import (
"github.com/prometheus/client_golang/prometheus"
)
// Try to use as little memory as possible for each entry: use a UNIX
// timestamp instead of a time.Time, and use an int32 as a saturating
// counter.
type ratelimitDatum struct {
stamp int64
counter int32
counter uint64
}
func (d ratelimitDatum) age(now int64) int64 {
......@@ -27,16 +24,18 @@ func (d ratelimitDatum) age(now int64) int64 {
// Ratelimiter is a simple counter-based rate limiter, allowing the
// first N requests over each period of time T.
type Ratelimiter struct {
limit int32
name string
limit uint64
period int64
mx sync.Mutex
c map[string]ratelimitDatum
}
func newRatelimiter(limit, period int) *Ratelimiter {
func newRatelimiter(name string, limit, period int) *Ratelimiter {
r := &Ratelimiter{
limit: int32(limit),
name: name,
limit: uint64(limit),
period: int64(period),
c: make(map[string]ratelimitDatum),
}
......@@ -107,7 +106,8 @@ type Blacklist struct {
func newBlacklist(name string, limit, period, blacklistTime int) *Blacklist {
return &Blacklist{
r: newRatelimiter(limit, period),
name: name,
r: newRatelimiter(name, limit, period),
bl: make(map[string]int64),
blTime: int64(blacklistTime),
}
......@@ -147,7 +147,7 @@ func (b *Blacklist) Incr(key string) {
d.counter++
b.r.set(key, d)
} else if d.counter == limitp1 {
log.Printf("blacklisted %s", key)
log.Printf("blacklisted %s (%s)", key, b.name)
blacklistCounter.WithLabelValues(b.name).Inc()
b.bl[key] = time.Now().Unix() + b.blTime
}
......@@ -276,14 +276,14 @@ type authRatelimiter struct {
rl *Ratelimiter
}
func newAuthRatelimiter(config *authRatelimiterConfig) (*authRatelimiter, error) {
func newAuthRatelimiter(name string, config *authRatelimiterConfig) (*authRatelimiter, error) {
r, err := newAuthRatelimiterBase(config)
if err != nil {
return nil, err
}
return &authRatelimiter{
authRatelimiterBase: r,
rl: newRatelimiter(config.Limit, config.Period),
rl: newRatelimiter(name, config.Limit, config.Period),
}, nil
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment