#!/usr/bin/env bash # Profile: sc-workstation (ares) # Role: XFCE desktop workstation — where the player works. # Distro: Debian 12 (bookworm) cloud image DOMAIN="sc-workstation" HOSTNAME="ares" RAM_MB=2048 VCPUS=2 DISK_SIZE="20G" GRAPHICS="${SC_WORKSTATION_GRAPHICS:-spice}" BASE_URL="https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-amd64.qcow2" BASE_IMAGE="$SC_BASE_DIR/debian-12-genericcloud-amd64.qcow2" READY_TIMEOUT=1200 READY_COMMAND='cloud-init status 2>/dev/null | grep -q "status: done" && ! uname -r | grep -q cloud && test -e /dev/dri/card0 && systemctl is-active --quiet lightdm' READY_PROGRESS_COMMAND='cloud-init status --long; echo "---"; tail -n 12 /var/log/cloud-init-output.log' READY_WATCH_TEMPLATE='ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o BatchMode=yes -o ConnectTimeout=5 -o LogLevel=ERROR -i ~/.ssh/sc_host_key opsbridge@{ADDR} "sudo tail -f /var/log/cloud-init-output.log"' # Extra variables used in user-data WALLPAPER_PATH="${SC_WALLPAPER_PATH:-$PROJECT_ROOT/server/public/wallpaper.png}" WALLPAPER_B64="" if [ -f "$WALLPAPER_PATH" ]; then WALLPAPER_B64="$(base64 -w 0 "$WALLPAPER_PATH")" fi WALLPAPER_B64_INDENT="$(printf '%s\n' "$WALLPAPER_B64" | fold -w 76 | sed 's/^/ /')" PRIVKEY_INDENT="$(sed 's/^/ /' "$SC_SSH_KEY")" source "$PROJECT_ROOT/tools/lib/internal-https.sh" sc_ensure_internal_certs "$PROJECT_ROOT" sc_export_internal_https_env SC_CERT_DIR="$(sc_cert_dir)" HUD_URL="$(sc_hud_url)" SAGE_URL="$(sc_sage_url)" COMPANY_URL="$(sc_company_url)" _SC_CA_CERT_PEM="" _SC_SERVER_CERT_PEM="" _SC_SERVER_KEY_PEM="" if [[ -f "$(sc_ca_cert)" && -f "$(sc_tls_cert)" && -f "$(sc_tls_key)" ]]; then _SC_CA_CERT_PEM="$(cat "$SC_CERT_DIR/ca.crt")" _SC_SERVER_CERT_PEM="$(cat "$SC_CERT_DIR/server.crt")" _SC_SERVER_KEY_PEM="$(cat "$SC_CERT_DIR/server.key")" fi _SC_CA_CERT_INDENT="$(printf '%s\n' "$_SC_CA_CERT_PEM" | sed 's/^/ /')" _SC_SERVER_CERT_INDENT="$(printf '%s\n' "$_SC_SERVER_CERT_PEM" | sed 's/^/ /')" _SC_SERVER_KEY_INDENT="$(printf '%s\n' "$_SC_SERVER_KEY_PEM" | sed 's/^/ /')" _SC_CA_CERT_JSON="$(printf '%s' "$_SC_CA_CERT_PEM" | tr '\n' '|' | sed 's/|/\\n/g')" PLAYER_SSH_CONFIG="$(cat <<'EOF' Host hermes HostName 10.42.0.40 User player IdentityFile ~/.ssh/sc_host_key StrictHostKeyChecking no UserKnownHostsFile /dev/null BatchMode yes ConnectTimeout 5 LogLevel ERROR Host vulcan HostName 10.42.0.24 User player IdentityFile ~/.ssh/sc_host_key StrictHostKeyChecking no UserKnownHostsFile /dev/null BatchMode yes ConnectTimeout 5 LogLevel ERROR Host 10.42.0.* User player IdentityFile ~/.ssh/sc_host_key StrictHostKeyChecking no UserKnownHostsFile /dev/null BatchMode yes ConnectTimeout 5 LogLevel ERROR EOF )" PLAYER_SSH_CONFIG_INDENT="$(printf '%s\n' "$PLAYER_SSH_CONFIG" | sed 's/^/ /')" _nginx_config() { printf '%s\n' \ ' server {' \ ' listen 443 ssl;' \ ' server_name axiomworks.corp www.axiomworks.corp;' \ ' ssl_certificate /etc/nginx/certs/server.crt;' \ ' ssl_certificate_key /etc/nginx/certs/server.key;' \ ' location / {' \ " proxy_pass https://${GAME_HOST_IP}:3000/company/;" \ ' proxy_ssl_verify off;' \ ' proxy_set_header Host $host;' \ ' proxy_set_header X-Real-IP $remote_addr;' \ ' }' \ ' }' \ ' server {' \ ' listen 80;' \ ' server_name axiomworks.corp www.axiomworks.corp;' \ ' return 301 https://$host$request_uri;' \ ' }' } _cert_write_files() { if [[ -z "$_SC_CA_CERT_PEM" ]]; then return; fi printf '%s\n' ' - path: /usr/local/share/ca-certificates/axiomworks-ca.crt' printf '%s\n' ' owner: root:root' printf '%s\n' " permissions: '0644'" printf '%s\n' ' content: |' printf '%s\n' "$_SC_CA_CERT_INDENT" printf '%s\n' ' - path: /etc/nginx/certs/server.crt' printf '%s\n' ' owner: root:root' printf '%s\n' " permissions: '0644'" printf '%s\n' ' content: |' printf '%s\n' "$_SC_SERVER_CERT_INDENT" printf '%s\n' ' - path: /etc/nginx/certs/server.key' printf '%s\n' ' owner: root:root' printf '%s\n' " permissions: '0600'" printf '%s\n' ' content: |' printf '%s\n' "$_SC_SERVER_KEY_INDENT" printf '%s\n' ' - path: /etc/chromium/policies/managed/axiomworks-ca.json' printf '%s\n' ' owner: root:root' printf '%s\n' " permissions: '0644'" printf '%s\n' ' content: |' printf '%s\n' ' {' printf '%s\n' ' "AdditionalTrustAnchors": [' printf '%s\n' " \"$_SC_CA_CERT_JSON\"" printf '%s\n' ' ]' printf '%s\n' ' }' } generate_user_data() { cat </dev/null 2>&1; do sleep 2; done exec chromium --no-first-run --no-default-browser-check --new-window "${HUD_URL}" - path: /usr/local/share/axiomworks-wallpaper.png owner: root:root permissions: '0644' encoding: b64 content: | ${WALLPAPER_B64_INDENT} - path: /usr/share/backgrounds/wallpaper.png owner: root:root permissions: '0644' encoding: b64 content: | ${WALLPAPER_B64_INDENT} - path: /home/player/Desktop/Portal.desktop owner: root:root permissions: '0755' content: | [Desktop Entry] Type=Application Name=Axiom Works Portal Exec=chromium --no-first-run --no-default-browser-check --new-window ${HUD_URL} Icon=chromium Terminal=false - path: /home/player/Desktop/Terminal.desktop owner: root:root permissions: '0755' content: | [Desktop Entry] Type=Application Name=Terminal Exec=tilix Icon=utilities-terminal Terminal=false Path=/home/player - path: /usr/local/bin/trust-desktop-launchers owner: root:root permissions: '0755' content: | #!/bin/bash # Trust every player desktop launcher from the real player login session. set -u PATH=/usr/local/bin:/usr/bin:/bin player_uid="\$(id -u player)" desktop_dir=/home/player/Desktop export HOME=/home/player export USER=player export LOGNAME=player export DISPLAY="\${DISPLAY:-:0}" export XAUTHORITY="\${XAUTHORITY:-/home/player/.Xauthority}" export XDG_RUNTIME_DIR="/run/user/\$player_uid" if [ -S "\$XDG_RUNTIME_DIR/bus" ]; then export DBUS_SESSION_BUS_ADDRESS="unix:path=\$XDG_RUNTIME_DIR/bus" fi metadata_daemon="" for candidate in /usr/libexec/gvfsd-metadata /usr/lib/gvfs/gvfsd-metadata /usr/lib/x86_64-linux-gnu/gvfs/gvfsd-metadata; do if [ -x "\$candidate" ]; then metadata_daemon="\$candidate" break fi done if [ -n "\$metadata_daemon" ] && ! /usr/bin/pgrep -u "\$player_uid" -x gvfsd-metadata >/dev/null 2>&1; then "\$metadata_daemon" >/dev/null 2>&1 & sleep 1 fi for i in \$(/usr/bin/seq 1 20); do trusted_any=false failed=false for launcher in "\$desktop_dir"/*.desktop; do [ -e "\$launcher" ] || continue chmod 0755 "\$launcher" 2>/dev/null || true checksum="\$(/usr/bin/sha256sum "\$launcher" | /usr/bin/awk '{print \$1}')" || { failed=true continue } if /usr/bin/gio set -t string "\$launcher" metadata::xfce-exe-checksum "\$checksum" 2>/dev/null; then actual_checksum="\$(/usr/bin/gio info -a metadata::xfce-exe-checksum "\$launcher" 2>/dev/null | /usr/bin/awk -F': ' '/metadata::xfce-exe-checksum:/ {print \$2; exit}')" owner_mode="\$(/usr/bin/stat -c '%U:%G %a' "\$launcher" 2>/dev/null || true)" if [ "\$actual_checksum" != "\$checksum" ] || [ "\$owner_mode" != "player:player 755" ]; then failed=true continue fi trusted_any=true else failed=true fi done if [ "\$trusted_any" = true ] && [ "\$failed" = false ]; then /usr/bin/xfdesktop --reload >/dev/null 2>&1 || /usr/bin/pkill -HUP xfdesktop 2>/dev/null || true rm -f /home/player/.config/autostart/trust-launchers.desktop exit 0 fi sleep 1 done # gvfsd not ready — will retry next login exit 1 - path: /home/player/.local/bin/trust-desktop-launchers.sh owner: root:root permissions: '0755' content: | #!/bin/bash exec /usr/local/bin/trust-desktop-launchers - path: /home/player/.config/autostart/trust-launchers.desktop owner: root:root permissions: '0644' content: | [Desktop Entry] Type=Application Name=Trust Desktop Launchers Exec=/usr/local/bin/trust-desktop-launchers Terminal=false X-GNOME-Autostart-enabled=true Hidden=false NoDisplay=true - path: /home/player/Desktop/VIEWER_HELP.txt owner: root:root permissions: '0644' content: | Workstation Viewer — Quick Reference ===================================== Toggle fullscreen: F11 Release mouse/kb: Shift+F12 (or Ctrl+Alt on some builds) Scale display: View → Zoom (or Ctrl+scroll) Copy from guest: Select text, then right-click → Copy Paste to guest: Right-click input field → Paste Switch USB redirect: Input → USB Device Redirection - path: /home/player/.config/xfce4/desktop/icons.screen0-1264x757.rc owner: root:root permissions: '0644' content: | [xfdesktop-version-4.10.3+-rcfile_format] 4.10.3+=true [/home/player/Desktop/VIEWER_HELP.txt] row=6 col=0 [/home/player/Desktop/Terminal.desktop] row=0 col=6 [/home/player/Desktop/Portal.desktop] row=0 col=7 [Trash] row=6 col=11 [/] row=0 col=4 [/home/player] row=0 col=5 - path: /home/player/.config/xfce4/desktop/icons.screen.latest.rc owner: root:root permissions: '0644' content: | [xfdesktop-version-4.10.3+-rcfile_format] 4.10.3+=true [/home/player/Desktop/VIEWER_HELP.txt] row=6 col=0 [/home/player/Desktop/Terminal.desktop] row=0 col=6 [/home/player/Desktop/Portal.desktop] row=0 col=7 [Trash] row=6 col=11 [/] row=0 col=4 [/home/player] row=0 col=5 - path: /home/player/.config/xfce4/xfconf/xfce-perchannel-xml/xfwm4.xml owner: root:root permissions: '0644' content: | - path: /home/player/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-screensaver.xml owner: root:root permissions: '0644' content: | - path: /home/player/.ssh/sc_host_key owner: root:root permissions: '0600' content: | ${PRIVKEY_INDENT} - path: /home/player/.ssh/config owner: root:root permissions: '0600' content: | ${PLAYER_SSH_CONFIG_INDENT} - path: /home/player/.config/chromium/Default/Preferences owner: root:root permissions: '0644' content: | { "bookmark_bar": { "show_on_all_tabs": true }, "browser": { "check_default_browser": false, "show_home_button": false }, "background_mode": { "enabled": false }, "signin": { "allowed": false }, "metrics": { "reporting_enabled": false }, "safebrowsing": { "enabled": false }, "translate": { "enabled": false } } - path: /home/player/.config/chromium/First Run owner: root:root permissions: '0644' content: '' - path: /home/player/.config/xfce4/xfconf/xfce-perchannel-xml/xsettings.xml owner: root:root permissions: '0644' content: | - path: /home/player/.config/xfce4/helpers.rc owner: root:root permissions: '0644' content: | TerminalEmulator=tilix - path: /home/player/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-desktop.xml owner: root:root permissions: '0644' content: | - path: /home/player/.bashrc owner: root:root permissions: '0644' content: | [ -z "\$PS1" ] && return export TERM=xterm-256color export EDITOR=nano PS1='\[\e[0;32m\]\u@\h\[\e[0m\]:\[\e[0;34m\]\w\[\e[0m\]\$ ' HISTSIZE=5000 HISTFILESIZE=10000 HISTCONTROL=ignoredups:erasedups shopt -s histappend alias ll='ls -lh --color=auto' alias la='ls -lha --color=auto' alias l='ls -CF --color=auto' alias grep='grep --color=auto' alias ..='cd ..' alias ...='cd ../..' export LS_COLORS='di=0;34:ln=0;36:ex=0;32:' if [ -f /usr/share/bash-completion/bash_completion ]; then . /usr/share/bash-completion/bash_completion fi - path: /etc/sysctl.d/99-sc-workstation.conf owner: root:root permissions: '0644' content: | vm.swappiness=10 vm.vfs_cache_pressure=50 vm.dirty_ratio=20 vm.dirty_background_ratio=5 net.ipv6.conf.all.disable_ipv6=1 net.ipv6.conf.default.disable_ipv6=1 - path: /etc/udev/rules.d/90-sysadmin-chronicles-hide-system-disk.rules owner: root:root permissions: '0644' content: | # Hide the internal VirtIO system disk from desktop file-manager device lists. KERNEL=="vd[a-z]", ENV{UDISKS_IGNORE}="1" KERNEL=="vd[a-z][0-9]*", ENV{UDISKS_IGNORE}="1" - path: /etc/nginx/sites-available/axiomworks owner: root:root permissions: '0644' content: | $(_nginx_config) $(_cert_write_files) runcmd: - mkdir -p /home/player/Desktop /home/player/projects /home/player/.ssh /home/player/.config/autostart /home/player/.config/xfce4/desktop /home/player/.config/xfce4/xfconf/xfce-perchannel-xml /home/player/.config/chromium/Default /home/opsbridge/.ssh /home/player/.local/bin - chown -R player:player /home/player - chown -R opsbridge:opsbridge /home/opsbridge - passwd -d player - chmod 700 /home/player/.ssh - chmod 700 /home/opsbridge/.ssh - touch /home/player/.ssh/authorized_keys - touch /home/opsbridge/.ssh/authorized_keys - chown player:player /home/player/.ssh/authorized_keys - chown opsbridge:opsbridge /home/opsbridge/.ssh/authorized_keys - chmod 600 /home/player/.ssh/authorized_keys - chmod 600 /home/opsbridge/.ssh/authorized_keys - printf '%s\n' 'Axiom Works workstation ready.' > /home/player/notes.txt - chown player:player /home/player/notes.txt - mkdir -p /var/lib/lightdm/data - chown lightdm:lightdm /var/lib/lightdm/data || chown 108:114 /var/lib/lightdm/data || true - test -f /swapfile || fallocate -l 1G /swapfile - chmod 600 /swapfile - mkswap -f /swapfile - swapon /swapfile || true - grep -q '^/swapfile ' /etc/fstab || echo '/swapfile none swap sw 0 0' >> /etc/fstab - ln -sf /etc/nginx/sites-available/axiomworks /etc/nginx/sites-enabled/axiomworks - mkdir -p /etc/nginx/certs - test -f /usr/local/share/ca-certificates/axiomworks-ca.crt && update-ca-certificates || true - mkdir -p /etc/chromium/policies/managed - | if [ -f /usr/local/share/ca-certificates/axiomworks-ca.crt ]; then mkdir -p /home/player/.pki/nssdb certutil -d sql:/home/player/.pki/nssdb -N --empty-password 2>/dev/null || true certutil -d sql:/home/player/.pki/nssdb -A -t "CT,," -n "Axiom Works CA" -i /usr/local/share/ca-certificates/axiomworks-ca.crt 2>/dev/null || true chown -R player:player /home/player/.pki fi - rm -f /etc/nginx/sites-enabled/default - systemctl enable --now nginx - systemctl enable --now qemu-guest-agent ssh spice-vdagent - systemctl enable lightdm - systemctl set-default graphical.target - DEBIAN_FRONTEND=noninteractive apt-get purge -y plymouth plymouth-label || true - DEBIAN_FRONTEND=noninteractive apt-get install -y linux-image-amd64 - cloud_kernels="\$(dpkg-query -W -f='\${Package}\\n' 'linux-image-*-cloud-amd64' 2>/dev/null | tr '\\n' ' ')"; if [ -n "\$cloud_kernels" ]; then DEBIAN_FRONTEND=noninteractive apt-get purge -y linux-image-cloud-amd64 \$cloud_kernels; fi - update-grub || true - update-alternatives --set x-www-browser /usr/bin/chromium || true - update-alternatives --set x-terminal-emulator /usr/bin/tilix || true - sysctl -p /etc/sysctl.d/99-sc-workstation.conf - udevadm control --reload-rules || true - udevadm trigger --subsystem-match=block || true - systemctl enable --now avahi-daemon - "sed -i 's/^hosts:.*/hosts: files mdns4_minimal [NOTFOUND=return] dns/' /etc/nsswitch.conf" - systemctl disable --now unattended-upgrades || true - systemctl disable --now apt-daily.timer apt-daily-upgrade.timer || true - systemctl disable --now ModemManager || true - systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target - rm -f /home/player/.config/autostart/game-hud.desktop - rm -f /home/player/.Xauthority /home/player/.ICEauthority - find /home/player/Desktop -maxdepth 1 -type f -name '*.desktop' -exec chmod 0755 {} + - chown -R player:player /home/player power_state: mode: reboot timeout: 30 condition: true final_message: "Ares XFCE workstation is ready." EOF }