Сборка nginx и php-fpm в bootstrap и установка в chroot

от автора

Продолжаем веселье. Я админ локалхоста и у меня нет денег на воздуххостинг. На хостинге мне было бы абсолютно все равно: плюя в потолок, делаешь себе бекапы, а когда тебя взламывают — сохраняешь логи, чтобы изучить в чем была проблема, полностью переустанавливаешь систему (берешь из последнего рабочего бекапа) и исправляешь ошибки. За сим все.

Локалхост же — семейная машина, частые переустановки здесь недопустимы, и чтобы тебя взломали, сделав частью своего ботнета, также недопустимо. Тем не менее, желание поковырять собственный веб-сайт есть, поэтому я хочу максимально оградить от основной рабочей системы все, что потенциально опасно и смотрит наружу.

Под хабракатом:

  • Сборка базовой ОС Linux в отдельную директорию;
  • Сборка nginx и php-fpm в «чистом» Linux;
  • Сборка chroot окружения для установки nginx и php-fpm.

Сборка Arch Linux

По правде говоря этот этап можно пропустить, но когда я впервые собирал софт из исходников, столкнулся с неприятной проблемой: autoconf любит подхватывать опциональные зависимости, которые уже установлены в системе, а чтобы собрать программу без них, приходится собственноручно указывать —disable-*, —without-*. Все бы ничего, если бы я знал из чего состоит моя система, но к сожалению у меня не LFS, опциональная зависимость может быть удалена когда-нибудь, и потом… что? Программа перестает работать. Придется пересобрать ее еще раз!
Чтобы такого не происходило, я ставлю bootstrap: грубо говоря, это отдельная, полностью рабочая система Linux с минимум пакетов, но лишь установленная в какую-то директорию. И когда вы в chroot’е будете собирать софт, опциональные зависимости не будут подхвачены autoconf — их попросту нет в нашем bootstrap, и вы получите чистую программу без лишних зависимостей.

Я плохо знаю nginx, php-fpm, — какие они опциональные зависимости могут подхватить, а может их вообще нет и они собираются, что называется, standalone, но моя задача не углубляясь в такие (читай: не нужные) тонкости, просто собрать программы, чтобы они работали в любом окружении, и не просили лишнего.

Скачаем уже готовый скрипт, который в любой системе (требуются: coreutils, wget, sed, gawk, tar, gzip, chroot, xz) соберет Arch Linux в отдельную директорию.

# wget http://tokland.googlecode.com/svn/trunk/archlinux/arch-bootstrap.sh
# chmod +x arch-bootstrap.sh

Соберем самую базу в /usr/local

# ./arch-bootstrap.sh /usr/local/arch-bootstrap

В нее будут скачаны и распакованы лишь самые небходимые для работы pacman пакеты. Теперь chroot’нимся в нее.

# mount -t proc none /usr/local/proc
# mount -t sysfs none /usr/local/sys
# mount -o bind /dev /usr/local/dev
# mount -o bind /dev/pts /usr/local/dev/pts

# chroot /usr/local /bin/bash

Настроим pacman (пакетный менеджер в Arch Linux) и установим базовую систему. Выполнение первой команды может занять некоторое время, будьте терпеливы.

# pacman-key --init
# pacman-key --populate archlinux
# pacman -S base base-devel libxml2

Все. Мы получили самый обычный Arch Linux, установленный в /usr/local/arch-bootstrap.

Сборка nginx и php-fpm

Находясь в свежеустановленной системе приступим к сборке и настройке nginx и php-fpm из исходников.

nginx

Соберем nginx и установим в /nginx (поскольку мы в bootstrap, то на самом деле будет установлено в /usr/local/arch-bootstrap/nginx)

# curl -O http://nginx.org/download/nginx-1.3.13.tar.gz
# curl -O https://www.openssl.org/source/openssl-1.0.1e.tar.gz
# curl -O ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.32.tar.bz2
# curl -O http://zlib.net/zlib-1.2.7.tar.gz

# tar xf nginx-1.3.13.tar.gz
# tar xf openssl-1.0.1e.tar.gz
# tar xf pcre-8.32.tar.bz2
# tar xf zlib-1.2.7.tar.gz

