Debian.pro/

Про Debian


Заруливаем локального пользователя в изолированную среду. Jailkit.

Достаточно часто меня просят сделать пользователя на сервере с доступом «только к хомяку». Частенько, всем хватает либо vsftpd, либо chroot’a в sftp. Но есть и те, кто хочет, чтобы у пользователя осталась возможность попадать в shell и редактировать файлики из консоли + запускать простейшие утилиты (да и тот же git, хотя бы). Но при всём этом — не выходить за пределы своей песочницы.

Сама по себе задача не то, чтобы тривиальная. Для того, чтобы пользователь смог запустить хотя бы bash — у него должен быть доступ ко всем нужным библиотекам (и к бинарнику, конечно). Это, в общем-то, делает невозможным вход по ssh, если у пользователя chroot его хомяк. И, опять же, если не ограничивать пользователя отдельным каталогом — он может почитать логи, посмотреть некоторые конфиги. А если системный администратор недостаточно опытный — то и получить доступ к сертификатам, скриптам с паролями и так далее. В общем, засада, казалось бы.

Когда-то году в 2005м я наткнулся на утилиту, которая делала ровно то, что мне нужно. Поигрался с ней. Да и забыл название. С тех пор много воды утекло, я узнал много нового. Когда передо мной снова возникла подобная задача, недолго думая я сделал отдельный chroot (при помощи debootstrap), поднял в нём sshd на отдельном порту, нужные каталоги смонтировал с —bind в основной системе… И года 3 потом меня не покидало чувство костыльности, каждый раз, когда я делал такое (а уж поверьте, сделал я таких чрутов много!). И вот, (тут должно быть «в алкогольном угаре», но я уже не пил к тому моменту) в январе этого года я хлопнул себя по лбу и вспомнил про эту утилиту. Я точно помнил, что она делала, но в упор не помнил, как называлась. Полгода неторопливых поисков, ковыряний гугла разными запросами, и вуаля — я наткнулся на jailkit. На самом деле, в 2005м я пользовался не им, ну да пофиг — делает он ровно то же самое =)

В чём суть. Один из бинарников jailkit’a прописывается пользователю в качестве шелла. При авторизации пользователя его автоматически chroot’ит в отдельный каталог (при том всё это происходит внутри контекста основной ОС, например — в «основном» sshd). В этот каталог при помощи специальной утилитки собираются нужные пользователю бинарники и библиотеки. Тут палка о двух концах — с одной стороны, мы очень четко ограничиваем список запускаемых пользователями утилит. С другой — каждый бинарник придется добавлять отдельно. В целом, меня такой вариант устроил (конечно же, уже давно есть список бинарников, по которому я for’ом пробегаюсь) и забытое знание снова уютненько устроилось в моей голове. На самом деле, если вы представляете, как работает linux — эта утилита охрененна.

Сам jailkit живет здесь. Официально собираемых deb-пакетов нет, поэтому будем собирать сами.

Ставим нужные для сборки пакеты:

root@server:~# apt-get install checkinstall

Скачиваем последнюю версию отсюда. На момент написания это выглядело так:

root@server:~# wget http://olivier.sessink.nl/jailkit/jailkit-2.16.tar.gz

Распаковываем, собираем:

root@server:~# tar -xvf jailkit-2.16.tar.gz
root@server:~# cd jailkit-2.16/
root@server:~# ./configure
root@server:~# make
root@server:~# checkinstall --pkgname jailkit --pkgversion 2.16

На wheezy оно сразу само поставилось, на squeeze нужно руками создать папку:

root@server:~# mkdir /etc/jailkit

И доставить пакет:

root@server:~# dpkg -i jailkit_2.16-1_amd64.deb

После установки можно начинать делать jail-ы. Для начала небольшие пояснения. В один jail можно заруливать сколько угодно пользователей (а не 1 пользователь = 1 jail). Любой бинарник, запущенный пользователем заворачивается в вызов chroot() со всеми вытекающими (на древних ядрах такой вызов без проблем обходился, кстати). На современных ядрах обойти его достаточно тяжело (если внутри чрута не окажется инструментов для разработки — gcc того же). Каждый бинарник, который нужно запускать пользователю нужно добавлять в его jail отдельно. Либо ставить туда пакеты (про это тоже напишу попозже). Файлы в jail-е не обновляются автоматически после установки пакетов в основной системе, но есть команда, которая делает это. Вооот. Если ещё не напугал вас непонятными словами — продолжаем.

Условимся, что у нас будет пользователь jailuser1.
Создаём каталог, где будут жить jail-ы (и сразу каталог под одну из них):

root@server:~# mkdir -p /jails/jailuser1

Инициилизируем jail в этом каталоге (по умолчанию даём возможность пользователю заходить туда по sftp и копировать туда/оттуда файлы через scp):

root@server:~# jk_init -v -j /jails/jailuser1/ sftp scp

Разрешим обитателям этого jail’a попадать в shell:

root@server:~# jk_init -j /jails/jailuser1/ jk_lsh

Создадим пользователя, если он ещё не существует:

root@server:~# useradd -d /home/jailuser1 -m jailuser1 -s /bin/bash #(либо любой другой подходящей вам командой)

«Сообщим» системе, что пользователь должен быть ущербным и чрутиться в /jails/jailuser1 сразу после входа:

root@server:~# jk_jailuser -m -j /jails/jailuser1/ jailuser1

Проверим, изменился ли shell у пользователя:

