Перейти к содержимому

Интеграция tessera в /etc/pam.d/*

Руководство по правке PAM-стеков на Astra/Debian/Ubuntu. Документ выделен из install.md §8 + §11 — здесь всё про integrate-pam.sh, two-include pattern, режимы, специфику fly-dm/sudo/login/sshd и SysV-init.

ВАЖНО. Перед правкой PAM-стека открыть второй рут-shell (например, ssh root@<host>). Если основной shell не сможет авторизоваться после изменений — второй терминал останется единственным способом отката.

tessera поставляет включаемый сниппет /etc/pam.d/tessera (см. dist/pam.d/tessera). Подключать его строкой @include tessera.

Поставочный скрипт /usr/share/tessera/integrate-pam.sh автоматически вставляет @include tessera в правильную позицию и сохраняет резервную копию <file>.bak.<UTC-timestamp>.

  • Если в файле есть auth ... pam_parsec_mac.so (типично для Astra SE /etc/pam.d/login, /etc/pam.d/fly-dm) — @include встаёт после этой строки. Иначе snippet tessera-only с success=done обрывал бы auth-стек до выполнения pam_parsec_mac, его account/session-инстансы валились бы с "Can't obtain required data" → login deny.
  • Иначе @include встаёт перед первой auth-строкой (legacy behaviour для систем без МКЦ-стека, Ubuntu/Debian).

Начиная с 0.3.12 integrate-pam.sh подключает модуль двумя строками:

  1. @include tessera* (auth + account фазы) — попадает в верх файла после auth ... pam_parsec_mac.so (или перед первой auth-строкой, если МКЦ выключен);
  2. session required pam_tessera.so — ставится после @include common-session (или после последней session-строки, если common-session нет).

pam_sm_open_session нашего модуля читает XDG_SESSION_ID из PAM-environment и пушит его в monitord, чтобы USB-removal action (Lock / Logout) умел адресовать logind-сессию пользователя. XDG_SESSION_ID создаётся pam_systemd.so (обычно через @include common-session) — поэтому наш session обязан идти после.

Поставочные snippets (tessera, tessera-only, tessera-optional) с 0.3.12 содержат только auth+accountsession живёт отдельной строкой в host pam.d-файле. После апгрейда с 0.3.11 операторам нужно один раз прогнать:

Окно терминала
sudo /usr/share/tessera/integrate-pam.sh --unintegrate /etc/pam.d/login
sudo /usr/share/tessera/integrate-pam.sh --mode=<режим> /etc/pam.d/login

для каждого ранее интегрированного сервиса — старая session-строка из snippet’а после обновления .deb исчезнет, а новую вставит только повторный прогон.

Daemon на старте валит ERROR pam_stack_session_misorder, если наша session-строка стоит перед @include common-session / pam_systemd.so. Проверить без рестарта:

Окно терминала
sudo tessera check

Иначе в journald появится:

WARN tessera.session: XDG_SESSION_ID not in PAM env during sm_open_session
WARN tessera.monitord: USB-removal action dropped: session has no logind id

При извлечении флешки logout НЕ произойдёт — см. troubleshooting.md §4.

fly-dm — графический display-manager Astra Linux SE; это первый PAM-потребитель, через который пользователь попадает в графическую сессию. Без интеграции tessera в /etc/pam.d/fly-dm USB-токен на этапе GUI-логина не проверяется, пользователь зайдёт по паролю как будто модуль не установлен. Остальные сервисы (sudo, login, sshd) защищают только последующие действия.

Конкретные причины:

  1. Точка входа в сессию. МКЦ-метка (pam_cert_max_integrity ∩ МНКЦ пользователя) применяется в pam_sm_open_session и наследуется всем дочерним процессам desktop-сессии. Если сессию открыл не tessera, метка не выставится.
  2. Привязка USB к сессии. tessera daemon регистрирует удаление токена и отправляет lock-event в screen-locker. Регистрация возможна только если сессию открыл сам модуль — иначе у демона нет записи (uid, session_id, token_serial).
  3. Hot-plug до логина. fly-dm стартует раньше пользовательских сервисов; tessera.service обязан быть Before=fly-dm.service (поставочный unit это делает) — иначе на первом логине после ребута USB может быть ещё не проинициализирован.
  4. GUI-prompt для PIN. fly-dm рендерит PAM_PROMPT_ECHO_OFF как password-field. Без интеграции PKCS#11-prompt уйдёт в stderr DM-процесса и пользователь его не увидит — выглядит как «токен не работает».
  5. Root-контекст на auth-этапе. fly-dm бежит как root, поэтому доступ к /dev/bus/usb/* и PCSC-сокету разрешён без дополнительной udev-настройки.
Окно терминала
sudo /usr/share/tessera/integrate-pam.sh /etc/pam.d/fly-dm
sudo cat /etc/pam.d/fly-dm | head -5

Ожидаемый верх файла:

@include tessera
auth requisite pam_nologin.so
auth required pam_env.so
...

Включение через sufficient (контроль определён в dist/pam.d/tessera): если модуль успешно аутентифицировал — пропустить пользователя; если нет — попробовать следующие модули (pam_unix.so).

fly-dm-screensaver / fly-wm-locker имеют собственный PAM-стек. Интеграция /etc/pam.d/fly-dm разлоком экрана не управляет. Чтобы разблокировка работала по токену:

Окно терминала
sudo /usr/share/tessera/integrate-pam.sh /etc/pam.d/fly-dm-screensaver

Без этого извлечение токена корректно блокирует экран (через tessera daemon + D-Bus screen-lock hook), но разблокировать сессию можно будет только паролем.

Окно терминала
systemctl status tessera # daemon up до старта fly-dm?
pamtester fly-dm $USER authenticate # сухой прогон auth-стека без GUI
journalctl -u fly-dm -f # логи во время живого логина

См. fly-dm-greeter.md — wallpaper writer для МКЦ-3 fly-modern, где PAM_TEXT_INFO не пробрасывается в UI.

tessera поддерживает три эксплуатационных режима, переключаемых выбором PAM-сниппета:

РежимsnippetСценарийВход без USB
2fa (default)/etc/pam.d/tesseraCert + пароль (классический 2FA)пароль работает, но без USB не зайти
optional/etc/pam.d/tessera-optionalCert ИЛИ пароль (миграция)да, по паролю
cert-only/etc/pam.d/tessera-onlyCert как единственный факторНЕТ, полная блокировка
Окно терминала
# 2FA на sudo (по умолчанию):
sudo /usr/share/tessera/integrate-pam.sh --mode=2fa /etc/pam.d/sudo
# Миграционный режим:
sudo /usr/share/tessera/integrate-pam.sh --mode=optional /etc/pam.d/sudo
# Cert-only (потеря флэшки = lockout!):
sudo /usr/share/tessera/integrate-pam.sh --mode=cert-only /etc/pam.d/sudo

Откат — одинаковый для всех режимов:

Окно терминала
sudo /usr/share/tessera/integrate-pam.sh --unintegrate /etc/pam.d/sudo

Перед переключением сервиса в cert-only админ обязан иметь резервный канал доступа:

  1. Открытый root-shell в другом терминале (TTY/SSH) на всё время проверки — минимум до того, как убедились, что cert-only auth работает на тестовом аккаунте на этой машине.
  2. Альтернативный путь логина, который НЕ проходит через tessera — например, отдельный sshd-stack с PubkeyAuthentication=yes + UsePAM=no, или sudoers-правило для админ-аккаунта без @include tessera. Иначе потеря или блокировка единственного токена (USBGuard, ЗПС, физическая утрата) выведет хост из строя — никто не сможет залогиниться, включая локальный root.

Откат — integrate-pam.sh --unintegrate из живого root-shell или через rescue-target (см. troubleshooting.md §4 «Замок-аут после неудачной правки PAM»).

Окно терминала
sudo /usr/share/tessera/integrate-pam.sh /etc/pam.d/sudo
Окно терминала
sudo /usr/share/tessera/integrate-pam.sh /etc/pam.d/login

Стек зависит от того, включено ли МКЦ-ядро PARSEC. pam_parsec_mac.so в стеке нужен только когда МКЦ-ядро реально работает. Подробности — mac-integrity.md §6 «PAM-стек для МКЦ-сценариев».

Окно терминала
mount | grep -i parsec # пусто → МКЦ выключен
cat /etc/parsec/mswitch.conf 2>/dev/null # zero_if_notfound: yes → МКЦ выключен
ls /sys/kernel/security/parsec 2>/dev/null # ENOENT → МКЦ выключен

МКЦ выключен — без pam_parsec_mac.so в стеке, [mac].runtime = "disabled".

МКЦ включёнauth required pam_parsec_mac.so + @include tessera

  • pam_parsec_cap.so/pam_parsec_mac.so в session. [mac].runtime = "required".

Смешанный паркruntime = "auto", стек с pam_parsec_mac.so безопасен.

Полные примеры стеков, валидация и matrix runtime × cert_integritymac-integrity.md.

  • Перед правкой убедиться, что есть второй открытый рут-shell.
  • Проверять каждое изменение командой pamtester сразу после правки.
  • В случае поломки восстановить из бекапа:
    Окно терминала
    sudo cp /etc/pam.d/sudo.bak.<TS> /etc/pam.d/sudo
  • Полный recovery из rescue.target — см. troubleshooting.md §4.
Окно терминала
pamtester sudo alice authenticate

Ожидание: Authentication successful (при вставленном USB-носителе или токене).

Окно терминала
sudo tessera check # ловит pam_stack_session_misorder и др.

Пакет tessera ставит оба init-варианта:

  • systemd-юнит tessera.service — основной, на хостах с systemd активируется автоматически через dh_installsystemd;

  • SysV init-скрипт /etc/init.d/tessera — для non-systemd окружений (чистый sysvinit, OpenRC). Включается через update-rc.d или вручную:

    Окно терминала
    sudo update-rc.d tessera defaults
    sudo service tessera start
    sudo service tessera status

Скрипт оборачивает запуск /usr/bin/tessera через start-stop-daemon, кладёт PID-файл в /run/tessera/tessera.pid и читает /etc/tessera/config.toml.

  • На SysV-хостах нет hardening-сэндбокса (cgroups, ProtectSystem) — оператор принимает компромисс осознанно.
  • USB-removal Lock/Logout без pam_systemd.so не работаетXDG_SESSION_ID физически не создаётся. Fallback: [on_usb_removed].action = "shutdown" или "hook". См. troubleshooting.md §4 «Logout requested but session has no logind id», Причина 3.
  • На systemd-хостах править SysV-скрипт не требуется — авторитативный источник конфигурации службы — tessera.service.