Как стать автором
Обновить

eBPF вместо всего: почему это новая эра сетей, мониторинга и безопасности?

Время на прочтение9 мин
Количество просмотров10K
Всего голосов 60: ↑60 и ↓0+73
Комментарии20

Комментарии 20

Если eBPF такой гибкий и быстрый, почему netfilter (nftables) ещё не переписали с его использованием? Вроде, есть facebook/bpfilter, но хоть его поддерживает столь крупная корпорация, всего 170 звёзд, т.е. вообще мало кто в курсе про его существование.

Там противоположное мнение, что мол переписать можно, но netfilter быстрее и эффективнее (?):

In theory it would be possible to re-implement firewalling in eBPF and bypass Netfilter, but why? Netfilter is kernel code that is far more efficient, performant, and integrated into the kernel. Writing a fully featured firewall module in eBPF is a huge waste of effort.

да я слышал про bpfilter от Facebook, он так и остался в подвешенном состоянии — его забросили, потому что впилить eBPF в классическую экосистему фильтрации оказалось не так-то просто. А netfilter (nftables) не переписывают, потому что он уже прочно впаян в сетевой стек Linux и закрывает большинство сценариев.

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


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

Хотелось бы чуть подробнее про "как свести риски к минимуму", п. 1, 2, 3. Кажется, их стоит разделить ещë на несколько.

Общие фразы понятны, но непонятно как конкретно это делать, или хотя бы ссылки бы на соответствующие статьи. Так сказать, чтобы было что-то вроде quick start в харденинге eBPF.

за харденинг ebpf отвечают несколько параметров ядра, связанных с ним, для quick start можно как раз про них почитать)

Если говорить конкретно, то минимизация рисков в eBPF начинается с жесткого ограничения прав на загрузку и выполнение кода. Например в реальных проектах всегда прописываем seccomp-профили, используем cgroup BPF для ограничения доступа к ресурсам и монтируем bpffs в режиме read-only.

Это позволяет не дать зловредному коду прорваться даже после прохождения верификатора, который, кстати, ловит лишь очевидные косяки. На этапе runtime обязательно применяем bpftool и bpftrace для отслеживания аномалий — это как наш watchdog, который сигналит, если что-то идет не так. Если нужна более конкретика, рекомендую посмотреть quick start-гайды: Security Best Practices for eBPF, Linux Kernel Documentation по eBPF. Надеюсь, такие примеры помогут разобраться, как реально настроить харденинг eBPF в продакшене.


В статье (которую писала ИИ?) явно не хватает главы "eBPF и руткиты".

Считаю нужно дополнить - без нее не канает.

eBPF - это костыль из-за того что в линуксе нет драйверной модели. А отсутствие драйверной модели - следствие того, что линукс - это монолитное ядро из 90х, на техническом уровне windows 3.х

Нужно давно было уходить от модели монолитного ядра как это сделали в Apple и Microsoft.

Почему eBPF — это революция

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

Революцией было бы уже наконец изобрести драйверную модель и перестать падать в kernel panic из-за сегфолта в коде мигания светодиодом, как это было во времена win98

Я просто не понимаю как во всем этом костыле на костылях, подпертых костылями может получиться что-то безопасное. Наверное, никак.

Где то с версии ядра 4.9 BPF verifier проверяет каждую eBPF-программу на предмет отсутствия бесконечных циклов, выхода за пределы выделенной памяти и других потенциально опасных операций. В результате кол-во аварий в ядре снизилось ~ на 80% по сравнению с версиями до, что уже говорит о повышении стабильности.

Та же Meta использует eBPF в датацентровых сетях для фильтрации пакетов на уровне XDP, снижая нагрузку на CPU на 30% за счет обхода классического сетевого стека. В Kubernetes-кластерах eBPF (например, в Cilium) обеспечивает динамическую фильтрацию трафика без overhead-а iptables, что критично для масштабируемых систем.

Linux — да, монолитное ядро, но eBPF добавляет ему гибкостьпозволяя динамически расширять функциональность без патчинга и перезагрузки, все таки уже не просто “костыль”


Затраты на освоение частного костыльного инструмента не считаем?

Где то с версии ядра 4.9 BPF verifier проверяет каждую eBPF-программу на предмет отсутствия бесконечных циклов