root@server:~# cat /etc/passwd | grep "^jailuser1"
jailuser1:x:1000:1000:,,,:/jails/jailuser1/./home/jailuser1:/usr/sbin/jk_chrootsh

Ещё пользователю в jail-е не помешает возможность запускать шелл и вообще терминал (здесь табличка «Sarcasm!») — на самом деле, иначе нихрена работать не будет:

root@server:~# jk_init -j /jails/jailuser1/ basicshell
root@server:~# jk_init -j /jails/jailuser1/ extendedshell
root@server:~# jk_cp -v -f /jails/jailuser1/ /bin/bash

В целом, на этом jail готов, за исключением одного но — пользователь всё ещё не может залогиниться и что-то поделать. Для исправления этого недоразумения есть 2 пути:
1) геморройный, но правильный и безопасный — насторить jk_lsh внутри jail-a
2) прописать внутри jail-a пользователю shell /bin/bash. Это всё ещё будет bash внутри chroot, но это позволит пользователю выполнять любые бинарники внутри него (в том числе и те, которые он сам притащит туда).

Второе сделать очень легко — в файле /jails/jailuser1/etc/passwd нужно заменить /usr/sbin/jk_lsh на /bin/bash в строке нужного нам пользователя.
Первое же достаточно нетривиально — нужно написать правильный конфиг в /jail/jailuser1/etc/jailkit/kj_lsh.ini и в качестве шелла пользователю выставить, например, /usr/bin/jk_lsh -c /bin/bash. Чтобы описать это — нужно написать целый трактат. Если вкратце, то в этом конфиге нужно указать, какие конкретно бинарники может запускать пользователь — остальные не сможет.

Воот. Ну и на закуску докидаем пользователю ещё немного утилит, чтобы ему было нескучно.
Например, netutils (wget, rsync and etc):

root@server:~# jk_init -f -v -j /jails/jailuser1/ netutils

Ну и git какой-нибудь:

root@server:~# jk_cp -v -f /jails/jailuser1/ /usr/bin/git

Как видите, я использовал команды jk_init и jk_cp. jk_init копирует бинарники и их зависимости по шаблонам, которые описываются в файле /etc/jailkit/jk_init.ini. jk_cp же копирует конкретный бинарник и нужные ему библиотеки (которые он выдергивает при помощи ldd). Если вам нужно разрешить запускать какой-либо скрипт внутри jail-a — то придется сделать jk_cp на все бинарники, которые используются внутри скрипта.

Ну и напоследок. Если вы в основной системе обновите какие-либо пакеты, то стоит запустить такую команду:

root@server:~# jk_update -j /jails/jailuser1/

Эта команда пробежится по jail-у и проверит, что файлы в основной системе не стали новее тех, которые есть в jail (оно не завязано на пакетный менеджер, а просто проверяет mtime для файлов).

Ну и напоследок:

root@server:~# passwd jailuser1

Теперь пользователем можно войти по ssh, а не только через su от рута.

На этом вроде всё, основное сделали.
Ах да, всё, чем нагадит пользователь из основной системы видно так же, как и с обычными chroot-ами.


Комментарии (11):

  1. yukra :

    >На современных ядрах обойти его достаточно тяжело (если внутри чрута не окажется инструментов для разработки — gcc того же)
    Тык, сам ведь пишешь что пользователь может притащить его с собой. Выходит второй путь может притормозить пользователя, а не остановить. Или тут все по другому?

  2. yukra :

    Влад, ты переехал из Москвы? что у тебя с часовым поясом?

  3. > Влад, ты переехал из Москвы? что у тебя с часовым поясом?
    Баг в wp =)
    Поправлю, когда не лень будет.

  4. > Тык, сам ведь пишешь что пользователь может притащить его с собой.
    Ну притащить что-то в духе gcc не так легко с собой.
    К тому же, если не давать /bin/bash, а писать нормальный конфиг для jk_lsh — хрен у него чего выйдет запустить =)

  5. Само собой, это не панацея — если поставить цель именно поломать — то всё у них получится. Но для этого нужно очень и очень неплохо понимать, как устроены никсы. Так что вся эта конструкция обеспечивает вполне неплохой уровень абстракции от основной системы.

    А панацеи нет — даже в KVM известные дырки есть, позволяющие выйти из виртуалки. Чего уж тут говорить про работу в контексте того же ядра.

  6. Василий :

    Все настроил, получилось! Только вот столкнулся с такой неудобной ситуацией: Я добавил нового пользователя в системе только для SFTP (То есть обычный пользователь не входящий в jail), в файле конфигурации sshd_config закомментировал строку «#Subsystem sftp /usr/lib/openssh/sftp-server» и указал «Subsystem sftp internal-sftp» новый пользователь отлично входил в систему по SFTP. А вот тот пользователь, что в jail, заимел возможность выходить за рамки свой абстракционной системы и читать все файлы системы через SFTP. Есть варианты как этого избежать?

  7. Василий :

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

  8. Сергей :

    apt-get install checkinstall
    Чтение списков пакетов… Готово
    Построение дерева зависимостей
    Чтение информации о состоянии… Готово
    E: Невозможно найти пакет checkinstall

    uname -a
    Linux 241443.local 4.19.0-5-amd64 #1 SMP Debian 4.19.37-5+deb10u1 (2019-07-19) x86_64 GNU/Linux

  9. Он в бастере есть почему-то только в backports — https://packages.debian.org/search?suite=buster-backports&searchon=names&keywords=checkinstall
    При том в sid-е есть в штатных репозиториях.

  10. Сергей :

    Спасибо

Написать комментарий