# cd nginx-1.3.13

# ./configure --user="http" --group="http" --with-file-aio --with-ipv6 --with-openssl="../openssl-1.0.1e" --with-http_ssl_module --with-pcre="../pcre-8.32" --with-pcre-jit --with-zlib="../zlib-1.2.7" --with-http_gzip_static_module

# mkdir /nginx
# make
# make DESTDIR="/nginx" install

php-fpm

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

# curl -O http://www.php.net/distributions/php-5.4.12.tar.bz2

# tar xf php-5.4.12.tar.bz2

# cd php-5.4.12

# ./configure --enable-fpm --with-fpm-user="http" --with-fpm-group="http" --disable-cli

# make

Устанавливать никуда не будем, а в директории ./sapi/fpm мы найдем весь наш php-fpm готовый к работе.

Сборка chroot окружения

^D (или exit) из нашего arch-bootstrap и попадаем в /usr/local.

# mkdir w3
# cd w3

Сюда же мы установим веб-сервер с php и дособерем необходимый мимимум системы для их работы.

# cp -a /usr/local/arch-bootstrap/nginx/* .

# mkdir -p ./usr/local/{sbin,etc,var{,/log}}
# cp /usr/local/arch-bootstrap/root/php-5.4.12/sapi/fpm/php-fpm ./usr/local/sbin/
# cp /usr/local/arch-bootstrap/root/php-5.4.12/sapi/fpm/php-fpm.conf ./usr/local/etc/

Теперь, неглядя копипастя, собираем систему в chroot.

# mkdir "./dev"
# mknod -m 0666 "./dev/null" c 1 3
# mknod -m 0666 "./dev/random" c 1 8
# mknod -m 0444 "./dev/urandom" c 1 9

# mkdir "./etc"
# touch "./etc/shells"

# echo "http:x:33:" >> "./etc/group"
# echo "nobody:x:99:" >> "./etc/group"

# echo "http:x:33:33:http:/:/bin/false" >> "./etc/passwd"
# echo "nobody:x:99:99:nobody:/:/bin/false" >> "./etc/passwd"

# echo "http:x:14871::::::" >> "./etc/shadow"
# echo "nobody:x:14871::::::" >> "./etc/shadow"

# echo "http:::" >> "./etc/gshadow"
# echo "nobody:::" >> "./etc/gshadow"

# mkdir "./usr/lib"

# cp "/usr/local/arch-bootstrap/usr/lib/libnss_"* "./usr/lib"

# ln -s "usr/lib" "./lib"

# for lib in $(ldd "./usr/local/nginx/sbin/nginx" | grep -o "[^ ]*\/lib[^ ]*"); do cp "/usr/local/arch-bootstrap/${lib}" ".${lib}"; done

# for lib in $(ldd "./usr/local/sbin/php-fpm" | grep -o "[^ ]*\/lib[^ ]*"); do cp "/usr/local/arch-bootstrap/${lib}" ".${lib}"; done

# mkdir "./usr/local/nginx/client_body_temp"
# mkdir "./usr/local/nginx/proxy_temp"
# mkdir "./usr/local/nginx/scgi_temp"
# mkdir "./usr/local/nginx/uwsgi_temp"
# mkdir "./usr/local/nginx/fastcgi_temp"

# mkdir "./tmp"

# chown -R "root:root" "."

# chown -R "http:http" "./usr/local/nginx/html"
# chown -R "http:http" "./usr/local/nginx/logs"

# chown "http:http" "./usr/local/nginx/client_body_temp"
# chown "http:http" "./usr/local/nginx/proxy_temp"
# chown "http:http" "./usr/local/nginx/scgi_temp"
# chown "http:http" "./usr/local/nginx/uwsgi_temp"
# chown "http:http" "./usr/local/nginx/fastcgi_temp"

# setcap "cap_net_bind_service=+ep" "./usr/local/nginx/sbin/nginx"

Система с одним лишь веб-сервером и php на борту собрана.

Заключение

Запускаем оба сервиса, без прав root.

# /usr/bin/chroot --userspec=http:http /usr/local/w3 /usr/local/nginx/sbin/nginx

# /usr/bin/chroot --userspec=http:http /usr/local/w3 /usr/local/sbin/php-fpm

