Pull to refresh

Comments 18

Distroless контенеры - поправьте заголовок пожалуйста

Сложно отлаживать. Нельзя просто зайти в shell на контейнере (на pod) и выполнить команды. Не конфиг посмотреть! Даже ps не сделать.

Достаточно получить PID процесса в контейнере, и в его пространствах имен можно запускать программы с хоста. Например, для Docker:


sudo nsenter -p -t $(docker inspect -f '{{ .State.Pid }}' $container) ps
sudo nsenter -n -t $(docker inspect -f '{{ .State.Pid }}' $container) ss -tnlp

Файлы контейнера доступны через /proc/$PID/root. Не очень актуально для distroless, но в обычных контейнерах так удобно редактировать файлы.

Спасибо! Отличная утилита. Я про нее не знал. Посмотрю поподробнее.

UFO landed and left these words here

Подéлитесь удачным опытом?


Если делать контейнер на базе NixOS, он получается не меньше и не факт, что безопаснее. Во-первых, пакеты деривации в nixpkgs не принято разбивать. Во-вторых, хотя в PATH не будет шелла, если его не попросить, он может быть подтянут в контейнер ради скрипта-обертки, которые в nixpkgs повсюду. Например, образ с clang и LLVM на базе Debian у меня получался около 900 МБ (и можно было чуть ужать), а с NixOS выходило около 1,5 ГБ. Можно было бы пересобирать зависимости, чтобы уменьшить размер, но это трудозатраты.

UFO landed and left these words here

Спасибо, хороший пример.


Отдельные outputs для dev, bin и lib — это не то же, что разбиение пакетов для минимизации зависимостей. Например, openssl.bin притащит за собой Perl ради скрипта c_rehash, а вот в Alpine скрипт разумно вынесли в другой пакет. Или DPDK, из десятков библиотек которого обычно нужна лишь малая часть, в nixpkgs сделан одной деривацией, а в Debian библиотеки вынесены в свои пакеты. Да, в nix подрихтовать деривации проще, чем пакеты в других дистрибутивах, но все равно надо разбираться в самой деривации и системе сборки, иногда выходит грязь.

Тем не менее, Distroless контейнеры далеко не всегда так безопасны, как кажутся. https://www.form3.tech/engineering/content/exploiting-distroless-images

Вот статья о методиках взлома контейнера от Google. Сам гугл не признает это уязвимостью и исправлять это не будет...

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

Да! Есть довольно много критики distroless именно в области безопасности. Скажем так нельзя считать их безопасными просто по факту.

Ссылка с методиками взлома контейнера для меня выглядит высосанной из пальца. Может я что не понимаю, но для доступа к openssl уже должна быть RCE в приложении или утечка доступа к exec контейнера - как при таких проблемах сможет помочь способ сборки image. На этот момент песенка уже спета, разве нет? Все что можно сделать - усложнить поиск payload, что и делает distroless подход

Сложно отлаживать. Нельзя просто зайти в shell на контейнере (на pod) и выполнить команды. Не конфиг посмотреть! Даже ps не сделать.

В версии кубера 1.25 выкатили - Ephemeral Containers. Как раз для дебага distroless based контейнеров в поде, с монтированием файловой системы etc etc. В ранних версиях куба, (1.23 проверял) можно активировать как future-feature.

Дебаг отдельная тема - достойна еще одной статьи ;).

Знать, что ты Совершенство, знать, что ты Идеал? Может просто обернуться к lxc?

Если говорить о .net, какие преимущества от контейнера можно получить в сравнении с обычным приложением опубликованным как self-hosted? В ряде случаев я могу понять удобство контейнеров (приложения на python или чем то подобном где так и не смогли победить проблему dll hell, а точнее package hell, или предподготовленные сборки со сложной конфигурацией). Но в случае .net, где нет проблем с версионностью библиотек, пока не могу найти ни одного плюса от них. По тестам, контейнеры еще и дают 2-5% падение производительности.

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

