VDI profiles for TRS projects:

This extension allows you to manage user connections to VMs in the context of a single TRS project. Now the Administrator can use Dashboard to flexibly limit device forwarding and some other services provided to the user within the RSclient session. This set of rules is called a VDI profile. The resulting VDI profile directly depends on the RSserver that processes the request. Using a balancer between the User and RSserver, you can give different VDI profiles, for example, if you set a rule for connecting from different networks. This is the case discussed in this documentation.

As with the standard TRS project configuration, the system is based on three key components: RSserver, RSclient and Dashboard.

With this extension, the Administrator has the ability to configure the TRS project in such a way that the User will receive a specific VDI profile, depending on the RSserver to which he connects.

  • After connection, the request is processed by the balancer.
  • Balancer forwards the request to one of the available RSserver.
  • RSserver returns the profile specified in /etc/aos/rsserver.conf, if the profile is not specified, RSserver returns the default profile.
  • Before connecting, the VM receives the user’s VDI profile depending on his source ip.
  • Users connect to the VM via RSclient installed on the thin client.

Extension operation scheme:

../../_images/1.png

Installing of TRS project components:

Installing RSserver:

Installing deb-package:

Install RSserver by following the documentation.

Installing pip-package:

  1. Get superuser rights:

    sudo -i
    
  2. Stop all running services on all hosts:

    systemctl -a stop aos-rs-* && systemctl -a status aos-rs-*
    
  3. Before starting the installation, save the list of previously installed packages:

    pip3 freeze > pip.lock
    
  4. Migrating an old version of RSserver:

    mv /usr/lib/python3/dist-packages/rs_server ~/rs_server_old
    
  5. Install the new pip package (if it starts installing dependencies that are not cached in the local environment, abort the process immediately):

    pip3 install rs_server-1.16.*-cp37-cp37m-linux_x86_64.whl
    
  6. Make sure you are using the new version:

    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. Apply migrations (only once per controller):

    openstack aos db migrate -n rs_server
    
  8. Change the version in bin files:

    sed -i "s/1.16.*/1.16.*/g" /usr/bin/aos-rs-*
    
  9. Restart all related services:

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

Configuration:

  1. In the /etc/aos/rs_server.conf file, make sure you have VDI profiles enabled, and also specify the default profile:

    vdi_profiles_enabled = True
    default_vdi_profile = 1..8
    

Installing RSclient:

  1. Install the package:

    apt-get install ~/vncm-client_0.5.6-7-agent_amd64.deb
    
  2. Run the setup script:

    configure-vncm-client.sh
    
  3. Enter the name of an existing user from which to connect (for new users, the default settings are already set).

  4. Wait until the setting is complete.

Installing Dashboard:

Installing deb-package:

Install Dashboard by following the documentation.

Installing pip-package:

Important

This installation procedure only applies if Dashboard is already installed as part of the system packages (dist-packages). Make sure this condition is met before proceeding.

  1. Get superuser rights:

    sudo -i
    
  2. Before starting the installation, save the list of previously installed packages:

    mkdir -p /tmp/rollback/dashboard
    pip3 freeze > /tmp/rollback/dashboard/pip_before.txt
    
  3. Stop all associated services with Horizon services:

    systemctl stop apache2 nginx dashboard-uwsgi memcached
    systemctl status apache2 nginx dashboard-uwsgi memcached
    
  4. Transfer the deb-version of the Dashboard:

    sudo mv /usr/lib/python3/dist-packages/dashboard /usr/lib/python3/dist-packages/dashboard-old
    
  5. Install the new pip-package (if it starts installing dependencies not cached in the local environment, abort the process immediately):

    pip3 install /tmp/dashboard-1.16.*.tar.gz
    
  6. Make sure that python will use the new Dashboard:

    python3 -c "import dashboard; print(dashboard.__file__)"
    
  7. Save the list of installed packages after installation to be able to roll back changes:

    pip3 freeze > /tmp/rollback/dashboard/pip_after.txt
    
  8. Collect static files:

    python3 /usr/share/openstack-dashboard/manage.py collectstatic -c
    
  9. Perform file compression:

    python3 /usr/share/openstack-dashboard/manage.py compress
    
  10. Restart all related services:

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

