Безопасность контейнеров. Фундаментальный подход к защите контейнеризированных приложений - Лиз Райс - E-Book

Безопасность контейнеров. Фундаментальный подход к защите контейнеризированных приложений E-Book

Лиз Райс

0,0
10,99 €

-100%
Sammeln Sie Punkte in unserem Gutscheinprogramm und kaufen Sie E-Books und Hörbücher mit bis zu 100% Rabatt.
Mehr erfahren.
Beschreibung

Во многих организациях приложения работают в облачных средах, обеспечивая масштабируемость и отказоустойчивость с помощью контейнеров и средств координации. Но достаточно ли защищена развернутая система? В этой книге, предназначенной для специалистов-практиков, изучаются ключевые технологии, с помощью которых разработчики и специалисты по защите данных могут оценить риски для безопасности и выбрать подходящие решения. Лиз Райс исследует вопросы построения контейнерных систем в Linux. Узнайте, что происходит при развертывании контейнеров и научитесь оценивать возможные риски для безопасности развертываемой системы. Приступайте, если используете Kubernetes или Docker и знаете базовые команды Linux.

Das E-Book können Sie in Legimi-Apps oder einer beliebigen App lesen, die das folgende Format unterstützen:

EPUB
MOBI

Seitenzahl: 249

Bewertungen
0,0
0
0
0
0
0
Mehr Informationen
Mehr Informationen
Legimi prüft nicht, ob Rezensionen von Nutzern stammen, die den betreffenden Titel tatsächlich gekauft oder gelesen/gehört haben. Wir entfernen aber gefälschte Rezensionen.



Лиз Райс
Безопасность контейнеров. Фундаментальный подход к защите контейнеризированных приложений
2021

Переводчик И. Пальти

Литературный редактор Н. Хлебина

Художник В. Мостипан

Корректоры О. Андриевич, Е. Павлович

Лиз Райс

Безопасность контейнеров. Фундаментальный подход к защите контейнеризированных приложений. — СПб.: Питер, 2021.

ISBN 978-5-4461-1850-2

© ООО Издательство "Питер", 2021

Все права защищены. Никакая часть данной книги не может быть воспроизведена в какой бы то ни было форме без письменного разрешения владельцев авторских прав.

Оглавление

Предисловие
Для кого эта книга
Структура издания
Примечание относительно Kubernetes
Примеры
Запуск контейнеров
Обратная связь
Условные обозначения
Использование примеров кода
От издательства
Благодарности
Глава 1. Угрозы безопасности контейнеров
Риски, угрозы и уменьшение их последствий
Модель угроз для контейнеров
Границы зон безопасности
Мультиарендность
Принципы безопасности
Резюме
Глава 2. Системные вызовы Linux, права доступа и привилегии
Системные вызовы
Права доступа к файлам
Привилегии Linux
Повышение полномочий
Резюме
Глава 3. Контрольные группы
Иерархии контрольных групп
Создание контрольных групп
Установка ограничений на ресурсы
Приписываем процесс к контрольной группе
Контрольные группы в Docker
Контрольные группы версии 2
Резюме
Глава 4. Изоляция контейнеров
Пространства имен Linux
Изоляция хост-имени
Изоляция идентификаторов процессов
Изменение корневого каталога
Сочетание возможностей пространств имен и изменения корневого каталога
Пространство имен монтирования
Пространство имен сети
Пространство имен пользователей
Пространство имен обмена информацией между процессами
Пространство имен контрольных групп
Процессы контейнера с точки зрения хоста
Хост-компьютеры контейнеров
Резюме
Глава 5. Виртуальные машины
Загрузка компьютера
Знакомство с VMM
«Перехватывай и эмулируй»
Обработка невиртуализируемых инструкций
Изоляция процессов и безопасность
Недостатки виртуальных машин
Изоляция контейнеров по сравнению с изоляцией виртуальных машин
Резюме
Глава 6. Образы контейнеров
Корневая файловая система и конфигурация образов контейнеров
Переопределение настроек во время выполнения
Стандарты OCI
Конфигурация образа
Сборка образов
Хранение образов
Идентификация образов
Безопасность образов
Безопасность этапа сборки
Безопасность хранилищ образов
Безопасность развертывания образов
GitOps и безопасность развертывания
Резюме
Глава 7. Программные уязвимости в образах контейнеров
Исследования уязвимостей
Уязвимости, исправления и дистрибутивы
Уязвимости уровня приложения
Управление рисками, связанными с уязвимостями
Сканирование на уязвимости
Установленные пакеты
Сканирование образов контейнеров
Средства сканирования
Сканирование в конвейере CI/CD
Предотвращение запуска образов с уязвимостями
Уязвимости нулевого дня
Резюме
Глава 8. Усиление изоляции контейнеров
Механизм seccomp
Модуль AppArmor
Модуль SELinux
«Песочница» gVisor
Среда выполнения контейнеров Kata Containers
Виртуальная машина Firecracker
Unikernels
Резюме
Глава 9. Нарушение изоляции контейнеров
Выполнение контейнеров по умолчанию от имени суперпользователя
Флаг --privileged и привилегии
Монтирование каталогов с конфиденциальными данными
Монтирование сокета Docker
Совместное использование пространств имен контейнером и его хостом
Вспомогательные контейнеры
Резюме
Глава 10. Сетевая безопасность контейнеров
Брандмауэры для контейнеров
Сетевая модель OSI
Отправка IP-пакета
IP-адреса контейнеров
Сетевая изоляция
Маршрутизация на уровнях 3/4 и правила
Сетевые стратегии
Service mesh
Резюме
Глава 11. Защищенное соединение компонентов с помощью TLS
Защищенные соединения
Сертификаты X.509
TLS-соединения
Защищенные соединения между контейнерами
Отзыв сертификатов
Резюме
Глава 12. Передача в контейнеры секретных данных
Свойства секретных данных
Передача информации в контейнер
Секретные данные в Kubernetes
Секретные данные доступны для суперпользователя хоста
Резюме
Глава 13. Защита контейнеров во время выполнения
Профили образов контейнеров
Предотвращение отклонений
Резюме
Глава 14. Контейнеры и десять главных рисков по версии OWASP
Внедрение кода
Взлом аутентификации
Раскрытие конфиденциальных данных
Внешние сущности XML
Взлом управления доступом
Неправильные настройки безопасности
Межсайтовое выполнение сценариев (XSS)
Небезопасная десериализация
Использование компонентов, содержащих известные уязвимости
Недостаток журналирования и мониторинга
Резюме
Заключение
Приложение. Контрольный список по безопасности
Об авторе
Об иллюстрации на обложке
Рекомендуем прочитать

