Назад | Перейти на главную страницу

Использование sudo внутри скрипта

Считается ли хорошей или плохой практикой использование команды sudo внутри сценария оболочки? Одно из преимуществ состоит в том, что если пользователь запускает сценарий как не-root, ему или ему по запросу будет предложено ввести пароль, а не произойдет сбой сценария. С другой стороны, если пользователь недавно запускал команду с помощью sudo, сценарий неявно запускает команды от имени пользователя root, что может не соответствовать ожиданиям пользователя.

Вот пример:

$ cat foo1
#!/bin/sh
sudo bar #implicit sudo
$ ./foo1

$ cat foo2
#!/bin/sh
bar
$ sudo ./foo2 #explicit sudo

Использование sudo - это всегда хорошая практика. Однако есть способы улучшить использование sudo. Один из методов - явно разрешить выполнение определенной команды с повышенными привилегиями.

Следующее позволит только людям из группы "users" выполнять команду foo1 без пароля.

%users ALL=(ALL) NOPASSWD: /full/path/to/foo1

Однако это не позволит выполнить foo2 в приведенном выше примере, если пользователь не введет правильный пароль.

Кроме того, часто лучше настроить sudo так, чтобы он запрашивал пароль пользователя, а не пароль root (на данный момент я забываю параметр конфигурации), и не иметь никаких записей, которые могут позволить пользователям повышать свои привилегии, например:

ALL ALL=(ALL) ALL

или

%users ALL=(ALL) ALL

Использование группы wheel или аналогичной группы для эскалации любой команды является хорошей практикой. В конце концов, лучше всего, чтобы пароль root был заперт в сейфе, чтобы никто (никогда) не мог его использовать, если только неприятный запах не попадет в вентилятор.

/ краткое мнение

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

/ конец мнения

Имейте в виду, вы всегда можете бежать sudo -k перед вызовом скрипта, чтобы потребовать первый неявный sudo вызовите запрос на ввод пароля, хотя, если он также не запускается после каждого sudo внутри скрипта, он ТОЛЬКО запросит у вас самый первый вызов sudo.

Есть несколько способов создать безопасный и разумный сценарий, используя sudo только при необходимости, некоторые из них более неприятны / опрометчивы, чем другие. В этом посте приводится несколько примеров / вариантов, которые я расскажу дальше. https://bitmingw.com/2017/01/22/use-sudo-in-scripts/

Вы можете запустить весь скрипт с помощью sudo который, как вы описали, является «явным», но это также означает, что ВСЕ команды в сценарии запускаются от имени пользователя root, и если он написан плохо или вы забыли, что $USER может измениться внутри скрипта на root и вместо этого вам нужно было использовать $SUDO_USER тогда вы можете оказаться в мире боли. Я случайно делал это в прошлом, и происходили странные и ужасные вещи, а затем вы (и я) в конечном итоге защищали свои скрипты с помощью if [ $EUID -eq 0 ]; then echo "Don't run as root!"; fi или наоборот -gt 0 и вы должны не забывать ставить одного из защитников в каждый сценарий, который вы пишете (или изучать инструменты управления конфигурацией, такие как SaltStack / Puppet / Chef, которые могут автоматизировать некоторые из них).

sudo somescript.sh

Я предпочитаю использовать ВРЕМЕННО запустить sudo с бесконечным временем кеширования, поэтому никакие другие команды sudo, выполняемые вами, не требуют повторного запроса (или, возможно, кого-либо, в зависимости от того, как вы его настроили). В идеале вы бы поместили правильно автоматизированную и протестированную функцию (или включили свой сценарий "cache_sudo.sh") в начале своих сценариев, а затем удалили бы бесконечный тайм-аут, разрешающий sudoers.d файл, как только сценарий завершится (убит / завершен / ошибка), используя trap а потом sudo -k для истечения срока действия сеанса / токена после удаления файла. Видеть этот ответ для примера тестирования и добавляйте файл, только если он действителен.

Это ручная версия, не добавляйте ее в свой сценарий.

sudo visudo -f /etc/sudoers.d/infinite_cache_myuser
#Add next line to the file
Defaults:YOUR_USER_NAME timestamp_timeout=-1

Преимущества бесконечного кеша заключаются в вашем сценарии, вы можете повышать ТОЛЬКО команды, требующие root, с помощью sudo, при этом вам не нужно «понижать» ВСЕ другие команды, используя su $MY_REGULAR_USER some_command или sudo -u $MY_REGULAR_USER some_command для КАЖДОЙ ОДНОЙ команды. (Мне очень не нравится бессмысленно повторяющийся код для отбрасывания привилегий, если есть менее болезненный и не совсем небезопасный способ написать его для повышения только при необходимости).

Один из способов уменьшить повторяющийся код - определить короткий командный «префикс», который добавляет sudo или su $MY_USER в зависимости от того, будет ли скрипт запускаться с sudo ./myscript.sh или ./myscript.sh с участием sudo внутри.

Вы могли бы написать sudoers правило, разрешающее выполнение целевого скрипта с sudo и без запроса пароля, но я думаю, что это такая же плохая идея, как и первый вариант, он помогает лишь незначительно, если вы хотите запустить sudo из задания cron, которое выполняется как пользователь без полномочий root, но необходимо изменить что-то, что требует root или другой пользователь, хотя вам нужно будет прочитать man sudoers чтобы изучить синтаксис, позволяющий пользователю выдавать себя за другого пользователя.

# Customize line below and add to /etc/sudoers or /etc/sudoers.d/my_script_runner
YOUR_USER_NAME ALL=(ALL:ALL) NOPASSWD:/abs/path/to/your/script

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

YOUR_USER_NAME ALL=(ALL:ALL) NOPASSWD:/usr/bin/apt-get update
YOUR_USER_NAME ALL=(ALL:ALL) NOPASSWD:/usr/bin/apt-get upgrade
YOUR_USER_NAME ALL=(ALL:ALL) NOPASSWD:/usr/bin/updatedb

Этот вариант, вероятно, является моим вторым выбором после трюка с бесконечным кешем. Обратной стороной является то, что вы редактируете файл sudoers каждый раз, когда находите новую команду, для которой требуется root, а не просто можете добавить sudo перед командой в вашем скрипте. Плюс в том, что вы разрешаете только без пароля sudo при необходимости, и вы все равно можете потребовать пароль для других sudo команды, таким образом, оставаясь намного безопаснее.