SBOM для контейнерів: робити під час збірки чи після?

SBOMбезпека контейнерівCI/CDланцюжок поставок

Просте пояснення, як зробити SBOM корисним під час CVE-інциденту: де шукати вразливий пакет, який контейнер зачеплено і що треба перевипустити

Проблема не в тому, щоб “мати SBOM”

SBOM часто сприймають як ще один файл для галочки. Згенерували JSON, поклали кудись у CI, можна звітувати. Але під час інциденту такий файл швидко показує свою справжню цінність або її відсутність.

Уявімо просту ситуацію: приходить CVE-алерт про вразливу бібліотеку. Команда відкриває SBOM і бачить назву пакета. Але далі починаються питання:

  • у якому саме контейнерному образі цей пакет є;
  • чи цей образ зараз працює в проді;
  • з якого коміту він зібраний;
  • хто має перевипустити образ;
  • чи треба оновити залежність застосунку, базовий образ або обидва.

Якщо SBOM не допомагає відповісти на ці питання, він є списком, але ще не є робочим інструментом.

Що таке SBOM простими словами

SBOM — це список складників програми або контейнера. Приблизно як етикетка на продукті: з чого це зроблено. Для контейнера туди можуть потрапити бібліотеки застосунку, системні пакети з базового образу, утиліти, транзитивні залежності та інші речі, які реально опинилися всередині.

Для безпеки це важливо тому, що CVE-алерт майже ніколи не звучить як “у вас проблема в сервісі X”. Частіше він звучить так: “пакет Y має вразливість”. Далі треба швидко зрозуміти, чи цей пакет є у ваших образах і де саме.

SBOM під час збірки: добре видно джерело

SBOM під час збірки створюється тоді, коли CI збирає застосунок. У цей момент добре видно вихідний код, package-lock.json, pnpm-lock.yaml, Dockerfile, параметри збірки та коміт.

Це зручно, коли треба зрозуміти, звідки прийшла залежність. Наприклад, у Node.js-додатку можна швидко побачити, що пакет з’явився не напряму, а через іншу бібліотеку.

Слабке місце таке: цей SBOM не завжди бачить усе, що потрапило у фінальний контейнер. Базовий образ міг принести системні пакети. У Dockerfile могли бути додаткові кроки. Після збірки могли додати файли або утиліти.

Тобто SBOM під час збірки добре відповідає на питання: “що ми планували зібрати і з якого коду це прийшло?”

SBOM після збірки: добре видно готовий контейнер

SBOM після збірки створюється вже з готового контейнерного образу. Він дивиться не на план, а на результат: що фактично лежить усередині образу, який може поїхати в реєстр і далі в прод.

Це корисно, коли CVE стосується базового образу або системного пакета. Наприклад, застосунок не підключав вразливу бібліотеку напряму, але вона є в операційній частині контейнера.

Слабке місце інше: якщо такий SBOM не прив’язаний до коміту, CI-збірки і digest образу, він стає окремою фотографією без контексту. Пакет видно, але незрозуміло, яка команда відповідає за виправлення і яку версію треба перевипустити.

Тобто SBOM після збірки добре відповідає на питання: “що реально потрапило в контейнер?”

Найкращий варіант для більшості команд

Для практичної роботи найчастіше потрібні обидва варіанти:

  • SBOM під час збірки пояснює, звідки взялася залежність;
  • SBOM після збірки показує, що реально є в готовому образі;
  • digest контейнера зв’язує все це з конкретним релізом.

Це не обов’язково має бути складна система. Для старту достатньо двох файлів на кожну збірку:

  • sbom-build.json — що видно під час збірки;
  • sbom-runtime.json — що видно в готовому контейнері.

Головне: обидва файли мають зберігатися поруч із digest образу і SHA коміту. Без цього під час інциденту доведеться знову вгадувати.

Мінімальні перевірки якості

  1. Є прив’язка до образу

Кожен SBOM має показувати, до якого саме digest він належить. Тег latest не підходить: сьогодні він вказує на один образ, завтра на інший.

  1. Є прямі й транзитивні залежності

