Управление большим парком qf
Для автоматического подключения хостов политики и группы объектов хранятся в Terraform, а начальные лейблы хостов задаются enrollment-токенами. Политика выбирает хосты по эффективным лейблам, поэтому отдельное назначение каждому хосту не требуется.
Что хранится в каждом контуре
| Объект | Интерфейс управления | Назначение |
|---|---|---|
qf_policy и selector | Terraform | Правила и область их действия |
qf_object_group | Terraform | Переиспользуемые наборы адресов, портов и хостов |
| Bootstrap-токен | Консоль или REST API | Начальные лейблы и параметры enrollment |
| Host group | Консоль или REST API | Общие лейблы и явный список участников |
Лейблы из label_template копируются на хост при enrollment. Последующее изменение
токена не меняет уже подключённые хосты.
Членство в host group всегда явное. Хост добавляется через консоль, REST API или
поле target_group_id bulk-токена. Совпадение лейблов само по себе не добавляет
хост в группу.
Для selector используются эффективные лейблы:
лейблы групп по приоритету + собственные лейблы хоста
Меньшее число означает более высокий приоритет группы. При конфликте собственный лейбл хоста имеет приоритет над групповым.
Рекомендуемая схема: selector по лейблам
В этой схеме Terraform описывает правила и selector, а bulk-токен выдаёт новым хостам те же лейблы.
Terraform: policy selector role=web, env=prod
│
▼
bulk-токен: label_template role=web, env=prod
│
▼
новый хост получает лейблы и автоматически попадает под политику
1. Описать политику в Terraform
resource "qf_object_group" "mgmt_net" {
name = "mgmt-net"
type = "ipset"
spec = jsonencode({ cidrs = ["10.0.0.0/16"] })
}
resource "qf_policy" "web" {
name = "web-ingress"
priority = 100
selector = jsonencode({
matchLabels = { role = "web", env = "prod" }
})
rule {
name = "allow-https"
priority = 10
direction = "ingress"
action = "allow"
match = jsonencode({ protocol = "tcp", dst_ports = ["443"] })
}
}
Пары внутри matchLabels соединены по AND. Политика из примера действует только
на хосты, у которых одновременно есть role=web и env=prod.
2. Выпустить bulk-токен для когорты
Токен создаётся в разделе Tokens или через POST /tokens:
{
"type": "bulk",
"label_template": { "role": "web", "env": "prod" },
"max_uses": 500,
"ttl_seconds": 2592000
}
Один токен обслуживает несколько хостов в пределах TTL и max_uses. Значение
max_uses меньше единицы заменяется сервером на 1.
3. Подключить хосты
Автоматизация распространяет agent.conf с адресом Control Plane, токеном и одним
из поддерживаемых способов проверки CA. При первом подключении агент получает
сертификат, а Control Plane сохраняет лейблы токена и вычисляет подходящие политики.
Настройка доверия и enrollment описаны в руководстве по подключению хоста.
Host groups для общих изменяемых лейблов
Host group полезна, когда одинаковый набор лейблов нужно менять для нескольких
хостов в одном месте. Например, группа может выдавать своим участникам
maintenance=true.
Порядок работы:
- Создать группу и задать её лейблы.
- Добавить существующие хосты через консоль или
POST /host-groups/{id}/members. - Для новых хостов при необходимости указать
target_group_idв bulk-токене. - Строить политики по эффективным лейблам.
Пример токена с автоматическим вступлением в группу:
{
"type": "bulk",
"target_group_id": "<group-uuid>",
"max_uses": 500,
"ttl_seconds": 2592000
}
label_template можно добавить в тот же токен. Собственные лейблы хоста будут
иметь приоритет над унаследованными лейблами группы.
Как работает назначение группы
В консоли добавление строки в таблице Группы записывает в selector текущие
matchLabels группы и служебное поле _groupId. При сопоставлении Control Plane
проверяет лейблы; _groupId не ограничивает результат явными участниками группы.
Следствия:
- политика действует на участников группы с подходящими эффективными лейблами;
- другой хост с тем же набором лейблов тоже попадает под политику;
- собственный лейбл участника может перекрыть групповой и исключить его;
- изменение лейблов группы меняет эффективные лейблы участников, но не переписывает сохранённый блок selector.
После изменения лейблов группы действие Зафиксировать изменение и посмотреть зону влияния создаёт черновик. В Зоне влияния проверяется новая область политики. Если selector должен следовать новому набору лейблов, назначение группы в политике нужно обновить.
Подробнее — в руководстве по selector.
Как выбрать между токеном и группой
| Задача | Подходящий механизм |
|---|---|
Выдать начальные role и env при enrollment | label_template токена |
| Автоматически подключать новые хосты к политике | Selector по лейблам токена |
| Менять общий лейбл у нескольких хостов | Лейбл host group |
| Явно вести состав административной группы | Членство в host group |
| Добавлять новые хосты в группу без ручного шага | target_group_id bulk-токена |
| Сделать исключение для одного хоста | _hostId через таблицу Хосты политики |
Обычно постоянные признаки, например role и env, задаются токеном. Временные
признаки, например maintenance или canary, удобнее выдавать через группы.
Изменение лейблов подключённых хостов
label_template не синхронизирует лейблы после enrollment. Для одного хоста
используется PATCH /hosts/{id}. Поле labels заменяет всю карту, поэтому перед
изменением нужно получить текущее значение, объединить его с новым и отправить
полный результат.
Отдельного bulk-endpoint для лейблов нет. Массовое изменение выполняется циклом запросов или через лейбл host group. Во время цикла другие изменения тех же лейблов следует приостановить: параллельный full-replace может потерять одну из правок.
Повторный enrollment не подходит для обычной смены лейбла. Он требует нового
single_host-токена и локального удаления прежней PKI после отзыва сертификата.
AND и OR в selector
Все пары matchLabels одного блока соединяются по AND:
{ "matchLabels": { "role": "web", "env": "prod" } }
Несколько блоков anyOf соединяются по OR:
{
"anyOf": [
{ "matchLabels": { "role": "web" } },
{ "matchLabels": { "role": "api" } }
]
}
В Terraform anyOf задаётся внутри jsonencode. Консоль формирует его при
добавлении нескольких назначений.
Пустой selector {} выбирает весь парк и требует confirm_match_all = true в
Terraform. Selector {"anyOf":[]} не выбирает ни одного хоста.
Группы объектов
Группа объектов хранит переиспользуемое ограничение правила:
| Тип | Содержимое | Результат при компиляции |
|---|---|---|
ipset | CIDR и IP-адреса | Список сетей и адресов |
portset | Порты и диапазоны | Список диапазонов портов |
hostset | Selector хостов | Адреса интерфейсов подходящих хостов |
ipset и portset не могут быть пустыми. Если hostset временно не находит
хосты или их dataplane-адреса, Control Plane не превращает пустой результат в
ANY и не выпускает зависимое поколение правил. Агент продолжает использовать
last-good generation до появления подходящих адресов.
Изменение группы объектов пересчитывает все политики, которые на неё ссылаются.
Группу с активными ссылками нельзя архивировать: API возвращает 409. Неиспользуемые
группы не удаляются автоматически; их жизненным циклом управляет оператор.
Проверка перед массовым изменением
Для изменения существующей политики или группы Зона влияния показывает результат
черновика до применения. При создании нового объекта такого предпросмотра нет, поэтому
область задаётся узким selector, а блокирующее правило сначала создаётся с действием
log.
Перед применением проверить:
- область действия в Зоне влияния;
- результат AND/OR и возможные совпадения общих лейблов;
- разрешения для SSH и других административных каналов перед широким
deny; - состояние desired и confirmed generation после применения;
- last-good generation на хостах, которые были офлайн.
Стабильные политики и группы объектов остаются в Git и проходят обычное ревью.
Токены имеют ограниченные TTL и max_uses, а временные изменения состава парка
выполняются через группы и лейблы.