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

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

Сценарий будет выполнен "myuser" на "myhost". Это не будет выполнено рутом, и это не будет в состоянии sudo.

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

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

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

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

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

На хосте "myhost" работает Ubuntu 12.04.5.


Изменить: резюме обсуждения по запросу @Jakuje:

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

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

Больше идей:

Как обнаружил @EricRenouf, вероятно, нет способа получить PID sshd по номеру порта открытого сокета или по индексу. Но мне любопытно, нет ли другой хитрости, как найти этот 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'

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

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