Закрыть ssh-туннель без рута и без завершения всех остальных ssh-соединений

Закрыть ssh-туннель без рута и без завершения всех остальных ssh-соединений

У меня есть туннель ssh, прослушивающий локальный порт, скажем, 8888, открытый с удаленной машины с помощью ssh -R 8888:localhost:80 myuser@myhost. Мне нужно написать скрипт для "myuser" на "myhost", который закроет этот туннель.

Скрипт будет выполнен пользователем "myuser" на "myhost". Он не будет выполнен пользователем root и не сможет использовать sudo.

Один из подходов заключается в том, чтобы найти PID процесса, прослушивающего 8888, с помощью lsof или netstat, а затем завершить процесс. Однако и lsof, и netstat отказываются выдавать мне PID без sudo. С netstat я просто получаю -вместо "PID/Program name" без sudo.

Есть ли способ узнать PID процесса, прослушивающего заданный порт, без привилегий root? Процесс, прослушивающий этот порт, запущен под тем же пользователем, что и мы. Или есть другой способ закрыть туннель ssh извне?

Обратите внимание, что использование escape-последовательности ssh для сброса соединения не является решением, поскольку мынетв туннеле. Наш скрипт должен запускаться отдельно от туннеля на том же хосте тем же пользователем.

Также обратите внимание, что простой запуск killall sshdне является решением, поскольку он завершит все остальные ssh-подключения, а не только это.

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

Хост «myhost» работает под управлением Ubuntu 12.04.5.


Редактировать: Краткое изложение обсуждения по просьбе @Jakuje:

  • @Patrick предложил подход, который можно использовать setuidили изменить /etc/sudoers, чтобы разрешить пользователю запускать скрипт с привилегиями root без полного sudo. Хотя, для этого setuidнам нужно будет написать двоичный файл вместо скрипта. Однако разрешение пользователю запускать скрипт с привилегиями root может быть потенциальной угрозой безопасности. И все же это решение не покрывает случай, когда у пользователя вообще нет прав root, поэтому он не может изменять /etc/sudoers. Если @Patrick напишет это как ответ, я определенно проголосую за него, но пока не отмечу его принятым.

  • @EricRenouf обнаружил, что sshd делает chown сокета для пользователя, поэтому пользователь не может использовать его /proc/*/fdдля поиска процесса, у которого есть сокет. Вероятно, поэтому ни lsof, ни netstat его не показывают.

Еще идеи:

Как обнаружил @EricRenouf, вероятно, нет способа получить sshd PID по открытому номеру порта сокета или inode. Но мне интересно, нет ли другого трюка, как узнать этот sshd PID или как сказать ему закрыть соединение. Может быть, как-то напрямую с sshd.

Например, если я включу режим отладки sshd, sshd -dто он будет регистрировать, какой процесс sshd открыл туннель, к какому порту, в /var/log/auth.logкотором пользователь может читать. Таким образом, скрипт может проанализировать журнал и найти там PID. Но запуск режима отладки sshd — не очень хорошая идея. На самом деле естьпростой патч для sshdдля регистрации открытых туннелей даже без режима отладки. Но я не уверен, что запуск пропатченного sshd будет хорошей идеей.

Есть ли еще какие-то хитрости?

решение1

Начните с настройки пользовательского ключа SSH для подключения к "myhost". Затем отредактируйте файл .ssh/authorized_keys на "myhost", чтобы родительский PID оболочки был записан в файл:

command="echo $PPID > tunnel.pid; bash" ssh-rsa AAA...

Вы можете захотеть настроить некоторые другие параметры для безопасности и/или вы можете написать пользовательский скрипт, чтобы просто записать PID и зависнуть. Принцип тот же в любом случае.

Как только вы узнаете PID процесса, который поддерживает сеанс SSH открытым, останется только написать скрипт...

kill `cat tunnel.pid`

...чтобы завершить процесс, тем самым закрыв сеанс SSH.

Обратите внимание, что вы можете использовать -iфлаг в sshкоманде, чтобы указать закрытый ключ, который будет использоваться для соединения.

Редактировать: Завершение процесса оболочки не закроет туннель, если есть активные соединения, поэтому мы завершаем родительский процесс SSH.

Редактировать: Хотя я изначально хотел использовать ключи SSH при любом автоматизированном SSH-подключении, тот же процесс можно сэмулировать с помощью:

ssh -R 8888:localhost:80 myuser@myhost 'echo $PPID > tunnel.pid; for ((;;)); do sleep 1; done'

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

Связанный контент