Перенаправление нескольких файлов с кодом Bash в SSH с экранированием (одна сессия SSH)

Вопрос или проблема

Необходимо перенаправить 3 файла с кодом bash (возможно, в будущем будет больше) в SSH, экранируя их (в пределах одного сеанса SSH), чтобы выполнить их на удаленном хосте. Полностью допустимо перечислить файлы с кодом bash вручную.

Первые 2 файла: functions1, functions2 содержат только функции Bash.

chroot_script.sh содержит как функции Bash, так и код вне функции (скрипты слишком длинные, чтобы публиковать здесь).

Образец кода для контекста:

cat "functions1"  <(echo) "functions2" <(echo) "chroot_script.sh" | ssh -tt ${ssh_command_target} "bash -s"

chroot_script.sh использует некоторые функции из “functions1” и “functions2”.

<(echo) используется для добавления новой строки между файлами с кодом bash (может быть удален, если есть лучший/другой способ добавить новую строку между файлами с кодом bash).

Я считаю, что указанная выше строка/код SSH не работает, потому что файлы с кодом Bash нужно экранировать. bash -s просто нашел в интернете (пока не знаю, действительно ли мне нужен -s).

Пытался сначала перенаправить так:

ssh -tt ${ssh_command_target} <"functions1"  <"functions2" <"chroot_script.sh"

Вышеуказанное, кажется, перенаправляет только один из файлов в списке.

Нужно ssh -tt, потому что внутри chroot_script.sh есть код Bash, выполняющий chroot на удаленном хосте (это не является предметом этого вопроса, скорее предоставляется для контекста):

cat << EOF | sudo chroot ${mount_root_path}
Код Bash
EOF

Ожидаемый результат: Перенаправить 3 файла с кодом bash в SSH, экранируя их (в пределах одного сеанса SSH) с новой строкой между каждым файлом.

OpenSSL 3.0.13 (та же версия на клиенте и сервере SSH). У меня полный контроль над обеими машинами.

Спасибо за внимание!

Вы бы использовали -s, когда хотите, чтобы bash получал свой код из stdin даже при передаче аргументов, как в:

<script bash -s arg1-for-the-script arg2-for-the-script

Иначе, в <script bash arg1-for-the-script arg2-for-the-script, bash пытался бы запустить скрипт arg1-for-the-script вместо этого (с script на stdin).

В <script bash -s параметр -s является избыточным, так как bash берет код из stdin, когда ему не переданы аргументы.


Что касается необходимости экранирования, да, но это, вероятно, не то экранирование, о котором вы думали, и это связано с ложным параметром -tt, который вы передаете ssh (подробнее об этом на Почему этот двоичный файл, переданный через “ssh -t”, изменяется?), и что -tt вызывает проблемы и на стороне вывода.

С параметром -tt sshd на удаленном хосте создает псевдотерминал для удаленной команды, которая ожидает взаимодействия с интерактивным пользователем, и stdin/stdout/stderr ssh предполагается вводом/выводом с терминальным устройством в небуферизованном режиме.

Например, если байт 0x3 (^C) отправлен на ssh, то это вызовет отправку SIGINT удаленной команде, символы, считанные из скрипта, будут интерпретироваться как будто они нажаты пользователем в редакторе строк псевдотерминала, с ^?, рассматриваемым как backspace, ^U как стирание строки и т.д.

Таким образом, действительно есть символы, которые нужно экранировать, но они обычно только управляющие символы, и вы бы не экранировали их с помощью \ или кавычек, а с помощью символа lnext (обычно ^V).

Более того, так как вход bash – это файл устройства tty, bash (с -s или без) войдет в интерактивный режим, где, например, он выдает подсказки для пользователя, читает ~/.bashrc и заменяет ограниченный редактор строк драйвера устройства tty на свой собственный редактор строк (readline), который обрабатывает даже больше управляющих последовательностей (обратите внимание, что переключение произойдет после того, как драйвер tty уже обработал большую часть, если не все входные данные в своем редакторе строк), так что если не отключить этот интерактивный режим (например, с cat | bash или bash -c 'source /dev/stdin' вместо bash), вам пришлось бы делать два экранирования: одно для редактора строк драйвера tty, другое для readline bash.

Но это не то, что вы хотите сделать здесь, и возможные управляющие символы в этих скриптах – это наименьшая из ваших проблем, когда ввод-вывод осуществляется через файл устройства tty.

Здесь вы хотите удалить этот -tt, который не имеет смысла. Если sudo требует терминал, исправьте (неправильную) конфигурацию sudo, которая вызывает это (см. Почему мне нужен tty для выполнения sudo, если я могу выполнять sudo без пароля?).

