Достаточно часто меня просят сделать пользователя на сервере с доступом «только к хомяку». Частенько, всем хватает либо 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-пакетов нет, поэтому будем собирать сами.
Ставим нужные для сборки пакеты:
Скачиваем последнюю версию отсюда. На момент написания это выглядело так:
Распаковываем, собираем:
На wheezy оно сразу само поставилось, на squeeze нужно руками создать папку:
И доставить пакет:
После установки можно начинать делать jail-ы. Для начала небольшие пояснения. В один jail можно заруливать сколько угодно пользователей (а не 1 пользователь = 1 jail). Любой бинарник, запущенный пользователем заворачивается в вызов chroot() со всеми вытекающими (на древних ядрах такой вызов без проблем обходился, кстати). На современных ядрах обойти его достаточно тяжело (если внутри чрута не окажется инструментов для разработки — gcc того же). Каждый бинарник, который нужно запускать пользователю нужно добавлять в его jail отдельно. Либо ставить туда пакеты (про это тоже напишу попозже). Файлы в jail-е не обновляются автоматически после установки пакетов в основной системе, но есть команда, которая делает это. Вооот. Если ещё не напугал вас непонятными словами — продолжаем.
Условимся, что у нас будет пользователь jailuser1.
Создаём каталог, где будут жить jail-ы (и сразу каталог под одну из них):
Инициилизируем jail в этом каталоге (по умолчанию даём возможность пользователю заходить туда по sftp и копировать туда/оттуда файлы через scp):
Разрешим обитателям этого jail’a попадать в shell:
Создадим пользователя, если он ещё не существует:
«Сообщим» системе, что пользователь должен быть ущербным и чрутиться в /jails/jailuser1 сразу после входа:
Проверим, изменился ли shell у пользователя:
jailuser1:x:1000:1000:,,,:/jails/jailuser1/./home/jailuser1:/usr/sbin/jk_chrootsh
Ещё пользователю в jail-е не помешает возможность запускать шелл и вообще терминал (здесь табличка «Sarcasm!») — на самом деле, иначе нихрена работать не будет:
В целом, на этом 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):
Ну и git какой-нибудь:
Как видите, я использовал команды jk_init и jk_cp. jk_init копирует бинарники и их зависимости по шаблонам, которые описываются в файле /etc/jailkit/jk_init.ini. jk_cp же копирует конкретный бинарник и нужные ему библиотеки (которые он выдергивает при помощи ldd). Если вам нужно разрешить запускать какой-либо скрипт внутри jail-a — то придется сделать jk_cp на все бинарники, которые используются внутри скрипта.
Ну и напоследок. Если вы в основной системе обновите какие-либо пакеты, то стоит запустить такую команду:
Эта команда пробежится по jail-у и проверит, что файлы в основной системе не стали новее тех, которые есть в jail (оно не завязано на пакетный менеджер, а просто проверяет mtime для файлов).
Ну и напоследок:
Теперь пользователем можно войти по ssh, а не только через su от рута.
На этом вроде всё, основное сделали.
Ах да, всё, чем нагадит пользователь из основной системы видно так же, как и с обычными chroot-ами.
>На современных ядрах обойти его достаточно тяжело (если внутри чрута не окажется инструментов для разработки — gcc того же)
Тык, сам ведь пишешь что пользователь может притащить его с собой. Выходит второй путь может притормозить пользователя, а не остановить. Или тут все по другому?
Влад, ты переехал из Москвы? что у тебя с часовым поясом?
> Влад, ты переехал из Москвы? что у тебя с часовым поясом?
Баг в wp =)
Поправлю, когда не лень будет.
> Тык, сам ведь пишешь что пользователь может притащить его с собой.
Ну притащить что-то в духе gcc не так легко с собой.
К тому же, если не давать /bin/bash, а писать нормальный конфиг для jk_lsh — хрен у него чего выйдет запустить =)
Само собой, это не панацея — если поставить цель именно поломать — то всё у них получится. Но для этого нужно очень и очень неплохо понимать, как устроены никсы. Так что вся эта конструкция обеспечивает вполне неплохой уровень абстракции от основной системы.
А панацеи нет — даже в KVM известные дырки есть, позволяющие выйти из виртуалки. Чего уж тут говорить про работу в контексте того же ядра.
Все настроил, получилось! Только вот столкнулся с такой неудобной ситуацией: Я добавил нового пользователя в системе только для SFTP (То есть обычный пользователь не входящий в jail), в файле конфигурации sshd_config закомментировал строку «#Subsystem sftp /usr/lib/openssh/sftp-server» и указал «Subsystem sftp internal-sftp» новый пользователь отлично входил в систему по SFTP. А вот тот пользователь, что в jail, заимел возможность выходить за рамки свой абстракционной системы и читать все файлы системы через SFTP. Есть варианты как этого избежать?
https://debian.pro/24
https://debian.pro/1915
Спасибо большое! Стоит перечитать весь ваш блог, зачем другие делают такие отвратительные мануалы — непонятно.
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
Он в бастере есть почему-то только в backports — https://packages.debian.org/search?suite=buster-backports&searchon=names&keywords=checkinstall
При том в sid-е есть в штатных репозиториях.
Спасибо