Для Node.js це особливо важливо. Вразливість часто приходить не з пакета, який команда додала напряму, а з глибшого рівня залежностей.

  1. SBOM створюється на кожну важливу збірку

Якщо образ оновився, а SBOM залишився старим, він уже не допомагає. Для релізних образів SBOM має створюватися щоразу.

  1. SBOM зберігається там, де його знайдуть під час інциденту

Кеш CI не підходить як єдине місце. Через кілька днів або тижнів він може зникнути. Краще зберігати SBOM як файл релізу поруч із образом або посиланням на нього.

План запуску на 7 кроків

  1. Виберіть один сервіс, не всі одразу.
  2. Додайте SBOM під час збірки і збережіть його як sbom-build.json.
  3. Після створення контейнера додайте SBOM готового образу як sbom-runtime.json.
  4. Запишіть у метадані SHA коміту, назву образу і digest.
  5. Додайте просте правило: якщо digest відсутній, реліз не проходить.
  6. Перевірте один реальний CVE-алерт або старий безпековий тикет і пройдіть шлях від алерта до образу.
  7. Запишіть, скільки часу зайняв пошук. Якщо більше 30 хвилин, процес ще треба спрощувати.

Як це виглядає для Node.js

Приходить алерт: вразливий пакет знайдено в одному з ваших образів.

Перший крок — не оновлювати все поспіль. Спочатку треба зрозуміти, де живе проблема.

Якщо пакет є в sbom-build.json, дивіться lock-файл і залежності застосунку. Можливо, треба оновити npm-пакет або бібліотеку, яка його підтягнула.

Якщо пакет є тільки в sbom-runtime.json, проблема, ймовірно, прийшла з базового образу або системного шару контейнера. Тоді треба оновити базовий образ, пересканувати готовий контейнер і перевипустити саме той digest, який був у проді.

У нормальному процесі відповідь має бути короткою:

  • який пакет вразливий;
  • у якому digest він є;
  • який сервіс використовує цей digest;
  • хто власник сервісу;
  • що перевипускаємо.

Антипатерни, які краще прибрати одразу

  • SBOM генерується раз на тиждень, а образи виходять щодня.
  • SBOM лежить тільки у тимчасовому кеші CI.
  • Команда використовує latest там, де потрібен digest.
  • Є SBOM під час збірки, але немає перевірки готового контейнера.
  • Є SBOM готового контейнера, але незрозуміло, з якого коміту він зібраний.

Короткий висновок

SBOM корисний не тоді, коли він просто існує. Він корисний тоді, коли під час CVE-алерта команда за кілька хвилин може перейти від назви вразливого пакета до конкретного контейнерного образу і відповідальної команди.

Для цього зазвичай потрібна проста гібридна схема: один SBOM під час збірки, один SBOM після збірки, і обов’язкова прив’язка до digest.

Джерела

Короткий чеклист

  • Прив’язати кожен SBOM до конкретного digest контейнерного образу.
  • Зберігати SBOM не тільки в кеші CI, а поруч із файлами релізу.
  • Перевіряти і прямі, і транзитивні залежності.
  • Описати короткий шлях: CVE-алерт -> SBOM -> digest -> відповідальна команда.

Налаштуйте SBOM, який допоможе під час CVE-інциденту

Твоя задача: допоможи мені налаштувати SBOM для контейнерів так, щоб він допомагав під час реального CVE-інциденту. Вхідні дані: - CI-система: - Кількість команд або проєктів: - Де зберігаються контейнерні образи: - Скільки годин команда може витратити на першу реакцію: - Які інструменти вже показують залежності: - Які безпекові алерти були за останні 90 днів: Виведи: 1) Що краще для нас: SBOM під час збірки, після збірки чи обидва варіанти. 2) Мінімальний список перевірок, без яких SBOM не можна вважати корисним. 3) План запуску на 7 простих кроків без купівлі нового сервісу. 4) Що має робити команда, коли приходить CVE-алерт. 5) Приклад для Node.js-додатку: як зрозуміти, чи проблема в залежності застосунку, чи в базовому контейнерному образі. Відповідь: пиши практично, короткими кроками, без маркетингу і без зайвого жаргону.