Тема: створення ssh тунелю і відкривання url
Поки що забиваю тему.
команда в консолі для створення ssh тунелю:
ssh -L 3081:172.16.0.4:81 user1@example.com -C -N
url:
http://127.0.0.1:3081/login
Шукаю як це зробити в Python.
Ви не увійшли. Будь ласка, увійдіть або зареєструйтесь.
Ласкаво просимо вас на україномовний форум з програмування, веб-дизайну, SEO та всього пов'язаного з інтернетом та комп'ютерами.
Будемо вдячні, якщо ви поділитись посиланням на Replace.org.ua на інших ресурсах.
Для того щоб створювати теми та надсилати повідомлення вам потрібно Зареєструватись.
Український форум програмістів → Python → створення ssh тунелю і відкривання url
Сторінки 1
Для відправлення відповіді ви повинні увійти або зареєструватися
Поки що забиваю тему.
команда в консолі для створення ssh тунелю:
ssh -L 3081:172.16.0.4:81 user1@example.com -C -N
url:
http://127.0.0.1:3081/login
Шукаю як це зробити в Python.
Тепер нащо це потрібно...
Оскільки відповідно до секуріті полісі сервіс повинен бути дотупним лише через ssh, то я створив доку для тіми як конектитися через ssh тунель, все працює ок.
Для зовнішніх користувачів це складно, бо вони технічно далекі. Тому це має бути апка яку просто запустять і вона всередині запустить ssh тунель і одразу ж відкриє веб апку.
import sys
import paramiko
from PyQt5.QtCore import QUrl
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout
from PyQt5.QtWebEngineWidgets import QWebEngineView
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("cool app")
self.setGeometry(150, 150, 900, 700)
# Create a web browser widget
self.browser = QWebEngineView()
self.browser.setUrl(QUrl("http://172.16.0.4:81"))
# Create a layout for the main window
layout = QVBoxLayout()
layout.addWidget(self.browser)
# Create a central widget and set the layout
central_widget = QWidget()
central_widget.setLayout(layout)
self.setCentralWidget(central_widget)
# Create an SSH tunnel to the Azure Virtual Machine
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_key = paramiko.RSAKey.from_private_key_file('/home/user1/.ssh/id_rsa')
ssh.connect('example.com', username='u1', pkey=ssh_key, port=22, timeout=100)
ssh_transport = ssh.get_transport()
ssh_channel = ssh_transport.open_channel('direct-tcpip', ('172.16.0.4', 81), ('172.16.0.4', 81))
# Set the web browser URL to use the SSH tunnel
self.browser.setUrl(QUrl("http://172.16.0.4:81"))
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
Поки що вікно апки відкривається і після деякого очікування показує повідомлення
172.16.0.4 took too long to respond
Буду думати далі.
При спробі дебажити за допомогою pdp
import pdb
...
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
pdb.set_trace()
...
отримую помилку:
Segmentation fault (core dumped)
За допомогою нехитрих принтів з'ясував, що падає на pdb.set_trace()
print("ok0")
import pdb
print("ok1")
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
print("ok2")
pdb.set_trace()
print("ok3")
ok0
ok1
ok2
Segmentation fault (core dumped)
Стаковерфлоу підказує, що може закінчилася пам'ять
https://stackoverflow.com/a/31048386
You might be working with a lot of data and your RAM is full
Однак в моєму випадку це не так
$ free -h
total used free shared buff/cache available
Mem: 15Gi 9,8Gi 622Mi 1,3Gi 5,0Gi 4,0Gi
Swap: 15Gi 7,5Gi 8,3Gi
Поки що незрозуміло як рухатися далі.
Переписав код без PyQt5 GUI щоб віддебажити в консолі, тепер pdb почав працювати, однак результати поки не дуже втішні.
(1)
self.ssh_channel = self.ssh_transport.open_channel('direct-tcpip', ('172.16.0.4', 81), ('127.0.0.1', 3084))
content = connection.get_url("http://127.0.0.1:3084")
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^requests.exceptions.ConnectionError: HTTPConnectionPool(host='127.0.0.1', port=3084): Max retries exceeded with url: / (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7fc6030fd8b0>: Failed to establish a new connection: [Errno 111] Connection refused'))
(2)
self.ssh_channel = self.ssh_transport.open_channel('direct-tcpip', ('127.0.0.1', 3084), ('172.16.0.4', 81))
self.ssh_channel = self.ssh_transport.open_channel('direct-tcpip', ('127.0.0.1', 3084), ('172.16.0.4', 81))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^paramiko.ssh_exception.ChannelException: ChannelException(2, 'Connect failed')
Нічо неясно.
Ось так все працює ок:
from sshtunnel import SSHTunnelForwarder
import requests
ssh_host = 'example.com'
ssh_user = 'user1'
local_port = 3081
remote_host = '172.16.0.4'
remote_port = 81
ssh_private_key_path = "/path/to/private/key"
with SSHTunnelForwarder(
(ssh_host, 22),
ssh_username=ssh_user,
ssh_private_key=ssh_private_key_path,
remote_bind_address=(remote_host, remote_port),
local_bind_address=('127.0.0.1', local_port)
) as tunnel:
response = requests.get(f'http://127.0.0.1:{local_port}/login')
print(response.text)
Версія GUI чомусь не працює
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtCore import QUrl
from sshtunnel import SSHTunnelForwarder
import sys
ssh_host = 'example.com'
ssh_user = 'user1'
local_port = 3081
remote_host = '172.16.0.4'
remote_port = 81
ssh_private_key_path = "/path/to/private/key"
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.browser = QWebEngineView()
self.setCentralWidget(self.browser)
def set_tunnel(self, tunnel):
self.tunnel = tunnel
def load_url(self):
self.browser.setUrl(QUrl(f'http://127.0.0.1:{local_port}/login'))
app = QApplication(sys.argv)
with SSHTunnelForwarder(
(ssh_host, 22),
ssh_username=ssh_user,
ssh_private_key=ssh_private_key_path,
remote_bind_address=(remote_host, remote_port),
local_bind_address=('127.0.0.1', local_port)
) as tunnel:
window = MainWindow()
window.set_tunnel(tunnel)
window.load_url()
window.show()
sys.exit(app.exec_())
127.0.0.1 refused to connect.
sys.exit(app.exec_())
Це було за межами with, тому тунель було закрито до запуску GUI.
Нарешті працює нормально...
Прохання зробити рев'ю:
https://github.com/marchelloUA/ssh_tunnel_wrapper
Апка дуже проста, мені працює для моїх потреб ідеально і в мене до себе нема ніяких питань. Однак я це планую включити в своє резюме і тому потребую конструктивної критики.
додав keepalive щоб впродовж 96 годин не закривалося з'єднання, навіть якщо не було ніякої активності
...
) as tunnel:
tunnel._transport.set_keepalive(96*60*60) # 96 hours
...
Сторінки 1
Для відправлення відповіді ви повинні увійти або зареєструватися