Я думаю основной плюс контейнеризации это их оркестрация, разве нет? Сварм Кубер etc всё это очень удобно. CI/CD опять же проще. Сервис же он не один .net приложение, с ним может поставляться куча инфраструктуры

Достаточно написать FROM scratch в Dockerfile и мы получим абсолютно пустую файловую систему и сможем запустить свою программу без файлов вообще.

Есть у меня большие сомнения, что вы пробовали это сделать ))
А я попробовал - нужен как минимум линкер (без него docker жалуется, что ваш executable файл вообще не найден)
Если уже добавлен линкер, то тогда система будет уже вразумительно ругаться на отсуутсвующие dll-ки.

Вот пример моего минимального образа. Здесь minimal-hello - это c-шный hello-world собранный статически (вроде, судя по настройкам в Eclipse, но... мог здесь и налажать)

FROM scratch

ADD minimal-hello /

# linker
ADD sys_linux_root/lib64/ld-linux-x86-64.so.2 /lib64/

# Standard C lib
ADD sys_linux_root/usr/lib/x86_64-linux-gnu/libc.so.6 /usr/lib/x86_64-linux-gnu/

CMD ["./minimal-hello"]

А вот немножко больший образ

FROM scratch

ADD minimal-hello /

# optional
ADD sys_linux_root/bin/* /bin/

#
# Required for ANY minimal executables
#  * dynamic linker
ADD sys_linux_root/lib64/ld-linux-x86-64.so.2 /lib64/

# Standard C lib
ADD sys_linux_root/usr/lib/x86_64-linux-gnu/libc.so.6 /usr/lib/x86_64-linux-gnu/

# Additional libs fo ls/sh/bash
ADD sys_linux_root/usr/lib/x86_64-linux-gnu/* /usr/lib/x86_64-linux-gnu/

# Some data files
COPY hello.txt /
COPY hello.txt /hello-002.txt

CMD ["./minimal-hello"]

Содержимое моего sys_linux_root.
Здесь bash, cat, sleep, ls, sh просто, чтобы поиграться и дополнительные ddl-ки, нужные им или программам, которые делают хоть что-то полезное. Все эти файлы скопированы просто с моего текущего линукса.

.
├── bin
│   ├── bash
│   ├── cat
│   ├── ls
│   ├── sh
│   └── sleep
├── lib64
│   └── ld-linux-x86-64.so.2
└── usr
    └── lib
        └── x86_64-linux-gnu
            ├── libc.so.6
            ├── libdl.so.2
            ├── libpcre2-8.so.0
            ├── libpthread-2.31.so
            ├── libpthread.so
            ├── libpthread.so.0
            ├── libselinux.so.1
            └── libtinfo.so.6

Если кто-то умудрился сделать образ даже без линкера, то будет интересно послушать.

PS: Жду минусов, как обычно ))

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

FROM alpine AS build

WORKDIR /static

RUN apk add build-base

COPY hello.c .

RUN gcc -o hello --static hello.c

FROM scratch

COPY --from=build /static/hello /

CMD [ "/hello" ]

Тогда все заработает. В этом бинаре нет ни одного динамического символа, только syscall в ядро с которыми и работает докер.
Конечно мой пример супер прост как только вы например подключите стандартную библиотеку вам понадобится куча возможностей системы и с ними файлы конфигурации. Например /etc/passwd для определения текущего пользователя, сертификаты для web и тп.
При подготовки статьи я не проверял вся на c я проверил все только на go. Go умеет делать все статическим по этому там такое сильно проще. Чтобы не проверять пример я нашел его в интернете: https://github.com/jeremyhuiskamp/golang-docker-scratch/blob/main/Dockerfile обратите внимание на 14 строку там копируются сертификаты .
Спасибо за вопрос!

Sign up to leave a comment.

Articles