Configuration:

Add a field to the /etc/aos/dashboard.conf configuration file (to display the RSclient settings tab):

group_policies_enabled = True

Creating a TRS-project and TRS-machine via Dashboard:

  1. Go to the TRS/TRS Projects section, create and configure the project, assign users.
  2. Fill in the VDI profiles. The default is Profile 1.
  3. Go to TRS/TRS Instances, create a virtual machine and assign security group.

Sample connection script:

#!/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 "# Starting a connection ..." > ~/.vnc/.vncm_status

    connect() {
    echo 20 > ~/.vnc/.vncm_progress
    echo "# Starting a connection to a virtual machine" > ~/.vnc/.vncm_status
    if [[ ! -z $(ps -aux | grep vncviewer | grep -v grep) ]]; then
        /bin/sh -c "zenity --info --text='vnc is already running'"
        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="You need to change your password"
        echo 100 > ~/.vnc/.vncm_progress
        echo "# Ending the connection" > ~/.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 "# Starting vnc connection" > ~/.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="Failed to connect to the virtual machine. Try connecting again or contact your system administrator."
        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 connected ..." > ~/.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="Starting a connection ..." \
        --percentage=0 \
        --auto-close \
        --no-cancel || pkill connect.sh
    ) & connect "$@"

Important

The connection script can use variables that will be automatically changed to real values ​during the process:

  • $RSC_VM_IP – VM address.
  • $RSC_USER – username for authentication.
  • $RSC_PASSWORD – password for user authentication.
  • $RSC_GROUP_POLICY_TEMP_PATH – local path to temporary file with group policies.
  • $RSC_ALLOWED_URLS_TEMP_PATH – local path to temporary file with allowed URLs.

Sample Group Policies:

---
# policies
policy:
scanner: true
printer: false
netfs: false
webcam: true
audio: true
microphone: true
smartcard: false
usb:
- device_1:
    vid: 0
    pid: 0
...

Sample of allowed URLs:

$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"
        }
    ]
}

Important

Allowed URLs can use a variable that will be automatically changed to the actual value during the process:

  • $RSC_CLIENT_IP – IP address of the client machine.

Installing and configuring the balancer:

The TRS-project system utilizes a HAProxy based load balancer to provide fault tolerance and load balancing.

Virtual Machine (VM) Requirements:

  • The VM must have two network interfaces.
  • Configure routing for accessing VMs from other networks. It is recommended to avoid the situation with two default gateways or use routing policy.

Installing HAProxy:

Install HAProxy using the package manager:

apt install haproxy

If access to repositories is limited, use a pre-built image with the HAProxy package already installed.

Configuring:

Sample configuration file:

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

Once the configuration is set, restart HAProxy to apply the changes:

systemctl restart haproxy

Important

Make sure that all RSservers in the same group use the same /etc/aos/.rs_server_secret_key key.

URL-plugin:

URL-plugin is an extension for Chromium-based browsers that provides control over URL transitions.

When a user tries to visit a URL, the plugin checks if the URL is in the list of allowed URLs. If the URL is allowed, the plugin automatically closes the tab on the VM and opens it on the thin client in the local browser.

This allows traffic to be redirected to the user’s device, providing security and control over access to external resources.

../../_images/2.png

Installing URL-plugin:

Important

Make sure that both the thin client and the VM have a Chromium engine browser installed.

Файл WEBfwd.admx:

Important

Make sure that the RSclient settings section of your TRS-project specifies the allowed URLs.

Allowed URLs are passed to the VM using the connection script:

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

Installing the URL-plugin extension:

On the VM, open a browser, enable Developer Mode and install the extension by specifying the path to it.