- place the
autossh@.servicefile in /etc/systemd/system - enable an instance -- suppose your remote host is called
frodothen you might run:systemctl enable autossh@frodo(do not use--nowhere!) - now it is time to create an override specific to the instance, e.g. :
systemctl edit autossh@frodo.serviceand adjust the following bunch of settings (commented out in the main unit template) like so:
adjust the ports, username and host name as needed. You may leave the[Service] Environment=MONITOR_PORT=1023 Environment=REMOTE_PORT=1022 Environment=TARGET_USER=username Environment=TARGET_HOST=frodo.example.com Environment=AUTOSSH_POLL=60 Environment=AUTOSSH_FIRST_POLL=30 Environment=AUTOSSH_LOGLEVEL=7 Environment=AUTOSSH_GATETIME=0AUTOSSH_*variables alone or tinker with them later! NB: you must not forget the[Service]to establish the section context.- This should have created a file
/etc/systemd/system/autossh@frodo.service.d/override.conf
- This should have created a file
- once you're done run:
systemctl daemon-reloadfor the changes to take effect - create an SSH identity in
/etc/ssh/id_nobodyusingssh-keygen -f; alternatively adjust theLoadCredential=stanza to some other credential you want to use- if you opt for a different path it probably makes sense to also place the
LoadCredential=stanza into theoverride.conf
- if you opt for a different path it probably makes sense to also place the
- run
systemd-analyze security autossh@frodo.serviceand witness something along the lines of:→ Overall exposure level for autossh@frodo.service: 1.1 OK 🙂 - start the service with systemctl start
autossh@frodo.serviceand observe any issues withjournalctl -f(if you need more context, i.e. previous lines, throw in a-n 200or so)
Last active
March 22, 2025 08:22
-
-
Save assarbad/d297ffa0fabb194eb405ac0f342c62ee to your computer and use it in GitHub Desktop.
Strictly hardened autossh systemd unit template for port-forwarding
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| [Unit] | |
| Description=Establish persistent SSH tunnel (%i) | |
| Requires=ssh.service | |
| Wants=network-online.target | |
| After=network-online.target | |
| [Service] | |
| DynamicUser=true | |
| # Import identity into unit namespace | |
| ; LoadCredential=identity:/etc/ssh/id_nobody | |
| ; Environment=MONITOR_PORT=1023 | |
| ; Environment=REMOTE_PORT=1022 | |
| ; Environment=TARGET_USER=username | |
| ; Environment=TARGET_HOST=example.com | |
| ; Environment=AUTOSSH_POLL=60 | |
| ; Environment=AUTOSSH_FIRST_POLL=30 | |
| ; Environment=AUTOSSH_LOGLEVEL=7 | |
| ; Environment=AUTOSSH_GATETIME=0 | |
| ExecStart=/usr/bin/env AUTOSSH_LOGFILE=${LOGS_DIRECTORY}/${TARGET_HOST}.log /usr/bin/autossh -M ${MONITOR_PORT} -- -4Nngi %d/identity -R localhost:${REMOTE_PORT}:localhost:22 -o IdentitiesOnly=yes -o ExitOnForwardFailure=yes -o StrictHostKeyChecking=no -o | |
| UserKnownHostsFile=/dev/null -o PasswordAuthentication=no -o PubkeyAuthentication=yes -o ServerAliveInterval=60 -o ServerAliveCountMax=3 -o BatchMode=yes ${TARGET_USER}@${TARGET_HOST} | |
| RestartSec=6 | |
| Restart=always | |
| AmbientCapabilities= | |
| CapabilityBoundingSet= | |
| NoNewPrivileges=true | |
| ProtectClock=true | |
| ProtectControlGroups=true | |
| ProtectHome=true | |
| ProtectHostname=true | |
| ProtectKernelLogs=true | |
| ProtectKernelModules=true | |
| ProtectKernelTunables=true | |
| ProtectProc=invisible | |
| ProcSubset=pid | |
| RestrictNamespaces=~cgroup | |
| RestrictNamespaces=~ipc | |
| RestrictNamespaces=~mnt | |
| RestrictNamespaces=~net | |
| RestrictNamespaces=~pid | |
| RestrictNamespaces=~user | |
| RestrictNamespaces=~uts | |
| RestrictRealtime=true | |
| RestrictSUIDSGID=true | |
| PrivateTmp=true | |
| PrivateDevices=true | |
| PrivateUsers=true | |
| InaccessiblePaths=-/etc/letsencrypt | |
| InaccessiblePaths=-/root | |
| InaccessiblePaths=-/usr/local/bin | |
| SystemCallArchitectures=native | |
| SystemCallFilter=~@clock | |
| SystemCallFilter=~@cpu-emulation | |
| SystemCallFilter=~@debug | |
| SystemCallFilter=~@module | |
| SystemCallFilter=~@mount | |
| SystemCallFilter=~@obsolete | |
| SystemCallFilter=~@privileged | |
| SystemCallFilter=~@raw-io | |
| SystemCallFilter=~@reboot | |
| SystemCallFilter=~@resources | |
| SystemCallFilter=~@swap | |
| LockPersonality=true | |
| MemoryDenyWriteExecute=true | |
| RemoveIPC=true | |
| SystemCallErrorNumber=EPERM | |
| RestrictAddressFamilies=AF_INET AF_UNIX | |
| RestrictAddressFamilies=~AF_NETLINK AF_PACKET | |
| ProtectSystem=strict | |
| ReadOnlyPaths=/etc/ssh | |
| LogsDirectory=autossh | |
| [Install] | |
| WantedBy=multi-user.target |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment