Безопасность и мониторинг

Redis быстр и прост — и поэтому открытый в интернет инстанс без пароля массово находят и захватывают. А когда он начинает тормозить, нужны инструменты, чтобы понять почему. Этот урок — про оборону и наблюдаемость.

ACL (Access Control List) — встроенная система пользователей Redis: можно завести несколько пользователей с паролями и точно ограничить, какие команды и к каким ключам каждому из них разрешены — по принципу наименьших привилегий.

Зачем это на практике

Исторически у Redis был лишь один общий пароль (requirepass) и полный доступ для всех, кто его знал. В проде этого мало: приложению нужен доступ только к своим ключам и только к нужным командам, а админу — больше. Незакрытый Redis — это реальный вектор атаки: через него удавалось и читать чужие данные, и закрепляться на сервере. Параллельно с защитой нужна наблюдаемость: INFO, SLOWLOG и LATENCY отвечают на вопрос «почему медленно и что внутри происходит». Дальше всё рассматривается оборонительно — как защитить свой инстанс, а не как атаковать чужой.

ACL и пользователи

Современный способ — завести отдельных пользователей с узкими правами. Синтаксис правил компактен: on/off включает пользователя, >пароль задаёт пароль, ~шаблон разрешает ключи по шаблону, +команда/-команда и категории вида +@read управляют доступом к командам:

# пользователь приложения: только чтение/запись по ключам app:*
redis-cli ACL SETUSER appuser on >StrongPass1 ~app:* +@read +@write

# аналитик: только чтение, любые ключи
redis-cli ACL SETUSER analyst on >StrongPass2 ~* +@read

# посмотреть пользователей и права
redis-cli ACL LIST
redis-cli ACL WHOAMI
redis-cli ACL GETUSER appuser

Пользователь default существует всегда. Хорошая практика — либо задать ему пароль, либо отключить (ACL SETUSER default off), оставив named-пользователей. Правила можно хранить в redis.conf или, надёжнее, в отдельном ACL-файле (aclfile /etc/redis/users.acl), который переживает перезапуск и удобен для версионирования.

Защита от опасных команд

Некоторые команды разрушительны или служебны: FLUSHALL (стереть всё), FLUSHDB, KEYS (блокирующий перебор всех ключей), CONFIG (менять конфиг на лету), DEBUG. Их доступ урезают двумя путями. Через ACL — просто не выдавать пользователю: например, отнять у приложения админ-команды (-@admin -@dangerous). Либо в конфиге переименовать или отключить команду глобально:

# redis.conf
# полностью отключить FLUSHALL (пустое имя = выключено)
rename-command FLUSHALL ""
# спрятать CONFIG под нетривиальным именем
rename-command CONFIG "CONFIG_a8f3z"

Базовый сетевой минимум не менее важен: привязка к приватному интерфейсу (bind 127.0.0.1 10.0.0.5), включённый protected-mode, файрвол и обязательный пароль/ACL. Redis не должен «смотреть» в публичный интернет.

Мониторинг: INFO

Команда INFO — главная сводка о состоянии сервера, разбитая на секции (server, clients, memory, stats, replication и др.). Можно запросить конкретную секцию:

redis-cli INFO memory
redis-cli INFO stats

Вывод:

used_memory_human:1.42G
maxmemory_human:2.00G
mem_fragmentation_ratio:1.18
evicted_keys:10293
keyspace_hits:980233
keyspace_misses:21044
instantaneous_ops_per_sec:14502

Что здесь читать: used_memory против maxmemory — близость к лимиту; растущий evicted_keys — память уже не вмещает рабочий набор, идёт вытеснение; keyspace_hits/keyspace_misses — эффективность кэша (доля попаданий); mem_fragmentation_ratio сильно больше 1 — память фрагментирована.

SLOWLOG и LATENCY

Redis однопоточен при выполнении команд: одна медленная команда задерживает все остальные. Найти такие команды помогает slow log — журнал команд, выполнявшихся дольше порога (в микросекундах):

# логировать команды дольше 10 мс (10000 микросекунд)
redis-cli CONFIG SET slowlog-log-slower-than 10000
redis-cli CONFIG SET slowlog-max-len 128

# последние медленные команды и сброс журнала
redis-cli SLOWLOG GET 10
redis-cli SLOWLOG RESET

Для пиков задержки есть отдельный мониторинг латентности — LATENCY: он фиксирует всплески по событиям (fork при сохранении, медленная команда, обращение к диску) и помогает понять источник «иголок» на графике времени ответа:

