VDI-профили для TRS-проектов:

Данное расширение позволяет управлять подключением пользователей к ВМ в контексте одного TRS-проекта. Теперь Администратор с помощью Dashboard может гибко ограничивать проброс устройств и некоторые другие сервисы, предоставляемые пользователю в рамках сессии RSclient. Такой набор правил называется VDI-профиль. Получаемый VDI-профиль напрямую зависит от RSserver, который обрабатывает запрос. Используя балансировщик между Пользователем и RSserver можно отдавать разные VDI-профили, например если установить правило для подключения из разных сетей. Именно такой кейс рассматривается в данной документации.

Как и в случае стандартной конфигурации TRS-проектов основу системы составляют три ключевых компонента: RSserver, RSclient и Dashboard.

С данным расширением у Администратора появляется возможность настроить TRS-проект таким образом, что Пользователь будет получать определенный VDI-профиль, в зависимости от RSserver к которому подключается.

  • После подключения, запрос обрабатывается балансировщиком (Balancer).
  • Balancer перенаправляет запрос на один из доступных RSserver.
  • RSserver, отдаёт профиль указанный в /etc/aos/rsserver.conf, если же профиль не указан, RSserver отдаёт профиль по-умолчанию.
  • Перед подключением ВМ получает VDI-профиль пользователя в зависимости от его source ip.
  • Пользователи подключаются к ВМ через RSclient установленный на тонкий клиент.

Схема работы расширения:

../../_images/1.png

Установка компонентов TRS-проекта:

Установка RSserver:

Установка deb-пакета:

Установите RSserver следуя документации.

Установка pip-пакета поверх deb-пакета:

  1. Получите права суперпользователя:

    sudo -i
    
  2. Остановите все запущенные службы на всех хостах:

    systemctl -a stop aos-rs-* && systemctl -a status aos-rs-*
    
  3. Перед началом установки сохраните список установленных ранее пакетов:

    pip3 freeze > pip.lock
    
  4. Перенос старой версии RSserver:

    mv /usr/lib/python3/dist-packages/rs_server ~/rs_server_old
    
  5. Установите новый pip-пакет (если начнётся установка зависимостей, не кэшированных в локальном окружении, немедленно прервите процесс):

    pip3 install rs_server-1.16.*-cp37-cp37m-linux_x86_64.whl
    
  6. Убедитесь, используется новая версия:

    python3 -c "from rs_server.core.helpers import check; print(check())"
    # > no err
    python3 -c "from rs_server.settings import CONF; print(CONF.broker_api.vdi_profiles_enabled)"
    # > False
    python3 -c "from rs_server.settings import CONF; print(CONF.broker.default_vdi_profile)"
    # > python3 -c "from rs_server.settings import CONF; print(CONF.broker.default_vdi_profile)" # no error
    VDIProfiles.PROFILE_1
    python3 -c "from rs_server.core.helpers import parse; print(parse())"  # no err
    
  7. Примените миграции (только один раз на одном контроллере):

    openstack aos db migrate -n rs_server
    
  8. Измените версию в bin-файлах:

    sed -i "s/1.16.*/1.16.*/g" /usr/bin/aos-rs-*
    
  9. Перезапустите все связанные сервисы:

    systemctl -a restart aos-rs-* && systemctl -a status aos-rs-*
    

Настройка:

  1. В файле /etc/aos/rs_server.conf включите VDI-профили, а также указан профиль по умолчанию:

    vdi_profiles_enabled = True
    default_vdi_profile = 1..8
    

Установка RSclient:

  1. Установите пакет:

    apt-get install ~/vncm-client_0.5.6-7-agent_amd64.deb
    
  2. Запустите скрипт настройки:

    configure-vncm-client.sh
    
  3. Введите имя существующего пользователя, с которого будет идти подключение (для новых пользователей настройки по умолчанию уже установлены).

  4. Дождитесь завершения настройки.

Установка Dashboard:

Установка deb-пакета:

Установите Dashboard следуя документации.

Установка pip-пакета поверх deb-пакета:

Важно

