ActiveScaleинженерная практика

Кейс: часы уехали — S3 отдаёт 403 всем клиентам при зелёном GUI

Кейсы cases3ntptime-skew403sigv4

Коротко. Кластер из трёх нод был здоров по GUI: узлы ONLINE, службы работают, внутренние запросы с самой ноды проходят 200 OK. При этом ни один внешний S3-клиент не мог получить листинг: шлюз отвечал 403, подпись отклонялась. Причина — системные часы одной ноды отстали на 23 ч 44 мин, а подпись S3 действует в окне ±15 мин. Починка — вернуть ntpd на штатный конфиг и убрать источник подмены конфига; после этого 403 исчезли без переустановки.


Симптом

Как это выглядело у оператора:

  • S3-клиент (командная строка, бэкап-агент) на любой запрос получал: 403 Forbidden — The difference between the request time and the current time is too large.
  • Листинг бакетов не проходил вообще, PUT/GET — тоже; поведение одинаковое у всех клиентов сразу, на разных площадках клиента.
  • GUI управления открывается, узлы зелёные. В модели все три ноды ONLINE, событий про диск, сеть или службы нет. Привычные ошибки по задачам — те же, что были и раньше.
  • Внутренние проверки с самой ноды (curl к локальному эндпоинту) отвечают 200.

Ключевое противоречие: статус узла в модели не показывает время, поэтому «зелёный GUI» не означает «S3 работает для клиента».


Что проверить первым (read-only)

  1. Время и синхронизация на каждой ноде: bash date -u timedatectl | grep -i synchronized ntpq -p Ожидается: одинаковое UTC на всех нодах, System clock synchronized: yes, в ntpq -p есть строка с * (сейчас выбранный источник) и стратум < 16. Пустой ntpq -p или st = 16 — нет рабочего источника.

  2. С каким конфигом запущен ntpd: bash ps -ef | grep "[n]tpd" Ожидается запуск с /etc/ntp.conf. Если в аргументах видно -c /run/ntp.conf.dhcp, демон читает конфиг, сгенерированный DHCP-хуком, — там нет кластерных peer'ов.

  3. Следы DHCP-хука на провижиненной ноде: bash ls -l /run/ntp.conf.dhcp ps -ef | grep "[d]hclient" systemctl is-enabled marvin-dhcp.service; systemctl is-active marvin-dhcp.service Ожидается: файла нет, dhclient не запущен, служба disabledи inactive. Наличие любого из трёх — повод разбираться.

  4. Что видит клиент снаружи: фронт отвечает и на 307/200 с заголовком Server: Quantum-ActiveScale, но конкретный подписанный запрос — 403. Разделять «фронт жив» и «подпись принята».

  5. Разброс часов между нодами — сравнить date -u трёх нод. Расхождение больше секунды — аномалия; расхождение в минуты/часы — это и есть причина 403.


Причина

Механизм: окно подписи

S3-подпись (SigV4) включает дату и время запроса в подписываемую строку. Шлюз принимает запрос, только если время подписи отличается от собственного времени шлюза не более чем на 15 минут (стандартное поведение S3-совместимых реализаций). При выходе за окно шлюз обязан ответить 403 с формулировкой про разницу времени — это не ошибка прав и не ошибка ключей.

В кейсе часы ноды отстали на 23 ч 44 мин. Отсюда:

  • любой внешний подписанный запрос — 403;
  • внутренние запросы с самой ноды, которые идут по локальному адресу и подписываются тем же локальным временем, проходят: клиент и шлюз «согласны» друг с другом, обе стороны ошибаются одинаково;
  • модель видит узел живым (ONLINE), heartbeat и внутренние вызовы работают. Время узла в статусе не инспектируется.

Как потерялся контроль времени

Причина здесь — не аппаратные часы: RTC (батарейные часы платы) были верны, ошибка была только в системном времени. Механика — наша, от правки установочного образа:

  1. Патч marvin-dhcp.service держит dhclient на сетевом порту без линка — «фантомный» DHCP-клиент.
  2. Каждые 300 с он продлевает аренду, а стоковый хук Ubuntu при продлении пишет /run/ntp.conf.dhcp и перезапускает ntpd с этим конфигом.
  3. В сгенерированном конфиге нет кластерных peer'ов — ntpd теряет синхронизацию с соседними нодами и остаётся на внешнем источнике, которого в сегменте нет.
  4. Служба была включена только на одной ноде — поэтому проблема была локальной: две другие держали время правильно, а шлюз на «уехавшей» ноде отклонял всё.

