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

Ручное подключение хоста

Руководство описывает ручное подключение одного Linux-хоста к Control Plane. Для массового подключения подходит Ansible-роль deploy/ansible/roles/qf-agent.

Что происходит при энролменте

При первом запуске агент предъявляет CP bootstrap-токен. CP выпускает для агента клиентский mTLS-сертификат через enrollment gRPC. Затем агент устанавливает постоянный mTLS-поток AgentService.Stream для heartbeat, политик и телеметрии. Число применений токена задаёт max_uses; сертификат действует дольше и ротируется отдельно.

Предпосылки

  • CP доступен с хоста по сети. Порты (при дефолтном QF_ENDPOINT без явного порта):
    • gRPC mTLS-стримcp.example.com:31443
    • enrollment gRPCcp.example.com:31444
    • REST/UIhttps://cp.example.com для получения CA и создания токена
  • На хосте: systemd, ядро с eBPF-фичами bpf_loop + ring-buffer (mainline ≥5.17 или дистро-бэкпорт; TC датапас), root для установки пакета.
  • Доступ к CP UI или REST с ролью admin (для выпуска токена).

Проверить связь с хоста:

CP_HOST=cp.example.com
nc -zv "$CP_HOST" 31443
nc -zv "$CP_HOST" 31444

Шаг 1. Выпустить enrollment-токен

Токен несёт лейблы хоста (через label_template) и/или привязку к конкретному хосту. Два типа:

  • bulk — проще для ручного случая: хост энроллится под своим hostname, лейблы берутся из label_template. Один токен можно переиспользовать (max_uses).
  • single_host — жёстко привязан к заранее созданной записи хоста (target_host_id) и подходит как для первого подключения этой записи, так и для повторного энролмента. При повторном энролменте CP атомарно отзывает прежний активный сертификат, выдаёт новый и разрывает старый stream. bulk-токен заменить identity уже активного хоста не может.

Через UI

CP → TokensNew token → выбрать тип, указать TTL / max_uses / лейблы → скопировать token (показывается один раз).

Через REST

Логин (сохранить cookie), затем выпуск:

CP_URL=https://cp.example.com
ADMIN_PASSWORD=REPLACE_WITH_ADMIN_PASSWORD

# 1) логин
curl --fail --silent --show-error -c cookie.txt \
-X POST "$CP_URL/auth/login" \
-H 'Content-Type: application/json' \
-d "$(jq -n --arg password "$ADMIN_PASSWORD" \
'{username:"admin", password:$password}')"

# 2) bulk-токен с лейблами (напр. env=prod, role=web)
curl --fail --silent --show-error -b cookie.txt \
-X POST "$CP_URL/tokens" \
-H 'Content-Type: application/json' \
-d '{"type":"bulk","label_template":{"env":"prod","role":"web"},"ttl_seconds":3600,"max_uses":1}'
# Поле token показывается только при создании.

ttl_seconds по умолчанию 3600, max_uses — 1. Для одного хоста max_uses:1 достаточно.

Шаг 2. Установить пакет агента

Пакеты публикуются в GitHub Release на каждый релиз vX.Y.Z. Репозиторий приватный — качать через gh (не прямым URL, он даст 404):

VER=0.25.6 # версия установленного Control Plane

# Debian/Ubuntu
gh release download v$VER -R qzmi4meister/qf -p "qf-agent_${VER}_amd64.deb"
sudo dpkg -i qf-agent_${VER}_amd64.deb

# RHEL/Alma/Rocky
gh release download v$VER -R qzmi4meister/qf -p "qf-agent-${VER}-1.x86_64.rpm"
sudo rpm -i qf-agent-${VER}-1.x86_64.rpm

Пакет устанавливает бинарный файл /usr/sbin/qf-agent, unit qf-agent.service и конфигурацию /etc/qf/agent.conf. При обновлении конфигурация сохраняется. Сервис включается, но не запускается до настройки.

Шаг 3. Настроить /etc/qf/agent.conf

Базовые параметры — адрес CP и токен:

# CP endpoint (host или host:port). Без порта: gRPC :31443, enroll :31444, REST https://host.
QF_ENDPOINT=cp.example.com

# Токен из Шага 1
QF_ENROLL_TOKEN=PASTE_ENROLL_TOKEN_HERE

До запуска к ним добавляется один из параметров доверия к CA из следующего раздела.

Доверие к CA