Предисловие

Во многих организациях приложения работают в нативных облачных средах, обеспечивая масштабируемость и отказоустойчивость с помощью контейнеров и средств координации. Как участнику команды Ops, DevOps или даже DevSecOps, отвечающему за настройку подобной среды для своей компании, гарантировать безопасность развертываемых приложений? Как специалисту по безопасности, имеющему опыт использования традиционных систем на основе серверов или виртуальных машин, адаптировать свои знания к контейнерному развертыванию? И что разработчику нативных облачных приложений стоит учесть, чтобы повысить безопасность своих контейнеризованных приложений? В данной книге описаны ключевые технологии, лежащие в основе контейнеров и нативного облачного программирования. Поэтому после ее прочтения вы сможете лучше оценить риски для безопасности и решения, подходящие для конкретной среды, а также избежать нерекомендуемых приемов, которые подвергают опасности технологии, развернутые вами.

С помощью этой книги вы изучите многие базовые технологии и механизмы, часто применяемые в контейнерных системах, а также способы их построения в операционной системе Linux. Вместе мы углубимся в основы функционирования контейнеров и их взаимодействия и ответим не только на вопрос «что» относительно безопасности контейнеров, но и, главное, «почему». При написании данной книги я ставила перед собой цель помочь читателю лучше разобраться в происходящем при развертывании контейнеров. Мне хотелось бы вдохновить вас на создание ментальных моделей, позволяющих вам самостоятельно оценить потенциальные риски для безопасности при развертывании.

В основном в этой книге обсуждаются контейнеры приложений, которые в настоящее время используют многие организации, чтобы запускать свои приложения в таких системах, как Kubernetes и Docker, а не контейнеры для систем наподобие LXC и LXD из проекта Linux Containers Project (https://linuxcontainers.org/). В контейнере приложений можно запускать неизменяемые контейнеры с помощью кода объемом не больше, чем требуется для запуска приложения. Наряду с этим в среде системного контейнера выполняется полный дистрибутив Linux, и работают с ним скорее как с виртуальной машиной. Вполне допустимо подключаться к системному контейнеру по SSH. Если же вы захотите подключиться по SSH к контейнеру приложений, то специалисты по их безопасности посмотрят на вас косо (по причинам, изложенным далее в этой книге). Впрочем, основные механизмы создания контейнеров для систем и приложений совпадают: контрольные группы, пространства имен и изменение корневого каталога. Так что фундамент, заложенный в данной книге, позволит вам и далее изучать разницу в подходах, которые используются в различных проектах контейнеров.

Для кого эта книга

Неважно, кем вы себя считаете: разработчиком, специалистом в области безопасности, оператором или менеджером, — эта книга подойдет, если вам интересно дойти до самой сути того, как функционирует что-либо, и нравится проводить время за терминалом Linux.

Если же вы ищете пошаговое руководство по безопасности контейнеров, то, возможно, эта книга не для вас. Я не верю в существование универсального рецепта, подходящего для всех приложений во всех средах и для всех орга­низаций. Напротив, я хочу помочь вам разобраться, что происходит при запуске приложений в контейнерах и как работают различные механизмы безопасности, чтобы вы могли сами оценить риски.

Как вы узнаете далее, контейнеры основаны на сочетании некоторых функцио­нальных возможностей ядра Linux. Механизмы обеспечения безопасности контейнеров во многом схожи с механизмами безопасности для хоста Linux (под словом «хост» я понимаю как виртуальные машины, так и физические серверы). Я разложу по полочкам все нюансы функционирования этих механизмов, а затем продемонстрирую их применение в контейнерах. Опытные системные администраторы могут спокойно пропустить часть разделов и перейти сразу к информации, относящейся к контейнерам.

Я предполагаю, что вы хотя бы поверхностно знакомы с контейнерами и, возможно, хотя бы немного «игрались» с Docker и Kubernetes. А также понимаете, как минимум в общих чертах, выражения типа «извлечь образ контейнера из реестра» или «запустить контейнер», даже если не знаете в точности, что происходит «под капотом» при подобных действиях. Я не жду от вас знаний нюансов работы конвейеров, по крайней мере до того, как вы прочитаете данную книгу.

Структура издания

Мы начнем в главе 1 с моделей угроз и векторов атак, встречающихся при контейнерном развертывании, а также нюансов безопасности контейнеров по сравнению с безопасностью при обычном развертывании. Цель оставшейся части книги — помочь вам разобраться в контейнерах и связанных с ними угрозах безопасности, равно как и в защите от них.

Прежде чем заняться собственно безопасностью контейнеров, необходимо разобраться, как они работают. Глава 2 описывает основные механизмы Linux, в частности системные вызовы и привилегии, используемые для контейнеров. Далее, в главах 3 и 4, мы углубимся в обсуждение компонентов Linux, из которых состоят контейнеры. Благодаря этому вы поймете, чем в действительности являются контейнеры и насколько они изолированы друг от друга. А в главе 5 мы сравним их степень изоляции с изоляцией виртуальных машин.

В главе 6 вы узнаете о содержимом образов контейнеров и некоторых практических рекомендациях по обеспечению их безопасности. А в главе 7 научитесь определять известные программные уязвимости контейнеров.

В главе 8 мы рассмотрим некоторые необязательные меры безопасности Linux, выходящие за рамки базовой реализации, представленной в главе 4, позволяющие усилить безопасность контейнеров. Вдобавок в главе 9 обсудим способы нарушения изоляции контейнеров в результате опасных, хотя и очень распространенных ошибок конфигурации.

Далее мы обратимся к вопросу взаимодействия контейнеров. Глава 10 рассказывает о способах обмена информацией между контейнерами и улучшения безопасности с помощью соединений между ними. Глава 11 посвящена основам ключей и сертификатов, благодаря которым контейнеризованные компоненты могут идентифицировать друг друга и создавать между собой защищенное соединение. Хотя их использование в случае контейнеров не отличается от любых других компонентов, мы включили этот вопрос в нашу книгу, поскольку в распределенных системах ключи и сертификаты часто вызывают затруднения. В главе 12 мы покажем, как безопасно (и как не столь безопасно) передавать сертификаты и прочие учетные данные в контейнеры во время выполнения.

В главе 13 мы поговорим о способах, позволяющих предотвращать атаки во время выполнения благодаря возможностям контейнеров.

Наконец, в главе 14 мы рассмотрим список из десяти основных рисков для безопасности, опубликованный открытым проектом обеспечения безопасности веб-приложений (Open Web Application Security Project, OWASP) и рассмотрим подходы к их устранению на основе контейнеров. Спойлер: некоторые риски для безопасности устраняются одинаково для контейнеризованных и неконтейнеризованных приложений.

Примечание относительно Kubernetes

Используемые в настоящее время контейнеры работают в основном под управлением механизма координации Kubernetes (https://kubernetes.io/). Он автоматизирует процесс выполнения различной рабочей нагрузки на кластере машин, и в некоторых местах книги я предполагаю, что в общих чертах эта идея вам понятна. В целом я старалась сосредоточиться на понятиях уровня контейнеров — «плоскости данных» при развертывании с помощью Kubernetes.

Поскольку рабочие задания Kubernetes выполняются в контейнерах, эта книга в определенной степени относится и к безопасности Kubernetes, однако ни в коем случае не является всесторонним обсуждением вопросов безопасности Kubernetes или нативных облачных развертываний. Многие прочие вопросы настройки и использования компонентов плоскости управления также выходят за рамки данной книги. Если вы хотите получить больше информации по этим вопросам, то рекомендую заглянуть в книгу Kubernetes Security издательства O’Reilly (https://oreil.ly/Of6yK) (которую я написала совместно с Майклом Хаузенбласом (Michael Hausenblas)).

Примеры

В данной книге вы найдете множество примеров, и я рекомендую вам поэкспериментировать с ними.

В этих примерах я предполагаю, что вы хорошо знакомы с основными утилитами командной строки Linux, наподобие ps и grep, а также с основными операциями, необходимыми для запуска контейнерных приложений с помощью таких утилит, как kubectl или docker. Первый из этих наборов утилит поможет нам пояснить очень многое из того, что происходит при использовании второго!

Чтобы следить за ходом примеров, вам понадобится доступ к машине с Linux или соответствующей виртуальной машине. Я создавала примеры с помощью виртуальной машины Ubuntu 19.04, работавшей в VirtualBox (https://www.virtualbox.org/) на моем Mac. Кроме того, для создания, запуска и останова моих виртуальных машин я применяла Vagrant (https://www.vagrantup.com/). Аналогичные результаты можно получить на самых различных дистрибутивах Linux, а также виртуальных машин от вашего излюбленного поставщика облачных сервисов.

Запуск контейнеров

Многие люди непосредственно запускали контейнеры в основном (а иногда и только) с помощью Docker. Он сильно упростил использование контейнеров за счет набора удобных утилит для разработчиков. Управлять контейнерами и их образами из командной строки позволяет команда docker.

Утилита docker фактически представляет собой тонкую прослойку, которая вызывает API основного компонента Docker, производящего всю основную работу демона. При каждом запуске контейнера вызывается компонент демона под названием containerd. Данный компонент проверяет наличие требуемого образа контейнера, после чего вызывает компонент runc, факти­чески создающий объект контейнера.

При желании можно запустить контейнер самостоятельно, вызвав containerd или даже непосредственно runc. Компания Docker в 2017 году безвозмездно передала проект containerd фонду Cloud Native Computing Foundation (CNCF) (https://cncf.io/).

В Kubernetes используется Container Runtime Interface (CRI), который пользователи могут при желании выбрать в качестве среды выполнения контейнеров. На сегодняшний день чаще всего применяются упомянутый выше containerd (https://containerd.io/) и CRI-O (https://cri-o.io/) (который, прежде чем его безвозмездно передали CNCF, был частью Red Hat).

Интерфейс командной строки Docker — лишь один из вариантов управления контейнерами и образами. Существуют и другие возможности запуска контейнеров приложений, наподобие тех, что обсуждаются в этой книге. Один из подобных вариантов — утилита podman из дистрибутива Red Hat, изначально предназначенная для устранения зависимости от компонента-демона.

В примерах, представленных в этой книге, используется множество разно­образных контейнерных утилит, чтобы показать большое количество реализаций контейнеров, значительная часть функциональности которых совпадает.

Обратная связь

В дополнение к этой книге существует сайт containersecurity.tech. Не стесняйтесь сообщать туда о найденных проблемах и поправках, которые вы хотели бы увидеть в следующих изданиях.

Условные обозначения

В данной книге используются следующие условные обозначения.

Курсив

Курсивом выделены новые термины и важные слова.

Моноширинный шрифт

Используется для листингов программ, а также внутри абзацев для обозначения таких элементов, как переменные и функции, базы данных, типы данных, переменные среды, операторы и ключевые слова, имена файлов и их расширений.

Моноширинный жирный шрифт

Показывает команды или другой текст, который пользователь должен ввести самостоятельно.

Моноширинный зеленый

Показывает текст, который должен быть заменен значениями, введенными пользователем, или значениями, определяемыми контекстом.

Шрифт без засечек

Используется для обозначения URL, адресов электронной почты, названий кнопок, каталогов.

Этот рисунок указывает на общее примечание.

Использование примеров кода

Дополнительные материалы (примеры кода, упражнения и т.д.) доступны для скачивания по адресу https://containersecurity.tech/.

Если при использовании примеров кода у вас возникнут технические вопросы или проблемы, то, пожалуйста, напишите нам на электронную почту по адресу [email protected].

Помочь вам делать вашу работу — вот цель создания этой книги. Если к ней прилагается какой-либо пример кода, то вы можете задействовать его в ваших программах и документации. Обращаться к нам за разрешением нет необходимости, разве что вы копируете значительную часть кода. Так, написание программы, в которой используется несколько фрагментов кода из этой книги, не требует отдельного разрешения, в отличие от продажи или распространения компакт-дисков с примерами из книг O’Reilly. Вы можете свободно цитировать эту книгу с примерами кода, отвечая на некий вопрос. А вот если хотите включить существенную часть приведенного здесь кода в документацию своего программного продукта, то вам следует связаться с нами.

Мы приветствуем, хотя и не требуем, ссылки на первоисточник. Она включает название, автора, издательство и ISBN. Например: «Лиз Райс. Безопасность контейнеров. СПб.: Питер, 2021. 978-5-4461-1850-2».

Если вам кажется, что ваше обращение с примерами кода выходит за рамки правомерного использования или условий, перечисленных выше, то можете обратиться к нам по адресу [email protected].

От издательства

Ваши замечания, предложения, вопросы отправляйте по адресу [email protected] (издательство «Питер», компьютерная редакция).

Мы будем рады узнать ваше мнение!

На веб-сайте издательства www.piter.com вы найдете подробную информацию о наших книгах.

Благодарности

Я благодарна множеству людей, которые помогали мне и поддерживали, пока я писала эту книгу:

• моему редактору из издательства O’Reilly Вирджинии Вилсон (Virginia Wilson), державшей весь процесс под контролем и следившей, чтобы эта книга оказалась на должной высоте;

• научным редакторам за их вдумчивые замечания и конструктивную обратную связь: Ахилю Белю (Akhil Behl), Эндрю Мартину (Andrew Martin), Эрику Ст. Мартину (Erik St. Martin), Филу Эстесу (Phil Estes), Рани Оснату (Rani Osnat) и Роберту П. Дж. Дею (Robert P.J. Day);

• моим коллегам из компании Aqua Security, за долгие годы научившим меня столь многому о безопасности контейнеров;

• Филу Перлу (Phil Pearl) — моему мужу, лучшему критику и учителю и в то же время моему лучшему другу.

Глава 1. Угрозы безопасности контейнеров

За последние несколько лет масштабы применения контейнеров резко возросли. Соответствующие концепции контейнеров существовали еще за несколько лет до Docker. Но большинство наблюдателей сходятся во мнении, что именно появление в 2013 году Docker с его удобными в использовании утилитами командной строки дало толчок популярности контейнеров среди сообщества разработчиков.

У контейнеров есть множество достоинств. Как гласит рекламный слоган Docker, с их помощью можно «создать один раз, выполнять где угодно» — благодаря объединению в пакет приложения и всех его зависимостей и изоляции приложения от остальной части машины, на которой оно работает. У контейнеризованного приложения есть все необходимое, его легко можно упаковать в образ контейнера, который будет работать одинаково на моем/вашем ноутбуке и на сервере в центре обработки данных (ЦОД).

Следствие этой изоляции — возможность параллельного выполнения нескольких различных контейнеров, которые не будут мешать друг другу. До появления контейнеров мешанина зависимостей могла легко превратиться в настоящий кошмар для разработчиков, в котором двум приложениям требовались различные версии одних и тех же пакетов. Проще всего решить данную проблему, выполняя приложения на отдельных машинах. Контейнеры изолируют зависимости друг от друга, и потому выполнение нескольких приложений на одном сервере не доставляет никаких проблем. Все быстро поняли, что благодаря контейнеризации можно запускать несколько приложений на одном хосте (неважно, виртуальной машине или реальном сервере), не беспокоясь о зависимостях.

Следующий логичный шаг — распределение контейнеризованных приложений по кластеру серверов. Благодаря средствам координации наподобие Kubernetes этот процесс автоматизируется до такой степени, что больше не нужно вручную устанавливать приложения на конкретных машинах, достаточно сообщить средству координации, какие контейнеры необходимо запустить, и оно само найдет подходящую машину для каждого из них.

С точки зрения безопасности контейнеризованная среда во многом схожа с обычным развертыванием. Нарушители пытаются похитить данные, или изменить поведение системы, или, скажем, использовать вычислительные ресурсы других людей для майнинга криптовалюты. При переходе к контейнерам ничего из этого не меняется. Однако контейнеры существенно меняют способ работы приложений, что приводит к иному набору рисков для безопасности.

Риски, угрозы и уменьшение их последствий

Риск (risk) — это потенциальная проблема, а также ее возможные последствия.

Угроза (threat) — путь реализации этого риска.

Уменьшение их последствий (mitigation) — контрмеры, с помощью которых можно предотвратить угрозу или по крайней мере уменьшить вероятность ее успешной реализации.

Скажем, существует риск, что какой-нибудь злоумышленник украдет из вашего дома ключи от вашей же машины и уедет на ней. Угрозы в данном случае — это различные способы кражи ключей: разбить окно, запустить руку и схватить ключи; просунуть удочку через щель для почты; постучать в дверь и отвлечь вас, пока сообщник быстро проскользнет внутрь и схватит ключи. Чтобы уменьшить последствия всех этих угроз, можно, например, убрать ключи от машины с видного места.

Риски очень различаются в разных организациях. Основной риск для банка, хранящего клиентские деньги, — их кража. Для интернет-магазина основная головная боль — мошеннические транзакции. Ведущий личный блог пользователь может бояться, например, что кто-то взломает его учетную запись, выдаст себя за него и начнет публиковать непристойные комментарии. В разных странах законодательство о защите персональной информации имеет свои особенности, поэтому различается и риск утечки личных данных пользователей — во многих странах риски «лишь» репутационные, в то время как в Европе Общий регламент защиты персональных данных (General Data Protection Regulation, GDPR) допускает штрафы до 4 % общего дохода компании (https://oreil.ly/guQg3).

А поскольку риски весьма разнятся, то сильно различается и относительная значимость потенциальных угроз, равно как и соответствующий набор средств уменьшения последствий. В основе управления рисками лежит процесс их систематизации, перечисления возможных угроз, расстановки их по приоритетам и выбора подхода к уменьшению их последствий.

Моделирование угроз (threat modeling) — процесс распознавания и перечисления возможных угроз системе. За счет планомерного анализа ее компонентов и вероятных векторов атаки модель угроз помогает определить места системы, наиболее уязвимые для атак.

Единой всеобъемлющей модели угроз не существует, все зависит от рисков конкретной среды, организации и запускаемых приложений. Но можно перечислить некоторые потенциальные угрозы, общие для многих, если не всех, контейнерных развертываний.

Модель угроз для контейнеров

В частности, модель угроз можно рассматривать с точки зрения ее участников, в число которых могут входить:

• внешние нарушители (external attackers), пытающиеся извне получить доступ к развернутой системе;

• внутренние нарушители (internal attackers), сумевшие получить доступ к некой части развернутой системы;

• внутренние действующие лица-злоумышленники (malicious internal actors), например, разработчики и администраторы с определенным уровнем полномочий доступа к развернутой системе;

• небрежные внутренние действующие лица (inadvertent internal actors), которые могут неумышленно вызывать проблемы;

• процессы приложений (application processes) — не люди-злоумышленники, тем не менее имеющие определенный программный доступ к системе.

Необходимо учитывать набор прав доступа каждого из действующих лиц.

• Какой доступ к системе есть у этого лица в соответствии с его учетными данными? Например, есть ли у него доступ к пользовательским учетным записям на машинах хостов, где работает развернутая система?

• Какие права доступа оно имеет в системе? В Kubernetes этот пункт относится к настройкам управления доступом для всех пользователей, в том числе анонимных, на основе ролей.

• Какие права доступа к сети есть у этого лица? Например, какие части системы включены в виртуальное частное облако (virtual private cloud, VPC)?

Существует несколько возможных путей атаки на развернутую контейнеризованную систему, и чтобы их систематизировать, можно, например, проанализировать потенциальные векторы атак на каждом из этапов жизненного цикла контейнера (рис. 1.1).

Рис. 1.1. Векторы атак на контейнеры

Рассмотрим эти векторы более подробно.

• Уязвимый код. Жизненный цикл приложения начинается с написания разработчиком его кода. Он, равно как и его зависимости, может содержать изъяны (уязвимости). Существуют списки из тысяч известных уязвимостей, которыми (если они есть в приложении) могут воспользоваться злоумышленники. Образы необходимо анализировать, как вы увидите в главе 7, чтобы не применять контейнеры с известными уязвимостями. Причем делать это нужно регулярно, поскольку уязвимости обнаруживаются в уже существующем коде постоянно. В процессе анализа должны также выявляться контейнеры с устаревшим ПО, которое необходимо обновить, установив исправления безопасности. Кроме того, есть анализаторы, способные выявлять встроенное в образы вредоносное программное обеспечение.

• Плохо настроенные образы контейнеров. Написанный код встраивается в образ контейнера. В ходе конфигурации сборки образа контейнера возникает множество возможностей создать уязвимости, которые открывают дорогу для дальнейших атак на работающий контейнер. В их число входит выполнение контейнера от имени суперпользователя, в результате чего у него оказывается больше полномочий, чем нужно. Больше информации об этом — в главе 6.

• Атаки на систему сборки. Если злоумышленник может изменить сборку образа контейнера или как-то повлиять на нее, то сможет вставить вредоносный код, который потом будет запущен в среде промышленной эксплуатации. Кроме того, возможность закрепиться внутри среды сборки — плацдарм для злоумышленника, позволяющий в дальнейшем проникать в среду промышленной эксплуатации. Этот вопрос также обсуждается в главе 6.

• Атаки на цепь поставок. Собранный образ контейнера сохраняется в реестре, откуда извлекается перед запуском. Как гарантировать соответствие извлекаемого образа тому, который был ранее помещен в реестр? Не могли ли злоумышленники внести в него изменения? Любой, кто может заменить образ или модифицировать его в промежутке между сборкой и развертыванием, сможет выполнить любой код в развернутой системе.

• Плохо настроенные контейнеры. Как мы обсудим в главе 9, контейнер можно запустить с настройками, в результате которых у них появляются ненужные, а порой и незапланированные полномочия. Скачивая файлы конфигурации YAML из Интернета, пожалуйста, не запускайте их, не убедившись в отсутствии в них небезопасных настроек!

• Уязвимые хосты. Контейнеры выполняются на хост-компьютерах, поэтому нужно проверять работающий на них код на наличие уязвимостей (например, отслеживать старые версии компонентов механизма координации, с известными уязвимостями). Имеет смысл уменьшить до минимума объем запущенного на каждом хосте программного обеспечения, чтобы сократить поверхность атаки. Кроме того, необходимо задать правильную конфигурацию хостов в соответствии с практическими рекомендациями по обеспечению безопасности. Все это обсуждается в главе 4.

• Общедоступные секретные данные. Чтобы взаимодействовать с другими компонентами системы, код приложения часто требует учетные данные, токены или пароли. При развертывании в контейнере эти секретные значения необходимо передавать в контейнеризованный код. Как вы увидите в главе 12, существует несколько различных вариантов решения этой задачи, имеющих разную степень безопасности.

• Незащищенная сеть. Контейнерам обычно требуется взаимодействовать друг с другом или с окружающим миром. В главе 10 обсуждается передача данных по сети в контейнерах, а в главе 11 — установление защищенных соединений между компонентами.

• Уязвимости выхода за рамки контейнера. Широко используемые среды выполнения контейнеров, включая containerd и CRI-O, уже хорошо проверены в деле, однако не исключено, что в них все же остаются программные ошибки, вследствие которых вредоносный код, работающий внутри контейнера, может просочиться за пределы контейнера, в хост. Одна из таких проблем — Runcescape (https://oreil.ly/cFSaJ) — обнаружилась в 2019 году. В главе 4 можно прочитать об изоляции, предназначенной для ограничения кода приложения рамками контейнера. Ущерб от выхода за рамки контейнера для ряда приложений может быть столь велик, что имеет смысл задуматься о применении более эффективных механизмов изоляции, таких как те, которые обсуждаются в главе 8.

Некоторые векторы атак выходят за рамки данной книги.

• Исходный код обычно хранится в репозиториях, потенциально доступных для атак, цель которых — взлом приложения. Необходимо обеспечить должный контроль доступа пользователя к репозиторию.

• Хост-компьютеры связываются между собой сетью, обычно подключенной к Интернету, причем в целях безопасности при этом часто применяется VPC. Как и при обычном развертывании, необходимо защитить хост-компьютеры (или виртуальные машины) от доступа злоумышленников. Безопасные настройки сети, использование брандмауэра, а также управление идентификацией и доступом для нативного облачного развертывания ничуть не менее релевантны, чем для обычного.

• Контейнеры обычно работают под управлением механизма координации — в современных развертываниях его роль обычно играет Kubernetes, хотя есть и другие варианты, например Docker Swarm и Hashicorp Nomad. Недостаточная безопасность настроек средства координации или отсутствие должного контроля над доступом с правами администратора открывают злоумышленникам дополнительные векторы атак.

Больше информации о моделях угроз при развертываниях на основе Kubernetes можно найти в отчете «Модель угроз Kubernetes» (Kubernetes Threat Model) (https://bit.ly/3sg7aBn), заказанном CNCF.

Кроме того, команда Financial User Group проекта CNCF опубликовала дерево атак Kubernetes (Kubernetes Attack Tree) (https://bit.ly/3mPGZR2), созданное на основе методологии STRIDE (https://oreil.ly/rNmPN).

Границы зон безопасности

Границы зон безопасности (иногда называемые границами доверия) между частями системы означают, что наборы прав доступа в этих частях отличаются. Иногда границы задаются в ходе администрирования — например, в системах под управлением Linux системный администратор может модифицировать границы зон безопасности, указывая, какие группы файлов доступны пользователю. Администратор делает это, изменяя группы, в которых состоит данный пользователь. Если вы подзабыли систему прав доступа к файлам Linux, то мы напомним ее в главе 2.

Контейнер представляет собой зону безопасности. Код приложения должен работать внутри него и не иметь доступа к коду или данным вне контейнера, за исключением случаев, когда явным образом получает подобное разрешение (например, путем подключения к нему внешнего тома).

Чем строже граница зон безопасности между злоумышленником и его целью (например, данными пользователей), тем сложнее ему достичь этой цели.

Векторы атак, описанные в разделе «Модель угроз для контейнеров» на с. 23, можно связывать цепочкой — чтобы проникнуть через несколько границ зон безопасности. Приведу следующие примеры.

• Злоумышленник может обнаружить, что уязвимость в одной из зависимостей приложения позволяет ему выполнять код удаленно, внутри контейнера.

• Допустим, у взломанного компьютера нет прямого доступа к каким-либо ценным данным. Злоумышленнику необходим способ выйти за рамки контейнера, в другой контейнер или на хост-компьютер. Один из путей наружу — уязвимость выхода за рамки контейнера; другой — небезопасная конфигурация контейнера. Если один из этих путей открыт для злоумышленника, то он может получить доступ к хосту.

• Следующий шаг — поиск способов получить на хосте полномочия суперпользователя, что может оказаться тривиальной задачей, если код приложения выполняется от имени суперпользователя внутри контейнера, как вы увидите в главе 4.

• Имея полномочия суперпользователя на хост-компьютере, злоумышленник может получить доступ ко всему, что доступно с хоста или из любого контейнера, запущенного на этом хосте.

Добавление и укрепление границ безопасности при развертывании значительно усложняет жизнь взломщиков.

Важный аспект модели угроз — учет возможности атак изнутри среды, в которой работает приложение. При развертывании в облаке отдельные ресурсы порой задействуются совместно с другими пользователями и их приложениями. Совместное использование ресурсов компьютера называется мультиарендностью (multitenancy) и серьезно влияет на модель угроз.

Мультиарендность

В мультиарендной среде различные пользователи — арендаторы (tenants) —выполняют задания на общем оборудовании. (Термин «мультиарендность» можно также встретить в контексте программных приложений, где означает нескольких пользователей, задействующих один и тот же экземпляр программы, но в нашем случае совместно применяется лишь аппаратное обеспечение.) В зависимости от владельцев этих различных рабочих заданий, а также степени взаимного доверия арендаторов, могут понадобиться более жесткие границы между ними, чтобы предотвратить возможное негативное влияние их друг на друга.

Мультиарендность — идея, появившаяся еще во времена мейнфреймов в 1960-х, когда пользователи арендовали время CPU, память и место на диске на совместно используемой ими машине. Эта концепция не так уж сильно отличается от современных общедоступных облачных сервисов, например Amazon AWS, Microsoft Azure и Google Cloud Platform, в которых пользователи арендуют время CPU, оперативную память, место для хранения наряду с прочими возможностями и управляемыми сервисами. С тех пор как в 2006 году Amazon AWS предоставил EC2, можно арендовать экземпляры виртуальных машин, запущенные на стойках серверов в центрах обработки данных, разбросанных по всему миру. На одной реальной машине может работать несколько виртуальных (VM), и работающий на группе виртуальных машин пользователь может не знать, кто работает на соседней VM.

Совместно используемые машины

В некоторых случаях одну (возможно, виртуальную) машину Linux задействуют несколько пользователей. Так, очень часто подобный пример истинной мультиарендности встречается в университетах, где пользователи не доверяют друг другу и, говоря откровенно, администраторы не доверяют пользователям. В такой среде доступ пользователей ограничивается благодаря средствам управления доступом Linux. У каждого пользователя есть свой идентификатор входа, и доступ ограничивается с помощью средств управления доступом Linux, чтобы, например, пользователь мог изменять только файлы в своих каталогах. Можете представить, какой бы возник беспорядок, если бы студенты могли читать или — хуже того — редактировать файлы своих однокурсников?

Как вы увидите в главе 4, ядро у всех контейнеров одного хоста — общее. Если на машине применяется демон Docker, то у всех пользователей, имеющих права на выполнение команд docker, по сути, есть доступ с полномочиями суперпользователя, и вряд ли администратору следует предоставлять не доверенным пользователям эту возможность.

В корпоративной и особенно в нативной облачной среде подобные совместно используемые машины встречаются реже. Вместо этого пользователи (или команды, доверяющие друг другу) обычно задействуют собственные ресурсы, выделенные им в виде виртуальных машин.

Виртуализация

Вообще говоря, считается, что виртуальные машины достаточно надежно изолированы друг от друга, то есть маловероятно, что ваши соседи смогут увидеть или вмешаться в происходящее в ваших виртуальных машинах. Как достигается подобная изоляция, можно узнать в главе 5. На самом же деле в соответствии с общепринятым определением (https://oreil.ly/yfkQI) виртуализация вообще не является мультиарендностью. Мультиарендность — это когда различные группы пользователей совместно работают с одним экземпляром программного обеспечения, а при виртуализации у пользователей нет доступа к гипервизору, управляющему их виртуальными машинами, поэтому они не используют совместно никаких программ.

Впрочем, изоляция виртуальных машин отнюдь не идеальна, и пользователи ранее жаловались на проблемы с «шумными соседями», когда совместное использование реальной машины может привести к неожиданным колебаниям производительности. Компания Netflix одной из первых начала применять общедоступные облачные сервисы. В 2010 году они опубликовали в своем блоге сообщение, в разделе «Совместная аренда — вещь непростая» (Co-tenancy is hard) (https://oreil.ly/CGlZ0) которого признаются, что создаваемые ими системы могли осознанно прекратить выполнение подзадачи, если она выполнялась слишком медленно. В последнее время можно услышать утверждения, что проблема «шумных соседей» больше не актуальна (https://oreil.ly/iE4qE).

Известны случаи, когда уязвимости в программном обеспечении приводили к нарушению границ между виртуальными машинами.

Возможные последствия несанкционированного доступа для некоторых приложений и организаций (особенно правительственных, финансовых и медицинских) настолько серьезны, что оправданно полное физическое разделение. Чтобы гарантировать полную изоляцию рабочих заданий, можно использовать частное облако, работающее в вашем собственном центре обработки данных либо под управлением выбранного вами поставщика сервисов. В частных облаках иногда встречаются дополнительные меры защиты, например дополнительные проверки анкетных данных персонала, имеющего доступ к ЦОД.

Многие поставщики облачных сервисов предоставляют вариант VM, при котором гарантируется, что одну реальную машину использует только один клиент. Можно также арендовать выделенные физические серверы, обслуживаемые поставщиками облачных сервисов. В обоих этих сценариях полностью устраняется проблема «шумных соседей», плюс вы получаете преимущества, вызванные более надежной изоляцией между реальными машинами.

Неважно, арендуете ли вы реальные или виртуальные машины в облаке или используете собственные серверы, но при работе с контейнерами может понадобиться учесть границы зон безопасности между различными группами пользователей.

Мультиарендность контейнеров

В главе 4 вы увидите, что изоляция контейнеров не так строга, как изоляция виртуальных машин. Хотя это зависит от профиля рисков, вряд ли имеет смысл использовать контейнеры на одной машине в качестве не доверенных сторон.

Даже если вы или люди, которым вы полностью доверяете, управляете всеми запущенными на ваших машинах контейнерами, все равно следует сделать скидку на склонность людей к ошибкам и сделать так, чтобы контейнеры не могли влиять друг на друга.

В Kubernetes с помощью пространств имен (namespaces) кластер компьютеров можно разбить на части, используемые различными людьми, командами или приложениями.

«Пространство имен» — термин с несколькими значениями. В Kubernetes пространство имен представляет собой высокоуровневую абстракцию, которая предназначена для разбиения ресурсов кластера с возможным применением к ним различных режимов управления доступом. В Linux пространство имен — низкоуровневый механизм изоляции ресурсов машины, доступных процессу. Более подробно эти пространства имен будут описаны в главе 4.