--- # ============================================================================ # life-church/playbooks/thinkcenter-rustdesk.yml # Install the RustDesk remote-desktop client (1.4.9) on thinkcenter and point # it at the self-hosted RustDesk server (racknerd2, via NetBird mesh). # thinkcenter ONLY. Idempotent. become password from Infisical /lc-hosts. # Server config (id/relay/key) pulled from Infisical /rustdesk at runtime. # # - Downloads the official .deb (Flutter build) from GitHub with SHA256 verify. # - Installs via apt (resolves deps automatically). # - Writes ~/.config/rustdesk/RustDesk2.toml with the custom rendezvous # (ID) server, relay server, and public key so the client auto-registers to # the self-hosted server instead of the public RustDesk network. # # UNDO: # sudo apt remove --purge rustdesk # rm -rf ~/.config/rustdesk # ============================================================================ # --- Play 1 (localhost): fetch creds + rustdesk server config from Infisical - - name: "thinkcenter RustDesk — resolve secrets from Infisical" hosts: localhost gather_facts: false tasks: - name: "[resolve] Infisical creds from env" ansible.builtin.set_fact: infisical_client_id: "{{ lookup('env','INFISICAL_CLIENT_ID') }}" infisical_client_secret: "{{ lookup('env','INFISICAL_CLIENT_SECRET') }}" infisical_project_id: "{{ lookup('env','INFISICAL_PROJECT_ID') }}" infisical_url: "{{ lookup('env','INFISICAL_API_URL') | default('http://192.168.122.41:8080', true) }}" infisical_env_slug: "{{ lookup('env','INFISICAL_ENV_SLUG') | default('prod', true) }}" - name: "[resolve] Assert Infisical creds present" ansible.builtin.assert: that: - infisical_client_id | length > 0 - infisical_client_secret | length > 0 - infisical_project_id | length > 0 fail_msg: "Infisical creds missing from Semaphore environment 'infisical-dev'." - name: "[infisical] Log in" infisical.vault.login: url: "{{ infisical_url }}" auth_method: universal_auth universal_auth_client_id: "{{ infisical_client_id }}" universal_auth_client_secret: "{{ infisical_client_secret }}" register: infisical_login no_log: true - name: "[infisical] Read /lc-hosts (sudo pass + user)" infisical.vault.read_secrets: login_data: "{{ infisical_login.login_data }}" project_id: "{{ infisical_project_id }}" env_slug: "{{ infisical_env_slug }}" path: "/lc-hosts" as_dict: true register: lc_secrets no_log: true - name: "[infisical] Read /rustdesk (server config)" infisical.vault.read_secrets: login_data: "{{ infisical_login.login_data }}" project_id: "{{ infisical_project_id }}" env_slug: "{{ infisical_env_slug }}" path: "/rustdesk" as_dict: true register: rd_secrets no_log: true - name: "[set] Stash sudo pass, user, and rustdesk server config" ansible.builtin.set_fact: thinkcenter_become_pass: "{{ lc_secrets.secrets['THINKCENTER_SUDO_PASS'] }}" thinkcenter_login_user: "{{ lc_secrets.secrets['THINKCENTER_USER'] }}" rd_id_server: "{{ rd_secrets.secrets['RUSTDESK_ID_SERVER'] }}" rd_relay_server: "{{ rd_secrets.secrets['RUSTDESK_RELAY_SERVER'] }}" rd_api_server: "{{ rd_secrets.secrets['RUSTDESK_API_SERVER'] | default('', true) }}" rd_key: "{{ rd_secrets.secrets['RUSTDESK_KEY'] }}" no_log: true # --- Play 2: RustDesk on thinkcenter ONLY ------------------------------------ - name: "Install + configure RustDesk client on thinkcenter" hosts: thinkcenter gather_facts: true become: true vars: ansible_become_pass: "{{ hostvars['localhost'].thinkcenter_become_pass }}" rd_user: "{{ hostvars['localhost'].thinkcenter_login_user }}" rd_version: "1.4.9" rd_deb_url: "https://github.com/rustdesk/rustdesk/releases/download/1.4.9/rustdesk-1.4.9-x86_64.deb" rd_deb_sha256: "7244ba47c40e804172044bfbe659467c54ce46554c98e78c8c0406f1d612fda3" rd_id_server: "{{ hostvars['localhost'].rd_id_server }}" rd_relay_server: "{{ hostvars['localhost'].rd_relay_server }}" rd_api_server: "{{ hostvars['localhost'].rd_api_server }}" rd_key: "{{ hostvars['localhost'].rd_key }}" tmp_dir: /tmp/rustdesk-install tasks: - name: "[safety] Confirm we are on thinkcenter" ansible.builtin.assert: that: inventory_hostname == 'thinkcenter' fail_msg: "Refusing to run — this play is scoped to thinkcenter only." - name: "[selfheal] Repair any half-configured dpkg/apt state (prevents cascade failures)" ansible.builtin.shell: | dpkg --configure -a || true apt-get -y -f install || true register: dpkg_selfheal changed_when: "'Setting up' in (dpkg_selfheal.stdout | default(''))" failed_when: false - name: "[safety] Assert rd_user resolved + exists" block: - name: "[safety] Non-empty user" ansible.builtin.assert: that: rd_user | length > 0 fail_msg: "rd_user empty — THINKCENTER_USER not read from Infisical." - name: "[facts] getent user" ansible.builtin.getent: database: passwd key: "{{ rd_user }}" - name: "[facts] Assert user exists" ansible.builtin.assert: that: rd_user in ansible_facts.getent_passwd fail_msg: "User '{{ rd_user }}' does not exist on host." - name: "[facts] Resolve user home" ansible.builtin.set_fact: rd_home: "{{ ansible_facts.getent_passwd[rd_user][4] }}" - name: "[dl] Create temp dir" ansible.builtin.file: path: "{{ tmp_dir }}" state: directory mode: "0755" - name: "[dl] Download RustDesk {{ rd_version }} .deb with SHA256 verify (retry)" ansible.builtin.get_url: url: "{{ rd_deb_url }}" dest: "{{ tmp_dir }}/rustdesk.deb" checksum: "sha256:{{ rd_deb_sha256 }}" mode: "0644" register: rd_dl until: rd_dl is succeeded retries: 3 delay: 15 - name: "[apt] Install RustDesk .deb (apt resolves dependencies; retry on lock)" ansible.builtin.apt: deb: "{{ tmp_dir }}/rustdesk.deb" state: present register: rd_install until: rd_install is succeeded retries: 3 delay: 15 - name: "[verify] rustdesk binary present" ansible.builtin.command: which rustdesk register: rd_which changed_when: false failed_when: false - name: "[verify] Assert RustDesk installed" ansible.builtin.assert: that: rd_which.rc == 0 fail_msg: "RustDesk binary not found after install." success_msg: "RustDesk installed at {{ rd_which.stdout | trim }}." # ---- Point the client at the self-hosted server (per-user config) ---- - name: "[config] Ensure rustdesk config dir for {{ rd_user }}" ansible.builtin.file: path: "{{ rd_home }}/.config/rustdesk" state: directory owner: "{{ rd_user }}" group: "{{ rd_user }}" mode: "0700" - name: "[config] Write RustDesk2.toml (custom ID/relay server + key)" ansible.builtin.copy: dest: "{{ rd_home }}/.config/rustdesk/RustDesk2.toml" owner: "{{ rd_user }}" group: "{{ rd_user }}" mode: "0600" content: | rendezvous_server = '{{ rd_id_server }}' nat_type = 1 serial = 0 [options] custom-rendezvous-server = '{{ rd_id_server }}' relay-server = '{{ rd_relay_server }}' {% if rd_api_server | length > 0 %}api-server = '{{ rd_api_server }}' {% endif %}key = '{{ rd_key }}' register: rd_config no_log: true - name: "[cleanup] Remove temp dir" ansible.builtin.file: path: "{{ tmp_dir }}" state: absent - name: "[report] RustDesk summary" ansible.builtin.debug: msg: - "===== thinkcenter RustDesk =====" - "packages changed this run : {{ rd_install.changed }}" - "rustdesk path : {{ rd_which.stdout | default('n/a') | trim }}" - "config written for : {{ rd_user }} ({{ rd_home }}/.config/rustdesk/RustDesk2.toml)" - "ID/relay server : self-hosted (from Infisical /rustdesk)" - "NOTE: restart RustDesk (or the rustdesk service) for the custom server to take effect. Client shows the server key is applied under Settings -> Network."