Курирование
Слой курирования обеспечивает детальный контроль доступа к пакетам для прокси-реестров. Он оценивает каждый запрос на скачивание по цепочке фильтров: список блокировки, список разрешений и изоляция пространств имён.
Курирование отвечает на вопрос: должен ли этот пакет быть допущен в мою организацию?
Цепочка фильтров выполняется в следующем порядке:
- Фильтр пространств имён — блокирует проксирование внутренних имён пакетов во внешний реестр (всегда активен, даже в режиме
off) - Фильтр списка блокировки — блокирует пакеты, соответствующие явным правилам запрета
- Фильтр списка разрешений — запрет по умолчанию: допускаются только явно указанные пакеты
Каждый фильтр возвращает одно из трёх решений:
- Allow — запрос продолжается
- Block — запрос отклоняется (403 в режиме enforce)
- Skip — нет решения, передать следующему фильтру
Если все фильтры вернули Skip, запрос разрешается.
| Режим | Поведение |
|---|---|
off | Курирование отключено. Все прокси-запросы проходят. Фильтр пространств имён по-прежнему активен. |
audit | Фильтры оценивают и логируют решения, но никогда не блокируют. Полезно для тестирования правил перед применением. |
enforce | Фильтры оценивают и блокируют совпадающие запросы ответом 403. Требует указания allowlist_path. |
Конфигурация
Заголовок раздела «Конфигурация»# Environment variableexport NORA_CURATION_MODE=audit[curation]mode = "audit" # "off", "audit", "enforce"on_failure = "closed" # "closed" (fail-safe) or "open" (fail-open)Параметр on_failure определяет поведение при ошибке или панике фильтра:
closed(по умолчанию) — расценивать как блокировку (безопасный отказ)open— расценивать как разрешение (открытый отказ)
Список блокировки
Заголовок раздела «Список блокировки»Список блокировки — это JSON-файл, содержащий правила запрета. Если любое правило совпадает с запросом пакета, он блокируется.
Формат файла
Заголовок раздела «Формат файла»{ "version": 1, "rules": [ { "registry": "npm", "name": "event-stream", "version": "3.3.6", "reason": "CVE-2018-16492: malicious dependency flatmap-stream" }, { "registry": "*", "name": "colors", "version": "1.4.1", "reason": "Maintainer protest: infinite loop in v1.4.1" }, { "registry": "pypi", "name": "colourama", "version": "*", "reason": "Typosquatting: malicious clone of colorama" }, { "registry": "maven", "name": "org.log4j.**", "version": "*", "reason": "Block all log4j packages pending security review" } ]}Сопоставление с шаблонами
Заголовок раздела «Сопоставление с шаблонами»Поля registry, name и version поддерживают простые glob-паттерны:
| Паттерн | Совпадения |
|---|---|
* | Всё |
foo* | Префикс: foo, foobar, foo-baz |
*foo | Суффикс: foo, barfoo |
foo.** | Иерархический префикс с разделителем-точкой: foo, foo.bar, foo.bar.baz (для Maven groupId) |
foo/** | Иерархический префикс с разделителем-слешем: foo, foo/bar, foo/bar/baz (для модулей Go) |
exact | Точное совпадение строки |
Включение списка блокировки
Заголовок раздела «Включение списка блокировки»export NORA_CURATION_MODE=enforceexport NORA_CURATION_BLOCKLIST_PATH=/etc/nora/blocklist.json[curation]mode = "enforce"blocklist_path = "/etc/nora/blocklist.json"Список разрешений
Заголовок раздела «Список разрешений»Список разрешений — это список с запретом по умолчанию: допускаются только явно указанные пакеты. Это самая строгая форма курирования.
Формат файла
Заголовок раздела «Формат файла»{ "version": 1, "entries": [ { "registry": "npm", "name": "lodash", "version": "4.17.21", "integrity": "sha256:abc123def456...", "integrity_source": "upstream" }, { "registry": "npm", "name": "express", "version": "4.18.2" }, { "registry": "cargo", "name": "serde", "version": "1.0.203", "integrity": "sha256:789abc...", "integrity_source": "local" } ]}Поля:
registry— точный тип реестра:npm,pypi,maven,cargo,docker,go,gems,terraform,ansible,nuget,pub,conanname— точное имя пакетаversion— точная строка версииintegrity(необязательно) — хеш SHA-256 для проверки после скачиванияintegrity_source(необязательно, информационное) —upstream,localилиmanual
Включение списка разрешений
Заголовок раздела «Включение списка разрешений»export NORA_CURATION_MODE=enforceexport NORA_CURATION_ALLOWLIST_PATH=/etc/nora/allowlist.jsonКогда mode=enforce, параметр allowlist_path является обязательным. NORA откажется запускаться без него.
Проверка целостности
Заголовок раздела «Проверка целостности»Когда require_integrity=true, каждая запись списка разрешений должна содержать хеш integrity. После скачивания артефакта из вышестоящего реестра NORA вычисляет его SHA-256 и сравнивает со значением из записи списка разрешений. При несовпадении запрос блокируется.
export NORA_CURATION_REQUIRE_INTEGRITY=trueЭто защищает от атак на цепочку поставок, при которых пакет заменяется после проверки.
Изоляция пространств имён
Заголовок раздела «Изоляция пространств имён»Изоляция пространств имён предотвращает атаки подмены зависимостей (dependency confusion), блокируя прокси-запросы для пакетов, соответствующих паттернам внутренних пространств имён. Этот фильтр всегда активен, даже когда режим курирования установлен в off.
export NORA_CURATION_INTERNAL_NAMESPACES="@mycompany/*,com.mycompany.**,github.com/myorg/**"[curation]internal_namespaces = [ "@mycompany/*", # npm scoped packages "com.mycompany.**", # Maven groupId hierarchy "github.com/myorg/**", # Go modules]Когда прокси-запрос совпадает с паттерном внутреннего пространства имён, NORA возвращает 403 вместо обращения к вышестоящему реестру. Это гарантирует, что внутренние пакеты обслуживаются только из локального хранилища.
Токен обхода
Заголовок раздела «Токен обхода»Для экстренных ситуаций (например, критическое обновление пакета заблокировано курированием) токен обхода позволяет определённым запросам пропускать фильтры курирования. Изоляция пространств имён по-прежнему применяется.
export NORA_CURATION_BYPASS_TOKEN="your-secret-token"Отправляйте токен в HTTP-заголовке X-Nora-Bypass-Token:
curl -H "X-Nora-Bypass-Token: your-secret-token" \ https://registry.example.com/npm/lodash/-/lodash-4.17.22.tgzСобытия обхода логируются с тегом [SECURITY] для целей аудита. Используйте токены обхода осторожно и регулярно выполняйте их ротацию.
Совместное использование списка блокировки и списка разрешений
Заголовок раздела «Совместное использование списка блокировки и списка разрешений»Когда оба файла настроены, порядок проверки следующий:
- Список блокировки проверяется первым. Если пакет соответствует правилу списка блокировки, он блокируется независимо от наличия в списке разрешений.
- Список разрешений проверяется вторым. Если пакета нет в списке разрешений, он блокируется.
Это означает, что список блокировки действует как наложение поверх списка разрешений. Вы можете одобрить пакет в списке разрешений, а затем заблокировать конкретную уязвимую версию через список блокировки без изменения списка разрешений.
[curation]mode = "enforce"blocklist_path = "/etc/nora/blocklist.json"allowlist_path = "/etc/nora/allowlist.json"Инструменты командной строки
Заголовок раздела «Инструменты командной строки»NORA включает CLI-команды для работы с файлами курирования.
Проверка (validate)
Заголовок раздела «Проверка (validate)»Проверьте JSON-файл списка блокировки или списка разрешений перед развёртыванием:
nora curation validate /etc/nora/blocklist.jsonВывод:
OK: Valid blocklist -- 4 rules [1] npm/event-stream@3.3.6 -- CVE-2018-16492: malicious dependency flatmap-stream [2] */colors@1.4.1 -- Maintainer protest: infinite loop in v1.4.1 [3] pypi/colourama@* -- Typosquatting: malicious clone of colorama [4] maven/org.log4j.**@* -- Block all log4j packages pending security reviewnora curation validate /etc/nora/allowlist.jsonВывод:
OK: Valid allowlist -- 3 entries (2 with integrity) [1] npm/lodash@4.17.21 [hash] [2] npm/express@4.18.2 [3] cargo/serde@1.0.203 [hash]Команда validate проверяет:
- Корректность синтаксиса JSON
- Версию схемы (должна быть
1) - Наличие обязательных полей
Объяснение (explain)
Заголовок раздела «Объяснение (explain)»Объясняет решение курирования для конкретного пакета. Требует работающей конфигурации (читает config.toml или переменные окружения):
nora curation explain cargo:serde@1.0.203Формат пакета: registry:name@version. Часть с версией необязательна:
nora curation explain npm:lodashКоманда explain загружает настроенные файлы списка блокировки и списка разрешений и моделирует цепочку фильтров, показывая, какой фильтр принял решение и почему.
Формат ответа при блокировке
Заголовок раздела «Формат ответа при блокировке»Когда курирование блокирует запрос в режиме enforce, ответ представляет собой JSON с кодом 403:
{ "error": "blocked_by_policy", "error_version": "v1", "context": { "rule": "blocklist", "reason": "CVE-2018-16492: malicious dependency flatmap-stream", "registry": "npm", "package": "event-stream", "version": "3.3.6" }, "hint": "Run: nora curation explain event-stream@3.3.6", "docs": "https://docs.getnora.dev/curation"}Заголовки ответа:
X-Nora-Decision: blockedX-Nora-Rule: blocklistX-Nora-Reason: CVE-2018-16492: ...
Эти заголовки позволяют CI/CD-пайплайнам обнаруживать и обрабатывать блокировки курирования программным путём.
Наблюдаемость
Заголовок раздела «Наблюдаемость»Решения курирования записываются в аудит-лог и видны через заголовки ответа:
| Заголовок | Описание |
|---|---|
X-Nora-Decision | allowed или blocked |
X-Nora-Rule | Какое правило сработало (blocklist, allowlist, cve, namespace) |
X-Nora-Reason | Человекочитаемая причина решения |
Используйте nora_http_requests_total{status="403"} в Prometheus для отслеживания заблокированных загрузок.
Примеры
Заголовок раздела «Примеры»Блокировка одного уязвимого пакета
Заголовок раздела «Блокировка одного уязвимого пакета»{ "version": 1, "rules": [ { "registry": "npm", "name": "event-stream", "version": "3.3.6", "reason": "CVE-2018-16492" } ]}Режим только со списком разрешений (строгий)
Заголовок раздела «Режим только со списком разрешений (строгий)»Одобряйте только проверенные пакеты. Всё остальное запрещено:
export NORA_CURATION_MODE=enforceexport NORA_CURATION_ALLOWLIST_PATH=/etc/nora/allowlist.jsonexport NORA_CURATION_REQUIRE_INTEGRITY=trueРежим аудита для тестирования
Заголовок раздела «Режим аудита для тестирования»Сначала запустите в режиме аудита, чтобы увидеть, что будет заблокировано, не мешая разработчикам:
export NORA_CURATION_MODE=auditexport NORA_CURATION_BLOCKLIST_PATH=/etc/nora/blocklist.jsonexport NORA_CURATION_ALLOWLIST_PATH=/etc/nora/allowlist.jsonПроверьте логи на наличие записей [AUDIT] Download would be blocked, затем переключитесь на enforce, когда будете удовлетворены результатом.
Блокировка всех пакетов из пространства имён
Заголовок раздела «Блокировка всех пакетов из пространства имён»{ "version": 1, "rules": [ { "registry": "maven", "name": "org.apache.log4j.**", "version": "*", "reason": "Log4Shell family - use logback instead" }, { "registry": "go", "name": "github.com/untrusted-org/**", "version": "*", "reason": "Untrusted organization" } ]}Смотрите также
Заголовок раздела «Смотрите также»- Справочник по конфигурации — все переменные окружения
- Аутентификация — управление пользователями и API-токены