Skip to content

Commit 8d44602

Browse files
committed
fix(collect): prevent caching argon2id timeout errors as invalid credentials
Timeout errors from the argon2id semaphore were cached as negative auth results, blocking legitimate systems for 1 minute even after load subsided. Also make the concurrency semaphore configurable via ARGON2_CONCURRENCY env var (default: 2) and initialize it at runtime instead of package init.
1 parent 901cfe9 commit 8d44602

5 files changed

Lines changed: 20 additions & 6 deletions

File tree

collect/.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ REDIS_URL=redis://localhost:6379
6464
# Authentication cache
6565
#SYSTEM_AUTH_CACHE_TTL=5m
6666

67+
# Argon2id concurrent verifications (each uses ~64MB RAM)
68+
#ARGON2_CONCURRENCY=2
69+
6770
# API configuration
6871
#API_MAX_REQUEST_SIZE=10485760 # 10MB
6972
#API_REQUEST_TIMEOUT=30s

collect/configuration/configuration.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ type Configuration struct {
6767
// System authentication configuration
6868
SystemSecretMinLength int `json:"system_secret_min_length"`
6969
SystemAuthCacheTTL time.Duration `json:"system_auth_cache_ttl"`
70+
Argon2Concurrency int `json:"argon2_concurrency"`
7071

7172
// API configuration
7273
APIMaxRequestSize int64 `json:"api_max_request_size"`
@@ -147,6 +148,7 @@ func Init() {
147148
// System authentication configuration
148149
Config.SystemSecretMinLength = parseIntWithDefault("SYSTEM_SECRET_MIN_LENGTH", 32)
149150
Config.SystemAuthCacheTTL = parseDurationWithDefault("SYSTEM_AUTH_CACHE_TTL", 5*time.Minute)
151+
Config.Argon2Concurrency = parseIntWithDefault("ARGON2_CONCURRENCY", 2)
150152

151153
// API configuration
152154
Config.APIMaxRequestSize = parseInt64WithDefault("API_MAX_REQUEST_SIZE", 10*1024*1024) // 10MB

collect/main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ func main() {
7171
// Init configuration
7272
configuration.Init()
7373

74+
// Initialize Argon2id concurrency semaphore (after config is loaded)
75+
middleware.InitArgon2Semaphore()
76+
7477
// Initialize database connection
7578
err = database.Init()
7679
if err != nil {

collect/middleware/auth.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,15 @@ import (
3131
)
3232

3333
// argon2Semaphore limits concurrent Argon2id verifications to prevent OOM.
34-
// Each Argon2id verification allocates ~64MB (m=65536), so limiting to 2
35-
// concurrent verifications caps auth memory at ~128MB.
36-
var argon2Semaphore = make(chan struct{}, 2)
34+
// Each Argon2id verification allocates ~64MB (m=65536). The concurrency limit
35+
// is configurable via ARGON2_CONCURRENCY (default: 2, ~128MB max auth memory).
36+
var argon2Semaphore chan struct{}
37+
38+
// InitArgon2Semaphore initializes the semaphore with the configured concurrency.
39+
// Must be called after configuration.Init().
40+
func InitArgon2Semaphore() {
41+
argon2Semaphore = make(chan struct{}, configuration.Config.Argon2Concurrency)
42+
}
3743

3844
// inProcessAuthCache provides an in-process cache for auth results.
3945
// After a service restart, Redis auth cache entries are gone; this avoids
@@ -284,9 +290,8 @@ func validateSystemCredentials(c *gin.Context, systemKey, systemSecret string) (
284290
Str("system_id", creds.SystemID).
285291
Msg("Failed to verify system secret part")
286292

287-
// Cache negative result
288-
cacheCredentialsResult(c, systemKey, systemSecret, "", false)
289-
setInProcessCache(systemKey, systemSecret, "", false)
293+
// Do not cache timeout errors as invalid: the credentials may be valid,
294+
// but the server is under load. Caching would block legitimate systems.
290295
return "", false
291296
}
292297

collect/middleware/auth_unit_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ func TestBasicAuthMiddleware(t *testing.T) {
3030

3131
// Initialize configuration for testing
3232
configuration.Init()
33+
InitArgon2Semaphore()
3334

3435
tests := []struct {
3536
name string

0 commit comments

Comments
 (0)