Automatically terminate OpenSSH sessions
The Clock Is Ticking
When configuring a system, a large number of settings are required to meet compliance requirements. Common Criteria [1] is an international standard for the security certification of computer systems. The standard defines the requirements as security targets.
Targets look different depending on the system you are using. For example, the requirements for a mobile device differ from those for a desktop system, which explains why protection profiles are different. The Protection Profile for general-purpose operating systems [2] clearly stipulates that user sessions must either be terminated or, alternatively, locked after a certain period of inactivity.
However, recent OpenSSH versions block a workaround frequently used to meet this requirement. We show you how to use the systemd-logind
service to solve this dilemma.
Compliance Undermined
The US Department of Defense (DOD) Defense Information Systems Agency (DISA) Security Technical Implementation Guides (STIGs) [3] also stipulate these requirements for operating systems. The Guide for Red Hat Enterprise Linux 8 [4] proposes implementing these rules with specific configurations of the OpenSSH service. Two statements, ClientAliveInterval
and ClientAliveCountMax
, are intended to help meet the compliance requirements:
grep -i clientalive /etc/ssh/sshd_config ClientAliveInterval 600 ClientAliveCountMax 0
Once you have made these changes to your OpenSSH configuration, an SSH connection to this system will be disconnected after 10 minutes of inactivity, in exactly the way required by the Common Criteria and DISA STIGs.
The problem is, though, that these two options were intended for a completely different purpose – checking the SSH connection itself – and not for user session activity. It was only possible to terminate the session at all by setting the ClientAliveCountMax=0
option in combination with an arbitrary value for ClientAliveInterval
, even if a user was inactive and even if the connection itself was intact. The positive result is merely a lucky side effect and was never the intended to way for this to work.
This "misbehavior" of the software was fixed in the OpenSSH upstream version 8.2 at the end of 2020 [5]. Unfortunately, it also ruled out the option of terminating an SSH connection when a user is inactive. This new behavior is particularly annoying in environments where the systems need to meet specific compliance requirements.
The OpenSSH upstream community has long seen feature requests [6] [7] for the implementation of a configuration option that lets the SSH server terminate inactive sessions. However, these requests have thus far been rejected. One of the reasons is that most shells support the TMOUT
environment variable, which lets you set a timeout for user input. That said, the approach is fraught with a number of disadvantages and is easy to work around [8].
systemd-logind to the Rescue
After the upstream changes slowly made their way into the various Linux distributions, the outcry from users was massive, of course. After all, Linux distributions such as Red Hat Enterprise Linux or SUSE Linux Enterprise Server are used by corporations in compliance-critical environments. Because the OpenSSH upstream community was not really willing to address the problem, alternative solutions were sought. The result now available is quite obvious when you think about it and is based on the systemd-logind
service [9].
This service is explicitly designed to monitor users and their sessions and can detect the idle state of user sessions, enabled with the use of a separate PAM module, pam_systemd
[10]. This module takes care of registering a user's session with the systemd-logind
service after login, which in turn, creates a separate systemd slice unit for each new user and a scope unit each for any sessions belonging to the same user and running in parallel.
A patch [11] was released at the end of 2022 to extend the systemd-logind
service. Armed with the patch, you can now pass in the new StopIdleSessionSec
configuration option to the service, which ensures that a user's session ends as soon as systemd-logind
detects that the session has been inactive for longer than allowed. For example, if you want inactive user sessions to expire automatically after 10 minutes, you would use a value of 600 with the new option:
# grep StopIdleSessionSec /etc/systemd/logind.conf StopIdleSessionSec=600
After making these changes, remember to restart the service by typing:
# systemctl restart systemd-logind
For test purposes, set the value to 10 seconds and log in to this system again with SSH. The command
journalctl -u systemd-logind
reads and filters the system journal and shows how the user's inactive session is automatically terminated after 10 seconds (Listing 1).
Listing 1
Terminated Session
Mar 7 05:06:07 kvm-04-guest19 systemd-logind[46596]: New session 5 of user root. Mar 7 05:06:17 kvm-04-guest19 systemd[1]: session-5.scope: Killing process 46282 (sshd) with signal SIGTERM. Mar 7 05:06:17 kvm-04-guest19 systemd[1]: session-5.scope: Killing process 46285 (sshd) with signal SIGTERM. Mar 7 05:06:17 kvm-04-guest19 systemd[1]: session-5.scope: Killing process 46286 (bash) with signal SIGTERM. Mar 7 05:06:17 kvm-04-guest19 systemd[1]: Stopping Session 5 of user root. Mar 7 05:06:17 kvm-04-guest19 systemd[1]: session-5.scope: Succeeded. Mar 7 05:06:17 kvm-04-guest19 systemd[1]: Stopped Session 5 of user root. Mar 7 05:06:17 kvm-04-guest19 systemd-logind[46596]: Removed session 5.
Conclusions
Typical compliance requirements stipulate that inactive user sessions must either be terminated or alternatively blocked. Until recently, you could use some of the OpenSSH service's own configuration options to do this. However, this behavior was deliberately changed in recent versions of the software without providing an alternative approach to terminating inactive SSH connections. To remedy this shortcoming, the missing function has now been added to the systemd-logind
systemd service. This option lets admins define an interval after which inactive user sessions are automatically terminated.
Infos
- Common Criteria: https://www.commoncriteriaportal.org/index.cfm
- Protection profile for general-purpose operating systems: https://www.niap-ccevs.org/MMO/PP/-442-/#FMT_SMF_EXT.1.1
- STIGViewer: https://www.stigviewer.com
- RHEL8 STIG: https://www.stigviewer.com/stig/red_hat_enterprise_linux_8/2021-12-03/finding/V-230244
- OpenSSH patch: https://github.com/openssh/openssh-portable/commit/69334996ae203c51c70bf01d414c918a44618f8e
- OpenSSH-RFE 1: https://bugzilla.mindrot.org/show_bug.cgi?id=3362
- OpenSSH-RFE 2: https://bugzilla.mindrot.org/show_bug.cgi?id=1338
- Stackoverflow article on TMOUT: https://stackoverflow.com/questions/17397069/unset-readonly-variable-in-bash/54705440#54705440
- systemd-logind: https://www.freedesktop.org/software/systemd/man/latest/systemd-logind.service.html
- pam_systemd PAM module: https://www.freedesktop.org/software/systemd/man/latest/pam_systemd.html
- systemd-logind idle patch: https://github.com/redhat-plumbers/systemd-rhel8/pull/332
Buy this article as PDF
(incl. VAT)