The Update Framework (TUF) — программный фреймворк с открытым кодом для защиты репозиториев, из которых скачиваются обновления. Главная задача TUF — предоставить возможность обновлять софт безопасно, а также минимизировать ущерб в случае, если обновление скомпрометировано. Фреймворк можно использовать для создания собственной системы обновления ПО (например, менеджера пакетов) либо для повышения безопасности существующей.
В 2017 году TUF приняли в экосистему Cloud Native Computing Foundation (CNCF), а в 2019-м он стал первым выпускником среди проектов из области безопасности. TUF ориентирован на внедрение в любые системы обновления ПО и системы управления конфигурациями (а раз проект в CNCF, то речь, конечно, идет про решения из мира cloud native). Его уже используют Microsoft, Amazon, Google, DigitalOcean, Docker, IBM, Datadog, VMware, Red Hat и другие компании.
Цель этого обзора — краткое верхнеуровневое знакомство с основными возможностями и архитектурой TUF.
Что такое TUF
The Update Framework — это набор библиотек, файловых форматов и утилит, которые применяются для организации доверенного репозитория (он так и называется: TUF repository). В качестве технической основы для такого репозитория может использоваться любое хранилище, с которым можно работать по HTTP (например, S3). TUF абстрагирован от файлового формата конкретного хранилища, а для проверки целостности и безопасности контента оперирует его метаданными. Для активной защиты применяются криптографические алгоритмы, в том числе различные схемы шифрования электронных подписей и ротация ключей. Основная задача фреймворка — обеспечить безопасную доставку программных пакетов, бинарных файлов и другого контента из репозитория конечным пользователям.
Создатели TUF подчеркивают, что фреймворк снижает риск доставки вредоносного контента, но не избавляет от него. Любой репозиторий может быть скомпрометирован, и TUF помогает минимизировать последствия.
Разработка The Update Framework началась в 2009 году под руководством Джастина Каппоса (Justin Cappos), доцента Нью-Йоркского университета, специалиста по информатике и инженерным системам. С 2011-го проект базируется в «Инженерной школе Тандон» при университете. В развитии TUF участвует не только вуз, но и компании вроде VMware и Datadog.
Первоначальная идея проекта вдохновлена Thandy, системой обновления Tor. Команда TUF решила использовать принципы, реализованные в Thandy, для создания универсального фреймворка, который можно было бы адаптировать для любой сторонней системы обновления. Главных принципа у TUF два:
-
Выявлять и предотвращать атаки.
-
Минимизировать ущерб от уже проведенных атак.
Уязвимость существующих систем обновления
Существуют тысячи систем обновления, которые можно разделить на три больших класса: средства обновления приложений, менеджеры библиотек, менеджеры пакетов. Все они в той или иной мере уязвимы к взломам ключей и другим атакам, которые могут распространять вредоносное ПО или скомпрометировать репозиторий. TUF был задуман как система, которая была бы защищена от любых атак, направленных на все этапы процесса обновления контента — от его загрузки в репозиторий до скачивания пользователями.
В контексте систем обновлений контент — это обычно какое-либо ПО в виде пакетов, бинарных файлов и т. п. Цепочка поставки контента, как правило, начинается с обновления кода разработчиками в Git и заканчивается тем, что пользователь скачивает образ из доверенного репозитория. Логично, что система доставки обновлений — излюбленная цель для атак. Если речь идет о глобальном продукте, ПО которого обновляется автоматически, такая атака может нанести ущерб миллионам пользователей. Поэтому важно быть уверенным в том, что пользователи скачивают именно тот контент, который они должны (или собираются) получить.
Самый распространенный сценарий атаки — подмена контента, когда пользователь вместо ожидаемого ПО получает вредоносное. Внутри могут быть, например, трояны, бэкдоры, предыдущие версии официального ПО с незакрытыми уязвимостями и т. д. Актуальность подобных угроз не снижается, скорее наоборот — увеличивается по мере появления всё большего количества менеджеров обновлений.
Недостатки популярных алгоритмов шифрования
HTTPS, SSL, TLS. Один из распространенных методов защиты, который применяется при обновлениях, — сочетание протокола HTTPS и SSL/TLS-сертификатов. Проблема в том, что они защищают соединения, но не контент. Система обновления подключается к нужному серверу, и пользователь безопасно получает файлы — но без каких-либо гарантий, что сами эти файлы безопасны.
Pretty Good Privacy (PGP) — ПО для шифрования различных типов данных, разработанное еще в начале 1990-х. PGP контролирует целостность контента, проверяя соответствие цифровых подписей и ключей, однако не защищает от многих типов современных угроз. Например, когда пользователь скачивает неактуальную и уязвимую версию ПО, пусть и подписанную верным ключом. Или от атак типа mix-and-match. Другая проблема PGP — неспособность справиться с уязвимостью пакетных менеджеров, известной как «путаница зависимостей».
По заверениям разработчиков, TUF избавлен от недостатков перечисленных алгоритмов и защищает ото всех известных атак, направленных на процесс обновления: установки произвольного ПО (arbitrary installation attacks), «заморозки» обновлений (indefinite freeze attacks), скачивания лишних зависимостей (extraneous dependencies attacks) и т. д. Подробнее со списком угроз, от которых защищает TUF, можно ознакомиться в документации.
Безопасность кода самого фреймворка проверяют не только разработчики, но и сторонние аудиторы. Отчеты с результатами некоторых пентестов выложены на сайте.
Как работает TUF
Фреймворк обеспечивает безопасное получение надежных целевых файлов — сам контент. Целевые файлы — «черный ящик» для TUF: это могут быть пакеты, в которых содержится несколько файлов, текстовые, исполняемые бинарные файлы и т. д.
TUF использует метаданные, которые описывают целевые файлы, — с такой информацией возможна безопасная идентификация файла. Метаданные также указывают на роли, которым доверено подписывать файл (подробнее о ролях и формате метаданных — ниже). TUF предоставляет доступ только к целевым файлам, которым можно доверять, то есть тем, на которые ссылаются правильно подписанные и актуальные метаданные.
Глобально The Update Framework решает три основных задачи безопасности:
-
защищает контент и репозиторий, обеспечивая актуальность, согласованность и целостность данных;
-
снижает влияние компрометации и потери ключей;
-
помогает восстанавливать ключи (механизм встроен в ядро фреймворка).
Защита контента
Механизм защиты контента основан на использовании криптографических подписей и регулировании срока действия ключей.
1. Криптографические подписи для контента и репозитория. Криптография на основе асимметричного шифрования обеспечивает контенту целостность (integrity), а репозиторию — согласованность (consistency). Подписывая программный пакет или образ контейнера, TUF дает гарантию их целостности — и здесь ничего необычного, так работают многие менеджеры обновлений. Но TUF гарантирует, что и сам репозиторий, то есть его содержимое согласовано. Зачем это нужно? Бывает, что злоумышленник контролирует, какие файлы передаются пользователю. Под видом доверенного репозитория он может передавать отдельные файлы, которые сами по себе могут быть безопасными, но все вместе — нет. TUF отслеживает такого рода атаки как раз за счет контроля согласованности.
2. Короткий срок жизни ключа как гарантия актуальности (freshness) контента. Фреймворк использует механизм неявного аннулирования (отзыва) ключа при истечении срока его действия. Срок указан в подписи. Если, например, хакер перехватит пакет и сообщит клиенту (пользователю), что обновлений нет, в какой-то момент подвох обнаружится. Потому что локальные подписи устареют, и клиент запросит новые.
В качестве примера практической реализации защиты контента на основе TUF — схема взаимодействия между клиентом и сервером, реализованная в системе безопасной дистрибуции Notary (тоже проект CNCF):
Снижение ущерба от потери и компрометации ключей
TUF использует 3 базовых подхода для снижения влияния потери и/или компрометации ключей: разделение ответственности, кворум подписей, а также баланс между уровнями доверия и риска.
1. Разделение ответственности. Для контроля согласованности, целостности и актуальности контента в TUF предусмотрены соответствующие роли, со своими ключами и подписями. Есть четыре фундаментальных верхнеуровневых роли: root, targets, snapshot и timestamp.
-
Root role — подписывает ключи, которым доверяют все другие роли верхнего уровня.
-
Targets role — ответственна за целостность единиц контента. Указывает, каким целевым файлам доверяют клиенты. Роль подписывает не сами целевые файлы, а метаданные для этих файлов.
-
Snapshot role — ответственна за согласованность контента. Подписывает метаданные файла с информацией о последней версии всех метаданных целевых файлов в репозитории. Тем самым клиенты понимают, какие файлы были обновлены.
-
Timestamp role — ответственна за актуальность контента. Подписывает инструкцию с временной меткой, которая содержит хэш-сумму снапшота файла. Механизм защищает от воспроизведения устаревшего файла, срок действия подписи которого еще не истек.
2. Пороговое количество подписей (кворум). Все роли могут использовать один или несколько ключей, и для проверки метаданных контента требовать пороговое количество подписей. Например, для роли, которая отвечает за целостность файлов, TUF может требовать определенный набор ключей и подписей этих файлов.
Если скомпрометировано менее порогового значения root-ключей, TUF-хранилище должно отозвать доверие к скомпрометированным ключам. Это реализуется с помощью обычной ротации root-ключей. Если пороговое значение ключей нарушено, безопаснее всего предположить, что злоумышленники установили вредоносное ПО и завладели машинами пользователей.
3. Баланс между уровнями доверия и риска. Допустим, ключ, который подписывает файлы каждые 2 минуты, должен быть доступным всегда, а значит — храниться онлайн. Риск компрометации у такого ключа высокий. TUF может подписать ограниченное количество ответственности для этого ключа и понизить уровень доверия к нему.
И наоборот, ключ, у которого больше ответственности и более высокий уровень доверия, должен храниться локально (офлайн). Клиенты могут безоговорочно доверять файлам, подписанным этим ключом. Спецификация TUF предписывает хранить все ключи offline, за исключением ключей для timestamp- и mirrors-ролей.
Разделение ответственности можно представить как «дерево иерархического делегирования доверия», где root-роль делегирует доверие остальным ролям. Диаграмма ниже показывает, как это реализовано в TUF-репозитории PyPI (The Python Package Index).
Стрелки соответствуют порядку делегирования доверия: root-роль подписывает роли timestamp, snapshot, targets и саму себя; роли targets и bins ответственны за подмножества/подгруппы целостности контента. Красным отмечены ключи с меньшим уровнем доверия (хранятся онлайн), зеленым — с более высоким (хранятся офлайн).
Формат файлов
TUF-репозиторий использует два типа файлов: целевые файлы (собственно, контент для распространения) и файлы с метаданными. Имена целевых файлов и структура их каталогов, доступных из репозитория, спецификацией не определяются, потому что зависят от конкретного ПО, в котором задействован фреймворк.
Имена и структура файлов с метаданными определены строго, а сам формат — нет: главное, чтобы клиенты TUF (пользователи) могли интерпретировать этот формат верно. В качестве примеров имплементации разработчики TUF используют JSON.
Формат файлов с метаданными:
{
"signed" : ROLE,
"signatures" : [
{ "keyid" : KEYID,
"sig" : SIGNATURE }
, ... ]
}
-
ROLE
— тип роли; -
KEYID
— уникальный идентификатор ключа, которым подписана роль; представляет собой шестнадцатеричный дайджест хэша SHA-256 канонической формы ключа; -
SIGNATURE
— шестнадцатеричная подпись канонической формы метаданных для типа роли.
Эталонная реализация TUF подразумевает использование трех схем шифрования подписи: rsassa-pss-sha256, ed25519 и ecdsa-sha2-nistp256. При этом администраторы TUF-системы сами решают, какую схему и и криптографическую библиотеку использовать для своего проекта.
Формат подписанной root-роли:
{
"_type" : "root",
"spec_version" : SPEC_VERSION,
"consistent_snapshot": CONSISTENT_SNAPSHOT,
"version" : VERSION,
"expires" : EXPIRES,
"keys" : {
KEYID : KEY,
...
},
"roles" : {
ROLE : {
"keyids" : [
KEYID,
...
] ,
"threshold" : THRESHOLD
},
...
}
}
С примерами реальных JSON-файлов для верхнеуровневых ролей можно ознакомиться в документации.
Примеры интеграций TUF
TUF — Open Source-проект. На GitHub есть его спецификация, а также эталонные реализации на языках Python и Go.
Фреймворк применяется во множестве других проектов, кроме упомянутых выше Notary и PyPI. Например, в системе обновления Bottlerocket — легковесной ОС на базе Linux, которая предназначена для запуска контейнеров. За обновление ОС на пользовательских машинах отвечает приложение-клиент (агент) — Updog. Он взаимодействует с TUF и в фоне загружает обновления Bottlerocket. Если речь идет об обновлении ОС на хостах, работающих в кластере Kubernetes, можно использовать оператор brupop. Оператор координирует корректное обновление всех узлов (nodes) кластера.
Среди других пользователей TUF:
-
Datadog — сервис мониторинга ИТ-инфраструктуры (к слову, представитель этой компании значится среди соавторов спецификации TUF);
-
CNAB (Cloud Native Application Bundle) — Open Source-спецификация для управления контейнеризированными приложениями в Docker, Kubernetes и других средах;
-
Foundries.io — платформа для создания IoT-приложений;
-
HERE — OTA-система (over-the-air) для обновления автомобильного софта.
Мы и сами используем TUF для своего нового универсального менеджера пакетов для непрерывной доставки обновлений пользователям — trdl. Он уже используется в утилите werf, а совсем скоро мы представим этот проект официально и расскажем о нем подробнее.
Резюме
Широкое и разнообразное применение TUF, в том числе в проектах со сложной инфраструктурой, говорит о том, что фреймворк зарекомендовал себя не только в теории. Признание Open Source-сообщества — в частности, в CNCF — этот факт только подтверждает.
Одно из важных преимуществ TUF в том, что он универсален. Кастомизировать фреймворк можно очень гибко, потому что он не зависит от языка, на котором написан проект, формата файлов, которые нужно распространять, и конкретной реализации хранилища, в котором они хранятся.
P.S.
Для подготовки статьи использовались документация и другие материалы, доступные на сайте проекта и в открытых источниках, а также видеодоклад контрибьюторов TUF Лукаса Пухрингера (Lukas Puehringer) и Джошуа Лока (Joshua Lock).
P.P.S.
Читайте также в нашем блоге:
-
«OPA и SPIFFE — два новых проекта в CNCF для безопасности облачных приложений»;
-
«Harbor — реестр для Docker-контейнеров с безопасностью из коробки» (подписывает Docker-образы с помощью Notary);
-
«Что и зачем Docker делает в Moby для интеграции с Kubernetes?» (в этой статье 2017 г. мы впервые упоминали TUF и Notary).
Автор: Oleg Zinovyev