Данная процедура установки применима только в случае, если Dashboard уже установлен как часть пакетов системы (dist-packages). Убедитесь, что это условие выполнено, прежде чем продолжить.

  1. Получите права суперпользователя:

    sudo -i
    
  2. Перед началом установки сохраните список установленных ранее пакетов:

    mkdir -p /tmp/rollback/dashboard
    pip3 freeze > /tmp/rollback/dashboard/pip_before.txt
    
  3. Остановите все связанные сервисы с сервисами Horizon:

    systemctl stop apache2 nginx dashboard-uwsgi memcached
    systemctl status apache2 nginx dashboard-uwsgi memcached
    
  4. Перенесите deb-версию Dashboard:

    sudo mv /usr/lib/python3/dist-packages/dashboard /usr/lib/python3/dist-packages/dashboard-old
    
  5. Установите новый pip-пакет (если начнётся установка зависимостей, не кэшированных в локальном окружении, немедленно прервите процесс):

    pip3 install /tmp/dashboard-1.16.*.tar.gz
    
  6. Убедитесь, что python будет использовать новый Dashboard:

    python3 -c "import dashboard; print(dashboard.__file__)"
    
  7. Сохраните список установленных пакетов после установки для возможности отката изменений:

    pip3 freeze > /tmp/rollback/dashboard/pip_after.txt
    
  8. Соберите статические файлы:

    python3 /usr/share/openstack-dashboard/manage.py collectstatic -c
    
  9. Выполните сжатие файлов:

    python3 /usr/share/openstack-dashboard/manage.py compress
    
  10. Перезапустите все связанные сервисы:

    systemctl restart apache2 nginx dashboard-uwsgi memcached
    systemctl status apache2 nginx dashboard-uwsgi memcached
    

Настройка:

Добавьте в конфигурационный файл /etc/aos/dashboard.conf поле (для отображения вкладки RSclient settings):

group_policies_enabled = True

Создание TRS-проекта и TRS-машины через Dashboard:

  1. Перейдите в раздел TRS/TRS Projects, создайте и настройте проект, назначьте пользователей.
  2. Заполните VDI-профили. По умолчанию используется Профиль 1.
  3. Перейдите в раздел TRS/TRS Instances, создайте виртуальную машину и назначьте security group.

Образец скрипта подключения:

