Commit 1be387b7 authored by Vitaly Lipatov's avatar Vitaly Lipatov

redis: support ACL authentication and TLS

parent 2a0e463d
......@@ -5,6 +5,9 @@ session_start();
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
$settings = parse_ini_file('/etc/eterban/settings.ini');
$host_redis = is_array($settings) ? ($settings['redis_server'] ?? '') : '';
$redis_username = is_array($settings) ? ($settings['redis_username'] ?? '') : '';
$redis_password = is_array($settings) ? ($settings['redis_password'] ?? '') : '';
$redis_tls = is_array($settings) && filter_var($settings['redis_tls'] ?? false, FILTER_VALIDATE_BOOLEAN);
$hostname = is_array($settings) ? ($settings['hostname'] ?? '') : '';
if (!filter_var($ip, FILTER_VALIDATE_IP) || empty($host_redis)) {
......@@ -60,9 +63,12 @@ if (!is_string($nonce) || !is_string($proof) || time() > $expires ||
try {
$redis = new Redis();
if (!$redis->connect($host_redis, 6379, 2.5)) {
if (!$redis->connect($host_redis, 6379, 2.5, null, 0, 0, $redis_tls ? ['stream' => ['verify_peer' => true]] : [])) {
throw new RedisException('connection failed');
}
if ($redis_password !== '' && !$redis->auth($redis_username !== '' ? [$redis_username, $redis_password] : $redis_password)) {
throw new RedisException('authentication failed');
}
$redis->xAdd('eterban:commands', '*', [
'command' => 'unban',
'ip' => $ip,
......
[Settings]
# blocking requests queue
#redis_server = 10.20.30.101
# Optional Redis ACL/TLS settings. Keep this file root-readable only when a
# password is configured.
#redis_username = default
#redis_password = change-this-secret
#redis_tls = false
# Redis stores the authoritative active-ban set. Configure the Redis server
# with durable persistence (for example: appendonly yes, appendfsync everysec).
......
......@@ -107,6 +107,19 @@ def parse_config (path_to_config, path_to_log):
else:
return (redis_server, ban_server, ban_server_ipv6, wan_ifaces, internal_interface, maxelem, whitelist_file)
def redis_connection_options(config):
options = {}
username = config.get('Settings', 'redis_username', fallback='').strip()
password = config.get('Settings', 'redis_password', fallback='')
if username:
options['username'] = username
if password:
options['password'] = password
if config.getboolean('Settings', 'redis_tls', fallback=False):
options['ssl'] = True
return options
def restore_legacy_ipsets():
"""One-time migration fallback for snapshots made by older releases."""
global ipset_eterban_1, ipset_eterban_1_ipv6, ipset_firehol
......@@ -488,6 +501,7 @@ def connect_redis():
socket_connect_timeout=5,
socket_keepalive=True,
health_check_interval=30,
**redis_options,
)
redis_client.ping()
try:
......@@ -503,11 +517,12 @@ def connect_redis():
time.sleep(5)
config = configparser.ConfigParser()
config.read(path_to_config)
redis_options = redis_connection_options(config)
r = connect_redis()
# Инициализация AutoBanManager
config = configparser.ConfigParser()
config.read(path_to_config)
auto_mgr = AutoBanManager(r, config)
......
......@@ -18,10 +18,19 @@ def get_settings (path_to_config):
# Читаем некоторые значения из конфиг. файла.
redis_server = config.get("Settings", "redis_server", fallback = "localhost")
hostname = config.get("Settings", "hostname", fallback = socket.gethostname())
return (redis_server, hostname)
options = {}
username = config.get("Settings", "redis_username", fallback="").strip()
password = config.get("Settings", "redis_password", fallback="")
if username:
options['username'] = username
if password:
options['password'] = password
if config.getboolean("Settings", "redis_tls", fallback=False):
options['ssl'] = True
return (redis_server, hostname, options)
path_to_config = '/etc/eterban/settings.ini'
redis_server, hostname = get_settings (path_to_config)
redis_server, hostname, redis_options = get_settings (path_to_config)
if len(sys.argv) > 1:
......@@ -39,7 +48,7 @@ except ValueError:
sys.exit(2)
try:
r = redis.Redis(host=redis_server, socket_connect_timeout=5, socket_timeout=5)
r = redis.Redis(host=redis_server, socket_connect_timeout=5, socket_timeout=5, **redis_options)
message = ip + " was unblocked by admin on " + hostname
r.xadd('eterban:commands', {'command': 'unban', 'ip': ip, 'by': message})
except redis.exceptions.RedisError as error:
......
......@@ -24,10 +24,19 @@ def get_settings (path_to_config):
# Читаем некоторые значения из конфиг. файла.
redis_server = config.get("Settings", "redis_server", fallback = "localhost")
hostname = config.get("Settings", "hostname", fallback = socket.gethostname())
return (redis_server, hostname)
options = {}
username = config.get("Settings", "redis_username", fallback="").strip()
password = config.get("Settings", "redis_password", fallback="")
if username:
options['username'] = username
if password:
options['password'] = password
if config.getboolean("Settings", "redis_tls", fallback=False):
options['ssl'] = True
return (redis_server, hostname, options)
path_to_config = '/etc/eterban/settings.ini'
redis_server, hostname = get_settings (path_to_config)
redis_server, hostname, redis_options = get_settings (path_to_config)
try:
ip = get_ip_argument(sys.argv)
......@@ -39,7 +48,7 @@ reason = sys.argv[2] if len(sys.argv) > 2 else "(set block: [name=NAME_OF_RULE]
message = ip + " was blocked by " + hostname + ": " + reason
try:
r = redis.Redis(host=redis_server, socket_connect_timeout=5, socket_timeout=5)
r = redis.Redis(host=redis_server, socket_connect_timeout=5, socket_timeout=5, **redis_options)
r.xadd('eterban:commands', {'command': 'ban', 'ip': ip, 'by': message})
except redis.exceptions.RedisError as error:
print("Unable to publish ban event: " + str(error), file=sys.stderr)
......
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