4

I have a normal Linux user that is:

  1. only allowed to login via ssh to execute a single command and nothing else
  2. may never login more the once at a single time

The first restriction is implemented using the command option in the user's authorized_keys file, and works without issue.

The second restriction is implemented using PAM to enforce /etc/security/limits.conf. This part doesn't seem to work at all when I use it in conjunction with the previous restriction, but works otherwise. That is, If I limit ssh logins to a single command, I can log in concurrently as many times as I want. If I do not use the command option, I am not allowed to login more than once at a given time. (login is rejected with the usual error: Too many logins for user 'X'.)

Why is PAM failing to restrict logins when the command option is used in authorized_keys and what can I do to enforce the two aforementioned restrictions as the same time?

sshd is configured to use pam (UsePAM yes).

Addendum: Upon further investigation, it appears that the maxlogins restriction is being evaluated for all ssh connections (both with the command option specified and without). However, because login/pty sessions are the only type of sessions being counted against maxlogins, any number of parallel non-interactive sessions can be opened as long as the number of interactive sessions remains bellow maxlogins.

I can see two ways I can tackle this problem:

  1. have sshd itself enforce the single connection per user restriction
  2. find a way to get linux to count non-interactive shells against maxlogins

I've skimed through the manual pages for both sshd (8) and sshd_config(8) but was unable to find anything relevant. I can force a tty client side (e.g. ssh -tt) but that would leave restriction enforcement in the hands of the clients.

Configuration Files

I'm attempting to set this up in a Debian-based docker container. Both /etc/pam.d/sshd and /etc/ssh/sshd_config are unchanged from upstream except for the four lines added to sshd_config.

/etc/pam.d/sshd

# PAM configuration for the Secure Shell service

# Standard Un*x authentication.
@include common-auth

# Disallow non-root logins when /etc/nologin exists.
account    required     pam_nologin.so

# Uncomment and edit /etc/security/access.conf if you need to set complex
# access limits that are hard to express in sshd_config.
# account  required     pam_access.so

# Standard Un*x authorization.
@include common-account

# SELinux needs to be the first session rule.  This ensures that any
# lingering context has been cleared.  Without this it is possible that a
# module could execute code in the wrong domain.
session [success=ok ignore=ignore module_unknown=ignore default=bad]        pam_selinux.so close

# Set the loginuid process attribute.
session    required     pam_loginuid.so

# Create a new session keyring.
session    optional     pam_keyinit.so force revoke

# Standard Un*x session setup and teardown.
@include common-session

# Print the message of the day upon successful login.
# This includes a dynamically generated part from /run/motd.dynamic
# and a static (admin-editable) part from /etc/motd.
session    optional     pam_motd.so  motd=/run/motd.dynamic
session    optional     pam_motd.so noupdate

# Print the status of the user's mailbox upon successful login.
session    optional     pam_mail.so standard noenv # [1]

# Set up user limits from /etc/security/limits.conf.
session    required     pam_limits.so

# Read environment variables from /etc/environment and
# /etc/security/pam_env.conf.
session    required     pam_env.so # [1]
# In Debian 4.0 (etch), locale-related environment variables were moved to
# /etc/default/locale, so read that as well.
session    required     pam_env.so user_readenv=1 envfile=/etc/default/locale

# SELinux needs to intervene at login time to ensure that the process starts
# in the proper default security context.  Only sessions which are intended
# to run in the user's context should be run after this.
session [success=ok ignore=ignore module_unknown=ignore default=bad]        pam_selinux.so open

# Standard Un*x password updating.
@include common-password

/etc/ssh/sshd_config

#       $OpenBSD: sshd_config,v 1.103 2018/04/09 20:41:22 tj Exp $

# This is the sshd server system-wide configuration file.  See
# sshd_config(5) for more information.

# This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin

# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented.  Uncommented options override the
# default value.

#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::

#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
#HostKey /etc/ssh/ssh_host_ed25519_key

# Ciphers and keying
#RekeyLimit default none

# Logging
#SyslogFacility AUTH
#LogLevel INFO

# Authentication:

#LoginGraceTime 2m
#PermitRootLogin prohibit-password
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10

#PubkeyAuthentication yes

# Expect .ssh/authorized_keys2 to be disregarded by default in future.
#AuthorizedKeysFile     .ssh/authorized_keys .ssh/authorized_keys2

#AuthorizedPrincipalsFile none

#AuthorizedKeysCommand none
#AuthorizedKeysCommandUser nobody

# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes

# To disable tunneled clear text passwords, change to no here!
#PasswordAuthentication yes
#PermitEmptyPasswords no

# Change to yes to enable challenge-response passwords (beware issues with
# some PAM modules and threads)
ChallengeResponseAuthentication no

# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no

# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes
#GSSAPIStrictAcceptorCheck yes
#GSSAPIKeyExchange no

# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication.  Depending on your PAM configuration,
# PAM authentication via ChallengeResponseAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
UsePAM yes

#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
X11Forwarding yes
#X11DisplayOffset 10
#X11UseLocalhost yes
#PermitTTY yes
PrintMotd no
#PrintLastLog yes
#TCPKeepAlive yes
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
#UseDNS no
#PidFile /var/run/sshd.pid
#MaxStartups 10:30:100
#PermitTunnel no
#ChrootDirectory none
#VersionAddendum none

# no default banner path
#Banner none

# Allow client to pass locale environment variables
# AcceptEnv LANG LC_*

# override default of no subsystems
Subsystem       sftp    /usr/lib/openssh/sftp-server

# Example of overriding settings on a per-user basis
#Match User anoncvs
#       X11Forwarding no
#       AllowTcpForwarding no
#       PermitTTY no
#       ForceCommand cvs server
PubkeyAcceptedKeyTypes            ssh-ed25519
HostKeyAlgorithms                 ssh-ed25519
ChallengeResponseAuthentication   no
PasswordAuthentication            no
2
  • 1
    What does the PAM stack for sshd contain?
    – muru
    Jun 27, 2020 at 3:54
  • Hi, @muru. I haven't changed anything regarding PAM and sshd. I've included the contents of /etc/pam.d/sshd in the post. Jun 27, 2020 at 5:04

1 Answer 1

0

This is not a general answer to this question, but it does solve the stated problem of disallowing concurrent logins while only allowing a single command to run:

If you're willing to side-step using maxlogins to limit users, you can wrap the value of authorized_keys's command option with flock. That is:

command="flock /path/to/lock ORIGINAL_COMMAND ARGS...", ssh-ed25519 AAAAA...

Depending on your use case, you many want to look into some of flock's options (noblock, timeout, etc).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.