Вопрос: Как я могу запустить произвольно сложную команду, используя sudo over ssh?


У меня есть система, в которую я могу войти только под своим именем пользователя (myuser), но мне нужно запускать команды как другой пользователь (scriptuser). До сих пор я придумал следующее для выполнения необходимых мне команд:

ssh -tq myuser@hostname "sudo -u scriptuser bash -c \"ls -al\""

Если, однако, когда я пытаюсь выполнить более сложную команду, например [[ -d "/tmp/Some directory" ]] && rm -rf "/tmp/Some directory" У меня быстро возникают проблемы с цитированием. Я не уверен, как передать этот пример сложной команде bash -c, когда \" уже ограничивает границы команды, которую я передаю (и поэтому я не знаю, как указать / tmp / Some каталог, который включает пробелы.

Есть ли общее решение, позволяющее мне передавать любую команду независимо от того, насколько сложна / сумасшедшая цитата, или это какое-то ограничение, которое я достиг? Существуют ли другие возможные и, возможно, более читаемые решения?


75
2017-09-02 09:21


Источник


Скопируйте сценарий в $ remote, затем выполните его. - Iain
Это будет работать, но я нахожу решение, которое не оставляет файлов сценариев (в случае если что-то не удается и т. Д.) Будет немного чище. - VoY
иметь скрипт rm сам в конце каждого прогона - thanasisk
Рассмотрите возможность использования ткани fabfile.org, Может сделать вас жизнь намного проще, если вам нужно много удалиться. - Nils Toedtmann
Если у вас установлен Ansible, эта команда показывает документацию для вашего прецедента: сценарий ansible-doc - bbaassssiiee


Ответы:


Иногда я использую трюк, чтобы использовать base64 для кодирования команд и передать его в bash на другом сайте:

MYCOMMAND=$(base64 -w0 script.sh)
ssh user@remotehost "echo $MYCOMMAND | base64 -d | sudo bash"

Это будет кодировать скрипт с любыми запятыми, обратными слэшами, кавычками и переменными внутри безопасной строки и отправлять их на другой сервер. (-w0 требуется отключить перенос строк, который по умолчанию происходит в столбце 76). На другой стороне, $(base64 -d) будет декодировать скрипт и передать его в bash для выполнения.

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


137
2017-09-02 13:10



Или даже: ssh user@remotehost "echo `base64 -w0 script.sh` | base64 -d | sudo bash" - Niklas B.
Стоит отметить, что в большинстве случаев вы можете заменить lzop или gzip на base64 на более быстрое время передачи. Тем не менее, могут быть краевые случаи. YMMV. - CodeGnome
Хорошо, но если это сценарий, я не ожидаю, что передача будет более чем на несколько килобайт. - ThoriumBR
Здесь тоже бесполезно использовать эхо. base64 script | ssh remotehost 'base64 -d | sudo bash' было бы достаточно :) - hobbs
Протестировано сегодня и отлично работает. Спасибо, ребята. - Soham Chakraborty


См. -tt вариант? Прочтите ssh(1) руководство.

