Настройка webssh с ограничением сетевых подключений
Прежде чем начать
Приведённый вариант настройки хоть и имеет некоторую условную степень защиты от посторонних, тем не менее он не предполагает публичного использования, включая обычных пользователей, он рассматривается как запасной канал управления для домашнего сервера и только для него в случае, если штатные и надёжные каналы нет возможности использовать, например, если доступен только браузер в телефоне.
Хотя, для телефона есть другие варианты, тот же Termux, и телефон не может в полной мере являться доверенным устройством, тем не менее, пример есть пример.
Несмотря на то, что сам wssh-клиент может использовать one-time-password, основной защитой должен являться nginx с auth_basic и связкой логин-пароль для location /webssh/ которые я советую генерировать новые после использования старых. Так как они могут быть использованы для авторизации с оборудования к которому нет полного доверия.
Так, конечно же, делать ни в коем случае не надо.
Но если очень хочется, что-то включить/выключить/перезапустить, то можно.
Начнём
Задача, иметь возможность использовать ssh в условиях недоступности полноценной и защищённой рабочей среды (ноут, openvpn, ssh), а веб-интерфейс управления, или из существующих, или самописный всё равно не даёт всех возможностей интерактивной консоли.
Выбрана наиболее компактная и развиваемая реализация клиента на python.
Согласно документации, блок-схема связей работает следующим образом.
1 2 3 4 5 6 7 |
[xterm.js] [python client] [any ssh server]
+---------+ http +--------+ ssh +-----------+
| browser | <==========> | webssh | <=======> | ssh server|
+---------+ websocket +--------+ ssh +-----------+
|
В этом случае клиент wssh может подключиться к любому серверу, включая локальный, используя при подключении любой логин. Но цель ограничить работу по ssh только с локальным сервером, при этом авторизуясь пользователем с ограниченными возможностями доступа к внешней сети.
Блок-схема реализации
1 2 3 4 5 6 7 8 9 10 | user:webssh
iptables:127.0.0.1<>127.0.0.1 only
sshd_config:AllowUsers webssh@127.0.0.1
+--------------------------------------+
| |
+---------+ http | +--------+ ssh +-----------+ |
| browser | <==========> | | webssh | <=======> | ssh server| |
+---------+ websocket | +--------+ ssh +-----------+ |
| |
+--------------------------------------+
|
К делу
Устанавливаем пакеты
1 2 3 | apt install python-setuptools python-pip apt install libpython2.7-dev gcc libffi-dev python-wheel make build-essential pip install webssh |
Добавляем пользователя, вводим достаточный пароль.
1 2 | groupadd --gid 29132 webssh adduser --home /home/webssh --shell /bin/bash --ingroup webssh --uid 29132 webssh |
Добавляем два правила в скрипт управления iptables или вам видней куда.
1 2 3 4 5 6 | # ~~~~~~~~~~~~~~~~~~~~~~~ webssh allow only localhost connections ~~~~~~~~~~~~~~~~~~~~~ # connect to sshd on localhost | connect from nginx to wssh client $I -A OUTPUT -s 127.0.0.1/32 -d 127.0.0.1/32 -m state --state NEW,RELATED,ESTABLISHED -m owner --uid-owner webssh -j ACCEPT $I -A OUTPUT -m state --state NEW,RELATED,ESTABLISHED -m owner --uid-owner webssh -j DROP # $I -A OUTPUT -m state --state NEW,RELATED,ESTABLISHED -m owner --uid-owner webssh -j ACCEPT # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ / webssh ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
В директиву AllowUsers в sshd_config добавляем разрешение для подключения пользователя webssh только с локальной системы.
Если у вас не была описана эта директива, то дополните её соответствующим образом, иначе потеряете связь с сервером!
Например:
1 2 | AllowUsers root@192.168.1.* user@192.168.1.102 another@192.168.1.201 webssh@127.0.0.1
|
nginx <> wssh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | location /webssh/ { rewrite /webssh/(.*) /$1 break; client_body_buffer_size 4k; client_max_body_size 512k; keepalive_timeout 240s; keepalive_requests 100; send_timeout 30s; # Время активности неактивной консоли, подключение будет сброшено при отсутствии активности. client_body_timeout 30s; more_set_headers "X-Frame-Options: SAMEORIGIN"; more_set_headers "X-Content-Type-Options: nosniff"; more_set_headers "X-XSS-Protection: \"1; mode=block\""; more_set_headers "Strict-Transport-Security: \"max-age=31536000; includeSubdomains; preload\" always"; auth_basic "ACCESS"; auth_basic_user_file /etc/nginx/auth/domain-webssh.pwd; # deny all; proxy_intercept_errors off; proxy_pass http://127.0.0.1:2222; # webssh proxy_http_version 1.1; proxy_read_timeout 120; proxy_set_header Upgrade $http_upgrade; # http://nginx.org/ru/docs/http/websocket.html proxy_set_header Connection "upgrade"; # ^ proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-PORT $remote_port; proxy_set_header X-Forwarded-For $remote_addr; proxy_redirect off; proxy_set_header Proxy ""; } |
wssh backend
Кому как удобней запускать демона, здесь я использую собственные скрипты/вочдоги, набросок:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #!/bin/bash # wssh run script # crontab # */5 * * * * /usr/local/bin/run-webssh.sh > /dev/null 2>&1 # rc.local # /usr/local/bin/run-webssh.sh > /dev/null 2>&1 EC="9" ps aux | grep -Ev "grep|su" | grep -Eo "/usr/local/bin/wssh" ; EC="$?" [[ "$EC" != "0" ]] && { WSPROC="`ps ax | grep "wssh" | grep -v "grep" | awk '{print $1}' | tr '\n' ' '`" kill -9 $WSPROC su - webssh -c "cd /home/webssh/ ; /usr/bin/python /usr/local/bin/wssh --address=127.0.0.1 --logging=info --log-file-prefix=webssh.log --port=2222 --encoding=utf-8 >/dev/null 2>&1" exit 0 } exit 0 |
Таким образом, python-клиент wssh (который является backend сервером для nginx) запущен от пользователя webssh, которому запрещены любые соединения, кроме 127.0.0.1.
Этот самый wssh-клиент может подключиться к серверному ssh-демону используя логин webssh и заданный пароль, для доступа к странице может должен использоватся другой логин и другой пароль, заданный в auth_basic_user_file /etc/nginx/auth/domain-webssh.pwd.
Изящно?
Изящно.
Конечно, поверх этого можно соорудить дополнительные средства и механизмы, как для ограничения, так и для расширения полномочий пользователя в системе.
На закуску
Переписываем стили шрифтов
nano /usr/local/lib/python2.7/dist-packages/webssh/templates/index.html
1 2 3 4 5 6 7 8 9 | @font-face {font-family: "LiberationMono";font-style:normal;font-weight:normal; src: url("/webssh/static/css/fonts/LiberationMono-Regular.eot"); src: url("/webssh/static/css/fonts/LiberationMono-Regular.eot?#iefix") format("embedded-opentype"), url("/webssh/static/css/fonts/LiberationMono-Regular.woff2") format("woff2"), url("/webssh/static/css/fonts/LiberationMono-Regular.woff") format("woff"), url("/webssh/static/css/fonts/LiberationMono-Regular.ttf") format("truetype"), url("/webssh/static/css/fonts/LiberationMono-Regular.otf") format("opentype"), url("/webssh/static/css/fonts/LiberationMono-Regular.svg") format("svg");font-display:swap;} body {font-family:'LiberationMono', monospace !important;} |
Копируем набор шрифтов в ls -la /usr/local/lib/python2.7/dist-packages/webssh/static/css/fonts/
1 2 3 4 5 6 7 8 9 10 | total 364 drwxr-sr-x 2 root staff 4096 Sep 27 13:10 . drwxr-sr-x 3 root staff 4096 Sep 26 23:02 .. -rw-r--r-- 1 root staff 0 Sep 26 22:30 .gitignore -rw-r--r-- 1 root staff 49031 May 1 22:39 LiberationMono-Regular.eot -rw-r--r-- 1 root staff 97288 May 1 23:57 LiberationMono-Regular.otf -rw-r--r-- 1 root staff 81738 May 1 23:57 LiberationMono-Regular.svg -rw-r--r-- 1 root staff 55212 May 1 22:05 LiberationMono-Regular.ttf -rw-r--r-- 1 root staff 40428 May 1 22:39 LiberationMono-Regular.woff -rw-r--r-- 1 root staff 33992 May 1 22:39 LiberationMono-Regular.woff2 |
Оригинальный пост на SecOps.it Blog • Настройка webssh с ограничением сетевых подключений