Агент проверяет серверный сертификат CP по CA. Источники выбираются в порядке: QF_ENROLL_CA → сохранённый <QF_PKI_DIR>/ca.crt → fingerprint → REST-fetch. Для первого enrollment выбирается один из трёх режимов ниже. При повторном enrollment сохранённый ca.crt уже является trust anchor; чтобы перейти на другую CA, он заменяется явно, а не перекрывается fingerprint.

  • Пин по отпечатку. Получить SHA-256 CA в доверенной административной среде и передать его на хост по каналу, отличному от соединения с CP. Например, команду ниже можно выполнить с рабочей станции, которая уже доверяет REST-сертификату CP:

    curl https://cp.example.com/pki/ca.sha256
    QF_ENROLL_CA_FINGERPRINT=PASTE_SHA256_HEX_HERE

    Агент тянет CA по REST и принимает только при совпадении отпечатка.

  • Пин PEM-файлом. Получить CA PEM через уже доверенный канал, скопировать его в /etc/qf/ca.crt и указать:

    QF_ENROLL_CA=/etc/qf/ca.crt
  • Получение через системно доверенный REST API. TLS-сертификат REST API должен проверяться системным хранилищем сертификатов агента:

    QF_ENROLL_CA_FETCH=true

Дополнительные параметры

# QF_IFACE=eth0 # по умолчанию — из default route
# QF_FAIL_CLOSED=false # true = fail-closed датапас
# QF_DROP_IPV6=true # ДЕФОЛТ: режет весь IPv6 (opt-in гейт).
# =false → полный v6-энфорс (CIDR/ipset/conntrack); на dual-stack/Cilium разрешить ICMPv6 ND/RA
# QF_DENY_UNKNOWN_PROTO=false # ДЕФОЛТ: непарсимый L4 (SCTP/GRE/ESP/…) проходит без
# enforcement. =true → подчинить его default-action (дроп при DENY).
# ESP=IPsec / GRE=VPN / SCTP=телеком могут быть легитимны — сначала проверить
# QF_LOG_LEVEL=info
# QF_PKI_DIR=/etc/qf

Переменные окружения перекрывают значения из файла.

Шаг 4. Запустить и проверить

sudo systemctl start qf-agent
sudo systemctl status qf-agent
journalctl -u qf-agent -f # смотреть энролмент + attach датапаса

Признаки успеха в логе: подписан сертификат, установлен стрим, приложен bundle. На CP:

curl --fail --silent --show-error -b cookie.txt "https://cp.example.com/hosts" \
| jq '.[] | {hostname,status,agent_version}'

Хост должен появиться со статусом active и текущей версией агента. В UI — на странице Hosts.

Повторный enrollment существующего хоста

Для нужного target_host_id выпускается single_host token. На хосте агент останавливается, текущие agent.crt/agent.key сохраняются для аварийного восстановления, новый token записывается в QF_ENROLL_TOKEN, а исходные agent.crt и agent.key удаляются. После запуска сохранённые ca.crt и bundle-signing.pub удалять не нужно: первый остаётся trust anchor enrollment, второй заменяется ответом CP. При успехе агент очищает token, CP отзывает прежний сертификат, а host ID остаётся прежним. Одновременно агент удаляет last-good policy cache прежней identity, очищает прежние правила и начинает новую синхронизацию с generation 0. Актуальный bundle придёт от CP и станет новым last-good. Поэтому вручную сохранять или возвращать /var/lib/qf/policy.blob после re-enrollment нельзя. Обычный рестарт без enrollment по-прежнему использует cache для offline enforcement. Старая пара удаляется после проверки нового stream.

Устранение неполадок

СимптомПричина / действие
token max uses reachedmax_uses исчерпан — выпустить новый токен.
Unimplemented ... AgentService при стримепопал не в тот порт: стрим = :31443, enroll = :31444. Проверить QF_ENDPOINT.
CA verify / fingerprint mismatchПолученный CA не совпал с отпечатком. CA и отпечаток повторно сверяются через доверенный административный канал; автоматически принимать новое значение нельзя.
хост stale после стартанет heartbeat >90с — проверить сетевую доступность :31443 и journalctl.
attach БПФ падаетядру не хватает eBPF-фич (bpf_loop/ringbuf) или нет CAP_BPF/CAP_PERFMON — смотреть лог агента и capabilities unit'а.
статус не меняетсязаведён single_host-токен на другой target_host_id — сверить hostname/host id.
generation mismatch on connect или Bundle DivergedАгент сообщил generation выше desired либо вне допустимого диапазона. CP не считает это синхронизацией и не отправляет меньший bundle. Проверить, что re-enrollment завершён исправленной версией агента и старый policy cache не восстанавливался.

Вывести хост из эксплуатации

Сначала запись удаляется в Hosts или через DELETE /hosts/{id}. Control Plane отзывает активные сертификаты и разрывает соединение. Затем агент удаляется с хоста:

sudo systemctl disable --now qf-agent
sudo dpkg -r qf-agent # или: sudo rpm -e qf-agent

Пакет не удаляет конфигурацию, PKI и last-good bundle. Если они больше не нужны, каталоги /etc/qf и /var/lib/qf сначала переносятся в защищённую резервную копию, а затем удаляются по принятому сроку хранения.

См. также

  • deploy/ansible/roles/qf-agent — автоматизированный (парковый) энролмент.
  • deploy/packaging/agent.conf — эталонный конфиг со всеми ключами.
  • Установка в закрытом контуре (air-gap) — install-airgapped.md.