#!/bin/bash
    set -x
    exec 2> ~/.rsclient/connect_error.log
    exec 1> ~/.rsclient/connect.log

    connect_timeout=30

    ipraw=$RSC_VM_IP
    user=$RSC_USER
    pass=$RSC_PASSWORD
    vncm_admx=$RSC_GROUP_POLICY_TEMP_PATH
    web_admx=$RSC_ALLOWED_URLS_TEMP_PATH

    echo 1 > ~/.vnc/.vncm_progress
    echo "# Запуск подключения ..." > ~/.vnc/.vncm_status

    connect() {
    echo 20 > ~/.vnc/.vncm_progress
    echo "# Запуск подключения к виртуальной машине" > ~/.vnc/.vncm_status
    if [[ ! -z $(ps -aux | grep vncviewer | grep -v grep) ]]; then
        /bin/sh -c "zenity --info --text='vnc уже запущен'"
        exit 0
    fi

    ip=$(nslookup "$ipraw" | grep "name = " | sed 's|.name = ||g')

    if [[ ! "$@" =~ 'magic_number_for_sso_mode' ]]; then
        ip=$ipraw
        # check if pass need change
        passexp=$(sshpass -v -p "$pass" ssh -o StrictHostKeyChecking=no "$user@$ip" 'whoami' 2>&1)
        if [[ $passexp =~ expired ]]; then
        zenity --error \
        --text="Необходимо сменить пароль"
        echo 100 > ~/.vnc/.vncm_progress
        echo "# Завершение подключения" > ~/.vnc/.vncm_status
        off-client.sh
        exit 0
        fi
        ssh_con="sshpass -p '$pass' ssh -tt -o StrictHostKeyChecking=no"
    else
        ssh_con="ssh -tt -o StrictHostKeyChecking=no"
    fi

    myip=$(sshpass -p "$pass" ssh -o StrictHostKeyChecking=no "$user@$ip" "echo \$SSH_CLIENT | sed 's| .||g'")

    userhome=$(eval $ssh_con "$user@$ip" env | grep HOME | sed 's|HOME=||g')
    userhome=$(echo "$userhome" | rev | cut -c 2- | rev)

    echo 50 > ~/.vnc/.vncm_progress
    echo "# Запуск vnc подключения" > ~/.vnc/.vncm_status

    eval $ssh_con "$user@$ip" "loginctl enable-linger $user"
    eval $ssh_con "$user@$ip" "systemctl --user daemon-reload"

    if [[ $(cat $HOME/.vnc/default.tigervnc | grep LocalhostForSSH=1 | grep -v -E "^ *#") ]]
    then
        eval $ssh_con $user@$ip "systemctl --user stop vncserver"
        eval $ssh_con $user@$ip "systemctl --user start vncserver_sock"
    else
        eval $ssh_con $user@$ip "systemctl --user stop vncserver_sock"
        eval $ssh_con $user@$ip "systemctl --user start vncserver"
    fi

    try=0
    while [[ ! $ok ]]; do
        ok=$(eval $ssh_con "$user@$ip" 'ps -aux | grep /usr/bin/Xvnc | grep -v grep')
        sleep 1
        try=$(expr $try + 1)
        if [ "$try" = $connect_timeout ]; then
        zenity --error \
        --text="Не удалось подключиться к виртуальной машине. Повторите попытку подключения или обратитесь к системному администратору"
        echo 100 > ~/.vnc/.vncm_progress
        echo "# Завершение подключения" > ~/.vnc/.vncm_status
        off-client.sh
        exit 0
        fi
    done

    loginctl enable-linger "$USER"
    systemctl --user daemon-reload

    sshpass -p $pass scp -o StrictHostKeyChecking=no $vncm_admx $user@$ip:/var/tmp/.vncm/VNCm.admx
    sshpass -p $pass scp -o StrictHostKeyChecking=no $web_admx $user@$ip:/var/tmp/.vncm/WEBfwd.admx
    eval $ssh_con $user@$ip 'chmod 666 /var/tmp/.vncm/*.admx'

    eval $ssh_con $user@$ip 'mkdir -p /tmp/share/'
    eval $ssh_con $user@$ip 'chmod 777 /tmp/share/'

    # wait for agent to start
    unset ok
    while [[ ! $ok =~ "OK" ]]
    do
        eval $ssh_con -q $user@$ip [[ -S /tmp/vnc.sock ]] && ok="OK" || ok="NO";
        sleep 1
    done

    if [[ $(cat $HOME/.vnc/default.tigervnc | grep LocalhostForSSH=1 | grep -v -E "^ *#") ]]
    then
        passes=$passes" -L 127.0.0.1:33333:$userhome/.vnc/vncm.sock"
    fi

    eval $ssh_con -R $userhome/.pcscd.comm:/var/run/pcscd/pcscd.comm $user@$ip &
    eval $ssh_con -R $userhome/.cups.sock:/var/run/cups/cups.sock $user@$ip &

    echo 100 > ~/.vnc/.vncm_progress
    echo "# vnc подключено ..." > ~/.vnc/.vncm_status
    if [[ "$@" =~ '--use-quictun' ]]; then
        if [[ $(cat "$HOME/.vnc/default.tigervnc" | grep LocalhostForSSH=1 | grep -v -E "^ *#") ]]; then
        systemctl --user start vncm-quic-server@$myip.service
        systemctl --user start vncm-socat-client.service
        eval $ssh_con "$user@$ip" "systemctl --user start vncm-quic-client@$myip.service"
        eval $ssh_con "$user@$ip" "systemctl --user start vncm-socat-server.service"
        unset ok
        while [[ ! $ok ]]; do
            ok=$(eval $ssh_con "$user@$ip" 'ps -aux | grep tcp:localhost:2322 | grep -v grep')
            sleep 1
        done
        eval $ssh_con "$passes" "$user@$ip" &
        unset ok
        while [[ ! $ok =~ '127.0.0.1:33333' ]]
        do
            ok=$(ps -aux | grep 127.0.0.1:33333 | grep -v grep)
            sleep 1
        done
        /usr/bin/vncviewer $HOME/.vnc/default.tigervnc localhost:33333
        else
        echo "ERROR: --use-quictun need LocalhostForSSH=1"
        fi
    else
        if [[ $(cat "$HOME/.vnc/default.tigervnc" | grep LocalhostForSSH=1 | grep -v -E "^ *#") ]]; then
        systemctl --user start vncm-socat-client.service
        passes="$passes -R 3240:localhost:3240 -R 5005:localhost:5005 -R 5007:localhost:5007 -R 5008:localhost:5008 -R 6566:localhost:6566 -R 2322:localhost:22"
        eval $ssh_con "$passes" "$user@$ip" &
        eval $ssh_con "$user@$ip" 'systemctl --user start vncm-socat-server.service'
        unset ok
        while [[ ! $ok =~ '2322:localhost:22' ]]; do
            ok=$(ps -aux | grep 2322:localhost:22 | grep -v grep)
            sleep 1
        done
        /usr/bin/vncviewer $HOME/.vnc/default.tigervnc localhost:33333
        else
        /usr/bin/vncviewer "$HOME/.vnc/default.tigervnc" "$ip:1"
        fi
    fi
    }

    (
    (
    while [[ $progress != 100 ]]; do
        progress=$(cat ~/.vnc/.vncm_progress)
        status=$(cat ~/.vnc/.vncm_status)
        echo "$progress"
        echo "$status"
        sleep 1
    done
    ) | zenity --progress \
        --title="VNCM" \
        --text="Запуск подключения ..." \
        --percentage=0 \
        --auto-close \
        --no-cancel || pkill connect.sh
    ) & connect "$@"

