Развёртывание qf
Руководство охватывает Control Plane в Kubernetes или на отдельном Linux-сервере, установку агентов через Ansible или вручную и развёртывание сервиса аналитики.
Репозиторий и пакеты qf закрыты. Перед установкой нужен доступ к репозиторию и пакетам
организации qzmi4meister в GitHub и GHCR.
Компоненты qf
| Компонент | Что это |
|---|---|
| qf-cp | Control Plane: REST API, Web UI, gRPC-сервер, PKI и компилятор политик. Требует PostgreSQL. |
| qf-agent | Агент фаервола с eBPF/TC datapath. Работает на каждом защищаемом Linux-хосте и требует bpf_loop, ring buffer и BTF. |
Матрица ядро → датапас
Агент выбирает режим attach по возможностям ядра (проверяет TCX, откат на classic); сборка матчера и лимит правил единые:
| Ядро | Attach | Сборка матчера | Лимит правил |
|---|---|---|---|
| ≥6.6 | TCX (bpf_link) | bpf_loop | 2048 |
| <6.6 (с нужными eBPF-фичами) | классический clsact+cls_bpf | bpf_loop | 2048 |
Агент проверяет функции ядра при старте, а не только номер версии. Mainline-ядро
5.17 и новее содержит нужные функции; подходит и более старое ядро дистрибутива
с соответствующими backport. Если функций нет, агент завершает запуск и называет
их в ошибке. На ядре 6.6 и новее агент использует TCX. На ядре ниже 6.6 рядом
с Cilium агент не запускается из-за конфликта общего clsact qdisc.
1. Control Plane в Kubernetes (Helm)
Предпосылки
- Kubernetes 1.24+
- PostgreSQL 14+, доступный из кластера
- Helm 3.10+
- CP нужен PersistentVolume под PKI-хранилище (CA, серты, ключ подписи бандлов)
1.1 Подготовить values-файл
Создать values-prod.yaml (не коммитить в git):
image:
repository: ghcr.io/qzmi4meister/qf-cp
pullPolicy: Always
imagePullSecrets:
- name: ghcr-secret
replicaCount: 1
secrets:
dbDSN: "postgres://qf:PASSWORD@postgres.qf.svc.cluster.local:5432/qf"
masterKey: "GENERATE_WITH: openssl rand -hex 32"
jwtSecret: "GENERATE_WITH: openssl rand -hex 32"
adminEmail: "admin@example.com"
adminPassword: "CHANGE_ME"
# metricsToken: "GENERATE_WITH: openssl rand -hex 32" # опц.: Bearer для /metrics; без него /metrics = 404
# oidcClientSecret: "..." # опц.: OIDC SSO (+ QF_OIDC_* в env)
env:
QF_CP_HOST: "qf.example.com" # hostname в TLS SAN; агенты подключаются по этому имени
QF_CP_ENDPOINT: "qf.example.com:31444" # адрес энролмента, анонсируемый агентам
QF_GRPC_ADDR: ":8443"
QF_ENROLL_ADDR: ":8444"
QF_HTTP_ADDR: ":8080"
QF_PKI_DIR: /etc/qf/pki
QF_LOG_LEVEL: info
pki:
persistentVolume:
storageClass: "longhorn" # или другой класс; "" = класс кластера по умолчанию
size: 1Gi
service:
type: ClusterIP
agentService:
enabled: true
type: NodePort
externalTrafficPolicy: Local
grpcNodePort: 31443
enrollNodePort: 31444
ingress:
enabled: true
className: "traefik" # или nginx
host: qf.example.com
tls:
- secretName: qf-cp-tls
hosts:
- qf.example.com
Master key и JWT-ключи генерируются до установки:
echo "masterKey: $(openssl rand -hex 32)"
echo "jwtSecret: $(openssl rand -hex 32)"
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:3072 \
-out jwt-private.pem
chmod 600 jwt-private.pem
Стабильный QF_JWT_PRIVATE_KEY сохраняет access-токены после перезапуска даже
одной реплики. Для нескольких реплик он обязателен вместе с общим PKI-хранилищем:
RWX PVC либо pki.existingSecret. Требования и пример описаны в
разделе о масштабировании.
1.2 Установка / апгрейд
Вход в закрытый OCI-реестр выполняется токеном с правом чтения пакетов:
GITHUB_USER="$(gh api user --jq .login)"
gh auth token | helm registry login ghcr.io -u "$GITHUB_USER" --password-stdin
Kubernetes использует отдельный image pull secret:
kubectl create namespace qf --dry-run=client -o yaml | kubectl apply -f -
kubectl -n qf create secret docker-registry ghcr-secret \
--docker-server=ghcr.io \
--docker-username="$GITHUB_USER" \
--docker-password="$(gh auth token)"
VERSION=0.25.6 # нужная версия релиза
helm upgrade --install qf-cp \
oci://ghcr.io/qzmi4meister/helm/qf-cp \
--version "$VERSION" \
--namespace qf --create-namespace \
-f values-prod.yaml \
--set-file secrets.jwtPrivateKey=jwt-private.pem
Дождаться пода:
kubectl -n qf rollout status deployment/qf-cp
kubectl -n qf get pods
CP прогоняет миграции БД автоматически при первом старте. Логи:
kubectl -n qf logs -l app.kubernetes.io/name=qf-cp --tail=50
1.3 Опубликовать порты для агентов
Control Plane слушает gRPC на 8443, enrollment на 8444, а REST/UI на 8080.
Внешние порты зависят от выбранного Service. В примере NodePort это 31443 и
31444; REST/UI публикуется через Ingress на 443.
Вариант A — NodePort для on-prem и bare metal:
Добавить в values:
agentService:
enabled: true
type: NodePort
externalTrafficPolicy: Local
grpcNodePort: 31443
enrollNodePort: 31444
Затем в env:
env:
QF_CP_ENDPOINT: "<agent-vip-or-dns>:31444"
QF_CP_HOST: "<agent-vip-or-dns>"
Вариант B — LoadBalancer для облака или MetalLB:
agentService:
enabled: true
type: LoadBalancer
externalTrafficPolicy: Local
После назначения EXTERNAL-IP QF_CP_HOST и QF_CP_ENDPOINT должны указывать на
этот IP или DNS-имя. Подробности о сохранении исходного IP агента описаны в
гайде по балансировщику.
Вариант C — отдельный Ingress для gRPC: TCP-passthrough Ingress/Gateway на порты 8443 и 8444 рядом с HTTP-Ingress под UI.
1.4 Проверка
# Health-check
curl https://qf.example.com/healthz
# Логин
curl -c cookies.txt -X POST https://qf.example.com/auth/login \
-H 'Content-Type: application/json' \
-d '{"username":"admin","password":"CHANGE_ME"}'
# Список хостов (изначально пуст)
curl -b cookies.txt https://qf.example.com/hosts | jq .
1.5 Апгрейд CP
NEW_VERSION=0.25.6
helm upgrade qf-cp \
oci://ghcr.io/qzmi4meister/helm/qf-cp \
--version "$NEW_VERSION" \
--namespace qf \
-f values-prod.yaml \
--set-file secrets.jwtPrivateKey=jwt-private.pem \
--set image.tag="$NEW_VERSION"
2. Control Plane на отдельной Linux-машине
Запуск qf-cp напрямую как systemd-сервис на любом Linux x86_64/arm64-сервере.
2.1 Предпосылки
- Linux x86_64 или arm64
- PostgreSQL 14+ (локальный или удалённый)
- Доступ к исходникам qf
- Go 1.25.12+
- Node.js 22.13–22.x или 24.x
- TLS reverse proxy на порту 443 для REST и UI
2.2 Установить PostgreSQL и создать базу
# Debian/Ubuntu
sudo apt install -y postgresql
sudo -u postgres psql <<'SQL'
CREATE USER qf WITH PASSWORD 'CHANGE_ME';
CREATE DATABASE qf OWNER qf;
SQL
2.3 Собрать бинарь из исходников
gh repo clone qzmi4meister/qf
cd qf
make ui-build build-cp
sudo install -m 0755 qf-cp /usr/local/bin/qf-cp
2.4 Создать конфигурацию
sudo mkdir -p /etc/qf/pki
sudo tee /etc/qf/cp.env <<'EOF'
QF_DB_DSN=postgres://qf:CHANGE_ME@localhost:5432/qf
QF_MASTER_KEY=GENERATE_WITH_openssl_rand_-hex_32
QF_JWT_SECRET=GENERATE_WITH_openssl_rand_-hex_32
QF_CP_HOST=qf.example.com
QF_CP_ENDPOINT=qf.example.com:8444
QF_HTTP_ADDR=127.0.0.1:8080
QF_GRPC_ADDR=:8443
QF_ENROLL_ADDR=:8444
QF_TRUSTED_PROXIES=127.0.0.1/32
QF_PKI_DIR=/etc/qf/pki
QF_LOG_LEVEL=info
QF_ADMIN_USERNAME=admin
QF_ADMIN_EMAIL=admin@example.com
QF_ADMIN_PASSWORD=CHANGE_ME
EOF
sudo chmod 600 /etc/qf/cp.env
Сгенерировать ключи перед правкой:
openssl rand -hex 32 # вставить как QF_MASTER_KEY
openssl rand -hex 32 # вставить как QF_JWT_SECRET
Опциональные переменные (добавить в cp.env по необходимости):
| Переменная | Назначение |
|---|---|
QF_METRICS_TOKEN | Bearer-токен для GET /metrics. Не задан → эндпоинт не смонтирован (404). Скрейпер шлёт тот же токен (см. ops-runbook §5.3). |
QF_MASTER_KEY_FILE | Путь к файлу с master-key (например на tmpfs). Имеет приоритет над QF_MASTER_KEY и рекомендуется для production. |
QF_OIDC_ISSUER / QF_OIDC_CLIENT_ID / QF_OIDC_CLIENT_SECRET / QF_OIDC_REDIRECT_URL | SSO через OIDC. Для включения обязательны первые три переменные; redirect по умолчанию — /auth/oidc/callback. CP требует email_verified, находит учётную запись по email и после первого входа привязывает её к стабильному sub. |
QF_TRUSTED_PROXIES | CIDR-список прокси, которым доверять X-Real-IP/X-Forwarded-For (иначе rate-limit по адресу прокси). |
QF_INGEST_SHARDS / QF_INGEST_LOG_WORKERS | Число очередей ingest и воркеров на очередь (по умолчанию 1×4). |
QF_HEARTBEAT_FLUSH_INTERVAL_MS / QF_HEARTBEAT_BATCH_MAX | Тюнинг батчинга heartbeat-записей под большим флотом. |
QF_UI_POLL_INTERVAL / QF_LIVENESS_INTERVAL | Интервалы UI-poll и host-liveness lane. |
2.5 Создать systemd-юнит
sudo tee /etc/systemd/system/qf-cp.service <<'EOF'
[Unit]
Description=qf Control Plane
After=network.target postgresql.service
Requires=network.target
[Service]
Type=simple
User=root
EnvironmentFile=/etc/qf/cp.env
ExecStart=/usr/local/bin/qf-cp
Restart=on-failure
RestartSec=5s
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now qf-cp
sudo systemctl status qf-cp
2.6 Проверка
# Проверить, что миграции прошли
sudo journalctl -u qf-cp -n 30
# Health-эндпоинт
curl http://localhost:8080/healthz
# Web UI через TLS reverse proxy
# https://qf.example.com/app/
2.7 Фаервол
Наружу открываются два agent-порта и HTTPS reverse proxy. Внутренний HTTP-порт
8080 остаётся доступен только на loopback:
# ufw (Debian/Ubuntu)
sudo ufw allow 8443/tcp comment "qf gRPC"
sudo ufw allow 8444/tcp comment "qf enrollment"
sudo ufw allow 443/tcp comment "qf REST and UI"
3. Агент: развёртывание через Ansible
Ansible-роль скачивает пакет из GitHub Releases, ставит его и запускает/включает systemd-сервис. Поддерживает и apt (Debian/Ubuntu), и dnf/yum (RHEL/Fedora/Rocky).
3.1 Настроить инвентори
Отредактировать deploy/ansible/inventory.yml:
all:
children:
qf_agents:
hosts:
web1:
ansible_host: 192.168.1.10
web2:
ansible_host: 192.168.1.11
db1:
ansible_host: 192.168.1.20
vars:
ansible_user: root
ansible_ssh_private_key_file: ~/.ssh/id_ed25519
qf_endpoint: qf.example.com
qf_enroll_token: "PASTE_BULK_TOKEN_HERE"
qf_ca_src: files/qf-ca.crt
# Сохраняет безопасное значение агента по умолчанию: весь IPv6 закрыт.
qf_drop_ipv6: true
3.2 Настроить агента перед деплоем
Роль пишет /etc/qf/agent.conf, когда заданы qf_endpoint и qf_enroll_token
в inventory. Без них роль сохраняет конфигурацию из пакета.
Базовые параметры /etc/qf/agent.conf:
QF_ENDPOINT=qf.example.com
QF_ENROLL_TOKEN=PASTE_ENROLL_TOKEN_HERE
Для первого подключения также нужен один из вариантов доверия к CA, описанных ниже.
QF_ENDPOINT=host выводит gRPC :31443, enrollment :31444 и REST
https://host. Это соответствует стандартному NodePort. Для отдельного сервера
используется QF_ENDPOINT=host:8443, а enrollment будет на 8444. Интерфейс
определяется по default route; для явного выбора используется QF_IFACE или
QF_IFACES.
CA энролмента: роль настраивает один из трёх способов проверки CA. Для этого
задаётся одна из переменных роли: qf_ca_src (путь к CA PEM CP на control-ноде,
файл копируется на хост),
qf_enroll_ca_fingerprint (SHA-256, 64 hex-символа) или
qf_enroll_ca_fetch: true при TLS-сертификате REST API, которому доверяет
системное хранилище агента. См.
install-airgapped.md.
Получить enrollment-токен: CP Web UI → Tokens → New token → скопировать значение.
Либо через API:
curl -s -b cookies.txt -X POST https://qf.example.com/tokens \
-H 'Content-Type: application/json' \
-d '{"type":"bulk","label_template":{"env":"prod"},"ttl_seconds":86400,"max_uses":100}' | jq -r .token
Поле
target_group_idbulk-токена может содержать UUID группы. Подключённые этим токеном хосты становятся членами группы и наследуют её лейблы. См.fleet-management.md.
3.3 Деплой
# Установить pip-зависимости (однократно)
pip install ansible
: "${GITHUB_PAT:?set GITHUB_PAT with repo access}"
# Установка на все хосты группы qf_agents
GITHUB_TOKEN="$GITHUB_PAT" \
ansible-playbook -i deploy/ansible/inventory.yml deploy/ansible/deploy-agent.yml
# Тот же запуск через Makefile с явным inventory
GITHUB_TOKEN="$GITHUB_PAT" \
make deploy-agent ANSIBLE_INVENTORY=deploy/ansible/inventory.yml
# Установка из внутреннего репозитория не требует GitHub PAT:
ansible-playbook -i deploy/ansible/inventory.yml deploy/ansible/deploy-agent.yml \
-e qf_agent_source=repo
# Установка на один хост
ansible-playbook -i deploy/ansible/inventory.yml deploy/ansible/deploy-agent.yml --limit web1
Роль:
- Получает
.debили.rpmиз выбранного источника. - Устанавливает пакет через
apt,dnfилиyum. - Формирует конфигурацию enrollment и запускает
qf-agent.service. - Проверяет активность сервиса. Агент сам проверяет функции eBPF при старте.
3.4 Переопределить версию пакета
ansible-playbook -i deploy/ansible/inventory.yml deploy/ansible/deploy-agent.yml \
-e qf_agent_version=0.25.6
4. Агент: ручная установка на Linux
Работает на любом Linux x86_64-хосте — bare metal, VM или k8s-нода. Нужно ядро с eBPF-фичами bpf_loop + ring-buffer (mainline ≥5.17 или дистро-бэкпорт).
4.1 Установить пакет
VERSION=0.25.6 # нужная версия релиза
# Debian / Ubuntu
gh release download v${VERSION} -R qzmi4meister/qf -p "qf-agent_${VERSION}_amd64.deb"
sudo dpkg -i qf-agent_${VERSION}_amd64.deb
# RHEL / Fedora / Rocky
gh release download v${VERSION} -R qzmi4meister/qf -p "qf-agent-${VERSION}-1.x86_64.rpm"
sudo rpm -i qf-agent-${VERSION}-1.x86_64.rpm
Пакет ставит:
/usr/sbin/qf-agent— бинарь/etc/qf/agent.conf— шаблон конфига/lib/systemd/system/qf-agent.service— systemd-юнит
После первого успешного применения политики агент создаёт runtime-state
/var/lib/qf/policy.blob: подписанный last-good bundle для рестарта без CP.
4.2 Настроить
sudo nano /etc/qf/agent.conf
# CP endpoint (host или host:port). Выводит gRPC :31443, enroll :31444,
# REST https://host. С явным портом P: gRPC :P, enroll :P+1.
QF_ENDPOINT=qf.example.com
# Bootstrap-токен — из CP UI (страница Tokens) или API.
QF_ENROLL_TOKEN=tok_xxxxxxxxxxxx
# ── Проверка CA энролмента: выбрать один вариант для первого подключения ──
# Enrollment gRPC использует внутренний CA CP, поэтому агент обязан ему доверять.
# QF_ENROLL_CA=/etc/qf/ca.crt # заранее положенный CA PEM (скопировать с CP)
# QF_ENROLL_CA_FINGERPRINT=PASTE_SHA256_HEX_HERE # получает CA по REST и сверяет SHA-256 DER
# QF_ENROLL_CA_FETCH=true # только если TLS-сертификат REST API системно доверен
# ── Дополнительные параметры ──
# QF_IFACE= # пусто = автодетект из дефолтного маршрута
# QF_PKI_DIR=/etc/qf
# QF_LOG_LEVEL=info
# QF_FAIL_CLOSED=false
# 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/…) проходит
# без энфорсмента. =true → подчиняется default-action (дроп при
# DENY). ESP=IPsec / GRE=VPN / SCTP=телеком могут быть легитимны —
# сначала проверить. См. ops-runbook §8.4.
Интерфейс автодетектится из дефолтного маршрута. Переопределить или проверить:
ip route get 8.8.8.8 | awk '{print $5; exit}'
4.3 Запустить агента
sudo systemctl enable --now qf-agent
sudo systemctl status qf-agent
При первом старте агент:
- Подключается к вычисленному адресу enrollment (
QF_ENDPOINT:31444) и предъявляет bootstrap-токен. - Отправляет CSR; CP подписывает его и возвращает mTLS-сертификаты.
- Хранит сертификаты в
QF_PKI_DIR; при следующих запусках повторное подключение не требуется. - Подключается к вычисленному адресу gRPC (
QF_ENDPOINT:31443) по mTLS и ждёт пакет правил.
4.4 Проверить энролмент
# Логи агента
journalctl -u qf-agent -f
# На CP — хост должен появиться со статусом "active"
curl --fail --silent --show-error -b cookies.txt \
https://qf.example.com/hosts | jq '.[] | {hostname, status}'
4.5 Апгрейд агента
VERSION=NEW_VERSION
# Debian / Ubuntu — сохраняет /etc/qf/agent.conf
sudo dpkg -i qf-agent_${VERSION}_amd64.deb
# RHEL
sudo rpm -U qf-agent-${VERSION}-1.x86_64.rpm
sudo systemctl restart qf-agent
4.6 Сетевые топологии
- Один интерфейс — агент выбирает интерфейс default route.
- Bond — в
QF_IFACEуказывается логический интерфейс, напримерbond0. - Несколько активных интерфейсов —
QF_IFACES=eth0,eth1включает отдельные срезы правил и conntrack для каждого интерфейса. Область политики описана в отдельном руководстве. - Хост с Cilium — на ядре 6.6 и новее qf использует TCX рядом с Cilium.
На ядре ниже 6.6 загрузчик останавливается из-за конфликта
clsactqdisc.
5. Сервис аналитики (Helm)
qf-analytics — отдельный read-only сервис отчётов по событиям фаервола (обзор работы —
analytics.md). Разворачивается своим чартом, вне релиза CP.
5.1 Предпосылки
- Доступ к источнику данных read-only: PostgreSQL (CP-primary или RO-реплика) либо OpenSearch (SIEM-tee фаервол-событий).
- JWKS-эндпоинт CP (
https://<cp>/.well-known/jwks.json) — по нему офлайн проверяются операторские токены; без него сервис не стартует. - Публикация под тем же родительским доменом, что CP (путь
/analytics), чтобы cookieqf_tokenдоходила и SSO работало из консоли CP.
5.2 Установка / апгрейд
VERSION=0.25.6 # нужная версия релиза
helm upgrade --install qf-analytics \
oci://ghcr.io/qzmi4meister/helm/qf-analytics \
--version "$VERSION" \
--namespace qf \
--set 'imagePullSecrets[0].name=ghcr-secret' \
--set env.ANALYTICS_JWKS_URL=https://qf.example.com/.well-known/jwks.json \
--set env.ANALYTICS_SOURCE=postgres \
--set-string 'env.ANALYTICS_ROLES=admin\,auditor' \
--set secrets.sourceDSN='postgres://ro_user:PASSWORD@postgres.qf.svc.cluster.local:5432/qf' \
--set traefikRoute.enabled=true \
--set traefikRoute.host=qf.example.com \
--set traefikRoute.tlsSecret=qf-cp-tls
Для источника opensearch: --set env.ANALYTICS_SOURCE=opensearch,
--set secrets.sourceDSN='https://user:PASSWORD@opensearch:9200',
--set env.ANALYTICS_SOURCE_INDEX='qf-events*'. Syslog-tee несёт только rule_id, поэтому
для имён правил и политик в отчёте задаётся PostgreSQL DSN с правами только на
чтение:
--set-string secrets.enrichDSN='postgres://ro_user:PASSWORD@postgres.qf.svc.cluster.local:5432/qf'.
Чарт помещает строку подключения в Kubernetes Secret и подключает её к контейнеру через
secretRef.
Полный справочник переменных — analytics-config.md.
Периметровый basic-auth (для контуров без SSO, напр. дев-стенд) включается секретом с
htpasswd: --set traefikRoute.basicAuthSecret=SECRET_NAME — middleware закрывает весь
/analytics (UI+API) первым в цепочке. По умолчанию выключен; в проде перед сервисом —
SSO-домен CP.
Проверка:
kubectl -n qf rollout status deployment/qf-analytics
curl https://qf.example.com/analytics/healthz
5.3 Непрерывный мониторинг в SIEM
Встроенный поиск аномалий выполняется только при построении отчёта. Для постоянных
уведомлений используется механизм мониторинга установленной версии SIEM. В
OpenSearch детектор ограничивается документами kind.keyword=rule, группируется
по hostname.keyword и анализирует число событий с msgid.keyword=deny.
qf-analytics не создаёт и не обслуживает такие детекторы.
Аутентификация и RBAC
- RBAC-роли:
admin(всё, включая управление пользователями),editor(мутации),auditor(только чтение). API-токены для автоматизации/CI. - OIDC SSO опционально (любой провайдер) рядом с локальными аккаунтами.
- Первичный admin создаётся при первом старте из
QF_ADMIN_EMAIL/QF_ADMIN_PASSWORD.
Устранение неполадок
Хост завис в enrolling
journalctl -u qf-agent -n 50— искать TLS- или connection-ошибкиnc -zv qf.example.com 31444— проверить доступность порта энролмента (голыйQF_ENDPOINTвыводит :31444; standalone CP использует :8444)- Проверить, что токен валиден и не истёк: CP UI → Tokens
- Проверить, что
QF_CP_HOSTна CP совпадает с hostname/IP вQF_ENDPOINT— mismatch TLS SAN валит handshake - Отсутствует/неверный CA энролмента →
certificate signed by unknown authority: задатьQF_ENROLL_CA/QF_ENROLL_CA_FINGERPRINT(см. install-airgapped.md)
Бандл не приходит
- В логах агента должны быть
bundle receivedиbundle applied - Проверить, что mTLS-серты есть:
ls -la /etc/qf/—agent.crt,agent.key,ca.crtдолжны присутствовать - Проверить доступность gRPC-порта:
nc -zv qf.example.com 31443(standalone CP: :8443) - Проверить срок серта:
openssl x509 -in /etc/qf/agent.crt -noout -dates - Если сертификат истёк, выполнить
повторный enrollment
с резервной копией текущей пары и новым
single_host-токеном.
Агент не стартует — BPF-ошибки
journalctl -u qf-agent -n 20
BPF load failed: permission denied— не хватает capabilities; проверить, что в systemd-юните естьAmbientCapabilities=CAP_NET_ADMIN CAP_BPF CAP_PERFMON(CAP_SYS_ADMIN не требуется)kernel lacks required eBPF features: bpf_loop helper (...)— ядру не хватает eBPF-хелпера/мапы для датапаса; нуженbpf_loop+ ring-buffer (mainline ≥5.17 или дистро-бэкпорт). Агент называет отсутствующую фичу в логе.interface not found—QF_IFACEне совпадает с реальным именем интерфейса; проверитьip link
CP не стартует — ошибки БД
migrations failed— PostgreSQL недоступен либо роль не владеет пустой базой и схемой. Для выделенной базы рольqfназначается владельцем базы; для отдельной схемы ей нужныUSAGEиCREATE.connection refused— проверить host/port вQF_DB_DSNи что PostgreSQL запущенmaster key must be 32 bytes—QF_MASTER_KEYдолжен быть 64-символьной hex-строкой (openssl rand -hex 32)
TLS-ошибки
| Ошибка | Причина | Решение |
|---|---|---|
certificate signed by unknown authority | У агента неверный ca.crt или изменился CA Control Plane | Сверить CA через доверенный канал; при смене CA выполнить повторный enrollment |
certificate has expired | Автоматическое продление 90-дневного сертификата не завершилось | Выполнить повторный enrollment с single_host-токеном |
x509: certificate is valid for X, not Y | Mismatch QF_CP_HOST | Задать QF_CP_HOST на hostname, который используют агенты |