Photo by Jon Tyson on Unsplash

Photo by Jon Tyson on Unsplash

Automatically terminate OpenSSH sessions

The Clock Is Ticking

Article from ADMIN 79/2024
By
Disconnect OpenSSH user sessions after a certain period of inactivity with the systemd-logind service.

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.

The Author

Thorsten Scherf is the global Product Lead for Identity Management and Platform Security in Red Hat's Product Experience group. He is a regular speaker at various international conferences and writes a lot about open source software.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy ADMIN Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

  • Integrating Podman and systemd
    With the integration of Podman and systemd, you can put any software inside a container under the control of systemd and see almost no difference between running the service directly on the host or inside a container.
  • Server administration using Cockpit
    Cockpit makes it easy to manage Linux servers: Four mouse clicks in the browser restart the crashed web server, and four more interconnect the server's network interfaces. Pilots flying in this cockpit, though, have to cope with a few limitations.
  • The achievements of and plans for systemd
    We talked to systemd maintainer Lennart Poettering about the sense and purpose of some systemd features.
  • 24 Useful systemd Commands
  • SSH on Windows

    For Linux admins, SSH is one the most important tools of remote administration. SSH also works in Windows, with tools such as PuTTY or WinSSH, MobaXterm, WinSCP, or Swish.

comments powered by Disqus
Subscribe to our ADMIN Newsletters
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs



Support Our Work

ADMIN content is made possible with support from readers like you. Please consider contributing when you've found an article to be beneficial.

Learn More”>
	</a>

<hr>		    
			</div>
		    		</div>

		<div class=