Интересно, с помощью какой магии оно это делает. Язык eBPF AFAIK - полный по Тьюрингу, а потому проблема останова решается в нем немного плохо :-) , то есть, никак. Но какие-то эвристики, таки да, могут оказаться полезными при отлове типичных ошибок. Только тут IMHO важно не впадать в восторженность неофита, а глядеть на вещи трезвым взглядом инженера. Например, говорить о том, что эти меры контроля смогли снизить уровень отказов в 5 раз по сравнению с неконтролируемым eBPF, но - не с отсутсвующей или выключенной этой функцией.

В Kubernetes-кластерах eBPF (например, в Cilium) обеспечивает динамическую фильтрацию трафика без overhead-а iptables, что критично для масштабируемых систем.

Есть у меня подозрение, что модули ядра, работающие с Netfilter в ядре Linux, способны обеспечить то же самое с ещё меньшими накладными расходами (например - на JIT-компиляцию). По крайней мере, WPF (это - функциональный аналог Netfilter, но для ядра Windows) callout drivers - способны. Но, видимо, реализовываь и поддерживать такие модули сложнее, особенно - с упомянутыми мной постом ранее трудностями со стандартизацией интерфейса модулей в Linux Kernel. Так что, возможно, eBPF, хоть и не революция, но оптимальный выбор для определенного круга организаций. Так это или нет - решать этим организациям.

Ну хоть кто-то не стесняется прямой речи.

Вы, так скажем, не совсем правы, потому что слишком категоричны.

eBPF - это костыль из-за того что в линуксе нет драйверной модели. А отсутствие драйверной модели - следствие того, что линукс - это монолитное ядро из 90х, на техническом уровне windows 3.х

Я не знаю, что вы называете "драйверной моделью". Если речь идет о подгружаемом внутрь ОС внешнем коде, то таковой был и Win3.x/9x тоже (помните такое название - VXD?). В Lixux внешний код, загружаемый в ядро, тоже можно было использовать, если оформить в виде модулей, ещё, как мимнимум, с конца 90-х. Правда, тогда ядро Linux не умело само грузить для себя модули, т.к. повторный вход в него был закрыт глобальным спинлоком (Big Kernel Lock, сокращенно - BKL). А потому для загрузки модулей использовался процесс пользовательского режима kerneld: он выполнял весь ввод-вывод для чтения файла модуля, загружал его содержимое в некую область памяти и сообщал ядру специальным системным вызовом, что код в этой области должен работать в режиме ядра). Так что революция в Linux - это не новость, она наступила уже тогда ;-) Правда, с тех пор инженеры IBM, которые занялись этой передовой операционной системой, избавились, наконец, в какой-то момент (где-то в самом начале нулевых) от BKL, так что ядро Linux стало способно загрузит свои модули самостоятельно, и выпилили за ненадобностью kerneld. И, кажется - тот системный вызов, который переводил область с кодом в режим ядра - так что революция тогда не состоялась :-)

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

Революцией было бы уже наконец изобрести драйверную модель и перестать падать в kernel panic из-за сегфолта в коде мигания светодиодом, как это было во времена win98

Увы, драйверная модель от этого никак не защищает: в случае возникновения ошибки в драйвере, в пространстве ядра, нет никакой гарантии, что не затронуты критические структуры ядра (например, связанные с файловой системой), а потому единственно надежный выход в такой ситуции - прекратить выполнение ОС. Ну, а уж как это оформить - как сообщение kernel panic на консоль или как известный многим синий экран (BSOD) - это вопрос эстетический. Защитить от сбоев в подсистемах ОС может только модель микроядра с выносом этих подсистем в пространство пользовательского режима. Но это оказалось слишком медленным, а потому индустрия по этому пути не пошла (хотя и пробовала).

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

Ну, это, конечно, не революция, но - удобный инструмент для решения специфических задач: все-таки интерпретируемый код на специальном языке писать и контролировать легче, чем полноценный модуль/драйвер на C. И, таки да, разработчики Linux были не первыми: в браузеры интерпретаторы кода пытались затащить, причем - не однажды (правда, там оно как-то плохо прижилось).

Увы, драйверная модель от этого никак не защищает: в случае возникновения ошибки в драйвере, в пространстве ядра, нет никакой гарантии, что не затронуты критические структуры ядра (например, связанные с файловой системой), а потому единственно надежный выход в такой ситуции - прекратить выполнение ОС. Ну, а уж как это оформить - как сообщение kernel panic на консоль или как известный многим синий экран (BSOD) - это вопрос эстетический.

