ssh некоторые команды через (переменное количество) промежуточных переходов

Мне нужны идеи, чтобы создать способ удаленного выполнения (любых) команд через несколько переходов. Основная проблема в том, что количество промежуточных переходов непостоянно! Итак, мне нужно 1) описать «топологию» серверов, а затем 2) иметь функцию? / Script, которая может выполнять некоторые команды на всех из них, используя промежуточные переходы по мере необходимости для достижения конечного пункта назначения.

пример топологии : (но это тоже может быть разным)

server A communicates with server B directly.
servers C and D are "behind" B.
server E is behing C
etc.... (many servers, many indirect ways to reach some of them, some have multiple ways)

Then from A, you can execute "some command" on E with:
    ssh foo@B ssh bar@C ssh baz@E "some command"
 or you can build intermediary tunnels connecting A to **C** and then:
    ssh -P 1234 baz@E "some command"

У меня есть несколько «основных переходов», которые могут напрямую подключаться к множеству серверов

Я хочу иметь возможность (потенциально сложную) на всех 5 серверах через не слишком сложную команду, позволяющую мне (в скрипте) сделать что-то вроде

do_on_all_servers "for dir in /something* ; do cd \"\$dir\" && something using $thisLOCALvariable ; done"
# with an easy way to say "from X, ssh to specificuser@Y using this ssh command and this username" to describe each intermediary hops
# dir is a remote variable, thisLOCALvariable is at the initiating script level, and the amount of "\" needs to be adjusted if going through multiple hops...

Дополнительное ограничение : нет инструментов GNU, нет "nc", просто простой (очень) старый ssh & awk и аналогичные старые инструменты, чтобы иметь переносимый способ. Переносимость должна быть высокой (следует избегать использования изящных опций и инструментов "> 1990?"). И я бы предпочел не делать этого, копируя скрипт поверх конечного пункта назначения & ssh через несколько переходов этого скрипта, но это может быть нормально, если вы думаете, что это проще / лучше.

Прямо сейчас я использую переменные для объединения ssh .... но это не помогает решить проблему «сколько -" \ "- нужно ли мне.

Моя идея заключалась в следующем: объединить переменные, содержащие "shh user @ host" вместе. Или, может быть, с помощью этого очень аккуратного https: // stackoverflow.com / a / 15198031/1841533 способ туннелирования, который, если я смогу сделать это должным образом, позволит выполнять scp и т. д., используя правильный локальный порт для достижения конечного пункта назначения "напрямую" (но не уверен, что этот способ доступен для всех хмель).

0
20.04.2019, 16:33
2 ответа

Вы можете написать / использовать функцию оболочки ssh , которая генерирует настраиваемый файл конфигурации, который использует вложенные ProxyCommands , чтобы добраться до вашего последнего хоста. Затем функция вызовет ssh с -F , указывающим на сгенерированный временный файл конфигурации.

Примерно так:

sssh() {
  TMPF=$(mktemp);
  echo -n "$1" |
  awk '
    BEGIN {RS=" "}
    { split($0,a,":"); u=a[1]; p=a[3]; h=a[2]
      print "\nHost "h"\n\tUser "u"\n\tPort "p;
      if (hop) print "\tProxyCommand ssh -q -W %h:%p "hop;
      hop=h }
    END {print "\nHost *\n\tControlMaster auto\n\tControlPath /tmp/%r@%h:%p"}
  ' > $TMPF;   TMPA=($1); TMPAA=(${TMPA[-1]//:/ }); TMPH=${TMPAA[1]}; shift;
  ssh -F $TMPF $TMPH $@;
  rm $TMPF; }

При таком запуске:

sssh "user1:so.me.ho.st:1234 user2:router.internal:2345 user3:device.internal:3456" do_complex_command

сгенерирует tmp-файл вроде этого:

Host so.me.ho.st
    User user1
    Port 1234

Host router.internal
    User user2
    Port 2345
    ProxyCommand ssh -q -W %h:%p so.me.ho.st

Host device.internal
    User user3
    Port 3456
    ProxyCommand ssh -q -W %h:%p router.internal

Host *
    ControlMaster auto
    ControlPath /tmp/%r@%h:%p

и, наконец, запустит:

ssh -F /tmp/tmp.IUVSRrer45 device.internal do_complex_command

Это выполнит do_complex_command на последнем "самый внутренний" хозяин.Если вам нужно, чтобы ваша команда выполнялась на всех посредниках, вам придется немного адаптировать функцию.

1
28.01.2020, 02:49

Я нашел довольно переносимое решение (не требует никаких изменений в файлах конфигурации ssh, и его легко содержать в вызывает сам скрипт, и его довольно легко использовать): просто соедините вместе ssh, и последний вызовет оболочку (ksh или bash хорошо работают для "немного старых" unix):

echo "for remotedir in /some/path/*/ ; do \
      cd \"\$remotedir\" && \
      something using $thisLOCALvariable \
      ; done" | ssh user1@host1 ssh user2@host2 ssh user3@host3 "bash"
# note: the 'obvious' approach: 
#     ssh u1@h1 ssh u2@h2 "cmd1 ; cmd2; ..."
#  does NOT work : it would execute "cmd2; ..." on h1, not on h2 !!!
#  only cmd1 would be executed on h2 ... BE CAREFUL ! (at least on a not-too-old cygwin)

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

Но это очень удобно, так как всегда есть один и тот же (только 1!) Уровень цитирования, даже если мы объединим 3 или более ssh-вложений, что очень удобно ...Это похоже на то, что приносит $ (cmd) по сравнению со старым подходом ` (обратная кавычка): он упрощает запись без необходимости принимать во внимание уровень вложенности.

предостережение : указав это в качестве параметров сценария (как я задал в вопросе: on_all_servers "для каталога в / something *; выполните cd \" \ $ dir \ "&& something с помощью $ thisLOCALvariable; done ") немного сложнее понять, поскольку вызывающая оболочка сначала интерпретирует" \ "и кавычки ... поэтому сейчас я использую версию для командной строки (или аналогичную конструкцию со сценарием, но не сценарий, который получает командную строку из своих аргументов) ...

Я по-прежнему оставляю вопрос открытым, надеясь, что кто-то получит еще лучшее решение (или его улучшение, например: разрешить передачу аналогичной команды как параметр "вызывающего сценария")

Edit : Я также узнал, как выполнять удаленное извлечение tar с помощью этого метода! Это нетривиально, поскольку stdin необходимо передать удаленной оболочке дважды, один раз, чтобы попасть в соответствующий каталог, затем локальный tar cf - необходимо перенаправить на этот удаленный tar в нужном месте: вот оно:

# the easy one, nothing special needed: from remote to local:
echo "cd /remote/path && tar cf - *" | ssh user1@host1 ssh user2@host2 ssh user3@host3 "bash" | ( cd /local/path && tar xvf - )

# and the hard one: the other way around: needs a trick:
( cd /local/path && tar cf - * ) | { { echo "cd /remote/path/ && tar xvf -" ; cat ;} | ssh user1@host1 ssh user2@host2 ssh user3@host3 "bash" ;}

#once again: this trick allows you to have 1, 2, or any level of ssh.
# PLEASE NOTE: I just run bash, and feed it the command, to avoid
#     the command to be split between the remote hose and the first hop!
#  ex of the way the 'obvious' way fails:
#       ssh user1@host1 ssh user2@host2 "hostname ; hostname;"
#    will return not twice the name "host2", but "host2" then "host1" !! 
#    which means the first part of the command was executed on the last hop,
#    but then the rest of it was executed on the first hop!!! DANGEROUS!
#    that is why I choose instead to use that way:
#       echo "hostname; hostname" | ssh user1@host1 ssh user2@host2 "bash"
#    this one properly executes the full (complex) command on host2
0
28.01.2020, 02:49

Теги

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