SSH с удаленной командой и поддержание сессии

Я хочу подключиться к ssh к удаленной машине при установке некоторой переменной окружения.

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

Я хочу сделать что-то вроде:

ssh remote-server "NAME=$NAME;"

Проблемы с вышеупомянутой командой:

  1. Я хочу сохранить сеанс живым. Но он закрывается, как только команда выходит.

    Я могу сделать:

    ssh -t remote-server "NAME=$NAME; bash"
    

    Но тогда в итоговой сессии NAME не определено.

  2. Я также хочу /etc/motd напечатать.

    Я также могу сделать:

    ssh -t remote-server "cat /etc/motd;NAME=$NAME; bash"
    

    , который работает (первая проблема все еще остается), но если есть более элегантные решения, пожалуйста, сообщите.

1
задан 29 August 2019 в 17:39

1 ответ

TL; DR: ssh -t remote-server "NAME=$NAME bash" (нет ; прежде bash), но рассмотрите другие пути.

Перед использованием чего-либо в этом ответе посмотрите на раздел Implications безопасности ниже.

Когда Вы работаете ssh и дайте ему определенную команду для выполнения, это работает, команда с помощью любой оболочки настроена как оболочка входа в систему удаленного пользователя. Эффект поэтому зависит от того, какая оболочка то есть, но самые популярные оболочки являются оболочками стиля Границы. Это включает sh, bash, zsh, ksh, и различные другие. Это не включает tcsh и fish, которые являются, вероятно, самыми популярными оболочками non-Bourne-style.

Ваша цель здесь состоит в том, чтобы работать bash на удаленной машине с новой или измененной переменной среды и оболочке на Вашей локальной машине (куда Вы работаете ssh команда), может быть bash, но оболочка входа в систему удаленного пользователя не обязательно bash. Та оболочка перечислена в базе данных пароля удаленной машины; это включено в запись, полученную путем выполнения getent passwd user на удаленной машине, где user удаленное имя пользователя.

В оболочке стиля Границы переменные среды являются переменными оболочки, но не все переменные оболочки переменные среды. Когда Вы выполняете что-то вроде формы NAME=value как полная команда, существует три случая:

  • Если NAME уже переменная среды, это - также переменная оболочки, и присваивающий той переменной оболочки также обновляет переменную среды.
  • Если NAME не переменная среды, но она существует, поскольку переменная оболочки, присваивая той переменной оболочки обновляет свое значение, но не заставляет ее становиться переменной среды.
  • Если NAME сброшен (т.е. нет никакой переменной тем именем), затем присваивание ему создает переменную оболочки с заданным значением, но эта переменная оболочки не является переменной среды.

Чтобы заставить переменную оболочки быть переменной среды для всех последующих команд, Вы экспортируете его с export встроенный:

export NAME

export встроенный также поддерживает синтаксис присвоения, для предоставления переменной нового значения - или его начальное значение - и экспорта его одновременно:

export NAME=value

Таким образом, одна опция, которую Вы имеете:

ssh -t remote-server "export NAME=$NAME; bash"

Это отличается от Вашего кода добавлением export.

Но оболочки стиля Границы также поддерживают установку переменной среды с определенным значением только на время единственной команды. Это - то, что делают присвоения в начале команды. Таким образом, можно использовать это вместо этого:

ssh -t remote-server "NAME=$NAME bash"

Это отличается от Вашего кода удалением ; это заставило присвоение быть взятым в качестве собственной команды.

Для покрытия non-Bourne-style входят в оболочки, можно использовать любой синтаксис, который ожидает оболочка. Чтобы попытаться покрыть как можно больше оболочек с тем же синтаксисом, можно использовать env управляйте, чтобы установить переменную и выполнить команду. env поддержки NAME=value синтаксис, даже если оболочка, выполняющая его, не делает.

ssh -t remote-server "env NAME=$NAME bash"

Предположение Вашего MOTD обычно отображается, лучший способ заставить это отображать - и достигать других эффектов, которые можно хотеть - должен сказать bash вести себя как оболочка входа в систему. Один способ сделать, который должен передать --login флаг к bash:

ssh -t remote-server "export NAME=$NAME; bash --login"
ssh -t remote-server "NAME=$NAME bash --login"
ssh -t remote-server "env NAME=$NAME bash --login"

Но если Вы предпочитаете, чтобы Вы могли cat файл прежде, чем выполнить Вашу команду, как Вы делали.

Последствия безопасности

Как Вы знаете (и предназначьте), Ваша собственная оболочка расширяется $NAME перед выполнением ssh. Если это содержит символы, которые рассматривает особенно удаленная оболочка, у Вас есть проблема. Это означает, что имеет недостаток не работы под некоторыми общими простыми случаями, как то, если то значение содержит пробелы. Это также означает, что можно случайно использовать значения, которые имеют эффекты, которые Вы не ожидаете. Как заключение, это только безопасно, если Вы всегда управляете содержанием той переменной. Если Вы устанавливаете значение сами, это хорошо. Если значение может быть установлено кем-то еще, тот человек может вызвать любую команду, они хотят работать на удаленной машине.

Вы могли бы попытаться управлять для этого путем записи NAME='$NAME' вместо этого. Это хорошо для случаев, где Вы сознательно делаете что-то простое, как когда $NAME может содержать пробелы. Но это не покрывает все случаи, и, что касается безопасности, что это, к сожалению, не обеспечивает смягчения вообще. Переменная может содержать ' символ. (Если Вы не знаете, какая оболочка настроена как оболочка входа в систему удаленного пользователя, существует также проблема, что оболочки non-Bourne-style имеют различные правила заключения в кавычки.)

Обратите внимание, что это не влияет на случай выполнения кода x="$y" в оболочке, где x и y переменные, и Вы хотите присвоить значение y кому: x. Это работает и безопасно. Но это не то, что Вы делаете здесь. Вместо этого Вы вставляете значение NAME, независимо от того, что это в код, который выполняет удаленная машина. Когда Вы не полностью управляете тем значением, нет никакого обычно безопасного способа сделать это.

Если Вы действительно управляете значением, и Вы знаете то, что Вы делаете, то это хорошо. Иначе один подход должен попытаться изменить свое значение во что-то, что полностью и безопасно заключается в кавычки и вставить это в команду, которая работает на удаленной машине. В этом трудно разобраться, но можно написать код для замены каждого ' символ с последовательностью '\''. Более сложные ситуации с заключением в кавычки, чем та здесь могут быть предприняты с %q спецификатор формата printf команда.

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

ssh -o SendEnv=NAME

Однако это не отвечает Вашему требованию, чтобы не изменять файлы, хранившие на удаленной машине. Удаленный сервер должен быть настроен для разрешения переменной среды NAME пройтись. Тот подход и другие как PermitUserEnvironment, потребуйте редактирования /etc/sshd_config на удаленной машине. Но если Вы, цель состоит в том, чтобы просто постараться не редактировать файлы на удаленной машине способом, которая встраивает любое определенное значение NAME переменная среды в любом файле на нем, затем необходимо использовать SendEnv.

1
ответ дан 7 December 2019 в 14:59

Другие вопросы по тегам:

Похожие вопросы: