mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-10-13 04:07:37 +00:00
fix(cache): harden cache backends, resilience, recovery, and transports
- RESP -ERR no longer closes healthy conn / aborts batch; global cap replacement-aware - global health-check pass serialized (latent data race); MemoryMonitor via ResourceManager - token-exchange retry, open-circuit rejections counted as failures - TLS-posture matching transport reuse (no silent InsecureSkipVerify handoff)
This commit is contained in:
@@ -94,6 +94,23 @@ func GetUniversalCacheManagerWithConfig(logger *Logger, redisConfig *RedisConfig
|
||||
return universalCacheManager
|
||||
}
|
||||
|
||||
// newBlacklistCacheConfig returns the UniversalCacheConfig used for the
|
||||
// shared token-blacklist cache. It MUST keep a CacheType distinct from
|
||||
// the token cache's CacheTypeToken: prefixKey composes the backend key
|
||||
// from c.config.Type, so a shared type would put blacklist and token
|
||||
// entries for the same raw token string in the same (e.g. Redis)
|
||||
// namespace — both rejecting valid claims-cached tokens as blacklisted
|
||||
// and letting token caching clobber a real blacklist marker (R128).
|
||||
func newBlacklistCacheConfig(logger *Logger) UniversalCacheConfig {
|
||||
return UniversalCacheConfig{
|
||||
Type: CacheTypeBlacklist,
|
||||
MaxSize: 1000,
|
||||
DefaultTTL: 24 * time.Hour,
|
||||
Logger: logger,
|
||||
SkipAutoCleanup: true, // Managed cleanup
|
||||
}
|
||||
}
|
||||
|
||||
// initializeDefaultCaches initializes caches with memory-only backends
|
||||
func initializeDefaultCaches(manager *UniversalCacheManager, logger *Logger) {
|
||||
// Initialize token cache - CRITICAL FIX: Reduced from 5000 to 1000
|
||||
@@ -106,14 +123,12 @@ func initializeDefaultCaches(manager *UniversalCacheManager, logger *Logger) {
|
||||
SkipAutoCleanup: true, // Managed cleanup
|
||||
})
|
||||
|
||||
// Initialize blacklist cache
|
||||
manager.blacklistCache = NewUniversalCache(UniversalCacheConfig{
|
||||
Type: CacheTypeToken,
|
||||
MaxSize: 1000,
|
||||
DefaultTTL: 24 * time.Hour,
|
||||
Logger: logger,
|
||||
SkipAutoCleanup: true, // Managed cleanup
|
||||
})
|
||||
// Initialize blacklist cache. Distinct CacheType so its (possibly
|
||||
// shared-backend) "blacklist:" namespace can never collide with the
|
||||
// token cache's "token:" namespace for the same raw token string; a
|
||||
// collision would both reject valid claims-cached tokens as blacklisted
|
||||
// and let token caching clobber a real blacklist marker (R128).
|
||||
manager.blacklistCache = NewUniversalCache(newBlacklistCacheConfig(logger))
|
||||
|
||||
// Initialize metadata cache with grace periods
|
||||
manager.metadataCache = NewUniversalCache(UniversalCacheConfig{
|
||||
@@ -156,8 +171,13 @@ func initializeDefaultCaches(manager *UniversalCacheManager, logger *Logger) {
|
||||
})
|
||||
|
||||
// Initialize introspection cache for OAuth 2.0 Token Introspection (RFC 7662)
|
||||
// Uses its own CacheType so its Redis namespace differs from the blacklist
|
||||
// (both in CacheTypeToken): with a shared Redis backend an opaque token is keyed
|
||||
// by its raw value in both caches, so sharing the "token:" prefix let an
|
||||
// introspection write clobber a same-token blacklist marker (revoked opaque
|
||||
// token could be re-accepted) across replicas. See R114.
|
||||
manager.introspectionCache = NewUniversalCache(UniversalCacheConfig{
|
||||
Type: CacheTypeToken, // Use token cache type for introspection results
|
||||
Type: CacheTypeIntrospection,
|
||||
MaxSize: 1000, // Cache up to 1000 introspection results
|
||||
DefaultTTL: 5 * time.Minute, // Short TTL for security (introspect frequently)
|
||||
Logger: logger,
|
||||
@@ -297,15 +317,13 @@ func initializeCachesWithRedis(manager *UniversalCacheManager, logger *Logger, r
|
||||
createBackend(CacheTypeToken),
|
||||
)
|
||||
|
||||
// Initialize blacklist cache (CRITICAL - must be consistent across replicas)
|
||||
// Initialize blacklist cache (CRITICAL - must be consistent across replicas).
|
||||
// Distinct CacheType so its "blacklist:" Redis namespace can't collide with
|
||||
// the token cache's "token:" namespace for the same raw token (R128); a
|
||||
// shared prefix would reject valid claims-cached tokens as blacklisted or
|
||||
// let token caching clobber a real blacklist marker.
|
||||
manager.blacklistCache = NewUniversalCacheWithBackend(
|
||||
UniversalCacheConfig{
|
||||
Type: CacheTypeToken,
|
||||
MaxSize: 1000,
|
||||
DefaultTTL: 24 * time.Hour,
|
||||
Logger: logger,
|
||||
SkipAutoCleanup: true, // Managed cleanup
|
||||
},
|
||||
newBlacklistCacheConfig(logger),
|
||||
createBackend("blacklist"),
|
||||
)
|
||||
|
||||
@@ -355,16 +373,18 @@ func initializeCachesWithRedis(manager *UniversalCacheManager, logger *Logger, r
|
||||
SkipAutoCleanup: true, // Managed cleanup
|
||||
})
|
||||
|
||||
// Introspection cache uses backend for sharing results
|
||||
// Introspection cache uses backend for sharing results. Distinct CacheType
|
||||
// so its Redis "introspection:" namespace can't collide with the blacklist's
|
||||
// "token:" namespace for the same raw opaque token (R114).
|
||||
manager.introspectionCache = NewUniversalCacheWithBackend(
|
||||
UniversalCacheConfig{
|
||||
Type: CacheTypeToken,
|
||||
Type: CacheTypeIntrospection,
|
||||
MaxSize: 1000,
|
||||
DefaultTTL: 5 * time.Minute,
|
||||
Logger: logger,
|
||||
SkipAutoCleanup: true, // Managed cleanup
|
||||
},
|
||||
createBackend(CacheTypeToken),
|
||||
createBackend(CacheTypeIntrospection),
|
||||
)
|
||||
|
||||
// Token type cache stays memory-only (local optimization)
|
||||
|
||||
Reference in New Issue
Block a user