Конфигурация
enodia читает до трёх файлов: enodia.yaml (обязателен — инвентарь
ваших сервисов), опциональный отдельный credentials.yaml и
опциональный settings.yaml (личные настройки отображения, никогда
не обязателен). Все три — обычный YAML.
enodia.yaml
Заголовок раздела «enodia.yaml»Верхний уровень
Заголовок раздела «Верхний уровень»schemaVersion: 1credentials_file: credentials.yaml # опционально, см. нижеdefaults: # опционально timeout: 10s concurrency: 5 retries: 2 backoff: 500mscve: # опционально, см. «Сопоставление с CVE» bdu: path: vulxml.zip nvd: path: nvd/ debian: path: debian.json oval: path: oval/ alpine: path: alpine/ mariadb: path: mariadb.md atlassian: path: atlassian.json postgresql: path: postgresql/ nginx: path: nginx.html update: # параметры TLS для «enodia cve update» ca_file: russian-trusted.pemcredentials: {} # опционально, см. «Credentials»targets: [] # ваши сервисыschemaVersion проверяется при чтении — будущая версия схемы будет
отклонена с советом обновиться, а не разобрана «на авось».
defaults
Заголовок раздела «defaults»Применяется к каждому таргету, если не переопределено на его уровне.
| Поле | Тип | Значение |
|---|---|---|
timeout |
duration | Таймаут на запрос (по умолчанию 10s, если нигде не задано) |
concurrency |
int | Сколько таргетов опрашивается одновременно |
retries |
int | Число повторов — повторяется только ErrUnreachable; отклонённый credential не станет лучше со второй попытки |
backoff |
duration | Задержка между повторами |
Длительности — в синтаксисе Go: 500ms, 10s, 2m, 1h30m.
Опционально. Указывает enodia на выгрузку БДУ ФСТЭК (cve.bdu.path),
JSON-фиды NVD (cve.nvd.path) и, для сопоставления по пакетам на
Linux-хостах, на выгрузку Debian Security Tracker (cve.debian.path),
OVAL-файлы вендоров (cve.oval.path) и secdb Alpine (cve.alpine.path),
а также собственные данные вендоров: таблицу исправленных CVE MariaDB
(cve.mariadb.path), данные Atlassian (cve.atlassian.path), PostgreSQL
(cve.postgresql.path) и nginx (cve.nginx.path) — любые из них,
каждый работает и по отдельности. enodia cve update скачивает их по
этим путям (её параметры TLS задаются в cve.update: ca_file,
ca_dir, tls_skip_verify), либо вы скачиваете их сами; check,
collect и serve никогда ничего не загружают. Относительные пути резолвятся относительно
директории этого конфига, а указанный, но несуществующий путь — это
ошибка. Что это даёт, как получить файлы и какие продукты
сопоставляются — см. Сопоставление с CVE.
targets
Заголовок раздела «targets»Одна запись на сервис:
targets: - id: jira-main # обязательно, стабилен при переименованиях - на нём завязаны метрики и история name: Jira (production) # опционально, по умолчанию = id product: jira # обязательно - см. Поддерживаемые продукты address: https://jira.example.com # обязательно credentials: jira-token # опционально, имя записи в credentials: timeout: 15s # опционально, переопределяет defaults.timeout path: /rest/api/2/serverInfo # опционально, специфично для продукта - у большинства проб разумный дефолт уже есть method: GET # опционально headers: # опционально, доп. заголовки на каждый запрос X-Custom: value allow_insecure_transport: false # опционально - см. «Сначала HTTPS» в Концепциях tls: # опционально, см. «TLS» ниже ca_file: /etc/enodia/ca.pem options: # опционально, специфичные для продукта настройки key: value parser: # только для product: generic - см. ниже type: regexaddress пишется ровно так, как вы бы его набрали — каждая проба
разбирает его сама. Голый хост без префикса https:///http://
резолвится автоматически (см.
Концепции),
либо запустите enodia config resolve, чтобы увидеть, какую схему
выберет каждый таргет, не отправляя ни одного credential.
options — произвольная карта для конкретного продукта; большинство
проб её вообще игнорируют. p4d/p4p
— первые, кто реально читает из неё значение: options.binary
переопределяет путь к CLI p4, к которому они обращаются.
freeradius читает
options.container (и options.container_runtime), чтобы найти
FreeRADIUS, запущенный в Docker или Podman, а
postgresql читает
options.database.
Раздел «Настройка продуктов» в боковом меню (или таблица
Поддерживаемые продукты) содержит точный эндпоинт,
требования к аутентификации и записываемые поля для каждой из 123
встроенных проб — path, credentials и options выше описывают общую
форму; страница конкретного продукта говорит, что ему нужно на самом
деле.
TLS (tls:)
Заголовок раздела «TLS (tls:)»Три уровня, в порядке убывания корректности:
tls: ca_file: /etc/enodia/corp-ca.pem # корпоративный CA-бандл - в большинстве закрытых контуров своя PKI pin_sha256: # отпечаток(и) закреплённого leaf-сертификата - "AB:CD:...:EF" server_name: internal.example.com # переопределение SNI min_version: "1.2" # минимальная версия TLS insecure: true # последний резерв - см. нижеinsecure: true предупреждает при каждом запуске, а не только при
валидации, потому что у этой настройки есть привычка добавляться
«временно» и жить годами. Она же попадает в observation, так что отчёт
заодно становится аудитом TLS по всему флоту — видно, какие сервисы
проверяются без верификации.
Credentials
Заголовок раздела «Credentials»Именованные записи, на которые ссылается поле credentials: таргета:
credentials: jira-token: kind: bearer value: "${JIRA_TOKEN}"
gitlab-token: kind: token-header header: PRIVATE-TOKEN value: "${GITLAB_TOKEN}"
vault-basic: kind: basic username: enodia password: "${VAULT_PASSWORD}"
redis-auth: kind: password password: "${REDIS_PASSWORD}"
linux-host-ssh: kind: ssh-key username: enodia-ro private_key_file: /etc/enodia/ssh/id_ed25519 passphrase: "${SSH_KEY_PASSPHRASE}" # опционально, только если ключ зашифрованkind |
Используемые поля | Что отправляется |
|---|---|---|
none (дефолт, если не указан) |
— | никакой credential |
bearer |
value |
Authorization: Bearer <value> |
token-header |
header, value |
произвольный заголовок, напр. PRIVATE-TOKEN, X-Vault-Token |
basic |
username, password |
HTTP Basic auth |
password |
password (плюс username — для протоколов, где он нужен: Redis ACL, PostgreSQL) |
нативная для протокола аутентификация (Redis AUTH, пароль SQL-подключения, …) |
ssh-key |
username, private_key_file, passphrase (опционально) |
SSH-аутентификация по публичному ключу — для SSH-проб определения ОС (см. Поддерживаемые продукты) |
Для SSH-таргетов также работает просто username вместе с kind: password и без private_key_file — SSH-пробы принимают либо пароль,
либо приватный ключ, как и любой SSH-клиент (username плюс password
под kind: password, либо username плюс private_key_file под
kind: ssh-key).
kind у credential должен совпадать с тем, что читает его продукт:
HTTP-продукты читают basic, bearer или token-header; SSH-пробы —
ssh-key или password; Redis, PostgreSQL и другие пробы на
wire-протоколах — password. Поэтому логин и пароль для веб-интерфейса
или REST API (RouterOS, Harbor, Jenkins, BMC) — это kind: basic, а не
kind: password. Какие виды принимает продукт, сказано на его
собственной странице. Несовпадение — жёсткая ошибка и в
enodia config validate, и при каждом запуске, с перечислением видов,
которые продукт принимает; прежние версии такой credential молча
отбрасывали и отправляли запрос вообще без аутентификации, а он потом
падал с ошибкой авторизации, которая указывала куда угодно, только не
на причину.
Проверка ключа хоста SSH
Заголовок раздела «Проверка ключа хоста SSH»Каждая SSH-проба использует тот же блок tls:, что и HTTPS-пробы для
проверки сертификата — pin_sha256 здесь хранит hex SHA-256 не TLS-
сертификата, а самого ключа хоста в его wire-кодировке, но форма та же:
«закрепите отпечаток, либо явно укажите insecure и получите
предупреждение»:
targets: - id: linux-host product: debian address: host.example.com credentials: linux-host-ssh tls: pin_sha256: - "AB:CD:...:EF" # sha256 ключа хоста, ssh-keyscan или аналог # insecure: true # последний резерв — полностью отключает проверку ключа хостаЕсли не указаны ни pin_sha256, ни insecure: true, соединение
отклоняется ещё до отправки хоть одного credential.
credentials_file
Заголовок раздела «credentials_file»Отдельный файл той же формы, что и инлайновая карта credentials::
jira-token: kind: bearer value: "${JIRA_TOKEN}"schemaVersion: 1credentials_file: credentials.yamltargets: - id: jira-main product: jira address: https://jira.example.com credentials: jira-tokenИменно это позволяет коммитить инвентарь сервисов в git, оставляя
секреты полностью снаружи. Записи из credentials_file имеют приоритет
над инлайновой записью с тем же именем. credentials_file резолвится
относительно файла конфига, который его называет, а не относительно
текущей директории.
Подстановка переменных окружения
Заголовок раздела «Подстановка переменных окружения»Любое строковое значение в enodia.yaml или credentials.yaml может
ссылаться на переменную окружения:
${VAR}— заменяется значением$VAR; если переменная не задана — ошибка.${VAR:-default}— заменяется значением$VAR, либоdefault, если переменная не задана.
Начиная с 2.2.1 подстановка выполняется после разбора YAML, внутри
каждого строкового значения, так что значение берётся дословно: пароль с
обратным слешем, #, : или ведущим *, & или [ больше не ломает
файл или enodia config validate, а значение, похожее на число или
true, остаётся строкой. До 2.2.0 включительно переменная сначала
вставлялась в сырой текст файла, поэтому такое значение приходилось
вручную брать в кавычки в YAML.
Интеграция с HashiCorp Vault Agent
Заголовок раздела «Интеграция с HashiCorp Vault Agent»Ни встроенную карту credentials: в enodia.yaml, ни отдельный
credentials.yaml не обязательно писать вручную. Оба — это просто
файлы, которые enodia читает заново при каждом запуске — подтверждено
по исходному коду: enodia check перечитывает конфиг и credentials с
нуля при каждом вызове, а enodia serve --interval делает то же самое
на каждом цикле обновления (Config.Build вызывает LoadCredentials
каждый раз, когда выполняется collectObservations — ничего не
кешируется на время жизни процесса, поэтому изменения в любом из этих
файлов вступают в силу без перезапуска). Это ровно та форма, под
которую заточен собственный рендеринг шаблонов у
Vault Agent.
У enodia нет собственной интеграции с Vault — она и не нужна, оба
механизма ниже уже сочетаются с ним напрямую.
Vault Agent рендерит переменные окружения
Заголовок раздела «Vault Agent рендерит переменные окружения»Направьте блок template (или env_template) Vault Agent на секреты,
которые нужны таргету, и ссылайтесь на них обычным способом — через
подстановку переменных окружения
выше:
jira-token: kind: bearer value: "${JIRA_TOKEN}"Режим exec у Vault Agent запускает саму enodia (или обёрточный скрипт,
вызывающий enodia check) как свой управляемый дочерний процесс,
вставляя отрендеренные переменные прямо в окружение этого процесса —
секрет вообще не попадает на диск как файл, который enodia должна
прочитать. Блок exec у Vault Agent также поддерживает перезапуск
дочернего процесса при изменении отрендеренного секрета, если вы хотите,
чтобы долгоживущий enodia serve подхватил обновлённый токен сразу, а
не дожидался, пока он просто останется валидным до следующего тика
--interval — точную настройку для этого смотрите в собственной
документации Vault Agent, это целиком на его стороне.
Vault Agent рендерит credentials.yaml напрямую
Заголовок раздела «Vault Agent рендерит credentials.yaml напрямую»Укажите credentials_file: на путь, по которому блок template Vault
Agent записывает файл, и отрендерите ровно ту форму, которую ожидает
credentials_file:
schemaVersion: 1credentials_file: /run/enodia/credentials.yamltargets: - id: jira-main product: jira address: https://jira.example.com credentials: jira-tokentemplate { destination = "/run/enodia/credentials.yaml" perms = "0600" contents = <<EOTjira-token: kind: bearer value: "{{ with secret "secret/data/enodia/jira" }}{{ .Data.data.token }}{{ end }}"EOT}Этот путь вообще не требует настройки exec/перезапуска: enodia check
перечитывает credentials_file с нуля при каждом вызове, а enodia serve — на каждом цикле обновления, независимо от того, как именно файл
изменился на диске. И cron-задача с enodia check, и долгоживущий
enodia serve просто подхватывают то, что Vault Agent записал
последним, по собственному расписанию — ничего специфичного для enodia
настраивать не нужно.
В любом случае — по правилам обработки credentials у enodia
Заголовок раздела «В любом случае — по правилам обработки credentials у enodia»Оба варианта всё равно попадают под всё, что уже описано в
Безопасности — credentials никогда не попадают в
инвентарь, экспортированные отчёты или логи, а проверка TLS остаётся
включённой, если вы не откажетесь от неё для конкретного таргета.
Именно настройки perms и выбор директории назначения у самого Vault
Agent защищают отрендеренный файл от доступа со стороны — у самой
enodia нет никакого мнения о том, где лежит credentials_file, кроме
того, что относительный путь резолвится относительно конфига, который
на него ссылается.
Generic-проба
Заголовок раздела «Generic-проба»product: generic — аварийный выход для таргета, который никогда не
получит отдельную пробу. Его словарь намеренно небольшой и заморожен —
ни условий, ни циклов, ни цепочек запросов, ни шаблонизации. Таргету,
которому нужно что-то из этого, нужна настоящая проба на Go, а не
расширение словаря generic-пробы.
targets: - id: in-house-api product: generic address: https://internal.example.com parser: type: regex # json | xml | header | plaintext | regex key: version # dotted path (json), путь вроде XPath (xml), или имя заголовка regex: 'v(\d+\.\d+\.\d+)' clean_regex: '^v' # побеждает первая захватывающая группа - snake_case, см. ниже line: 1 # только для plaintext - какую строку читатьРасположение файлов
Заголовок раздела «Расположение файлов»И enodia.yaml, и settings.yaml ищутся одинаково: явный путь
(--config/--settings, либо $ENODIA_CONFIG/$ENODIA_SETTINGS для
точного файла) всегда побеждает и обязан существовать — опечатка должна
быть ошибкой, а не тихим переключением на какой-то другой файл. Если
явного пути нет, запускается поиск в порядке ниже; первое совпадение
побеждает безоговорочно, ничего не сливается из нескольких найденных
файлов. Расположение важнее имени: совпадение в текущей директории всегда
побеждает совпадение в $XDG_CONFIG_HOME, которое всегда побеждает
совпадение в /etc/enodia/, независимо от того, какое имя где совпало.
enodia.yaml:
./enodia.yaml./enodia.yml./config.yaml./config.yml./.enodia.yaml./.enodia.yml./.config.yaml./.config.yml$XDG_CONFIG_HOME/enodia/enodia.yaml(~/.config/enodia/enodia.yaml, если$XDG_CONFIG_HOMEне задан)$XDG_CONFIG_HOME/enodia/enodia.yml$XDG_CONFIG_HOME/enodia/config.yaml$XDG_CONFIG_HOME/enodia/config.yml/etc/enodia/enodia.yaml/etc/enodia/enodia.yml/etc/enodia/config.yaml/etc/enodia/config.yml
Если не найдено ничего — это ошибка: конфиг, который не удалось найти,
стоит того, чтобы упасть громко, потому что это обычно значит, что вот-вот
будет использован не тот файл (или вообще никакой). Запустите
enodia config path, чтобы увидеть, какой файл реально будет
использован.
settings.yaml — та же идея, с несколькими отличиями: дополнительно
проверяется голое имя settings. (не только enodia.settings.),
дополнительно проверяется директория, где лежит сам исполняемый файл (не
только текущая директория — см. ниже), и отсутствие файла вообще — не
ошибка: каждое поле просто откатывается к встроенному значению по
умолчанию, поскольку этот файл полностью опционален:
./enodia.settings.yaml./enodia.settings.yml./settings.yaml./settings.yml./.enodia.settings.yaml./.enodia.settings.yml./.settings.yaml./.settings.yml<директория, где лежит исполняемый файл>/settings.yaml<та же>/settings.yml$XDG_CONFIG_HOME/enodia/settings.yaml(~/.config/enodia/settings.yaml, если$XDG_CONFIG_HOMEне задан)$XDG_CONFIG_HOME/enodia/settings.yml/etc/enodia/settings.yaml/etc/enodia/settings.yml
Шаг 9-10 отличается от текущей директории (шаги 1-8): портативная
установка (распаковал куда угодно, без пакетного менеджера) запускается
из той директории, где в данный момент стоит оператор, а это на Windows,
в частности, практически никогда не сама директория установки
(install.ps1 по умолчанию ставит в %LOCALAPPDATA%\enodia, добавляя в
PATH — весь смысл PATH в том, что текущая директория перестаёт иметь
значение). Этот шаг намеренно ограничен только settings.yaml — это
опциональные настройки отображения, так что неверный или подменённый
файл в общей директории установки — в худшем случае косметическая
проблема. enodia.yaml несёт credentials и такого шага не получает.
settings.yaml
Заголовок раздела «settings.yaml»Личные, персональные для оператора настройки отображения — никогда не
таргеты, никогда не credentials, никогда не то, чем обычно делятся так
же, как enodia.yaml.
schemaVersion: 1
render: # compact (по умолчанию) | lifecycle | drift | fleet default_view: fleet
export: # json (по умолчанию) | prometheus | html - используется, когда сам # export запущен без --format default_format: html
html: # inline (по умолчанию, полностью офлайн) | cdn (грузит Bootstrap/Bootswatch) assets: cdn
# none (вообще без стилей) | default (чистый Bootstrap) | любая из # 26 настоящих тем Bootswatch: brite, cerulean, cosmo, cyborg, darkly, # flatly, journal, litera, lumen, lux, materia, minty, morph, pulse, # quartz, sandstone, simplex, sketchy, slate, solar, spacelab, # superhero, united, vapor, yeti, zephyr theme: lumen
# auto (по умолчанию: гонка между jsdelivr и cdnjs, побеждает тот, кто # первым ответит) | jsdelivr | cdnjs cdn: auto
# опционально: ограничить экспорт одним представлением вместо всех четырёх # view: fleetrender.default_view применяется к --view команды check, когда сам
флаг не передан. export.default_format делает то же самое для
--format команды export. html.* имеет значение только для
export --format html — см. Отчёты, что именно меняет
каждое поле.