Почему вы умалчиваете что операционных системах 21 века есть поддержка драйверов в userspace? Еще во времена win 9x стало понятно что падать всей системой из-за сегфолта в минорной подсистеме - плохо.

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

Ложь. Драйвера в юзерспейсе как раз работают быстрее из-за того что в них нет ненужного копирования памяти userspace <-> ядро. И не надо виртуальную машину с интерпретатором байткода в ядро засовывать.

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

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

И, таки да, разработчики Linux были не первыми: в браузеры интерпретаторы кода пытались затащить, причем - не однажды (правда, там оно как-то плохо прижилось).

Что? В браузерах давно есть JavaScript. И WebAssembly если нужен перф.

Бинарная совместимость между ядрами - это межгалактические технологии для этого ядра из прошлого века.

Вроде ж это намеренная фича потому что драйвера должны быть в исходниках а лучше - в ядре и не проблема пересобрать а отсутствие стабильных интерфейсов позволяет упростить разработку и вообще - вы еще скажите что все что EXPORT_SYMBOL_GPL тоже должно быть в стабильном интерфейсе :)

А реально - гугл более менее решает проблему с этим для андроида, из-за того КАК пишутся драйвера под андроид и КАК они обновляются и почему (см https://medium.com/@turbojedi/почему-мой-телефон-не-обновится-до-нового-андроеда-e4cd5fa3fa85 например)

Почему вы умалчиваете что операционных системах 21 века есть поддержка драйверов в userspace?

А почему вы спрашиваете? Как будто, "за косяк", как это принято у обитателей "Дома Нашего Общего", по "понятиям" живущих? Откуда обвинительный уклон? Почему вы не сформулировали вопрос нейтрально: "Почему вы не указали..." и далее по тексту?
Вот на такой вопрос я ответить могу. Автор статьи специально обращает внимание на то, что код eBPF выполняется в режиме ядра, как на преимущество, позволяющее не терять производительность. Потому в контексте статьи драйверы в режиме пользователя обсуждать незачем.

Посмеялся в голос сейчас.

Любителям таких аргументов я всегда напоминаю русскую пословицу "Смех без причины - признак дурачины". Вам что, нравится выглядеть дурачиной, раз вы не стесняетесь таких, типа, аргументов?

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

Ну, для мира Unix, откуда Linux родом, это нормально. Ещё Эд Пост более 40 лет назад писал про Unix в своей известной статье: "the typical Unix hacker never can remember what the PRINT command is called this week" (точно я перевести затрудняюсь, но, надеюсь, смысл вы поняли).
А вообще, мне лично вполне по силам взять и подправить модуль под новые сигнатуры вызываемых им функций. Более того, мне иногда за подобную деятельность деньги платят (ну, программист я, хоть и не настоящий, про которых Эд Пост писал). Так что лично у меня возможность - есть.
И, кстати, зря вы так пренебрежительно относитсь к прошлому веку. Хотя бы потому, что ядро Windows - оно тоже из прошлого века родом: это - эволюционное развитие архитектурных решений, принятых группой разработки NT в начале 1990-х годов.

Нужно давно было уходить от модели монолитного ядра как это сделали в Apple и Microsoft.

И как там, уже ушли? Теперь там замечательные драйвера ко всему в драйверной модели, но только те, которые дозволены вендором, когда он соизволил подписать драйвер? Шоб вам так жить.

Из последнего: https://www.opennet.ru/opennews/art.shtml?num=62942 Теперь уже и светодиодиком вообще не помигать. Лучше пусть у меня будет возможность помигать, пусть и с сегфолтом.

У меня в компании eBPF основа мониторинга и оптимизации. Однажды словили жесткий инцидент: кто-то загрузил кастомную eBPF-прогу, которая обошла верификатор и начала подглядывать за трафиком. Заподозрили неладное, когда bpftool и bpftrace показали резкий рост событий, а bpffs внезапно стал активнее обычного. В итоге копнули глубже — bpffs был с правами записи, а cgroup BPF и seccomp недонастроены. Сразу зарезали bpffs в read-only, подкрутили cgroup BPF и жестко фильтранули syscalls через seccomp. После этого дыры закрылись, но осадочек остался. Кто-нибудь еще нарывался на такое?

Зарегистрируйтесь на Хабре, чтобы оставить комментарий