Можно проверить, что все работает, традиционным <?php phpinfo(); ?>

image

Когда взломщик через какую-либо ошибку в php-движке сайта доберется до системы, он увидит такую картину:

Скрытый текст

./etc
./etc/shadow
./etc/shells
./etc/gshadow
./etc/passwd
./etc/group
./dev
./dev/urandom
./dev/null
./dev/random
./lib
./tmp
./usr
./usr/lib
./usr/lib/libnss_files-2.17.so
./usr/lib/libnss_myhostname.so.2
./usr/lib/libnss_nis-2.17.so
./usr/lib/libxml2.so.2
./usr/lib/libnss_hesiod-2.17.so
./usr/lib/ld-linux.so.2
./usr/lib/librt.so.1
./usr/lib/libpthread.so.0
./usr/lib/libnss_db.so.2
./usr/lib/libnss_nisplus.so
./usr/lib/libnsl.so.1
./usr/lib/libnss_hesiod.so.2
./usr/lib/libnss_db-2.17.so
./usr/lib/liblzma.so.5
./usr/lib/libnss_dns.so
./usr/lib/libnss_compat-2.17.so
./usr/lib/libresolv.so.2
./usr/lib/libnss_files.so
./usr/lib/libz.so.1
./usr/lib/libm.so.6
./usr/lib/libnss_dns-2.17.so
./usr/lib/libnss_nis.so
./usr/lib/libnss_nis.so.2
./usr/lib/libdl.so.2
./usr/lib/libnss_compat.so
./usr/lib/libc.so.6
./usr/lib/libnss_dns.so.2
./usr/lib/libnss_db.so
./usr/lib/libcrypt.so.1
./usr/lib/libnss_compat.so.2
./usr/lib/libnss_hesiod.so
./usr/lib/libnss_files.so.2
./usr/lib/libnss_nisplus.so.2
./usr/lib/libnss_nisplus-2.17.so
./usr/local
./usr/local/etc
./usr/local/etc/php-fpm.conf
./usr/local/nginx
./usr/local/nginx/client_body_temp
./usr/local/nginx/proxy_temp
./usr/local/nginx/html
./usr/local/nginx/html/index.html
./usr/local/nginx/html/50x.html
./usr/local/nginx/html/index.php
./usr/local/nginx/logs
./usr/local/nginx/logs/access.log
./usr/local/nginx/logs/nginx.pid
./usr/local/nginx/logs/error.log
./usr/local/nginx/conf
./usr/local/nginx/conf/koi-win
./usr/local/nginx/conf/uwsgi_params
./usr/local/nginx/conf/fastcgi_params
./usr/local/nginx/conf/koi-utf
./usr/local/nginx/conf/mime.types
./usr/local/nginx/conf/win-utf
./usr/local/nginx/conf/scgi_params
./usr/local/nginx/conf/nginx.conf
./usr/local/nginx/conf/fastcgi.conf
./usr/local/nginx/sbin
./usr/local/nginx/sbin/nginx
./usr/local/nginx/fastcgi_temp
./usr/local/nginx/scgi_temp
./usr/local/nginx/uwsgi_temp
./usr/local/sbin
./usr/local/sbin/php-fpm
./usr/local/var
./usr/local/var/log
./usr/local/var/log/php-fpm.log

Как я писал уже, я плохо знаю nginx, php-fpm, и чтобы не тратить время на их досканальное изучение и чтение документации, «как сделать хорошо и безопасно», я пошел самым тупым путем и собрал chroot из которого (поправьте, если ошибаюсь) не выбраться — какие для того есть средства? В этом же chroot’е никаких.

Если я ошибаюсь и выбраться возможно, то у пользователя нет прав root’а (nginx и php-fpm запущены под пользователем http). Но это плохо, потому что я хочу совсем-совсем оградить реальную систему от опасных сервисов, которые смотрят наружу.

У меня самого нет никакого опыта в этом, поэтому буду рад любым советам. Или… может, мне кто-нибудь VDS/VPS подарит, и я тогда брошу страдать огораживанием сервисов от локалхоста. =)

ссылка на оригинал статьи http://habrahabr.ru/post/171345/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *