Skip to content

Instantly share code, notes, and snippets.

@assarbad
Last active October 22, 2024 22:15
Show Gist options
  • Save assarbad/d297ffa0fabb194eb405ac0f342c62ee to your computer and use it in GitHub Desktop.
Save assarbad/d297ffa0fabb194eb405ac0f342c62ee to your computer and use it in GitHub Desktop.
Strictly hardened autossh systemd unit template for port-forwarding
[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

How to "install" the above unit template (all require superuser permissions)

  1. place the [email protected] file in /etc/systemd/system
  2. enable an instance -- suppose your remote host is called frodo then you might run: systemctl enable autossh@frodo (do not use --now here!)
  3. now it is time to create an override specific to the instance, e.g. : systemctl edit [email protected] and adjust the following bunch of settings (commented out in the main unit template) like so:
    [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=0
    
    adjust the ports, username and host name as needed. You may leave the AUTOSSH_* variables alone or tinker with them later! NB: you must not forget the [Service] to establish the section context.
  4. once you're done run: systemctl daemon-reload for the changes to take effect
  5. create an SSH identity in /etc/ssh/id_nobody using ssh-keygen -f; alternatively adjust the LoadCredential= 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 the override.conf
  6. run systemd-analyze security [email protected] and witness something along the lines of:
    → Overall exposure level for [email protected]: 1.1 OK 🙂
    
  7. start the service with systemctl start [email protected] and observe any issues with journalctl -f (if you need more context, i.e. previous lines, throw in a -n 200 or so)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment