Курс СРС SRS04
до ЛР2 рівень 3 → «5»↔ Лабораторна 2↔ Лекція 2⌨️ команди 3
Самостійна робота · ~3 год

Відтворюваність збірки і довіра до образу (digest, pin версій)

🌌 Цифровий відбиток фундаменту — С.І.Д. не любить сюрпризів від «ТехНови»: варто їм підмінити фундамент його міста — базовий образ — під тим самим іменем, і привид уже не привид. Розберися разом із ним, як зафіксувати точний цифровий відбиток (digest) довіреної збірки замість мінливого людяного тега.

📚 ТЕОРЕТИЧНІ ВІДОМОСТІ

Тег — це вказівник, digest — це відбиток

Людяний тег на кшталт ubuntu:24.04 або myapp:latest технічно є не ідентифікатором вмісту, а мутабельним посиланням у реєстрі (registry) — записом у таблиці «ім'я → digest», який власник репозиторію (чи будь-хто з правами push) може будь-коли перезаписати на інший вміст під тим самим іменем. Це зручно для розробки (latest завжди вказує на щось нове), але небезпечно для відтворюваності й довіри: два docker pull ubuntu:24.04 у різний час можуть повернути різні байти, і жодним чином це не видно з самого тега.

Digest, навпаки, — це криптографічний хеш (SHA-256) маніфесту образу: структури, що описує список шарів та їхні власні digest-и. Формат посилання — образ@sha256:<64 hex-символи>. Оскільки SHA-256 практично неможливо підібрати колізію, digest однозначно й незмінно прив'язаний до конкретного бінарного вмісту: docker pull ubuntu@sha256:abcd... завжди поверне побайтово ідентичний результат, незалежно від того, коли й де ця команда виконується, — навіть якщо власник репозиторію тим часом перепризначив тег 24.04 на щось інше.

Це має пряме відношення до content trust: коли конвеєр CI/CD чи продакшн-скрипт посилається на образ за тегом, він фактично довіряє реєстру не підміняти вміст непомітно — а це і є вектор атаки типу «tag mutation» чи компрометації облікового запису в реєстрі. Посилання за digest усуває цю довіру як залежність: навіть якщо зловмисник отримає доступ до реєстру й перезапише тег на шкідливий образ, вже зафіксований у скрипті digest продовжить резолвитись у старий, довірений вміст (або ж docker pull за digest, якого більше немає в реєстрі, просто впаде з помилкою — що теж краще за тиху підміну).

Практична рекомендація — «pinning»: у продакшн-Dockerfile та CI-конфігураціях фіксувати базові образи саме за digest, отриманим одноразово й перевіреним (наприклад, FROM ubuntu@sha256:2e8...), а не за мінливим тегом. Це не заважає оновлюватися свідомо: коли потрібна нова версія, digest у конфігурації змінюють явним коммітом, що проходить рев'ю, — на відміну від тега, зміна вмісту за яким відбувається «десь у реєстрі» без жодного сліду в репозиторії коду.

Окремо варто розрізняти digest конкретного образу для однієї архітектури і manifest list (multi-arch index) — той самий тег може резолвитись у різні digest-и залежно від архітектури (amd64 проти arm64); docker inspect --format '{{.RepoDigests}}' покаже, який саме digest фактично був витягнутий на цій машині, що корисно для аудиту вже наявних образів.

📖 ОПРАЦЮВАТИ

Прочитати Docker docs «Image digests» і розділ про Content Trust/Notation; порівняти docker pull ubuntu:24.04 з docker pull ubuntu@sha256: і пояснити різницю в гарантіях, які надає кожен спосіб посилання на образ.

🖥️ ТЕРМІНАЛ — СПРОБУЙ САМ
🎯 ЗАВДАННЯ
  1. Виконати docker pull ubuntu:24.04, потім docker inspect ubuntu:24.04 --format '{{.RepoDigests}}' і зафіксувати точний digest, який отримала саме ваша машина.
  2. Через 5-10 хвилин повторно витягнути образ за digest із попереднього кроку (docker pull ubuntu@sha256:) і переконатися, що docker inspect повертає той самий Id — довести незмінність.
  3. Переписати FROM ubuntu:24.04 у власному Dockerfile на FROM ubuntu@sha256: і зібрати образ; пояснити письмово, що зміниться в поведінці збірки, якщо видавець оновить тег 24.04 на нову патч-версію Ubuntu.
  4. Дослідити docker manifest inspect ubuntu:24.04 (або docker buildx imagetools inspect) і знайти в результаті кілька різних digest для різних платформ (linux/amd64, linux/arm64) під одним тегом.
  5. Сформулювати політику пінування образів для гіпотетичного продакшн-конвеєра: які образи фіксувати за digest завжди, а для яких допустиме посилання за тегом (наприклад, у dev-оточенні), і чому.
❓ КОНТРОЛЬНІ ПИТАННЯ
  1. Чим тег образу принципово відрізняється від digest із погляду мутабельності?
  2. Який криптографічний алгоритм лежить в основі digest образу Docker, і що саме він хешує?
  3. Чому pull за digest гарантує побайтову ідентичність вмісту, а pull за тегом — ні?
  4. Який сценарій атаки описує термін «tag mutation», і як фіксація на digest від нього захищає?
  5. Що поверне docker inspect --format '{{.RepoDigests}}' для щойно витягнутого образу?
  6. Чому той самий тег може відповідати різним digest для різних архітектур процесора?
  7. Яку практичну перевагу має явна зміна digest у Dockerfile через коміт порівняно з мовчазним оновленням тега в реєстрі?
✅ САМОПЕРЕВІРКА

Чому тег latest (чи будь-який інший людяний тег) не гарантує відтворюваності збірки, а digest (sha256:...) — гарантує?

🥚 ПАСХАЛКА
Digest образу, з якого двоє творців зібрали С.І.Д. уперше, він пам'ятає напам'ять — і каже, що починався той із sha256:c1d3101…. Імовірність такого — один до кількох мільярдів, тож або творці перебирали збірки до ранку, або на клавіатурі знову спав Пиксель. Так чи інак: довіряй відбитку, а не імені — як довіряєш голосу зі 101.9, а не назві станції.
⌨️ КОМАНДИ НА ЦІЙ СТОРІНЦІ 3

Кожна команда терміналу з цієї сторінки — одним реченням. Позначка нове — команда зустрічається в курсі вперше; далі вважаємо її знайомою.

docker pull
Завантажує образ із реєстру (Docker Hub) на машину.
docker
Клієнт Docker: усі дії з образами й контейнерами — через його підкоманди (docker <підкоманда> --help — довідка).
docker inspect
Друкує повний JSON-опис контейнера чи образу; -f '{{.State.Pid}}' — витягнути одне поле.

💡 Прочитати README прямо в терміналі: cat README.md (виведе весь файл) або less README.md (посторінково; вихід — клавіша q).
Довідка з будь-якої команди: man curl (повний посібник, вихід — q) або коротко curl --help; для підкоманд — docker run --help, cargo build --help.

← SRS03усі темиSRS05 →