ssh -tt root@host << EOF
sudo some # sudo shouldn't ask for a password, otherwise, this fails. 
lines
of
code 
but be careful with \$variables
and \$(other) \`stuff\`
exit # <- Important. 
EOF

Одна вещь, которую я часто делаю, это использовать vim и использовать :!cat % | ssh -tt somemachine трюк.


31
2017-09-02 13:01



Конечно :!cat % | (command) может быть выполнено как :w !(command) или :!(command) < %, - Scott
Да. Моя линия злоупотребление кошкой - moebius_eye


Я думаю, что самое легкое решение заключается в модификации комментария @ thanasisk.

Создайте сценарий, scp это к машине, затем запустите ее.

Попросите сценарий rm сам в начале. Оболочка открыла файл, поэтому он был загружен и может быть удален без проблем.

Делая вещи в этом порядке (rm во-первых, другой материал второй), он даже будет удален, когда он в какой-то момент сработает.


9
2017-09-02 11:26





Вы можете использовать %q спецификатор формата с printf позаботиться о том, чтобы сбежать от вас:

cmd="ls -al"
printf -v cmd_str '%q' "$cmd"
ssh user@host "bash -c $cmd_str"

printf -v записывает вывод в переменную (в этом случае, $cmd_str). Я думаю, что это самый простой способ сделать это. Нет необходимости передавать файлы или кодировать командную строку (насколько мне нравится трюк).

Вот более сложный пример, показывающий, что он работает для таких вещей, как квадратные скобки и амперсанды:

$ ssh user@host "ls -l test"
-rw-r--r-- 1 tom users 0 Sep  4 21:18 test
$ cmd="[[ -f test ]] && echo 'this really works'"
$ printf -v cmd_str '%q' "$cmd"
$ ssh user@host "bash -c $cmd_str"
this really works

Я не тестировал его с помощью sudo но это должно быть так просто:

ssh user@host "sudo -u scriptuser bash -c $cmd_str"

Если вы хотите, вы можете пропустить шаг и не создавать промежуточную переменную:

$ ssh user@host "bash -c $(printf '%q' "$cmd")"
this really works

Или даже просто не создавайте переменную целиком:

ssh user@host "bash -c $(printf '%q' "[[ -f test ]] && echo 'this works as well'")"

7
2017-09-04 20:10



это удивительное решение. Мне действительно приходилось использовать printf раньше для аналогичной ситуации, но я всегда забываю об этом. Спасибо, что опубликовали это :-) - Jon L.


Вот «правильный» (синтаксический) способ выполнить что-то подобное в bash:

ssh user@server "$( cat <<'EOT'
echo "Variables like '${HOSTNAME}' and commands like $( uname -a )"
echo "will be interpolated on the server, thanks to the single quotes"
echo "around 'EOT' above.
EOT
)"

ssh user@server "$( cat <<EOT
echo "If you want '${HOSTNAME}' and $( uname -a ) to be interpolated"
echo "on the client instead, omit the the single quotes around EOT."
EOT
)"

Для подробного объяснения того, как это работает, см. https://stackoverflow.com/a/21761956/111948


5
2018-05-28 17:48





Знаете ли вы, что можете использовать sudo чтобы дать вам оболочку, в которой вы можете запускать команды в качестве выбранного пользователя?

-i, --login

Запустите оболочку, указанную в записи базы данных пользователя целевого пользователя, в качестве оболочки входа. Это означает, что файлы ресурсов для входа в систему, такие как                    .profile или .login будут прочитаны оболочкой. Если задана команда, она передается оболочке для выполнения через опцию -c оболочки. Если нет                    команда задана, выполняется интерактивная оболочка. sudo пытается перейти в домашний каталог этого пользователя перед запуском оболочки. Ком-                    mand запускается со средой, подобной той, которую пользователь будет получать при входе в систему. Раздел Command Environment в sudoers (5)                    как параметр -i влияет на среду, в которой выполняется команда, когда используется политика sudoers.


4
2017-09-03 09:22



это кажется очевидным решением для меня. > sudo -i -u brian - code_monk
Это лучше всего работает в сочетании с «ssh -t» в случае удаленного доступа. Что входит в вопрос, но повторяется для «Я не могу читать это / целых / страниц». :) - dannysauer


Вы можете определить сценарий на своей локальной машине, а затем cat и подключите его к удаленной машине:

user@host:~/temp> echo "echo 'Test'" > fileForSsh.txt
user@host:~/temp> cat fileForSsh.txt | ssh localhost

Pseudo-terminal will not be allocated because stdin is not a terminal.
stty: standard input: Invalid argument
Test

3
2017-09-02 09:39



UUOC вы можете использовать < - Iain
Можете ли вы изменить пример, чтобы включить sudo -u scriptuser? Будет ли heredoc использоваться, учитывая, что мне нужно иметь переменные в сценарии, который я бы подключил к машине? - VoY
Я пытался: echo "sudo `cat fileForSsh.txt`" | ssh ... но я продолжаю получать sudo: sorry, you must have a tty to run sudo, - jas_raj
Несмотря на то что этот вопрос может помочь, если вы можете получить /etc/sudoers файл изменен - jas_raj
Это работает для меня: ssh -tq user@host "sudo bash -s" < test.sh - AVee


Простой и легкий.

ssh user @ servidor "bash -s" <script.sh


1
2017-09-03 20:15