Kubernets as DevSecOps and NIST compliance
Last updated
Last updated
https://habr.com/ru/companies/oleg-bunin/articles/646111/
Данная статья — взгляд на то, как Kubernetes способен повысить уровень безопасности, упростив управление ею и ускорив внедрение механизмов безопасности с точки зрения специалиста по ИБ, который большую часть своей карьеры занимался наступательной безопасностью. Сейчас на примере Kubernetes я вижу, что на нем можно организовать так называемую self defense (самозащищающуюся) систему.
Меня зовут Дмитрий Евдокимов, я founder и CTO компании Лантри, а кто-то может меня лучше знать, как автора канала k8s (in)security. Про безопасность я буду говорить, исходя из моего опыта, как человека, который десять лет атаковал различные системы, реализуя угрозы и риски. Ссылка на мое выступление на конференции DevOps Conf 2021 будет в конце статьи.
Я не очень люблю термин DevSecOps — это модное маркетинговое слово, ловко сформированное из DevOps и с которым очень удобно продавать те или иные security-решения (сканеры, анализаторы, бечмарки): «Вот вам инструмент в пайплайн — и у вас появляется DevSecOps!». Из-за этого у людей складывается неправильное представление, как всё происходит — они думают, что есть отдельные стадии разработки, безопасности и operation.
В последнее время появилось много таких направлений:
Мне нравится комментарий в левом нижнем углу. По факту это значит, что безопасность — часть всех процессов, как DevOps, а не отдельная стадия
Рынок даже перевернул термин Shift Left Security — некоторые восприняли напрямую, что, мол, достаточно просто перенести безопасность на более ранние стадии разработки. Недавно создатели стандарта Building Security In Maturity Model (BSIMM) выпустили его 11 версию, подчеркнув — правильно не Shift Left Security, а Shift Everywhere Security. Потому что мы должны применять техники, механизмы и инструменты безопасности на всем жизненном цикле приложения — и как можно раньше.
К сожалению, многие классические безопасники оказались не готовы, что с приходом микросервисов, cloud-native разработки и DevOps-процессов их ландшафт расширился на весь процесс разработки и выкатки приложений. Они продолжают думать о безопасности только в рамках периметров. Я не против применения тех же сканеров безопасности, встраиваемых в пайплайн, но это не панацея. Если бы это решало все задачи, то выиграла бы компания с самым большим бюджетом на покупку лучших инструментов анализа. Но безопасность более сложная вещь.
Безопасность — это процесс, который вплетен в весь жизненный цикл приложения и инфраструктуры. И при этом по отношению к Secure Software Development Lifecycle — это всего лишь его маленькая часть. Потому что, когда найдена какая-то уязвимость (либо вам о ней сообщили со стороны), вы должны не только ее закрыть, но и понять, что через нее никто не реализовал никакую угрозу. Не говоря уже, что работающим приложением вы должны управлять, всегда понимая, что у вас внутри происходит.
В текущих реалиях быстрой разработки и облачных технологий мне ближе определение Cloud Native security или Continuous Security по аналогии с Continuous Integration и Continuous Delivery. Три его основные вещи — люди, процессы и технологии — отлично ложатся на важные для любой компании сферы:
Безопасность должна быть на всех стадиях — Develop, Distribute, Deploy, Runtime
Люди в Cloud Native security — это совместная работа разработчиков, команд безопасности, operation, SRE. В каждой компании своя топология взаимодействия команд, но главное, чтобы они хорошо между собой взаимодействовали. Относительно процессов необходимо, чтобы безопасность была задействована на всех жизненных стадиях приложения.
Технологии отвечают за скорость доставки фич, чтобы быстро доставлять ценность продукта. У некоторых компаний бывает по 10 деплойментов в день, и очень важно, чтобы безопасность не стала блокером (бутылочным горлышком), который мешает выкатить новую фичу. Безопасность должна помогать компании идти к своим бизнес-целям и их реализовывать. По большому счету — это управление рисками. Вы где-то можете затянуть гайки, где-то — ослабить, а где-то компенсировать, снижая тот или иной риск.
И в рамках этой статьи я расскажу, как вижу этот процесс на примере Kubernetes. Также это применимо к другим решениям на его базе, например, OpenShift или менеджмент-Kubernetes. И, возможно, какие-то из подходов можно реализовать и на других оркестраторах (Swarm, Mesos), но я их не настолько хорошо знаю. Но определенные механизмы, я точно знаю, есть только у Kubernetes.
Не знаю, насколько хорошо вы знакомы с Kubernetes, поэтому буквально пара слов о нем, чтобы был единый контекст о том, как я его вижу. Сконцентрируемся мы на стадии Runtime, где k8s играет всеми красками — в отличие от стадий Develop, Distribute и Deploy, где хорошо ложится концепция сканеров.
Каждая инсталляция Kubernetes уникальна, но по умолчанию он небезопасный, потому что он создавался так, чтобы его было проще освоить. В Control plane флаги с безопасностью не используются (но от версии к версии в Kubernetes данная ситуация меняется и становится лучше), а для workloads ни один ограничивающий проверяющий механизм не включен. Namespace сам по себе не является security boundary. В итоге при дефолтном разворачивании нет никаких проверок по используемым image, нет ограничений по поведению контейнеров в подах и сетевому взаимодействию. Логи также неактивны и, как итог, вы даже не поймете, как к вам проник атакующий и что делал в системе.
Впрочем, это актуально для любой системы, потому что мы живем во время критически важного показателя time-to-market (TTM). Чтобы вы смогли быстрее попробовать новую концепцию и понять, что, например, для TTM вам это подходит, почти во всех системах по умолчанию не активируют секьюрити-фичи. Потому что если на стадии освоения новой программы у вас будут сложности с сертификатами или с какими-то ее политиками, то, скорее всего, у вас улетучится желание осваивать новую технологию.
Поэтому все настройки в Kubernetes по умолчанию призваны ускорить ваш старт, а почти все механизмы и функции безопасности деактивированы, хотя у него их огромное количество, как мы дальше увидим. По умолчанию безопасность частично реализуется через другие компоненты. Порой часть этих задач берет на себя облачный провайдер если вы используете managed Kubernetes в shared responsibility model. Об этом нужно помнить и настраивать их, когда вы эту систему выводите в прод.
Everything in this talk exploits features, not bugs' Kubernetes is powerful, and it’s insecure by design. Let’s sec what it can do, and then let us show you how to better secure it.
«The Path Less Traveled: Abusing Kubernetes Defaults», Ian Coldwater, Duffie Cooley, BlackHat USA 2019
Всё, что в нем есть — это YAML. Это очень здорово и играет огромную роль в создании автоматизированных систем. Декларативность позволяет просто описать тот результат, который мы хотим видеть, в отличие от императивных систем, где вы должны четко прописать, как получить результат (логику, достижение, конкретные цели).
Благодаря декларативной природе можно получить много преимуществ:
Self-documenting;
Концентрация на результате, а не на процессе;
Предсказуемость результата;
Удобно хранить, менять и отслеживать изменения;
Something as Code (Infrastructure as Code, Security as Code, …)
Может обрабатывать машина (меньше вероятность ошибки, можно автоматизировано проверить статическим анализом).
Примером декларативной системы может быть система «Инфраструктура как код», где YAML используется для описания конфигурации аппаратных и программных компонентов, которые затем реализует сервер автоматизации. В Kubernetes реализовано похоже. Например, разработчик решает, что контейнер должен иметь возможность автоматически масштабироваться до пяти копий, и Kubernetes обеспечивает это. При этом любой человеко-читаемый декларативный файл легко использовать и проверить любым анализатором.
Kubernetes придуман Google, но его прародителем являемся Borg. Первая публичная работа о Borg появилась в 2015 году. При этом ребята из Google не были в этом первопроходцами. Немного поискав, и я нашел статью 2006 года о самолечащихся системах, где и объясняются принципы автоматизированных систем:
Google просто вывел более user friendly технологию для давно известной концепции
Можно даже найти работы 70-80-х годов от IBM, где рассказывается точно такая же концепция. Так что в основе Kubernetes лежит Control loop или еще его называют Reconciliation loop, который сравнивает желаемое состояние и текущее состояние. Если они не сходятся, то Control loop автоматически приводит текущее состояние в желаемое, благодаря чему Kubernetes является self-healing системой. Например, если нужно, чтобы у определенного сервиса было 10 реплик, то Kubernetes переведет сервис в нужное количество реплик, если их станет меньше.
С Custom Resources можно написать свою собственную логику. Например, можно запретить интерактивный shell, и система сама потушит под и поднимет новый без интерактивного shell внутри. То, что это не потребует никаких усилий от пользователя — тоже очень важный момент для организации самолечащихся, самозащищаемых и самовосстанавливающихся систем. И Kubernetes определенно обладает всеми задатками такой системы. Как это можно реализовать для self-protecting системы, мы и посмотрим.
Рассмотрим стадии риск-менеджемента и как различные стадии обеспечения безопасности хорошо мапятся на жизненные стадии приложения в Kubernetes и его механизмы работы. За основу возьмем NIST CyberSecurity Framework, разработанный NIST — организацией, которая занимается безопасностью. NIST выделил пять основных стадий управления угрозами:
В последнее время стали добавлять еще шестую стадию — deception. Если кратко, то это обманка, которая может специально или случайно даваться атакующему. Например, IP-адрес или DNS-имя, на который ни один сервис не ходит, и любое обращение к нему будет сигналом, что кто-то начал сканировать сеть. Это могут быть honeypots или технологии canary tokens, когда разбрасываются специальные файлы, адреса, ключи, пароли и логины. И, начиная этим пользоваться, атакующий обнаруживает себя. Kubernetes позволяет реализовывать deception, но мы пока сосредоточимся на этих пяти стадиях.
Все пять стадий важны, и при работе с угрозами вы обязательно должны предусмотреть их все. Расставляйте приоритеты: где какую меру по управлению рисками можно применить сейчас, постепенно подпиливая процессы, чтобы бюджет смог всё покрыть. Потому что уязвимости, проблемы, атаки были, есть и будут. Серебряной пули, чтобы от них избавиться, все еще не существует. Вы должны жить в контексте, что вас точно взломают, и вам так или иначе придется искать следы атакующего в своей инфраструктуре. Никто от этого не застрахован — ни Apple, ни Google, ни Microsoft с их огромными бюджетами и секьюрити-командами.
Я назвал эту стадию инвентаризацией, потому что невозможно сделать безопасным и надежным то, что вы не видите и не контролируете. Здесь важную роль играет observability — под ним я понимаю не логи, трейсы и метрики, а знание в любой момент в каком состоянии находится ваша система: что, где и как работает — вплоть до того что и как происходило внутри контейнеров. Сейчас в рамках CNCF пишется документ Observability Whitepaper, и там этому уделяется отдельное внимание. Всё это на самом деле достойно отдельной статьи.
Это могут быть образы и процессы, которые запущены внутри контейнеров. Kubernetes и контейнеры сами по себе предоставляют в принципе все, чтобы всегда видеть, что происходит в инфраструктуре, либо на уровне процессов внутри контейнера, либо на уровне ресурсов.
https://kubernetes.io/docs/concepts/security/overview/
Есть подходящий пример — нашумевшая история про взлом производителя ПО SolarWinds и внедрение вредоносного обновления в программу Orion. В Kubernetes многие компании используют OpenSource решения, в которые также может быть внедрен вредоносный код. Но он останется незамеченным, потому что предполагается, что поставщик провел должную проверку своих продуктов.
Тем не менее, если бы это было в контейнерах в том же Kubernetes, то вы, имея полное observability, поняли бы — это приложение (сервис) всегда делало только одно, а сейчас ходит по всей сети и пытается обращаться к другим контейнерам. В микросервисной архитектуре такое поймать намного проще. Мы с командой сейчас создаем решение для observability и visibility всего происходящего поведения в Kubernetes, чтобы у вас не было в вашей K8s-инфраструктуре слепых зон.
Часто в компаниях можно встретить такую картину: «XX.XXX уязвимостей в образах — не проблема. Мы закрываем уязвимости с высоким уровнем и спим спокойно». Тогда как в моей практике и в историях моих друзей было огромное количество случаев, когда вектор атаки создавался из low или medium уязвимостей.
При этом уровень атакующего определяется в том, как он может собрать несколько малокритичных уязвимостей в успешный вектор. Например, один мой товарищ победил в конкурсе от Google по взлому Chrome, сделав побег из его песочницы — там не было ни одной бинарной уязвимости, а просто вектор из 11 различных веб-уязвимостей. Он получил за это 31 337 долларов.
В моей практике был случай, когда с помощью двух DoS и одного race condition мы выполнили произвольный код на чужом сервере. Думаю, вряд ли кто-то из безопасников начнет первым делом закрывать DoS и race condition. Поэтому нужно помнить, что подход «закрывать только high» имеет проблемы.
Kubernetes представляет огромное количество механизмов защиты. Это как хорошо известные интегрированные механизмы ОС Linux, так и его собственные механизмы: seccomp, AppArmor, SeLinux, PodSecurityPolicy, securityContext, NetworkPolicy, Admission controllers и много чего еще. В сочетании с контейнеризацией это дает просто огромный набор возможных улучшений безопасности, даже без модификации кода в целевом контейнере.
При этом все эти концепции безопасности также отражаются в YAML. То есть это всё реализовано очень прозрачно и задается в тех же ресурсах, что описывают и рабочую нагрузку (Deployments, DaemonSet и т.д.), или специальные ресурсы (NetworkPolicy или PodSecurityPolicy), или в кастомных ресурсах от Kubernetes операторов (типа Starboard). Это очень важно, чтобы все команды (разработки, operation и секьюрити) видели и понимали, какие механизмы работают и как влияют на рабочую нагрузку — для них безопасность не должна быть чужеродным элементом, находящимся где-то в стороне.
Если, например, контроль сети сделан через NetworkPolicy, то через него все команды понимают, что может и что не может делать сервис. У них есть общее видение происходящего, к чему какие правила применяются, и на уровне ресурсов это всегда можно контролировать. А с помощью тех же Admission controllers (Policy Engine) можно полностью собственную логику написать.
История третья: «BugBounty: а ты точно ничего не делал дальше?» или «О результатах пентестов мы узнаем из отчетов». Например, те, у кого-то есть программа BugBounty, знают, что если вы подтвердили факт какой-либо уязвимости, то запрещено проводить атаку дальше. Но некоторые багхантеры, чтобы подтвердить успех своей крутой уязвимости, могут залезть в контейнер и взять оттуда какие-то файлы в качестве доказательства.
Также бывает обидный момент, когда сдается отчет по аудиту и пентесту, а заказчик только из него узнает обо всем, что было сделано, а мониторинг ничего не сообщил и служба безопасности ничего не поняла. Потому что очень часто люди вообще не понимают, что у них происходит в контейнерах. Чтобы у вас информация была сразу, требуется то самое observability, которое дает Kubernetes.
С другой стороны, поды с контейнерами живут не так долго, как классические приложения: они часто обновляются и скейлятся как в одну, так и другую сторону. Одновременно ресурсы не позволяют просто так висеть контейнерам, занимать место и ждать, когда кто-то из ИБ-специалистов обратит на них внимание. В итоге часто под убивается вместе со всеми следами.
В итоге получаем, что скорость разработки, разворачивания и сопровождения приложения накладывают такие же требования по скорости и на стадии безопасности. Они должны друг другу соответствовать. Выход из ситуации — своевременное уведомление и обработка инцидентов по данным от RunTime-решений, системы аудита и логов без откладывания в долгий ящик.
Со стороны Kubernetes, с его с ОС Linux и контейнерной спецификой, есть все возможности просмотреть происходящее внутри контейнеров и обнаружить аномалии. На уровне всей системы можно вести аудит-лог и пользоваться преимуществами observability, о которой мы говорили раньше. То есть защищаемая система для нас не будет черным ящиком.
Была история «Шелл Шредингера» в практике моих друзей. Они сделали пентесты, залили shell, проект закончился, shell удалили, а через несколько дней он обратно к ним постучался: «Я в этой компании успешно запустился, у меня есть туда доступ». Друзья написали в службу безопасности заказчика, shell убрали, но через пару дней он опять написал, что успешно работает в той же инфраструктуре.
Понадобилась неделя, чтобы разобраться, почему они, ничего в проекте не делая, получали постоянно shell. Оказалось, что когда они проводили пентест, то одновременно у заказчика проводился бэкап, в него и улетел shell атакующего. Каждый раз, когда бэкап восстанавливался, shell возвращался. Такая долгая или неправильная реакция приводит к печальным последствиям. За короткий промежуток времени атакующий может получить всё, за чем приходил и уйти. Или находиться в сетях компании незамеченным по полгода и даже год.
Здесь в Kubernetes может помочь Control loop и возможности создать свой кастомный ресурс с оператором. Можно сделать так, что система при понимании, что находится не в должном состоянии, сама реагирует и восстанавливается в нужное состояние. То есть одним махом и ответить на изменение, и восстановить картину.
На этой стадии хорошо применяется концепция Pets vs Cattle или «домашние животные против сельскохозяйственного скота», которая описывает два противоположных подхода к инфраструктуре. Подход Pets — когда сервера выбираются и настраиваются индивидуально, им даются уникальные имена, а в случае поломки чинят (водят домашнего любимца к ветеринару). Но порой, чтобы предотвратить какую-то проблему, проще поднять новый сервер вместо старого, чем разбираться. Это подход Cattle, когда все ресурсы создаются по шаблону и массово настраиваются. А если происходит какая-то нездоровая активность как на уровне Kubernetes-ресурсов, так и на уровне контейнеров, то ресурс просто можно поставить на паузу или пересоздать для последующего анализа или удалить.
На Kubernetes и микросервисную архитектуру также отлично ложится идеология OODA loop:
По сути, OODA loop (Observe, Orient, Decide, Act) — немного преобразованный Collect - Analyse - Decide – Act с добавлением фидбека на каждой стадии. Он наиболее актуален для микросервисов, которые ежедневно очень быстро меняются, но при этом атакующие тоже очень быстро адаптируются ко всему происходящему. Для микросервисов не подходит Plan-Do-Check-Act, потому что безопасность это процесс, а не состояние.
В энтерпрайзе это можно собрать из множества security-решений разных вендоров, объединенных в один цикл. Это очень-очень не просто и не дешево. Для этого даже создали новых класс решений — SOAR, который является логическим развитием IDS -> SIEM -> SOAR:
Здесь видно, что делает SOAR — у них есть некоторые сценарии реакции на события или информацию. Легко тут заметить слово «оркестрация», и Kubernetes отлично для этого годится. А операторы и желаемое состояние, которое система может сама автоматически вернуть, у нас уже есть.
Это одна из моих любимых тем. Благодаря большому количеству security boundaries в Kubernetes и концепции контейнеров, реализовать в K8s ZeroTrust намного проще, чем в какой-либо другой системе. И вы можете ограничить доступ не только на сетевом уровне, но и на уровне приложений.
You know yourself, your team and your product. Build around your requirement.
Kubernetes для этого предлагает такое количество точек встраивания и расширения, что я не знаю, какая еще система это может предложить:
Kubectl plugins;
Authentication Webhook;
Authorization Webhook;
Admission controllers (Image Policy webhook, MutatingAdmissionWebhook, ValidatingAdmissionWebhook, PolicyEngines);
Container Lifecycle Hooks
Kubernetes Audit Log
То есть Kubernetes дает интерфейсы, которые вы можете удобно использовать с учетом специфики, как бизнеса компании и ее продукта, так и процессов и команд в ней. Всё это отлично программируется.
Такой может быть реализация эшелонированной обороны в Kubernetes:
Уверен, что на этой схеме отражено далеко не всё, с учетом того что Kubernetes очень активно развивается. Но я постарался охватить все стадии жизненного цикла приложения. И если теперь кто-то скажет что у Kubernetes проблемы с безопасностью, то 1) У кого их не бывает? и 2) Какая еще система может предложить столько механизмов повышения уровня безопасности? Скорее всего тот, кто так говорит, недостаточно хорошо знает возможности Kubernetes ;)
K8s реально позволяет строить Defence in depth и очень гибко управлять рисками в условиях быстрой доставки ценности клиенту. Благодаря такому обилию механизмов вы обязательно найдете компромисс между своими командами. Естественно, за раз это всё не реализовать, но можно постепенно делать каждую часть с учетом моделей угроз и риска каждой стадии.
Безопасность и управление рисками — это такая игра компромиссов между теми или иными элементами. С точки зрения cloud-native это очень важно, потому что мы не должны негативно влиять на скорость развития приложений. Мы должны делать так, чтобы всем было удобно, никто никому не мешал и все удачно шли к общей цели.
Не ведитесь на маркетинг. Стройте безопасность на основе собственных рисков и угроз, специфики ваших бизнес-процессов, команд и бюджетов. Идите от себя, а не так как кто-то сказал, что принято. Определите, что сейчас для вас наиболее критично, и с этого и начинайте.
K8s – это фреймворк, который дает много возможностей, способов и точек встраивания для своего расширения. Это не конкретное расширение, и его можно так закрутить под свои бизнес-процессы, необходимости и нужды, что он будет полностью удовлетворять вас: и с точки зрения доставки новых фич, и с точки зрения безопасности.
Сейчас в Kubernetes рабочая группа создает документ Observability White Paper, где говорится, что observability можно построить без логов, метрики и трейсов — трех основных столпов k8s. Главное, чтобы вы всегда понимали, в каком состоянии находится система. Имея актуальную информацию о происходящем в Kubernetes и в ваших микросервисах, вы всегда можете обеспечить и надежную, и безопасную работу.
В Kubernetes хорошие предпосылки для self-protecting. Потому что нам достаточно поймать всего один шаг атакующего, чтобы раскрутить всю цепочку. Можно раскидывать те же canary tokens, делать тригеры, запрещающие правила — атакующий в любом случае будет делать то, что обычно в вашей инфраструктуре не делается, и так или иначе себя проявит.
Максимально усложняйте атакующему путь для проникновения!
Видео моего выступления на DevOps Conf 2021:
Kubernetes: трансформация к SecDevSecOpsSec / Дмитрий Евдокимов (Luntry)