diff --git a/.ansible-lint b/.ansible-lint index 38f5606..f7c8aa6 100644 --- a/.ansible-lint +++ b/.ansible-lint @@ -8,3 +8,5 @@ loop_var_prefix: "^(__|{role}_)" exclude_paths: - .github/ - .ansible/ + # ansible-lint thinks it's a playbook so gives an error, but its tasks are for include_task. decided to exclude it + - roles/rustdesk/molecule/default/client-binary-existance.yml diff --git a/README.md b/README.md index da62590..f383011 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ - [nginx](roles/nginx/README.md) - [prometheus](roles/prometheus/README.md) - [rclone_yandex](roles/rclone_yandex/README.md) +- [rustdesk](roles/rustdesk/README.md) - [sftp_share](roles/sftp_share/README.md) - [smartctl_exporter](roles/smartctl_exporter/README.md) - [ufw](roles/ufw/README.md) diff --git a/galaxy.yml b/galaxy.yml index 0c316c6..a760250 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: genlab name: common -version: 0.17.0 +version: 0.18.0 readme: README.md authors: - Alexander Gorelyshev (corvus-migratorius@proton.me) diff --git a/roles/rustdesk/README.md b/roles/rustdesk/README.md new file mode 100644 index 0000000..390a16c --- /dev/null +++ b/roles/rustdesk/README.md @@ -0,0 +1,42 @@ +Rustdesk Server +========= + +Rustdesk server role for ansible + +Requirements +------------ + +Ports: +``` +tcp 21115, 21116, 21117, 21118, 21119 +udp 21116 +``` + +Role Variables +-------------- + +``` rustdesk_server_version ``` — contains rustdesk-server version to be installed +``` rustdesk_client_version ``` — contains rustdesk-client version for executable to be configured + +Dependencies +------------ + +None + +Example Playbook +---------------- + +```yaml +roles: + - role: genlab.rustdesk_server +``` + +License +------- + +BSD + +Author Information +------------------ + +malyuk.ss@genlab.llc diff --git a/roles/rustdesk/defaults/main.yml b/roles/rustdesk/defaults/main.yml new file mode 100644 index 0000000..315c715 --- /dev/null +++ b/roles/rustdesk/defaults/main.yml @@ -0,0 +1,3 @@ +--- +rustdesk_server_version: "1.1.14" +rustdesk_client_version: "1.4.1" diff --git a/roles/rustdesk/files/generate-rustdesk-exe.sh b/roles/rustdesk/files/generate-rustdesk-exe.sh new file mode 100644 index 0000000..2fb454d --- /dev/null +++ b/roles/rustdesk/files/generate-rustdesk-exe.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# shellcheck disable=SC2155 +set -eu -o pipefail + +readonly RUSTDESK_SERVER_IP="$(curl -s ifconfig.me)" +readonly RUSTDESK_SERVER_KEY="$(cat /opt/rustdesk-server/lib/id_ed25519.pub)" + +cp /opt/rustdesk-server/lib/rustdesk-client.exe \ + /opt/rustdesk-server/lib/rustdesk-host="$RUSTDESK_SERVER_IP",key="$RUSTDESK_SERVER_KEY".exe diff --git a/roles/rustdesk/files/rustdesk-hbbr.service b/roles/rustdesk/files/rustdesk-hbbr.service new file mode 100644 index 0000000..6b0f672 --- /dev/null +++ b/roles/rustdesk/files/rustdesk-hbbr.service @@ -0,0 +1,32 @@ +[Unit] +Description=Rustdesk Relay Server + +[Service] +Type=simple +LimitNOFILE=10000 +Environment="RUST_LOG_LEVEL=trace" +WorkingDirectory=/opt/rustdesk-server/lib/ + +ExecStart=/opt/rustdesk-server/amd64/hbbr + +Restart=on-failure +RestartSec=10 +StartLimitIntervalSec=60 +StartLimitBurst=2 + +User=rustdesk +Group=rustdesk + +# Security +ProtectSystem=strict +ReadWritePaths=/opt/rustdesk-server/lib/ +NoNewPrivileges=true +PrivateTmp=true +ProtectKernelModules=true +ProtectControlGroups=true +ProtectKernelTunables=true +ProtectClock=yes +RestrictSUIDSGID=true + +[Install] +WantedBy=multi-user.target diff --git a/roles/rustdesk/files/rustdesk-hbbs.service b/roles/rustdesk/files/rustdesk-hbbs.service new file mode 100644 index 0000000..d84f44e --- /dev/null +++ b/roles/rustdesk/files/rustdesk-hbbs.service @@ -0,0 +1,35 @@ +[Unit] +Description=Rustdesk Signal Server + +[Service] +Type=simple +LimitNOFILE=10000 +Environment="RUST_LOG_LEVEL=trace" +WorkingDirectory=/opt/rustdesk-server/lib/ + +ExecStartPre=/bin/sh -c 'rm -rf /opt/rustdesk-server/lib/id_ed25519*' +ExecStartPre=/bin/sh -c 'rm -rf /opt/rustdesk-server/lib/rustdesk-host=*' +ExecStart=/opt/rustdesk-server/amd64/hbbs +ExecStartPost=/opt/rustdesk-server/generate-rustdesk-exe.sh + +Restart=on-failure +RestartSec=10 +StartLimitIntervalSec=60 +StartLimitBurst=2 + +User=rustdesk +Group=rustdesk + +# Security +ProtectSystem=strict +ReadWritePaths=/opt/rustdesk-server/lib/ +NoNewPrivileges=true +PrivateTmp=true +ProtectKernelModules=true +ProtectControlGroups=true +ProtectKernelTunables=true +ProtectClock=yes +RestrictSUIDSGID=true + +[Install] +WantedBy=multi-user.target diff --git a/roles/rustdesk/handlers/main.yml b/roles/rustdesk/handlers/main.yml new file mode 100644 index 0000000..976fccb --- /dev/null +++ b/roles/rustdesk/handlers/main.yml @@ -0,0 +1,15 @@ +--- + +- name: "Start and enable rustdesk-hbbr.service" + ansible.builtin.service: + name: "rustdesk-hbbr" + state: started + enabled: true + daemon_reload: true + +- name: "Start and enable rustdesk-hbbs.service" + ansible.builtin.service: + name: "rustdesk-hbbs" + state: started + enabled: true + daemon_reload: true diff --git a/roles/rustdesk/meta/main.yml b/roles/rustdesk/meta/main.yml new file mode 100644 index 0000000..d396088 --- /dev/null +++ b/roles/rustdesk/meta/main.yml @@ -0,0 +1,17 @@ +--- +galaxy_info: + role_name: "rustdesk" + namespace: genlab + author: "Sergey Malyuk" + company: "Genlab, LLC" + description: "" + license: "MIT" + min_ansible_version: "2.1" + + platforms: + - name: "Ubuntu" + versions: ["focal", "jammy", "noble"] + + galaxy_tags: [] + +dependencies: [] diff --git a/roles/rustdesk/molecule/default/client-binary-existance.yml b/roles/rustdesk/molecule/default/client-binary-existance.yml new file mode 100644 index 0000000..f1f76f8 --- /dev/null +++ b/roles/rustdesk/molecule/default/client-binary-existance.yml @@ -0,0 +1,28 @@ +--- +- name: "Get public IP" + register: rustdesk_public_ip + changed_when: false + ansible.builtin.uri: + url: https://ifconfig.me + return_content: true + headers: + Accept: text/plain + User-Agent: curl/7.68.0 + +- name: "Get public key" + register: rustdesk_public_key + changed_when: false + ansible.builtin.command: "cat /opt/rustdesk-server/lib/id_ed25519.pub" + +- name: "Get client rustdesk binary information" + changed_when: false + register: rustdesk_bin + ansible.builtin.stat: + path: "/opt/rustdesk-server/lib/rustdesk-host={{ rustdesk_public_ip.content }},key={{ rustdesk_public_key.stdout }}.exe" + +- name: "Check if client binary exists" + changed_when: false + ansible.builtin.assert: + that: "rustdesk_bin.stat.exists" + success_msg: "Rustdesk binary exists and named correctly" + fail_msg: "Rustdesk binary not found" diff --git a/roles/rustdesk/molecule/default/converge.yml b/roles/rustdesk/molecule/default/converge.yml new file mode 100644 index 0000000..66aeafe --- /dev/null +++ b/roles/rustdesk/molecule/default/converge.yml @@ -0,0 +1,5 @@ +--- +- name: Converge + hosts: all + roles: + - role: "genlab.common.rustdesk" diff --git a/roles/rustdesk/molecule/default/molecule.yml b/roles/rustdesk/molecule/default/molecule.yml new file mode 100644 index 0000000..d82158e --- /dev/null +++ b/roles/rustdesk/molecule/default/molecule.yml @@ -0,0 +1,27 @@ +--- +dependency: + name: galaxy + +driver: + name: docker + +platforms: + - name: ubuntu + image: geerlingguy/docker-${MOLECULE_DISTRO:-ubuntu2404}-ansible:latest + pre_build_image: true + command: ${MOLECULE_DOCKER_COMMAND:-""} + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:rw + cgroupns_mode: host + privileged: true + +provisioner: + name: ansible + +verifier: + name: ansible + +lint: | + set -e + yamllint . + ansible-lint . diff --git a/roles/rustdesk/molecule/default/verify.yml b/roles/rustdesk/molecule/default/verify.yml new file mode 100644 index 0000000..f4832ef --- /dev/null +++ b/roles/rustdesk/molecule/default/verify.yml @@ -0,0 +1,27 @@ +--- + +- name: Verify + hosts: all + gather_facts: false + any_errors_fatal: true + vars_files: + - ../../defaults/main.yml + + tasks: + - name: "Gather service facts" + ansible.builtin.service_facts: + + - name: "Check if rustdesk-hbbr is running" + ansible.builtin.assert: + that: "ansible_facts.services['rustdesk-hbbr.service'].state == 'running'" + success_msg: "rustdesk-hbbr is running" + fail_msg: "rustdesk-hbbr is NOT running" + + - name: "Check if rustdesk-hbbs is running" + ansible.builtin.assert: + that: "ansible_facts.services['rustdesk-hbbs.service'].state == 'running'" + success_msg: "rustdesk-hbbs is running" + fail_msg: "rustdesk-hbbs is NOT running" + + - name: "Check client binary existance" + ansible.builtin.include_tasks: client-binary-existance.yml diff --git a/roles/rustdesk/tasks/check-rustdesk-version.yml b/roles/rustdesk/tasks/check-rustdesk-version.yml new file mode 100644 index 0000000..776b702 --- /dev/null +++ b/roles/rustdesk/tasks/check-rustdesk-version.yml @@ -0,0 +1,25 @@ +--- + +- name: "Check hbbr version" + register: rustdesk_hbbr_output + changed_when: false + ansible.builtin.command: + cmd: "/opt/rustdesk-server/amd64/hbbr --version" + +- name: "Check if the version of hbbr is the expected one" + ansible.builtin.assert: + that: "rustdesk_hbbr_output.stdout == 'hbbr {{ rustdesk_server_version }}'" + success_msg: "hbbr is installed and is the correct version" + fail_msg: "hbbr is either not installed or does not match the target version" + +- name: "Check hbbs version" + register: rustdesk_hbbs_output + changed_when: false + ansible.builtin.command: + cmd: "/opt/rustdesk-server/amd64/hbbs --version" + +- name: "Check if the version of hbbs is the expected one" + ansible.builtin.assert: + that: "rustdesk_hbbs_output.stdout == 'hbbs {{ rustdesk_server_version }}'" + success_msg: "hbbs is installed and is the correct version" + fail_msg: "hbbs is either not installed or does not match the target version" diff --git a/roles/rustdesk/tasks/install-curl.yml b/roles/rustdesk/tasks/install-curl.yml new file mode 100644 index 0000000..7729e18 --- /dev/null +++ b/roles/rustdesk/tasks/install-curl.yml @@ -0,0 +1,30 @@ +--- + +- name: "Install curl for generate-rustdesk-bat.sh script on Debian family" + when: ansible_os_family == "Debian" + ansible.builtin.apt: + name: curl + state: present + update_cache: true + +- name: "Install curl for generate-rustdesk-bat.sh script on RedHat family" + when: ansible_os_family == "RedHat" + ansible.builtin.dnf: + name: curl + state: present + +- name: "Install curl for generate-rustdesk-bat.sh script on FreeBSD family" + when: ansible_os_family == "FreeBSD" + community.general.pkgng: + name: curl + state: present + +- name: "Install curl for generate-rustdesk-bat.sh script on other OS" + when: + - ansible_os_family != "Debian" + - and ansible_os_family != "RedHat" + - and ansible_os_family != "FreeBSD" + ansible.builtin.package: + name: curl + state: present + update_cache: true diff --git a/roles/rustdesk/tasks/install-unzip.yml b/roles/rustdesk/tasks/install-unzip.yml new file mode 100644 index 0000000..efff4b1 --- /dev/null +++ b/roles/rustdesk/tasks/install-unzip.yml @@ -0,0 +1,30 @@ +--- + +- name: "Install unzip for unarchiving the binaries archive on Debian family" + when: ansible_os_family == "Debian" + ansible.builtin.apt: + name: unzip + state: present + update_cache: true + +- name: "Install unzip for unarchiving the binaries archive on RedHat family" + when: ansible_os_family == "RedHat" + ansible.builtin.dnf: + name: unzip + state: present + +- name: "Install unzip for unarchiving the binaries archive on FreeBSD family" + when: ansible_os_family == "FreeBSD" + community.general.pkgng: + name: unzip + state: present + +- name: "Install unzip for unarchiving the binaries archive on other OS" + when: + - ansible_os_family != "Debian" + - and ansible_os_family != "RedHat" + - and ansible_os_family != "FreeBSD" + ansible.builtin.package: + name: unzip + state: present + update_cache: true diff --git a/roles/rustdesk/tasks/main.yml b/roles/rustdesk/tasks/main.yml new file mode 100644 index 0000000..94a3998 --- /dev/null +++ b/roles/rustdesk/tasks/main.yml @@ -0,0 +1,67 @@ +--- + +- name: "Install unzip" + ansible.builtin.include_tasks: install-unzip.yml + +- name: "Install curl" + ansible.builtin.include_tasks: install-curl.yml + +- name: "Add user rustdesk" + ansible.builtin.user: + name: "rustdesk" + shell: /usr/sbin/nologin + create_home: false + +# Rustdesk uses /opt/rustdesk-server/lib/ as a working directory. When it's first started it generates key pairs and puts them in lib directory +- name: "Create lib directory" + ansible.builtin.file: + path: /opt/rustdesk-server/lib/ + state: directory + mode: "0755" + owner: "rustdesk" + group: "rustdesk" + +- name: "Download rustdesk-client" + ansible.builtin.get_url: + url: "https://github.com/rustdesk/rustdesk/releases/download/{{ rustdesk_client_version }}/rustdesk-{{ rustdesk_client_version }}-x86_64.exe" + dest: /opt/rustdesk-server/lib/rustdesk-client.exe + mode: "0644" + owner: "rustdesk" + group: "rustdesk" + +- name: "Copy generate-rustdesk-exe.sh to target machine" + ansible.builtin.copy: + src: "generate-rustdesk-exe.sh" + dest: /opt/rustdesk-server/ + mode: "0755" + owner: "rustdesk" + group: "rustdesk" + +- name: "Install rustdesk" + block: + - name: "Check rustdesk version" + ansible.builtin.include_tasks: check-rustdesk-version.yml + rescue: + - name: "Download and unarchive the binaries" + ansible.builtin.unarchive: + src: "https://github.com/rustdesk/rustdesk-server/releases/download/{{ rustdesk_server_version }}/rustdesk-server-linux-amd64.zip" + dest: /opt/rustdesk-server/ + remote_src: true + +- name: "Copy rustdesk-hbbr.service to /etc/systemd/system/" + notify: "Start and enable rustdesk-hbbr.service" + ansible.builtin.copy: + src: "rustdesk-hbbr.service" + dest: /etc/systemd/system/ + mode: "0755" + owner: "rustdesk" + group: "rustdesk" + +- name: "Copy rustdesk-hbbs.service to /etc/systemd/system/" + notify: "Start and enable rustdesk-hbbs.service" + ansible.builtin.copy: + src: "rustdesk-hbbs.service" + dest: /etc/systemd/system/ + mode: "0755" + owner: "rustdesk" + group: "rustdesk" diff --git a/roles/rustdesk/vars/main.yml b/roles/rustdesk/vars/main.yml new file mode 100644 index 0000000..ed97d53 --- /dev/null +++ b/roles/rustdesk/vars/main.yml @@ -0,0 +1 @@ +---