Securing SSH access is one of the most important tasks for Linux administrators. Most Linux servers expose SSH to the internet, making it a common target for automated attacks, brute-force login attempts, and privilege escalation vulnerabilities.
Modern Linux distributions using systemd provide built in service hardening features that can significantly improve the security of sshd.service without affecting normal SSH access.
Why Harden sshd.service?
By default, the OpenSSH service works with minimal isolation. While OpenSSH itself is secure and well maintained, additional hardening reduces the damage an attacker could do if the service is ever compromised.
Using systemd hardening options, we can
- Restrict filesystem access
- Limit dangerous system calls
- Isolate temporary files
- Protect kernel interfaces
- Reduce privilege escalation risks
The key is applying protections carefully so remote SSH access continues to work normally.
Checking current score
The current score before applying with Assessment Test Identifiers
root@gateway1:~# systemd-analyze security sshd.service | grep sshd.service
→ Overall exposure level for sshd.service: 9.6 UNSAFE 😨
root@gateway1:~#
Listing Assessment
To retrieve all available assessment test identifiers, execute the following command using the service name that is to be hardened.
NAME DESCRIPTION EXPOSURE
✗ RootDirectory=/RootImage= Service runs within the host's root directory 0.1
SupplementaryGroups= Service runs as root, option does not matter
RemoveIPC= Service runs as root, option does not apply
✗ User=/DynamicUser= Service runs as root user 0.4
✗ CapabilityBoundingSet=~CAP_SYS_TIME Service processes may change the system clock 0.2
✗ NoNewPrivileges= Service processes may acquire new privileges 0.2
✓ AmbientCapabilities= Service process does not receive ambient capabilities
✗ PrivateDevices= Service potentially has access to hardware devices 0.2
✗ ProtectClock= Service may write to the hardware clock or system clock 0.2
✗ CapabilityBoundingSet=~CAP_SYS_PACCT Service may use acct() 0.1
✗ CapabilityBoundingSet=~CAP_KILL Service may send UNIX signals to arbitrary processes 0.1
✗ ProtectKernelLogs= Service may read from or write to the kernel log ring buffer 0.2
✗ CapabilityBoundingSet=~CAP_WAKE_ALARM Service may program timers that wake up the system 0.1
✗ CapabilityBoundingSet=~CAP_(DAC_*|FOWNER|IPC_OWNER) Service may override UNIX file/IPC permission checks 0.2
✗ ProtectControlGroups= Service may modify the control group file system 0.2
✗ CapabilityBoundingSet=~CAP_LINUX_IMMUTABLE Service may mark files immutable 0.1
✗ CapabilityBoundingSet=~CAP_IPC_LOCK Service may lock memory into RAM 0.1
✗ ProtectKernelModules= Service may load or read kernel modules 0.2
✗ CapabilityBoundingSet=~CAP_SYS_MODULE Service may load kernel modules 0.2
✗ CapabilityBoundingSet=~CAP_BPF Service may load BPF programs 0.1
✗ CapabilityBoundingSet=~CAP_SYS_TTY_CONFIG Service may issue vhangup() 0.1
✗ CapabilityBoundingSet=~CAP_SYS_BOOT Service may issue reboot() 0.1
✗ CapabilityBoundingSet=~CAP_SYS_CHROOT Service may issue chroot() 0.1
✗ PrivateMounts= Service may install system mounts 0.2
✗ SystemCallArchitectures= Service may execute system calls with all ABIs 0.2
✗ CapabilityBoundingSet=~CAP_BLOCK_SUSPEND Service may establish wake locks 0.1
✗ MemoryDenyWriteExecute= Service may create writable executable memory mappings 0.1
✗ RestrictNamespaces=~user Service may create user namespaces 0.3
✗ RestrictNamespaces=~pid Service may create process namespaces 0.1
✗ RestrictNamespaces=~net Service may create network namespaces 0.1
✗ RestrictNamespaces=~uts Service may create hostname namespaces 0.1
✗ RestrictNamespaces=~mnt Service may create file system namespaces 0.1
✗ CapabilityBoundingSet=~CAP_LEASE Service may create file leases 0.1
✗ CapabilityBoundingSet=~CAP_MKNOD Service may create device nodes 0.1
✗ RestrictNamespaces=~cgroup Service may create cgroup namespaces 0.1
✗ RestrictSUIDSGID= Service may create SUID/SGID files 0.2
✗ RestrictNamespaces=~ipc Service may create IPC namespaces 0.1
✗ ProtectHostname= Service may change system host/domainname 0.1
✗ CapabilityBoundingSet=~CAP_(CHOWN|FSETID|SETFCAP) Service may change file ownership/access mode/capabilities unrestricted 0.2
✗ CapabilityBoundingSet=~CAP_SET(UID|GID|PCAP) Service may change UID/GID identities/capabilities 0.3
✗ LockPersonality= Service may change ABI personality 0.1
✗ ProtectKernelTunables= Service may alter kernel tunables 0.2
✗ RestrictAddressFamilies=~AF_PACKET Service may allocate packet sockets 0.2
✗ RestrictAddressFamilies=~AF_NETLINK Service may allocate netlink sockets 0.1
✗ RestrictAddressFamilies=~AF_UNIX Service may allocate local sockets 0.1
✗ RestrictAddressFamilies=~… Service may allocate exotic sockets 0.3
✗ RestrictAddressFamilies=~AF_(INET|INET6) Service may allocate Internet sockets 0.3
✗ CapabilityBoundingSet=~CAP_MAC_* Service may adjust SMACK MAC 0.1
✗ RestrictRealtime= Service may acquire realtime scheduling 0.1
✗ CapabilityBoundingSet=~CAP_SYS_RAWIO Service has raw I/O access 0.2
✗ CapabilityBoundingSet=~CAP_SYS_PTRACE Service has ptrace() debugging abilities 0.3
✗ CapabilityBoundingSet=~CAP_SYS_(NICE|RESOURCE) Service has privileges to change resource use parameters 0.1
✗ DeviceAllow= Service has no device ACL 0.2
✗ CapabilityBoundingSet=~CAP_NET_ADMIN Service has network configuration privileges 0.2
✗ ProtectSystem= Service has full access to the OS file hierarchy 0.2
✗ ProtectProc= Service has full access to process tree (/proc hidepid=) 0.2
✗ ProcSubset= Service has full access to non-process /proc files (/proc subset=) 0.1
✗ ProtectHome= Service has full access to home directories 0.2
✗ CapabilityBoundingSet=~CAP_NET_(BIND_SERVICE|BROADCAST|RAW) Service has elevated networking privileges 0.1
✗ CapabilityBoundingSet=~CAP_AUDIT_* Service has audit subsystem access 0.1
✗ CapabilityBoundingSet=~CAP_SYS_ADMIN Service has administrator privileges 0.3
✗ PrivateNetwork= Service has access to the host's network 0.5
✗ PrivateUsers= Service has access to other users 0.2
✗ PrivateTmp= Service has access to other software's temporary files 0.2
✗ CapabilityBoundingSet=~CAP_SYSLOG Service has access to kernel logging 0.1
✓ KeyringMode= Service doesn't share key material with other services
✓ Delegate= Service does not maintain its own delegated control group subtree
✗ SystemCallFilter=~@clock Service does not filter system calls 0.2
✗ SystemCallFilter=~@cpu-emulation Service does not filter system calls 0.1
✗ SystemCallFilter=~@debug Service does not filter system calls 0.2
✗ SystemCallFilter=~@module Service does not filter system calls 0.2
✗ SystemCallFilter=~@mount Service does not filter system calls 0.2
✗ SystemCallFilter=~@obsolete Service does not filter system calls 0.1
✗ SystemCallFilter=~@privileged Service does not filter system calls 0.2
✗ SystemCallFilter=~@raw-io Service does not filter system calls 0.2
✗ SystemCallFilter=~@reboot Service does not filter system calls 0.2
✗ SystemCallFilter=~@resources Service does not filter system calls 0.2
✗ SystemCallFilter=~@swap Service does not filter system calls 0.2
✗ IPAddressDeny= Service does not define an IP address allow list 0.2
✓ NotifyAccess= Service child processes cannot alter service state
✗ UMask= Files created by service are world-readable by default 0.1
→ Overall exposure level for sshd.service: 9.6 UNSAFE 😨
Hardening sshd.service
As root user make the required changes, below are the tested and working options
# systemctl edit sshd.service
[Service]
# Basic hardening
PrivateTmp=yes
PrivateDevices=yes
# Filesystem protections
ProtectSystem=full
ProtectHome=read-only
ProtectHostname=yes
ProtectClock=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
ProtectKernelLogs=yes
# Process protections
ProtectProc=invisible
ProcSubset=pid
# Restrict privilege escalation
RestrictSUIDSGID=yes
LockPersonality=yes
RestrictRealtime=yes
# IPC cleanup
RemoveIPC=yes
# Namespace restrictions
RestrictNamespaces=yes
# Architecture restriction
SystemCallArchitectures=native
# Allow only common socket families required by sshd
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
# Safer umask
UMask=0077
Making change into effect
Reload the configuration and restart the sshd service to ensure the changes take effect.
# systemctl daemon-reload
# systemctl restart sshd.service
Next, verify the systemd security score for the sshd service.
Check the new score
root@gateway1:~# systemd-analyze security sshd.service | grep sshd.service
→ Overall exposure level for sshd.service: 5.3 MEDIUM 😐
root@gateway1:~#
Systemd hardening provides an extra security layer for OpenSSH without requiring additional software. The safest approach is to apply changes gradually, test thoroughly, and avoid overly aggressive restrictions that may interrupt remote access.
For most production Linux servers, a balanced hardening setup can improve the systemd-analyze security score significantly while keeping SSH stable and fully functional.