redis-cli LATENCY RESET
redis-cli LATENCY HISTORY command
redis-cli LATENCY DOCTOR     # человекочитаемый разбор

Отдельно стоит MONITOR — он показывает поток всех команд в реальном времени. Незаменим для отладки, но сам по себе заметно нагружает сервер, поэтому в проде его держат включённым лишь короткими сессиями.

Бенчмарк: redis-benchmark

Чтобы оценить пропускную способность инстанса и сравнить конфигурации, в комплект входит redis-benchmark:

# 100000 запросов, 50 параллельных клиентов, только SET и GET
redis-benchmark -h 127.0.0.1 -p 6379 -n 100000 -c 50 -t set,get

# с конвейеризацией по 16 команд — оценить эффект pipelining
redis-benchmark -n 100000 -P 16 -t set

Один важный вывод бенчмарка: флаг -P (pipelining) обычно даёт кратный рост пропускной способности. Это подсказывает реальную оптимизацию — слать команды пачками (pipeline), а не по одной с ожиданием ответа на каждую, экономя сетевые round-trip'ы.

Как это работает под капотом

ACL проверяются на каждую команду: Redis сопоставляет команду и затрагиваемые ключи с правилами пользователя ещё до выполнения; нарушение — мгновенная ошибка NOPERM. Slow log хранится в памяти как кольцевой буфер на slowlog-max-len записей и измеряет только время исполнения команды — без учёта сетевой передачи и ожидания в очереди; поэтому «у клиента медленно, а в slowlog пусто» обычно означает не саму команду, а сеть либо очередь за другой долгой командой. Это прямое следствие однопоточной модели: пока выполняется тяжёлый KEYS * или O(n)-команда над огромной коллекцией, все прочие клиенты ждут. Память же отслеживается аллокатором (часто jemalloc), а mem_fragmentation_ratio — это отношение памяти, занятой процессом по мнению ОС, к памяти, реально используемой Redis под данные.

Частые ошибки

  • Оставить Redis без пароля и открытым в сеть. Классическая причина компрометации. Включайте ACL/requirepass, protected-mode, привязку к приватному адресу и файрвол.
  • Давать приложению полные права. Утечка такого доступа = FLUSHALL и чтение всех ключей. Узкий ACL: только нужные категории команд и шаблон ключей (~app:*).
  • Запускать KEYS * в проде. Команда блокирует сервер на время полного перебора ключей и копит латентность у всех. Используйте неблокирующий SCAN.
  • Держать MONITOR постоянно включённым. Он сам нагружает Redis и роняет throughput. Только короткие отладочные сессии.
  • Верить, что пустой slow log = всё быстро. Slow log меряет только исполнение команды; сетевые задержки и ожидание в очереди он не видит — смотрите ещё LATENCY и метрики клиента.

Итоги

  • ACL заводит пользователей с узкими правами (команды и шаблоны ключей) по принципу наименьших привилегий; default стоит запаролить или отключить.
  • Опасные команды (FLUSHALL, KEYS, CONFIG) ограничивают через ACL либо rename-command; обязателен сетевой минимум: пароль, protected-mode, приватный bind, файрвол.
  • INFO даёт сводку (память, попадания/промахи, вытеснения, ops/sec); следите за близостью к maxmemory и долей попаданий.
  • SLOWLOG ловит долгие команды (Redis однопоточен — одна медленная блокирует всех), LATENCY — всплески задержки; MONITOR только для коротких сессий.
  • redis-benchmark измеряет пропускную способность; -P показывает выгоду pipelining — реальный приём оптимизации.
Проверьте себя
1. Что позволяет сделать система ACL в Redis по сравнению со старым единым паролем requirepass?
AУскорить выполнение команд
BЗавести несколько пользователей и ограничить каждому набор разрешённых команд и шаблоны доступных ключей (least privilege)
CАвтоматически шифровать все данные на диске
DВключить репликацию без настройки
2. Почему одна медленная команда в Redis способна затормозить все остальные запросы?
AПотому что Redis выполняет команды в одном потоке, и тяжёлая команда (например, KEYS *) держит очередь, пока не завершится
BПотому что медленная команда удаляет другие ключи
CПотому что Redis перезапускается после каждой медленной команды
DПотому что остальные команды уходят на реплику
3. Растущий счётчик evicted_keys в выводе INFO о чём говорит?
AО сетевых ошибках при репликации
BО том, что рабочий набор не помещается в maxmemory и Redis вытесняет ключи согласно политике
CО числе подключённых клиентов
DО количестве выполненных команд CONFIG