diff --git a/examples/systemd/vnet/README.md b/examples/systemd/vnet/README.md new file mode 100644 index 0000000000000..6deb8c83b7f37 --- /dev/null +++ b/examples/systemd/vnet/README.md @@ -0,0 +1,33 @@ +# Teleport VNet Linux Files + +This directory contains files needed for VNet to work on Linux. +Teleport Connect ships these files in its package. + +## Files + +- `teleport-vnet.service`: systemd unit for the privileged VNet daemon. +- `dbus/org.teleport.vnet1.conf`: D-Bus system bus policy for `org.teleport.vnet1`. +- `dbus/org.teleport.vnet1.service`: D-Bus service activation entry for `org.teleport.vnet1`. +- `polkit/org.teleport.vnet1.policy`: polkit policy used to authorize starting and stopping the privileged VNet daemon. + +## Install locations (package defaults) + +- `teleport-vnet.service` -> `/usr/lib/systemd/system/teleport-vnet.service` +- `dbus/org.teleport.vnet1.conf` -> `/usr/share/dbus-1/system.d/org.teleport.vnet1.conf` +- `dbus/org.teleport.vnet1.service` -> `/usr/share/dbus-1/system-services/org.teleport.vnet1.service` +- `polkit/org.teleport.vnet1.policy` -> `/usr/share/polkit-1/actions/org.teleport.vnet1.policy` + +Notes: +- For packaged vendor files, `/usr/share/...` is the standard location. +- `/etc/dbus-1/system.d/` is typically for local admin overrides, not vendor package files. + +## Manual install example + +```bash +sudo cp teleport-vnet.service /usr/lib/systemd/system/teleport-vnet.service +sudo cp dbus/org.teleport.vnet1.conf /usr/share/dbus-1/system.d/org.teleport.vnet1.conf +sudo cp dbus/org.teleport.vnet1.service /usr/share/dbus-1/system-services/org.teleport.vnet1.service +sudo cp polkit/org.teleport.vnet1.policy /usr/share/polkit-1/actions/org.teleport.vnet1.policy +sudo systemctl daemon-reload +sudo dbus-send --print-reply --system --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.ReloadConfig +``` diff --git a/examples/systemd/vnet/dbus/org.teleport.vnet1.conf b/examples/systemd/vnet/dbus/org.teleport.vnet1.conf new file mode 100644 index 0000000000000..c6da201ab42b4 --- /dev/null +++ b/examples/systemd/vnet/dbus/org.teleport.vnet1.conf @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/examples/systemd/vnet/dbus/org.teleport.vnet1.service b/examples/systemd/vnet/dbus/org.teleport.vnet1.service new file mode 100644 index 0000000000000..ff67eb869c4bd --- /dev/null +++ b/examples/systemd/vnet/dbus/org.teleport.vnet1.service @@ -0,0 +1,5 @@ +[D-BUS Service] +Name=org.teleport.vnet1 +SystemdService=teleport-vnet.service +User=root +Exec=/bin/false diff --git a/examples/systemd/vnet/polkit/org.teleport.vnet1.policy b/examples/systemd/vnet/polkit/org.teleport.vnet1.policy new file mode 100644 index 0000000000000..49f6a1f2d4777 --- /dev/null +++ b/examples/systemd/vnet/polkit/org.teleport.vnet1.policy @@ -0,0 +1,18 @@ + + + + + + Start Teleport VNet + Authentication is required to start Teleport VNet + + no + no + + yes + + + + diff --git a/examples/systemd/vnet/teleport-vnet.service b/examples/systemd/vnet/teleport-vnet.service new file mode 100644 index 0000000000000..bd1db2e775343 --- /dev/null +++ b/examples/systemd/vnet/teleport-vnet.service @@ -0,0 +1,11 @@ +[Unit] +Description=Teleport VNet D-Bus service +After=dbus.service +Requires=dbus.service + +[Service] +Type=dbus +BusName=org.teleport.vnet1 +ExecStart=/usr/local/bin/tsh vnet-daemon +User=root +Group=root diff --git a/web/packages/teleterm/build_resources/linux/after-install.sh.tmpl b/web/packages/teleterm/build_resources/linux/after-install.sh.tmpl index fb2385535ac0d..aa2e66e489155 100644 --- a/web/packages/teleterm/build_resources/linux/after-install.sh.tmpl +++ b/web/packages/teleterm/build_resources/linux/after-install.sh.tmpl @@ -105,4 +105,44 @@ else fi fi +has_systemd() { + [ -d /run/systemd/system ] && command -v systemctl >/dev/null 2>&1 +} + +install_vnet_file() { + src="$1" + dst="$2" + mode="$3" + + [ -f "$src" ] || return 0 + mkdir -p "$(dirname "$dst")" + install -m "$mode" "$src" "$dst" +} + +reload_dbus_config() { + # Normally packages that install files into + # D-Bus configuration directories (for example): + # /usr/share/dbus-1/system.d/ + # /usr/share/dbus-1/system-services/ + # + # rely on package manager to reload the system bus configuration after installation. + # + # In our case, these files are copied into place by post-install script, so we reload + # dbus config manually. + dbus-send --print-reply --system \ + --dest=org.freedesktop.DBus \ + /org/freedesktop/DBus \ + org.freedesktop.DBus.ReloadConfig >/dev/null 2>&1 || true +} + +if has_systemd; then + VNET_SOURCE_DIR=$APP/resources/vnet + install_vnet_file "$VNET_SOURCE_DIR/polkit/org.teleport.vnet1.policy" /usr/share/polkit-1/actions/org.teleport.vnet1.policy 0644 + install_vnet_file "$VNET_SOURCE_DIR/dbus/org.teleport.vnet1.conf" /usr/share/dbus-1/system.d/org.teleport.vnet1.conf 0644 + install_vnet_file "$VNET_SOURCE_DIR/dbus/org.teleport.vnet1.service" /usr/share/dbus-1/system-services/org.teleport.vnet1.service 0644 + install_vnet_file "$VNET_SOURCE_DIR/teleport-vnet.service" /usr/lib/systemd/system/teleport-vnet.service 0644 + systemctl daemon-reload || true + reload_dbus_config +fi + # vim: syntax=sh diff --git a/web/packages/teleterm/build_resources/linux/after-remove.sh.tmpl b/web/packages/teleterm/build_resources/linux/after-remove.sh.tmpl index 11b4d0b1d88de..6f3f650b41192 100644 --- a/web/packages/teleterm/build_resources/linux/after-remove.sh.tmpl +++ b/web/packages/teleterm/build_resources/linux/after-remove.sh.tmpl @@ -54,6 +54,40 @@ if [ -L "$TSH_SYMLINK_TARGET" ] && [ ! -e "$TSH_SYMLINK_TARGET" ]; then rm -f "$TSH_SYMLINK_TARGET" fi +has_systemd() { + [ -d /run/systemd/system ] && command -v systemctl >/dev/null 2>&1 +} + +remove_vnet_file() { + dst="$1" + rm -f "$dst" +} + +reload_dbus_config() { + # Normally packages that install files into + # D-Bus configuration directories (for example): + # /usr/share/dbus-1/system.d/ + # /usr/share/dbus-1/system-services/ + # + # rely on package manager to reload the system bus configuration after installation. + # + # In our case, these files are copied into place by post-install script, so we reload + # dbus config manually. + dbus-send --print-reply --system \ + --dest=org.freedesktop.DBus \ + /org/freedesktop/DBus \ + org.freedesktop.DBus.ReloadConfig >/dev/null 2>&1 || true +} + +if has_systemd; then + remove_vnet_file /usr/share/polkit-1/actions/org.teleport.vnet1.policy + remove_vnet_file /usr/share/dbus-1/system.d/org.teleport.vnet1.conf + remove_vnet_file /usr/share/dbus-1/system-services/org.teleport.vnet1.service + remove_vnet_file /usr/lib/systemd/system/teleport-vnet.service + systemctl daemon-reload || true + reload_dbus_config +fi + # shellcheck disable=SC2016 # This is custom electron-builder macro expansion, not Bash templating. APPARMOR_PROFILE_DEST='/etc/apparmor.d/${executable}' diff --git a/web/packages/teleterm/electron-builder-config.js b/web/packages/teleterm/electron-builder-config.js index ade99097601a9..5d649bac844ab 100644 --- a/web/packages/teleterm/electron-builder-config.js +++ b/web/packages/teleterm/electron-builder-config.js @@ -1,5 +1,6 @@ const { env, platform } = require('process'); const fs = require('fs'); +const path = require('path'); const { spawn } = require('child_process'); const isMac = platform === 'darwin'; const isWindows = platform === 'win32'; @@ -86,9 +87,9 @@ module.exports = { return; } - const path = `${packed.appOutDir}/Teleport Connect.app/Contents/MacOS/tsh.app/Contents/Info.plist`; + const plistPath = `${packed.appOutDir}/Teleport Connect.app/Contents/MacOS/tsh.app/Contents/Info.plist`; if (packed.appOutDir.endsWith('mac-universal-x64-temp')) { - tshAppPlist = fs.readFileSync(path); + tshAppPlist = fs.readFileSync(plistPath); } if (packed.appOutDir.endsWith('mac-universal')) { if (!tshAppPlist) { @@ -96,7 +97,7 @@ module.exports = { 'Failed to copy tsh.app Info.plist file from the x64 build. Check if the path "mac-universal-x64-temp" was not changed by electron-builder.' ); } - fs.writeFileSync(path, tshAppPlist); + fs.writeFileSync(plistPath, tshAppPlist); } }, files: ['build/app'], @@ -259,6 +260,34 @@ module.exports = { from: env.CONNECT_TSH_BIN_PATH, to: './bin/tsh', }, + { + from: path.resolve( + __dirname, + '../../../examples/systemd/vnet/polkit/org.teleport.vnet1.policy' + ), + to: './vnet/polkit/org.teleport.vnet1.policy', + }, + { + from: path.resolve( + __dirname, + '../../../examples/systemd/vnet/dbus/org.teleport.vnet1.conf' + ), + to: './vnet/dbus/org.teleport.vnet1.conf', + }, + { + from: path.resolve( + __dirname, + '../../../examples/systemd/vnet/dbus/org.teleport.vnet1.service' + ), + to: './vnet/dbus/org.teleport.vnet1.service', + }, + { + from: path.resolve( + __dirname, + '../../../examples/systemd/vnet/teleport-vnet.service' + ), + to: './vnet/teleport-vnet.service', + }, { from: 'build_resources/linux/apparmor-profile', to: './apparmor-profile',