Справочник формата TOML Census
Полный пофайловый и пополевой справочник по всем TOML-файлам, которые читает
Census. Дополняет getting-started.md (где показан
типовой случай) полной поверхностью: каждое поле, его тип, обязательность,
значение по умолчанию и смысл.
Census читает такие виды файлов:
| Файл | Кто пишет | Строгость | Этот док |
|---|---|---|---|
Декларация (declaration.toml) | оператор / control plane | строгая (неизвестные ключи отвергаются) | §1 |
Слайс роли (role-store <role>.toml) | оператор / Tessera | толерантный верхний уровень; строгий [[payload.files]] | §2 |
Permission каталога (share/permissions/**/*.toml) | автор каталога | строгая | §3 (сводка + ссылки) |
Framework (frameworks/<fw>/*.toml) | автор compliance | строгая | §4 (сводка + ссылки) |
Managed-реестр (/var/lib/census/managed.toml) | только Census | — | §5 (не редактировать) |
Конфиг аудита (/etc/census/exposure.toml) | оператор | строгая | §6 (опционально) |
Авторитетные машиночитаемые схемы лежат в contract/*.schema.json (сгенерированы
из парсеров, контрактно-залочены). Этот документ — их прозаическое зеркало; при
любом расхождении побеждает схема.
Конвенции. «Обязательно» — без него парсинг падает. «Строгая» означает
deny_unknown_fields— опечатка в ключе это ошибка (fail-closed), а не молчком проигнорированный ключ. «Толерантная» — неизвестные ключи пропускаются (формат, которым совладеет другой инструмент).
1. Декларация — declaration.toml
Заголовок раздела «1. Декларация — declaration.toml»Декларация — желаемое состояние устройства: какие роль-учётки и группы должны существовать. Парсится строго — неизвестный ключ где угодно это ошибка.
1.1 Верхний уровень
Заголовок раздела «1.1 Верхний уровень»| Ключ | Тип | Обязателен | Смысл |
|---|---|---|---|
schema | целое | да | Версия формата парсера декларации. Сейчас 1. Census проверяет её первой, до любой другой валидации, и отвергает декларацию, чья schema превышает поддерживаемую этой сборкой (fail-closed, без мутаций) — см. §1.1.1. |
version | целое | да | Монотонный anti-rollback счётчик контента декларации (защита подписи от replay) — не версия формата. Проверяется только в managed/signed-режиме; под --trust-fs не проверяется. Бампайте при каждой новой подписанной декларации. См. §1.1.1. |
role_store | путь | да | Путь к каталогу role-store, разрешается относительно рабочего каталога, из которого запущен Census (или абсолютный). |
[defaults] | таблица | да | Атрибуты учёток по умолчанию (§1.2). |
[[role_account]] | массив таблиц | нет | Роль-учётки для подготовки (§1.3). |
[[group]] | массив таблиц | нет | Самостоятельные группы (§1.4). |
[[role_group]] | массив таблиц | нет | Привязка grant’ов роли к объявленной группе (§1.5). |
signature | строка (hex) | только в managed | Открепленная подпись Ed25519 над байтами декларации. Присутствует, когда декларация централизованно подписана; отсутствует под --trust-fs (standalone). Вручную не пишется — её добавляет control plane. |
1.1.1 schema vs version — два разных числа
Заголовок раздела «1.1.1 schema vs version — два разных числа»Эти два целочисленных поля похожи и их легко спутать, но они отвечают на разные вопросы:
| Поле | На что отвечает | Enforce |
|---|---|---|
schema | «Какой это формат TOML?» — версия формата парсера. | Всегда. Проверяется первой, до любого другого поля; schema новее, чем поддерживает сборка → отказ, fail-closed, без мутаций. |
version | «Насколько свежий это контент?» — монотонный anti-rollback счётчик, защищающий подпись от replay. | Только в managed-режиме (с подписью); под --trust-fs не проверяется. |
schema— про форму файла. Бампайте её только при несовместимом изменении самого формата; сборка, не понимающая более новуюschema, останавливается чисто, с внятным сообщением, а не падает где-то внутри на неизвестном ключе.version— про содержимое. Бампайте её при каждой новой подписанной декларации, чтобы атакующий не мог переиграть (replay) старую подписанную копию и откатить устройство к устаревшему доступу. В standalone-режиме (--trust-fs) переигрывать нечего — подписи нет, поэтомуversionфиксируется, но не проверяется.
Они двигаются независимо: перевыдача доступа устройства бампает version, а
schema остаётся; миграция формата файла бампает schema, а version не
затрагивается. Слить их в одно поле — это либо ложный rollback-отказ при
апгрейде формата, либо дыра в replay-защите при рефакторинге схемы.
1.2 [defaults]
Заголовок раздела «1.2 [defaults]»Применяется к каждой роль-учётке, если та не переопределяет. Строго.
| Ключ | Тип | Обязателен | Смысл |
|---|---|---|---|
uid_range | [целое, целое] | да | Включительное окно [low, high] для UID. Каждый uid учётки должен попадать в него. |
shell | строка | да | Login-shell по умолчанию (например /bin/bash). |
home_base | путь | да | Родительский каталог домашних каталогов; home учётки по умолчанию <home_base>/<role>. |
[defaults]uid_range = [9000, 9999]shell = "/bin/bash"home_base = "/var/lib/census/home"1.3 [[role_account]]
Заголовок раздела «1.3 [[role_account]]»По одной записи на роль-учётку. Строго. Учётка — это один из двух взаимоисключающих видов, различаемых источником идентичности:
- Created (создаваемая) — несёт явный
uid. Census создаёт Unix-юзера (именованного по роли) с этим стабильным для парка UID. Обычный случай. - Adopted (усыновляемая) — несёт
user(имя существующей OS-учётки) иadopt = true, и не должна нестиuid. Census привязывает grant’ы роли к этой предсуществующей учётке и никогда не вызываетuseradd/userdel— он не присваивает UID юзеру, которого не создавал.
uid и user взаимоисключающие; объявление обоих отвергается.
| Ключ | Тип | Обязателен | По умолч. | Смысл |
|---|---|---|---|---|
role | строка | да | — | Имя роли; должно совпадать со слайсом в role-store (§2). |
uid | целое | Created: да | — | Явный стабильный для парка UID. Должен быть в uid_range. Отсутствует ⇒ учётка должна быть Adopted. |
user | строка | Adopted: да | — | Имя существующего OS-юзера для усыновления. Взаимоисключающе с uid; требует adopt = true. |
adopt | bool | нет | false | true помечает учётку Adopted (требует user, запрещает uid). false — Created-учётка по uid. |
shell | строка | нет | [defaults].shell | Переопределение login-shell для учётки. |
home | путь | нет | <home_base>/<role> | Переопределение home для учётки. |
# Created-учётка (обычный случай)[[role_account]]role = "oper"uid = 9001
# Adopted-учётка — привязать grant'ы роли к существующему юзеру `svc`[[role_account]]role = "legacy-svc"user = "svc"adopt = trueCreated роль-учётка создаётся с заблокированным паролем и без
authorized_keys— единственный путь входа это PAM-сервис аутентификатора. Это не поля декларации; Census навязывает их при создании. У Adopted учётки состояние учётных данных остаётся как есть (Census никогда не вызывает над нейuseradd/userdel).
1.4 [[group]]
Заголовок раздела «1.4 [[group]]»Самостоятельные группы, которыми должен владеть Census. Строго.
| Ключ | Тип | Обязателен | По умолч. | Смысл |
|---|---|---|---|---|
name | строка | да | — | Имя группы. |
gid | целое | нет | авто | Закреплённый GID. Если GID уже принадлежит другой группе, apply отказывается — он никогда не перенумеровывает. |
adopt | bool | нет | false | Усыновить предсуществующую группу с этим именем вместо создания. |
members | массив строк | нет | [] | Имена учёток-членов. |
[[group]]name = "kiosk-ops"members = ["oper"]1.5 [[role_group]]
Заголовок раздела «1.5 [[role_group]]»Привязка grant’а: прикрепить разрешённые permissions роли к группе, чтобы каждый член группы их наследовал (многие-к-одному — несколько ролей могут привязываться к одной группе). Строго.
| Ключ | Тип | Обязателен | Смысл |
|---|---|---|---|
role | строка | да | Роль, чьи grant’ы привязываются. |
group | строка | да | Целевая группа — должна именовать [[group]], объявленную в той же декларации (§1.4). |
[[group]]name = "kiosk-ops"
[[role_group]]role = "oper"group = "kiosk-ops"2. Слайс роли — <role-store>/<role>.toml
Заголовок раздела «2. Слайс роли — <role-store>/<role>.toml»По одному файлу на роль. Верхний уровень толерантный — Census читает только
потребляемые ключи и игнорирует остальные (схемой роли совладеет Tessera,
добавляющая adapter-поля, которые Census не нужны). Всё, на что Census
действует, лежит под [payload].
2.1 Верхний уровень (общероле́вой)
Заголовок раздела «2.1 Верхний уровень (общероле́вой)»| Ключ | Тип | Используется Census | Смысл |
|---|---|---|---|
role | строка | информационно | Имя роли (должно совпадать с role декларации). |
version | целое | информационно | Версия схемы слайса. |
os | строка | информационно | Целевое семейство ОС (например linux). |
name | строка | информационно | Человекочитаемое название роли. |
level | целое | информационно | Тир/уровень роли (владеет Tessera). |
[payload] | таблица | да | Доступ, который Census материализует (§2.2). |
Неизвестные ключи верхнего уровня игнорируются (толерантно).
2.2 [payload]
Заголовок раздела «2.2 [payload]»Все поля опциональны; толерантно (неизвестные ключи игнорируются). Сырые
примитивы (groups, sudo, sudo_role, limits, files) — это
escape-hatch, который объединяется с разворотом permissions:
используйте либо то, либо другое, либо оба.
| Ключ | Тип | Смысл |
|---|---|---|
permissions | массив | Ссылки на permissions, разворачиваемые против каталога (§2.3). Обычный способ выдать доступ. |
groups | массив строк | Сырые supplementary-группы напрямую (escape-hatch — в обход каталога). |
sudo | массив строк | Сырые inline sudo-правила напрямую (escape-hatch — в обход каталога). Только литеральные абсолютные пути команд; см. §2.7. |
sudo_role | строка | Сырое имя sudo-роли напрямую (escape-hatch). |
[payload.limits] | таблица | Ресурсные лимиты (§2.4). |
[[payload.files]] | массив таблиц | Сырые inline файловые grant’ы (§2.5). |
role = "oper"version = 1os = "linux"name = "Оператор устройства"level = 3
[payload]permissions = ["service-restart", "log-read", { id = "service-control", units = "nginx" }, "nginx.operate"]groups = ["video"] # escape-hatch, объединяетсяsudo = ["/usr/sbin/reboot"] # escape-hatch, сырая sudo-команда (§2.7)sudo_role = "operations" # escape-hatch
[payload.limits]nofile = 8192
[[payload.files]]path = "/var/lib/app/state"access = "rw"recursive = true2.3 permissions — три формы
Заголовок раздела «2.3 permissions — три формы»Каждый элемент permissions — одно из:
- Голый id — строка, именующая leaf, bundle или package:
permissions = ["log-read", "network-config", "nginx.operate"]
- Параметризованная — таблица с обязательным
idплюс параметрами, которые заполняют шаблоны{placeholder}permission’а (например unit(ы), к которым применяется permissionservice-*). Списочный параметр разворачивается в одно правило на элемент:Табличная форма толерантна: ключи кромеpermissions = [{ id = "service-control", units = "nginx" },{ id = "service-observe", units = ["nginx", "mosquitto"] },]idзахватываются как параметры, так что параметр, который запись каталога не использует, просто инертен (не ошибка).
Leaf — единичная способность; bundle агрегирует другие (разрешается
транзитивно, его класс риска = максимум по членам); package — курируемый тир
<app>.{observe|operate|admin}. Полный список permissions — см. §3 и сам каталог.
2.4 [payload.limits]
Заголовок раздела «2.4 [payload.limits]»| Ключ | Тип | Смысл |
|---|---|---|
nofile | целое | RLIMIT_NOFILE (макс. открытых файлов). |
nproc | целое | RLIMIT_NPROC (макс. процессов). |
2.5 [[payload.files]]
Заголовок раздела «2.5 [[payload.files]]»Inline файловые grant’ы, той же формы что и каталожный [[file]]. В отличие от
остального payload, этот блок строгий (deny_unknown_fields): файловый grant
роли материализуется от root через setfacl, так что опечатка в ключе падает
fail-closed.
| Ключ | Тип | Обязателен | По умолч. | Смысл |
|---|---|---|---|---|
path | строка | да | — | Абсолютный путь к каталогу, файлу или glob. Должен быть литеральным — placeholder/шаблон в файловом grant’е роли отвергается (никаких {…}). |
access | строка | да | — | Биты доступа — см. §2.6. |
recursive | bool | нет | false | Для каталога: применить рекурсивно и поставить default-ACL, чтобы новые файлы наследовали доступ. |
Каталог против одиночного файла. Grant на каталог (
recursive = true) устойчив к перезаписи и обеспечивается всегда доступным ACL-backend’ом. Grant на одиночный файл требует per-file backend; на системе без негоapplyего отвергает (атомарно — ничего не применяется). Предпочитайте grant’ы на каталоги.
2.6 Значения access
Заголовок раздела «2.6 Значения access»access — набор битов: read (r), write (w), execute (x), traverse (X,
поиск по каталогу / условное исполнение). Два legacy-алиаса покрывают типовые
случаи, для остального есть канонические компактные строки:
| Значение | Биты | Применение |
|---|---|---|
"ro" | {read, traverse} (r-X) | только чтение дерева |
"rw" | {read, write, traverse} (rwX) | чтение-запись дерева |
| канонические компактные строки | любая комбинация r w x X | точный контроль |
Для большинства grant’ов нужны именно "ro" и "rw".
2.7 payload.sudo — сырые sudo-команды (escape-hatch)
Заголовок раздела «2.7 payload.sudo — сырые sudo-команды (escape-hatch)»sudo под [payload] — командный близнец [[payload.files]]: сырой список
sudo-правил, несомый напрямую в роль и объединяемый с тем, во что
разворачиваются permissions роли — тем же путём, что и поле sudo каталожного
permission’а. Используйте для команды, под которую ещё нет permission’а в
каталоге.
[payload]sudo = ["/usr/sbin/reboot", "/usr/bin/systemctl"]Ограничения — проверяются до записи чего-либо в sudoers, fail-closed при
нарушении:
- Только литеральные абсолютные пути команд — каждый элемент должен
начинаться с
/. - Без аргументов и без шаблонов
{placeholder}. Параметризация с confinement ({unit}, ограниченный constraints в[params]) остаётся прерогативой catalog-id — инлайн-параметр подпереть нечем, поэтому он отвергается. - Печатный ASCII, без shell-метасимволов (
; | & $ < >…) — отвергаются, чтобы значение не протащило вторую команду в строку sudoers.
Каждый элемент материализуется в sudoers.d/census-<role> от root, так что
это настоящая выдача привилегий. Поскольку он минует курируемый каталог, у него
нет risk-метки — поэтому census show и census compile --lint помечают
инлайн-payload.sudo (как и [[payload.files]]) как raw / unlabeled
escalation-capable, чтобы ревьюер всегда его видел. Предпочитайте permission
каталога, когда он есть; беритесь за payload.sudo только как за осознанный
escape-hatch.
3. Файлы permissions каталога (сводка)
Заголовок раздела «3. Файлы permissions каталога (сводка)»Файлы каталога под share/permissions/<layer>/*.toml определяют permissions, на
которые ссылается роль. Их авторинг подробно описан в
catalog-authoring.md и
authoring-packages.md; форма вкратце:
| Ключ | Тип | Смысл |
|---|---|---|
id | строка | Id permission’а (точечный для пакетов, например nginx.operate). |
risk | строка | contained или escalation-capable (у bundle = максимум по членам). |
category | строка | Доменная группировка (например network, app, os-config). |
sudo | массив строк | Абсолютные sudo-правила (могут нести шаблоны {placeholder}). |
groups | массив строк | Выдаваемые supplementary-группы. |
[limits] | таблица | nofile / nproc. |
[[file]] | массив таблиц | Файловые grant’ы (та же форма что §2.5; каталожные grant’ы могут использовать шаблоны {placeholder}). |
includes | массив | Id других permissions, которые этот агрегирует (bundle); элемент-таблица { id, <bindings> } привязывает параметры члена. |
include_categories | массив строк | Агрегировать все permissions из названных категорий. |
[params.<name>] | таблица | Guard rail параметра (`kind = token |
Слоистость по ОС: permission разрешается по linux → linux-<distro> → linux-<distro>-<version>; слой может replace или append поля базы.
Человеческий текст (title / summary / risk_note) лежит в отдельном дереве
l10n/<locale>/, ключ [<id>], а не в файле permission’а.
Авторитетная схема: contract/catalog-permission.schema.json.
4. Файлы framework (сводка)
Заголовок раздела «4. Файлы framework (сводка)»Advisory cross-reference compliance. Frameworks лежат под frameworks/<fw>/:
framework.toml— манифест (dimension = flat | os-layered, версия, provides).mappings/*.toml— ключ по id permission’а; каждый link несёт полярность:satisfies(адресует контрол — единственная полярность, которую считает coverage),risk(подрывает его),related(нейтрально).controls.toml(опц.) — список контролов; флагownedпомечает контролы, которые Census реально покрывает (чтобыframework coverageсообщал gap’ы).
Это read-only и advisory — никогда не участвует в compile/grant/apply,
так что подделанный mapping может лишь исказить покрытие, но не поднять
привилегии. Авторитетная схема: contract/framework.schema.json. См. раздел
«Compliance frameworks» в README.
5. Managed-реестр — /var/lib/census/managed.toml
Заголовок раздела «5. Managed-реестр — /var/lib/census/managed.toml»Доступная только root запись о том, что подготовил Census (учётки, группы,
grant’ы при каждом, применённая версия декларации). Этим файлом владеет
Census — не редактируйте его руками. По нему Census знает, что его для
reconcile или teardown, так что правка может осиротить реальные OS-объекты или
заставить Census тронуть то, что он не создавал. Смотрите read-only через
census status. Авторитетная схема: contract/managed-registry.schema.json.
6. Конфиг аудита — /etc/census/exposure.toml
Заголовок раздела «6. Конфиг аудита — /etc/census/exposure.toml»Опциональная конфигурация для read-only аудита экспозиции
(census audit fs / census audit expose). Парсится строго
(deny_unknown_fields). Файл опционален, и каждый ключ опционален: отсутствие
файла или отсутствие ключа откатывается к встроенному дефолту.
Присутствующий, но битый файл — жёсткая ошибка, никогда не молчаливый дефолт
(неправильно настроенный security-инструмент должен падать громко, а не
сканировать не то, выглядя при этом здоровым). Нестандартный путь передаётся
через --config.
| Ключ | Тип | Обязателен | По умолч. | Смысл |
|---|---|---|---|---|
scan_roots | массив путей | нет | ["/etc","/var","/opt","/usr/local","/srv","/home","/root"] | Деревья, которые покрывает сканирование по умолчанию. Каждая запись должна быть абсолютной; пустой список отвергается (сканирование ничего, рапортующее «всё чисто», — ловушка). Переопределяется на запуск через --root/--full. |
secret_globs | массив строк | нет | ["/etc/shadow*","**/*.key","**/*.pem","**/id_rsa*","**/.env*","**/*credentials*"] | Globs, помечающие объект secret-классом (так что читаемое other совпадение — это leak). Каждый шаблон может нести не более одного ** (матчер бэктрекает через **; два были бы экспоненциальны на --full-сканировании) — шаблон с бо́льшим числом отвергается при загрузке. |
broad_groups | массив строк | нет | ["adm","wheel","sudo","staff","users"] | Имена групп, считаемых «широкими» для оси broad-group-writable. Сопоставляются по реальному имени группы, разрешённому из /etc/group, так что хост, перенумеровавший gid, всё равно ловится. |
scan_roots = ["/etc", "/var", "/opt", "/usr/local", "/srv", "/home", "/root"]secret_globs = ["/etc/shadow*", "**/*.key", "**/*.pem", "**/id_rsa*", "**/.env*", "**/*credentials*"]broad_groups = ["adm", "wheel", "sudo", "staff", "users"]Дефолтный glob
**/*.pemловит и публичные сертификаты (например/etc/ssl/certs), которые читаемы всеми по замыслу и всплывают как малосигнальные findings классаsecret, — сузьтеsecret_globs, если этот шум нежелателен. См. audit.md §6.
7. Предпросмотр изменений — режим диффа
Заголовок раздела «7. Предпросмотр изменений — режим диффа»census plan печатает высокоуровневые действия create/update/delete. Добавьте
--diff, чтобы увидеть конкретные артефакты, которые записало бы каждое
изменение, как unified-дифф — текущее managed-состояние против разрешённого
target:
census plan --declaration declaration.toml --additional-catalog-dir /opt/census/share/permissions --diffplan --diff показывает, по каждой изменённой учётке:
sudoers-фрагмент, который был бы записан (включая run-as спецификацию), и его целевой путь (/etc/sudoers.d/census-<role>);- дельту файловых ACL-grant’ов — какие path-grant’ы добавляются или убираются.
Это read-only: никаких мутаций ФС, root не нужен. Используйте, чтобы перед
запуском apply точно осмотреть, что он изменит — особенно после правки
permissions роли, чтобы убедиться, что итоговые sudo-строки и ACL — те, что вы
задумали.
Дальнейшее чтение
Заголовок раздела «Дальнейшее чтение»getting-started.md— установка, настройка, первый apply, эксплуатация.catalog-authoring.md— авторинг permissions каталога и слоёв по ОС.authoring-packages.md— авторинг add-on пакетов и курируемых тиров приложений.contract/*.schema.json— авторитетные машиночитаемые схемы.