Что доказано, а что нет. Подмена конфига и отставание часов доказаны прямыми выводами (ps с -c /run/ntp.conf.dhcp, date -u против соседей, возврат времени после остановки ntp). Точный момент и источник скачка часов по журналам восстановить не удалось — журнал на этой ноде был пуст. Поэтому «сбой внешнего NTP-сервера» мы не объявляем: причиной считается отсутствие синхронизации с кластером, а не конкретное событие.


Решение (штатное)

  1. Остановить ntpd, убрать конфиг от DHCP, запустить снова — на ноде с уехавшим временем: bash sudo systemctl stop ntp sudo rm -f /run/ntp.conf.dhcp sudo systemctl start ntp Проверить: date -u, timedatectl | grep synchronized, ntpq -p — есть *, стратум < 16. В кейсе после этого стратум был 2, offset около 0.2 мс.

  2. Убедиться, что проблема не вернётся через 5 минут. Подмена возвращалась на каждой аренде, поэтому удалить файл недостаточно. По отмашке оператора на всех нодах: bash sudo systemctl stop marvin-dhcp.service sudo systemctl disable marvin-dhcp.service Убедиться, что фантомный dhclient снят (вместе с cgroup службы).

  3. Вернуть ntpd на вендорский /etc/ntp.conf и проверить, что в ntpq -p снова видны кластерные peer'ы — соседние ноды, а не только внешний источник.

  4. Поставить исправленный DHCP-скрипт с защитой (marvin-dhcp.sh из нашего образа): даже случайное включение службы на провижиненной ноде больше не подменяет конфиг NTP. Старую версию сохранить вне каталога продукта.

  5. Контроль через 4 минуты (один период аренды): dhclient — 0 процессов, /run/ntp.conf.dhcp отсутствует, date -u верный, листинг бакетов клиентом — OK.

Если штатный путь недоступен

Если доступа к службе нет или перезапуск ntpd запрещён в окне обслуживания — временная мера, не штатно: разово выставить время с соседней ноды (sudo date -u -s "$(ssh <USER>@<NODE_IP> date -u +%Y-%m-%dT%H:%M:%SZ)") и немедленно открыть заявку на штатную правку NTP. Пометка обязательна: это маскирует симптом, но не убирает источник подмены — часы уедут снова на следующем цикле аренды, а date -s без синхронизации даст дрейф. Проверить причину и закрыть её в тот же день.


Проверка

Что Ожидаемое значение
date -u на всех нодах совпадает до секунды
timedatectl synchronized: yes
ntpq -p источник с *, st ≤ 3, offset — единицы миллисекунд
ps -ef \| grep ntpd запуск с /etc/ntp.conf, без -c /run/ntp.conf.dhcp
/run/ntp.conf.dhcp файла нет
dhclient 0 процессов
marvin-dhcp.service inactive, disabled
S3 листинг бакета клиентом 200 (не 403)
События нет новых WARNING/CRITICAL про NTP или службы

Отдельно: сравнение date -u против RTC (hwclock --show) — расхождение означает, что системное время рассинхронизировано с платой, а не что плата сломана.


Профилактика

  1. NTP — не «настройка по умолчанию», а кластерный механизм. ntpd должен ходить к peer'ам соседних нод; внешние источники — дополнение, а не единственный путь.
  2. Не оставлять работающий DHCP в mgmt-сегменте после провижина. marvin-dhcp (или его аналог) на провижиненной ноде — disabled; скрипт — с защитой от подмены конфига.
  3. Добавить время в полевой health-check. Наш as-field-health.sh за ~30 секунд проверяет: синхронизацию, отсутствие -c /run/ntp.conf.dhcp, отсутствие dhclient и /run/ntp.conf.dhcp, выключенность службы, разброс часов между нодами — и это вышло прямо из этого кейса.
  4. S3-мониторинг делать снаружи. Проверка «листинг бакета подписанным запросом» раз в несколько минут ловит 403 от расхождения часов раньше, чем клиент напишет в поддержку. Внутренние проверки с самой ноды эту проблему не видят по устройству.
  5. Регламент: время и NTP — в чек-лист еженедельного обслуживания, подробности — в регламенте обслуживания и статье про NTP.

Источники и дата

  • Вендор: Управление системой (GUI) (доступ 2026-11-07)
  • Вендор: Software Documentation Center (доступ 2026-11-07)
  • Наша практика: обезличенный разбор — 3-нодный кластер, отставание одной ноды 23 ч 44 мин, RTC при этом верный; окно подписи ±15 мин.
  • Обновлено: 2026-11-07.

Нужен инженер? Разберу вашу ситуацию и скажу, что делать — по шагам, с проверками.

Обсудить задачу