Важно

В скрипте подключения могут быть использованы переменные, которые в процессе будут автоматически изменены на реальные значения:

  • $RSC_VM_IP – адрес ВМ.
  • $RSC_USER – Имя пользователя для аутентификации.
  • $RSC_PASSWORD – Пароль для аутентификации пользователя.
  • $RSC_GROUP_POLICY_TEMP_PATH – Локальный путь к временному файлу с групповыми политиками.
  • $RSC_ALLOWED_URLS_TEMP_PATH – Локальный путь к временному файлу с разрешёнными URL.

Образец групповых политик:

---
# политики
policy:
scanner: true
printer: false
netfs: false
webcam: true
audio: true
microphone: true
smartcard: false
usb:
- device_1:
    vid: 0
    pid: 0
...

Образец разрешённых URL:

$RSC_CLIENT_IP|{
    "rules": [
        {
        "active": true,
        "conditions": [
            {
            "id": 1739955810043,
            "request": {
                "redirect": "http://$RSC_CLIENT_IP/v1/urls/[example.com$1]",
                "search": "REGEX",
                "value": "https?://example.com(.*)"
            }
            }
        ],
        "description": "Redirect с example.com",
        "enableNotifications": true,
        "id": 1739955654113,
        "name": "example.com"
        }
    ]
}

Важно

В разрешённых URL может быть использована переменная, которая в процессе будет автоматически изменена на реальное значение:

  • $RSC_CLIENT_IP – IP-адрес клиентской машины.

Установка и настройка балансировщика:

Для обеспечения отказоустойчивости и распределения нагрузки в системе TRS-проектов используется балансировщик на основе HAProxy.

Требования к виртуальной машине (ВМ):

  • ВМ должна иметь два сетевых интерфейса.
  • Настройте маршрутизацию для доступа к ВМ из других сетей. Рекомендуется избегать ситуации с двумя default шлюзами или использовать routing policy.

Установка HAProxy:

Установите HAProxy с помощью пакетного менеджера:

apt install haproxy

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

Настройка:

Образец конфигурационного файла:

global
    log /dev/log local0
    log /dev/log local1 notice
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin
    stats timeout 30s
    user haproxy
    group haproxy
    daemon

defaults
    log global
    mode http
    option httplog
    timeout connect 5s
    timeout client  50s
    timeout server  50s

frontend trs_proxy
    bind 10.40.14.151:9365
    acl from_vm src 10.40.15.0/24
    acl from_tk src 10.40.251.0/24
    use_backend backend_vm if from_vm
    use_backend backend_tk if from_tk
    http-request deny if !from_tk !from_vm

backend backend_vm
    balance roundrobin
    server srv1 10.40.13.11:9365 check
    server srv2 10.40.13.12:9365 check

backend backend_tk
    balance roundrobin
    server srv3 10.40.13.13:9365 check

После настройки конфигурации перезапустите HAProxy для применения изменений:

systemctl restart haproxy

Важно

Убедитесь, что для всех RSserver из одной группы используется один и тот же ключ /etc/aos/.rs_server_secret_key.

URL-plugin:

URL-plugin — расширение для браузеров на движке Chromium, которое обеспечивает контроль за переходами по URL-адресам.

Когда пользователь пытается перейти по URL, плагин проверяет, находится ли этот адрес в списке разрешённых. Если URL разрешён, плагин автоматически закрывает вкладку на ВМ и открывает её на тонком клиенте в локальном браузере.

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

../../_images/2.png

Установка URL-plugin:

Важно

Убедитесь, что на тонком клиенте и на ВМ установлен браузер на движке Chromium.

Файл WEBfwd.admx:

Важно

Убедитесь, что в разделе настроек RSclient settings вашего TRS-проекта указаны разрешённые URL.

Разрешённые URL передаются на ВМ с помощью скрипта подключения:

#sshpass -p "$pass" scp "$RSC_ALLOWED_URLS_TEMP_PATH" "$user@$ipraw:/var/tmp/.vncm/WEBfwd.admx"

Установка расширения URL-plugin:

На ВМ откройте браузер, включите Developer Mode и установите расширение, указав путь к нему.