🕵️ Игнорируем Sudo в shell скриптах, если вы работаете от имени Root |

🕵️ Игнорируем Sudo в shell скриптах, если вы работаете от имени Root

Мануал

Это можно использовать для запуска команды от имени root вне и внутри Docker, где sudo может быть недоступен.

Это довольно специфический случай использования, но, допустим, у вас есть скрипт, который устанавливает инструменты в /usr/local/bin, а также устанавливает инструменты с помощью чего-то вроде pip, где вы можете захотеть использовать –user, чтобы ваши инструменты попадали в ~/.local/bin от имени пользователя, не являющегося root.

Мало того, вы хотите, чтобы этот скрипт работал как на вашей основной системе, так и внутри Docker, где sudo будет недоступен.

Недавно мы столкнулись этой проблемой, когда надо было установить такие инструменты, как kubectl, argocd и другие, в /usr/local/bin, а также установить несколько pip от имени локального пользователя без права рута.

Это был установочный скрипт для помощи разработчикам в работе с macOS и различными дистрибутивами Linux, но он также должен был работать внутри базового образа Docker для запуска в CI.

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

Все могло бы быть проще.

Если бы не было локальной установки pip, это не было бы проблемой.

Ваш скрипт может устанавливать и копировать файлы в /usr/local/bin, и ожидается, что вы запустите его с помощью sudo ./install-tools на вашей персональной машине, а затем внутри Docker вы запустите ./install-tools, поскольку вы уже являетесь пользователем root.

Преимущество здесь в том, что вашему скрипту не нужно использовать sudo для кучи команд, и мне это нравится, потому что это кажется менее грубым.

Либо скрипт не сработает, потому что у вас нет прав root и вы не можете писать в /usr/local/bin, либо вы явно дали скрипт разрешение писать в /usr/local/bin, используя sudo в качестве конечного пользователя.

Переопределение sudo в вашем скрипте

Иногда в реальной жизни случается так, что вы не можете использовать идеальное решение из-за специфического случая использования, и в этом случае вы можете сделать что-то вроде этого.

Вы можете создать этот файл как demo, chmod +x demo и затем запустить его с помощью ./demo:

#!/usr/bin/env bash

set -o errexit
set -o pipefail
set -o nounset

# Source: https://askubuntu.com/a/937596
sudo() {
  [[ "${EUID}" == 0 ]] || set -- command sudo "${@}"
  # If you're the root user then short circuit out of this OR condition. This
  # is the Docker use case.
  #
  # $EUID is the effective user. Unlike $USER, $EUID should be defined in most
  # Docker images. I've seen it available in every Debian Slim based image.
  #
  # Otherwise, take whatever arguments you passed into this function and then
  # run it through the sudo command. This is the personal machine use case and
  # is the other side of the OR condition.
  #
  # `command` is a bash command to execute or display info about a command and
  # we're using `set` to modify the args of ${@}.

  "${@}"
  # Run whatever arguments you passed into this function. This would be whatever
  # the command was but without `sudo`.
}

sudo cp demo /usr/local/bin

echo "Hello world"

Вы также можете убедиться, что он работает в Docker, выполнив команду:

docker container run --rm -v "${PWD}:/app" -w "/app" debian:bookworm-slim ./demo

Система скопирует демонстрационный скрипт в /usr/local/bin, и теперь вы можете запустить demo, чтобы запустить его.

Это предназначено для демонстрационных целей, установка “настоящих” инструментов может включать их сворачивание, распаковку и последующее перемещение бинарных файлов в /usr/local/bin.

В этом подходе хорошо следующее:

  • На вашей персональной системе он будет работать и предложит вам либо ввести пароль пользователя, либо пассивно работать, если у вас включен беспарольный sudo.
  • Вам не нужно засорять свой скрипт кучей условий if, чтобы проверить, существует ли команда sudo, что является проблемой, если вы устанавливаете 10 инструментов.
  • В системах без sudo, например в Docker, команда будет выполняться без sudo и “просто работать”, если она выполняется от имени пользователя root.

Недостатком является необходимость внутреннего использования sudo внутри скрипта, где это необходимо, что кажется немного антипользовательским поведением.

Может быть, есть другой способ с SUDO_USER

Если вы вызываете команду с помощью sudo, то переменная окружения $SUDO_USER будет установлена в значение пользователя, вызвавшего команду, например nick.

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

Основная идея заключается в том, что если $SUDO_USER не определен, то мы знаем, что скрипт был запущен без sudo, поэтому мы можем ожидать, что это пользователь root.

Это будет в том случае, если все запущено в Docker, но, конечно, это не ограничивается Docker.

Если эта env var установлена, то на вашем персональном компьютере все будет устанавливаться в /usr/local/bin без проблем, потому что вы выступаете в качестве пользователя root.

Тогда для команд установки pip install в ~/.local/bin с параметром –user или чего-либо еще, что вам нужно сделать от имени локального пользователя, не являющегося root, вы можете использовать su для предварительного переключения на $SUDO_USER.

Какой метод следует использовать?

Как и в большинстве случаев, это зависит от ваших целей.

Первый вариант, на наш взгляд, идеален, если у вас есть только общесистемные инструменты для установки.

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

Если у вас есть небольшая горстка локально установленных инструментов, то третий вариант кажется более “правильным”.

Это также зависит от того, где будет использоваться этот скрипт.

Если он используется внутри организации, где все должны быть настроены одинаково, то это немного отличается от скрипта с открытым исходным кодом.

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

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

см. также:

Пожалуйста, не спамьте и никого не оскорбляйте. Это поле для комментариев, а не спамбокс. Рекламные ссылки не индексируются!
Добавить комментарий