Задача:
с помощью приложения на PHP порождать некие процессы, работающие от конкретного (отличного от пользователя, от которого работает web-сервер) пользователя.
ПО:
Debian Linux
Apache
PHP
Сейчас, как вы можете догадаться, от apache отпочковываются процессы, работающие под его же пользователем, что естественно не есть гуд по нескольким причинам: 1) если понадобилось ребутнуть apache (или он не дай бог крэшнется сам), то упадут все процессы, порожденные от него 2) кривые права доступа для учетки www-data в связи с тем, что ей тоже нужны права на запуск экземпляров приложения, лежащего вне директории web-сервера. Хватит это терпеть, подумал я…
Решение:
Был написан shell script, который умеет запускать приложение от конкретного пользователя. Он был протестирован от root-а через консольку — работет. Через PHP выполняем shell_exec(), который запускает наш скрипт с некоторыми параметрами (условно, для простоты понимания, с сетевым портом, который будет слушать экземпляр приложения). Осталось разобраться с правами www-data на запуск скрипта от root-а. Ну так же ж есть sudo, подумал я… Вот тут-то и возникли сложности.
Реализация:
Положим, что бинарник приложения лежит (условно) тут
/home/app/bin. Пользователь username, от которого мы собираемся запускать экземпляры, имеет полный доступ (rwx) как к директории так и к бинарнику.
Файлы web-сервера как и положено валяются где-то в /var/www. Apache работает от пользователя www-data.
Shell script лежит (условно) в
/var/www/script.sh. Полные права доступа (rwx) к нему имеет только root, все остальные делать с ним ни чего не могут. Он тщательно проверяет входные параметры (существование пути, существование бинарника и другие проверки) и запускает экземпляр приложения следующей командой:
su -s /bin/bash -c "cd $APP_PATH; ./$APP_BIN $APP_PARAMS > /dev/null 2>&1 &" "$USER_NAME"
или условно
su -s /bin/bash -c "cd /home/app/; ./bin -p 27100 > /dev/null 2>&1 &" username
Остается позволить www-data запускать script.sh от root-а. Ставим sudo,
идем в /etc/sudoers и добавляем:
www-data ALL=(root) NOPASSWD: /var/www/script.sh
По ощущениям этого достаточно и по тем же ощущениям подозрения — слишком просто.
Теперь из PHP вызываем наш скрипт:
shell_exec("cd /var/www/; sudo ./script.sh -p 27100");
Не работает :(
Пробуем по другому (через консоль):
su -s /bin/bash www-data
cd /var/www/
sudo ./script.sh -p 27100
Появляется мало ожидаемое приглашение ввести пароль пользователя www-data:
[sudo] password for www-data:
А NOPASSWD на что? Да и вообще какого хрена пароль у www-data? :(
Собственно, что я делаю не так?
Понятное дело, что православность решения мягко говоря под сомнением, но пока хочется «добить» хотя бы его (силы-то и время уже потрачены). Другие решения придут (надеюсь) позднее с новым опытом.