Ручное подключение хоста
Руководство описывает ручное подключение одного 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 gRPC —
cp.example.com:31444 - REST/UI —
https://cp.example.comдля получения CA и создания токена
- gRPC mTLS-стрим —
- На хосте: 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 → Tokens → New 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.sha256QF_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 reached | max_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.