1
0
mirror of https://github.com/bitwarden/server.git synced 2025-04-05 21:18:13 -05:00

[PM-6153] Dedicated redis connection for rate limiter (#3763)

* rearrange how redis is registered

* separate redis connection string for rate limiter
This commit is contained in:
Kyle Spearrin 2024-02-07 17:38:18 -05:00 committed by GitHub
parent 039d3cbce7
commit 7747744ff9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 9 additions and 18 deletions

View File

@ -520,6 +520,7 @@ public class GlobalSettings : IGlobalSettings
public class DistributedIpRateLimitingSettings public class DistributedIpRateLimitingSettings
{ {
public string RedisConnectionString { get; set; }
public bool Enabled { get; set; } = true; public bool Enabled { get; set; } = true;
/// <summary> /// <summary>

View File

@ -2,6 +2,7 @@
using AspNetCoreRateLimit.Redis; using AspNetCoreRateLimit.Redis;
using Bit.Core.Settings; using Bit.Core.Settings;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using StackExchange.Redis; using StackExchange.Redis;
@ -26,6 +27,7 @@ public class CustomRedisProcessingStrategy : RedisProcessingStrategy
private const string _redisTimeoutCacheKey = "IpRateLimitRedisTimeout"; private const string _redisTimeoutCacheKey = "IpRateLimitRedisTimeout";
public CustomRedisProcessingStrategy( public CustomRedisProcessingStrategy(
[FromKeyedServices("rate-limiter")]
IConnectionMultiplexer connectionMultiplexer, IConnectionMultiplexer connectionMultiplexer,
IRateLimitConfiguration config, IRateLimitConfiguration config,
ILogger<CustomRedisProcessingStrategy> logger, ILogger<CustomRedisProcessingStrategy> logger,

View File

@ -49,7 +49,6 @@ using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc.Localization; using Microsoft.AspNetCore.Mvc.Localization;
using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.StackExchangeRedis;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
@ -667,7 +666,8 @@ public static class ServiceCollectionExtensions
services.AddHostedService<IpRateLimitSeedStartupService>(); services.AddHostedService<IpRateLimitSeedStartupService>();
services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>(); services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
if (!globalSettings.DistributedIpRateLimiting.Enabled || string.IsNullOrEmpty(globalSettings.Redis.ConnectionString)) if (!globalSettings.DistributedIpRateLimiting.Enabled ||
string.IsNullOrEmpty(globalSettings.DistributedIpRateLimiting.RedisConnectionString))
{ {
services.AddInMemoryRateLimiting(); services.AddInMemoryRateLimiting();
} }
@ -679,7 +679,8 @@ public static class ServiceCollectionExtensions
services.AddSingleton<IClientPolicyStore, MemoryCacheClientPolicyStore>(); services.AddSingleton<IClientPolicyStore, MemoryCacheClientPolicyStore>();
// Use a custom Redis processing strategy that skips Ip limiting if Redis is down // Use a custom Redis processing strategy that skips Ip limiting if Redis is down
// Requires a registered IConnectionMultiplexer services.AddKeyedSingleton<IConnectionMultiplexer>("rate-limiter", (_, provider) =>
ConnectionMultiplexer.Connect(globalSettings.DistributedIpRateLimiting.RedisConnectionString));
services.AddSingleton<IProcessingStrategy, CustomRedisProcessingStrategy>(); services.AddSingleton<IProcessingStrategy, CustomRedisProcessingStrategy>();
} }
} }
@ -698,22 +699,9 @@ public static class ServiceCollectionExtensions
return; return;
} }
// Register the IConnectionMultiplexer explicitly so it can be accessed via DI services.AddStackExchangeRedisCache(options =>
// (e.g. for the IP rate limiting store)
services.AddSingleton<IConnectionMultiplexer>(
_ => ConnectionMultiplexer.Connect(globalSettings.Redis.ConnectionString));
// Explicitly register IDistributedCache to re-use existing IConnectionMultiplexer
// to reduce the number of redundant connections to the Redis instance
services.AddSingleton<IDistributedCache>(s =>
{ {
return new RedisCache(new RedisCacheOptions options.Configuration = globalSettings.Redis.ConnectionString;
{
// Use "ProjectName:" as an instance name to namespace keys and avoid conflicts between projects
InstanceName = $"{globalSettings.ProjectName}:",
ConnectionMultiplexerFactory = () =>
Task.FromResult(s.GetRequiredService<IConnectionMultiplexer>())
});
}); });
} }