FERRUM — enforcement plane: он решает, какой pod создастся и какой процесс переживёт syscall. Дефект в нём — это не «упало», а «разрешило». Поэтому сообщать о таком надо не в публичный issue.
Единственный канал — private vulnerability reporting GitHub: https://github.com/onixus/Ferrum/security/advisories/new.
Кнопка появляется у любого, кто видит репозиторий; переписка идёт в приватном advisory, куда не имеет доступа никто, кроме сопровождающих и вас.
Другого канала нет, и это сказано явно, чтобы его не пришлось выдумывать:
- почтового адреса для сообщений об уязвимостях у проекта нет. Ни одного
адреса в этом дереве не написано, и адрес, найденный в
git logили в профиле GitHub, каналом раскрытия не является — он никем не читается как канал и ничем не подтверждён; - PGP-ключа у проекта нет. Ни ключа, ни отпечатка здесь не опубликовано. Отпечаток, который вам предъявят от имени FERRUM где-то ещё, — не наш;
- баунти нет, оплаты за сообщения нет, и обещать её этот файл не будет.
Публичный issue, PR с исправлением уязвимости и сообщение в любой чат — это раскрытие. Если уязвимость уже раскрыта публично, всё равно откройте advisory: дальше нужен как минимум фиксированный релиз.
Что приложить: версию (git-тег или commit SHA), затронутый компонент
(ferrum-admission, ferrum-agent, ferrum-controller, ferrum-compiler,
ferrum-crypto, ferrum-cli), включённые cargo-фичи (attach, apiserver —
в сборке по умолчанию их нет, и без этой строки половина сообщений
невоспроизводима), версию ядра и архитектуру, если дефект в датапейсе, и
минимальный воспроизводимый случай: политику YAML, манифест pod, запись
датапейса.
Проект ведёт один человек, и сроки написаны исходя из этого, а не из шаблона:
| Шаг | Срок |
|---|---|
| Подтверждение получения | 5 рабочих дней |
| Первичная оценка: воспроизведено или нет, в модели угроз или вне её | 14 дней |
| Исправление или названная дата исправления | 90 дней с подтверждения |
| Публичное раскрытие | после релиза с исправлением, по согласованию |
Если ответа нет 14 дней — считайте, что канал не сработал, и раскрывайте публично. Тишина сопровождающего не должна быть вашей проблемой.
Сроки — обязательство приложить усилия, а не SLA: коммерческой поддержки у проекта нет.
Тегированных релизов пока нет ни одного. Пока это так, поддерживается
ровно одна вещь — текущий main; сообщение против него принимается всегда.
С появлением первого тега поддерживается последняя минорная линия, и не
больше: 0.x — версии, где ломающее изменение приезжает в минорной, а
бэкпортировать исправления в предыдущие минорные некому.
| Версия | Поддержка |
|---|---|
main |
да |
0.1.x |
да, с момента выхода v0.1.0 |
| всё, что раньше | нет; таких версий не существует |
Продукт про то, что enforcement нельзя обойти незаметно, и подпись нельзя подделать. Уязвимость — всё, что ломает одно из этих двух.
Обход enforcement:
- pod, который проходит admission вопреки применённой политике: неподписанный
образ,
privileged, привязка кcluster-admin, нарушение PSS restricted; - процесс, который переживает правило
Kill/Isolate, совпавшее с ним; - совпадение по правилу, которое молча не наступает: путь, комм или syscall,
который датапейс видит иначе, чем ядро, и потому не матчится. Гонка на
чтении пути (double-fetch на
sys_enter) в базовой форме — известное ограничение, см. ниже; уязвимость — конкретный сценарий, где она даёт обход конкретного поставляемого правила; - вылет из scope:
PolicyException, действующее шире своего scope или послеexpiresAt;allow, побеждающийdeny.
Подделка доверия:
- принятый bundle с неверной, отсутствующей или чужой подписью; любой путь, на
котором проверка подписи возвращает
Ok, не проверив; - смешение доменов подписи: Ed25519-seed bundle (
BUNDLE_SIGNATURE_CONTEXT), принятый как TLS-ключ (KEY_BIND_MSG), или наоборот; - подмена метки: событие, приписанное чужому pod через cgroup→pod-индекс;
- фальшивый control plane, чей bundle агент принимает.
Отказ в безопасную сторону, которого не случилось:
- fail-open вместо last-known-good при недоступном CP;
- деградация, о которой узел не сообщил: enforcement, не работающий без
Degraded=trueи без записи в статусе, — это уязвимость, а не «известное поведение». Молчаливое «работает» хуже честного «не работает»; - потеря события без учёта в
events_dropped_total.
Поставка: подделываемая цепочка от git-тега до образа в ghcr.io/onixus/*
— подпись cosign, которую проходит образ, собранный не этим воркфлоу; SBOM,
описывающий не то, что внутри.
Модель угроз — RFC-02, раздел C. Этот раздел не список отговорок: это то, от чего продукт не защищает, и сообщение об этом будет закрыто как «вне модели» без исправления. Лучше прочитать это здесь, чем узнать после установки.
- Root на ноде enforcement не побеждает. Так и записано в RFC-02. Атакующий с root в host namespace снимает eBPF-программы, останавливает агента, правит last-known-good на диске. Контрмеры, которые это осложняют (LSM на pin path, self-watch вне процесса), в этом дереве не реализованы — это записано и в RFC-02, и в границе. Сообщение «под root я выгрузил агента» — воспроизведение известного факта.
- Компрометация kubelet и apiserver. Агент — вторая цель после kubelet, а не защита kubelet. Кто владеет apiserver, владеет и объектами политики.
- Гонка на чтении пути (TOCTOU) как класс. Путь читается из user memory на
sys_enter; это double-fetch по построению tracepoint-режима. Известно, записано в ROADMAP как п. 3, закрывается переходом на BPF LSM. Нечитаемая страница закрыта fail-closed (path_unknownутверждает совпадение), подменённая — нет. Конкретный обход конкретного правила интересен; сам факт double-fetch — нет. - Detect-then-kill — не prevent. Датапейс исполняет
SIGKILLиз userspace послеsys_enter. К моменту сигналаexecveуже произошёл. Это архитектура текущего режима, а не дефект в нём. - Доступность кластера от fail-closed admission.
failurePolicy=Failпри упавшем webhook останавливает создание pod в scope. Это выбранное поведение: fail-open в admission — то, от чего продукт написан. HA-профиль и break-glass — ROADMAP, фаза 1. - Сборка без датапейса. По умолчанию фичи
attachиapiserverвыключены. «Runtime enforcement не сработал» на такой сборке — не дефект: датапейса в ней нет. Продуктовая комбинация —attach,apiserver. - Ядра, на которых ничего не мерялось. Матрица ядер не определена (ROADMAP, п. 7). Незацепленный syscall, о котором attach честно сообщил, — свойство ядра, а не уязвимость. Уязвимость — если он сообщил зацепленным то, что не зацепил.
- Компоненты, ещё не работавшие в живом кластере. Ни один компонент не проверялся против настоящего apiserver; что исполнено, а что нет — только docs/MVP-1-BOUNDARY.md. Ненаписанная интеграция — не уязвимость в написанной.
- Уязвимости в зависимостях, о которых уже знает
cargo-audit: они видны стадиейSecurity: supply chainи заводятся обычным issue. Уязвимость — та, которую advisory-база ещё не знает, или та, которую этот код делает достижимой вопреки advisory. - Чужая инфраструктура: GitHub, ghcr.io, Sigstore, реестр образов получателя. Сообщайте им.
Если сомневаетесь, вне модели ваша находка или нет, — открывайте advisory. Разобрать лишнее сообщение дешевле, чем пропустить обход.
Заявлений о безопасности продукта здесь нет. Что исполнено, а что принято на веру, — docs/MVP-1-BOUNDARY.md, и это единственный документ, который держится гейтом. Наличие политики раскрытия — не свидетельство, что раскрывать будет нечего.