cat functions1 functions2 chroot_script.sh | ssh "$ssh_command_target" bash

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

Также помните, что в bash, раскрытия параметров почти всегда должны быть заключены в кавычки. Если $ssh_command_target должен быть одним аргументом для ssh, он должен быть "$ssh_command_target" и если это массив аргументов (определенный, например, как ssh_command_target=( -p 222 "root@$host" )) "${ssh_command_target[@]}".

Если вы не можете исправить конфигурацию sudo, используйте другой метод для создания псевдотерминала для него, такие как те, которые используют expect или script, описанные в моем ответе на Почему мне нужен tty для выполнения sudo, если я могу выполнять sudo без пароля?.

Пример:

$ echo $'ps -o tty -p "$$"; echo \3 | hexdump -C' |
   ssh localhost 'SHELL=/bin/sh script -qec "
     bash <&3 >&4 2>&5 3<&- 4>&- 5>&-
     " /dev/null 3<&0 </dev/null 4>&1 5>&2'
TT
pts/3
00000000  03 0a                                             |..|
00000002

Выход ps показывает, что процесс bash имеет управляющий tty, так что sudo с настройкой Defaults requiretty будет доволен, и байт 0x3 был передан не изменившись на bash. В вашем случае вы бы запустили:

cat functions1 functions2 chroot_script.sh |
  ssh "$ssh_command_target" 'SHELL=/bin/sh script -qec "
    exec bash <&3 >&4 2>&5 3<&- 4>&- 5>&-
    " /dev/null 3<&0 </dev/null 4>&1 5>&2'

(но опять с всеми этими усилиями только для обхода контрпродуктивной настройки sudo).

Ответ или решение

Теория

Вопрос касается передачи нескольких файлов с Bash-кодом через SSH в одном сеансе для их выполнения на удаленном хосте. Указанные файлы содержат функции Bash и скрипт, использующий эти функции. Вопрос также поднимает тему использования опции -tt при установлении SSH-сессии и символа -s в Bash.

Опция -tt

Опция -tt в SSH принуждает создание псевдотерминала. Это полезно, если выполняемые на удаленном сервере команды требуют наличия терминала (например, sudo с настройками, требующими терминал). Однако, использование -tt может вызвать проблемы, так как стандартные потоки ввода/вывода могут обрабатываться как терминальные устройства, что означает, что некоторые символы могут интерпретироваться как управляющие.

Аргумент -s в Bash

Агрегат -s в Bash указывает, что код должен быть взят из стандартного ввода. Это полезно, если вы передаете аргументы, а код должен выполняться с использованием стандартного ввода, но на самом деле, когда аргументы отсутствуют, он не нужен.

Пример

Давайте рассмотрим, как следует корректно создавать SSH-соединение для выполнения нескольких файлов с Bash-кодом без непосредственного использования -tt.

Пример кода

cat functions1 functions2 chroot_script.sh | ssh -T ${ssh_command_target} 'bash'

Этот код соединяет содержимое файлов в единый поток и передает его на удаленную машину. Опция -T отключает выделение псевдотерминала, что, скорее всего, именно то, что требуется, если нет необходимости в терминале.

Применение

  1. Настройка соединения: Убедитесь, что ssh_command_target является корректным аргументом, который определяет сервер и, возможно, дополнительные параметры для подключения, такие как порт и имя пользователя.

  2. Более сложные сценарии с терминалом: Если действительно требуется псевдотерминал (например, для взаимодействия с sudo), рекомендуется изменять конфигурацию sudo, чтобы исключить требование наличия терминала. Это делает процесс более управляемым и менее подверженным ошибкам, связанным с неверной обработкой данных ввода/вывода.

  3. Обеспечение переносимости: Важно убедиться, что все файлы заканчиваются новой строкой. Это позволяет избежать необходимости искусственного добавления перевода каретки между отдельными файлами.

  4. Обработка ошибок: Добавление проверки ошибок с использованием условных конструкций Bash (if, &&, ||) может повысить надежность выполнения, особенно если скрипты выполняются в критически важных системах.

  5. Продвинутое использование: Если настройка sudo остается неудобной, можно использовать другие методики, например, expect или script, для эмуляции терминала. Это требует дополнительной настройки и больше подходит для опытных пользователей, хорошо знакомых с системой Unix.

Заключение

Выполнение нескольких файлов с Bash-кодом в едином SSH-сеансе является мощным подходом, который требует понимания работы с терминалами, Bash и SSH. Правильная настройка и использование инструментов может значительно облегчить процесс администрирования и автоматизации задач. Изучение и настройка конфигурации инструментов безопасности, таких как sudo, может существенно повысить гибкость и производительность управления системами.

Оцените материал
Добавить комментарий

Капча загружается...