Linux login control

Recently I received an interesting question from one my regular reader:

What is the basic and important difference between password and passphrase when implementing SSH with DSA/RAS public key authentication? Which one is recommended for daily usage?

The main and basic difference is that you can use multi string phrase including spaces and tabs using a passphrase under ssh. Normal /etc/shadow password is a single string password and many application will breaks with spaces and tabs while using authentication. So your account password must be a single word/string.

For example my account password can be iF33%gNCyzDy
I could create a passphrase: Th1s 1s A t3sT and s3cur3 pa$$phra$3

The advantage is simple you can use spaces and tabs to create a more secure and hard to break authentication method. This makes dictionary based attack quite difficult.

Further readings:

Passwords vs. Pass Phrases
The Great Debates: Pass Phrases vs. Passwords. Part 1 of 3

If anyone aware of more differences please add in comments section 🙂


I’ve already written about howto log in, on your local system, and make passwordless ssh connections using ssh-keygen command. However, you cannot just follow these instructions over and over again, as you will overwrite the previous keys.

It is also possible to upload multiple public keys to your remote server, allowing one or more users to log in without a password from different computers.

Step # 1: Generate first ssh key

Type the following command to generate your first public and private key on a local workstation. Next provide the required input or accept the defaults. Please do not change the filename and directory location.
workstation#1 $ ssh-keygen -t rsa
Finally, copy your public key to your remote server using scp
workstation#1 $ scp ~/.ssh/id_rsa.pub user@remote.server.com:.ssh/authorized_keys

Step # 2: Generate next/multiple ssh key

a) Login to 2nd workstation

b) Download original the authorized_keys file from remote server using scp:
workstation#2 $ scp user@remote.server.com:.ssh/authorized_keys ~/.ssh

c) Now create the new pub/private key:
workstation#2 $ ssh-keygen -t rsa

d) Now you have new public key. APPEND this key to the downloaded authorized_keys file using cat command:
workstation#2 $ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

e) Finally upload authorized_keys to remote server again:
workstation#2 $ scp ~/.ssh/authorized_keys user@remote.server.com:.ssh/

You can repeat step #2 for each user or workstations for remote server.

Step #3: Test your setup

Now try to login from Workstation #1, #2 and so on to remote server. You should not be asked for a password:
workstation#1 $ ssh user@remote.server.com
workstation#2 $ ssh user@remote.server.com

Updated for accuracy.

How do you prevent non-root users from login into the system? How do you assign user ftp and mail access only? How do you make or set shell to nologin to politely refuse a login?

Fear not, it is easy to deny access to login shell 😀 . If the file /etc/nologin exists, login will allow access only to root. Other users will be shown the contents of this file and their logins will be refused. However if you need to give ftp or mail access add user shell /sbin/nologin.

Redhat (RHEL)/Fedora core/Cent OS specific example

For example allow user tom to use ftp and mail but no shell access. Use usermod command to setup new shell:
# usermod -s /sbin/nologin tom

You can also edit the /etc/passwd file and change the shell
From
/bin/bash
To
/sbin/nologin

Following program will not affected by this shell (/sbin/nologin):

  • FTP clients
  • mail clients
  • sudo
  • many setuid programs

Please note that it prevents access to the shell and logs the attempt. All of the following programs are prevented from accessing the user account:

  • telnet/login
  • gdm/kdm/xdm (graphical login)
  • su
  • ssh/scp/sftp etc

Debian / Ubuntu Linux specific example

Use /bin/false shell under Debian / Ubuntu Linux(do nothing, unsuccessfully login). To make shell nologin under Debian / Ubuntu for tom user, use :
$ sudo usermod -s /bin/false tom
OR
# sudo usermod -s /bin/false tom

Caution: Do not set root user shell to /sbin/nologin or /bin/false.

su is used to become another user during a login session. Invoked without a username, su defaults to becoming the super user. The user will be prompted for a password, if appropriate. Invalid passwords will produce an error message. All attempts, both valid and invalid, are logged to detect abuses of the system.

By default almost all distro allows to use su command. However you can restrict the use of su command for security reasons.

Both UNIX and Linux have a group called wheel. If user is member of this group she can use su command. We can add user to this group.

For example add existing user rocky to wheel group
# usermod -G wheel rocky

Now open /etc/pam.d/su PAM config file:
# vi /etc/pam.d/su
Append line as follows:
auth required /lib/security/pam_wheel.so use_uid
OR
auth required pam_wheel.so use_uid

Save and close the file.

Because of above setting only members of the administrative group wheel can use the su command. However I still recommend sudo over su for better control, security and ease of use. This is also default behavior on FreeBSD.

Lightweight Directory Access Protocol, or LDAP , is a directory services running over TCP/IP. Most large business and organization use LDAP for centralized authentication.

You can read LDAP Linux HOWTO for setup and configuration. If your workstation or server setup to authenticate via LDAP, open ssh will not work when user try to connect from remote system. You need to make little modification to openssh, so that it can authenticate you via LDAP:

Open /etc/ssh/sshd_config file
# vi /etc/ssh/sshd_config file

Append or modify line as follows:
PAMAuthenticationViaKbdInt yes

Restart OpenSSH
# /etc/init.d/sshd restart

Now ssh server will accept login for remote users.

So how do you force sshd to listen on multiple IP addresses? Let us say you have total 8 public IP address and one private IP address. You would like to bind sshd to one selected public IP (ex 70.5.xx.xx) and private IP (10.1.5.1) only.

Luckily there is an easy way to achieve this using ListenAddress option. It specifies the local addresses sshd should listen on. If this directive is skipped from configuration file sshd will bind or list on all available IP address.

Open sshd_config:
# vi /etc/ssh/sshd_config

Specify multiple ip address on each new line with ListenAddress (multiple ListenAddress options are permitted):
ListenAddress 70.5.1.1
ListenAddress 10.1.5.1

Save and close the file.

Restart the sshd:
# /etc/init.d/sshd restart

Verify that sshd is only listing to specified IP address:
# netstat -tulpn | grep :22Output:

tcp        0      0 70.5.1.1:22              0.0.0.0:*                   LISTEN      26472/sshd
tcp        0      0 10.1.5.1:22              0.0.0.0:*                   LISTEN      26472/sshd

This is good if public SSHD IP address is not available due to configuration issues. You can always login via private IP connected to KVM or on board server IPMI card 🙂

One of our article generated few more question regarding root login issues over ssh session. One of reader (eMBee) asks, “I need something that allows me to say: allow any users except root from anywhere, and root only from localhost. (over ssh session)”.

PAM offers very powerful authentication control. You need to use the pam_access PAM module, which is mainly for access management. It provides login access control based on

  • Login names
  • Host or domain names
  • Internet addresses or network IP numbers
  • Terminal line names etc

Why pam_access matters?

On a production server, authorized login can come from any networked computer. Therefore, it is important to have tight control over users who are allowed to connect server via OpenSSH server.

How do I configure pam_access?

You need to edit following files:

  1. /etc/pam.d/sshd – Linux PAM configuration file.
  2. /etc/security/access.conf – By default rules for access management are taken from configuration this file. When someone logs in, the entry in this scanned and matched against rule. You can specify whether the login will be accepted or refused to user. General syntax is as follows:
    permission : username: origins

Where,

  • permission : Permission field should be a “+” (access granted) or “-” (access denied)
    character.
  • username : Linux system username/login name such as root, vivek etc. You can also specify group names. You can also use special keywod ALL (to match all username).
  • origins : It is a list of one ore more tty names, host name, IP address, domain names that begin with . or special key words ALL or LOCAL

Let us say you want to allow user root and vivek login from IP address 202.54.1.20 only.

Open file /etc/security/access.conf

# vi /etc/security/access.conf

Append following line:

-: ALL EXCEPT root vivek:202.54.1.20

Save the file and Open /etc/pam.d/sshd file :

# vi /etc/pam.d/sshd

Append following entry

account required pam_access.so

Save and close the file.

Now ssh will only accept login access from root/vivek from IP address 202.54.1.20. Now if user vivek (or root) try to login ssh server from IP address 203.111.12.3 he will get
Connection closed by xxx.xxx.xx.xx‘; error and following log entry should be written to your log file:

# tailf /var/log/message

Output:

Aug  2 19:02:39 web02 pam_access[2091]: access denied for user `vivek' from `203.111.12.3'

Remember, as soon as you save changes to /etc/security/access.conf, they are applied by PAM configuration. So be careful when writing rules.

More examples

a) I need something that allows me to say: allow any users except root from anywhere, and root only from localhost.

-:root:ALL EXCEPT LOCAL

OR

-:root:ALL EXCEPT localhost

b) Deny network and local login to all users except for user root and vivek:

-:ALL EXCEPT root vivek:ALL

c) Only allow root user login from 192.168.1.0/24 network:

+ : root : 192.168.1.0/24

Please note that this kind of restriction can be applied to any PAM aware application/service such as ftpd, telnet etc.

The idea is very simple you want to limit who can use sshd based on a list of users. The text file contains a list of users that may not log in (or allowed to log in) using the SSH server. This is used for improving security.

PAM (Pluggable authentication modules) allows you to define flexible mechanism for authenticating users. My previous post demonstrated how to deny or allow users using sshd configuration option. However, if you want to block or deny a large number of users, use PAM configuration.

A note for new sys admins

  1. Backup all data and PAM configuration files before any modification 🙂
  2. Please be careful to perform the configuration option. Wrong configuration can lock down all login access including root access.
  3. Read this Linux-PAM configuration file syntax guide
  4. Now continue reading below for pam_listfile.so configration…

Use of pam_listfile.so module

This PAM module authenticates users based on the contents of a specified file. For example, if username exists in a file /etc/sshd/ssh.allow, sshd will grant login access.

How do I configure pam_listfile.so module to deny access?

You want to block a user, if user-name exists in a file /etc/sshd/sshd.deny file.

Open /etc/pam.d/ssh (or /etc/pam.d/sshd for RedHat and friends)
# vi /etc/pam.d/ssh

Append following line:
auth required pam_listfile.so item=user sense=deny file=/etc/sshd/sshd.deny onerr=succeed

Save and close the file

Now add all usernames to /etc/sshd/sshd.deny file. Now a user is denied to login via sshd if they are listed in this file:
# vi /etc/sshd/sshd.deny

Append username per line:
user1
user2
...

Restart sshd service:
# /etc/init.d/sshd restart

Understanding the config directives:

  • auth required pam_listfile.so : Name of module required while authenticating users.
  • item=user : Check the username
  • sense=deny : Deny user if existing in specified file
  • file=/etc/sshd/sshd.deny : Name of file which contains the list of user (one user per line)
  • onerr=succeed : If an error is encountered PAM will return status PAM_SUCCESS.

How do I configure pam_listfile.so module to allow access?

You want to ALLOW a user to use ssh, if user-name exists in a file /etc/sshd/sshd.allow file.
Open /etc/pam.d/ssh (or /etc/pam.d/sshd for RedHat and friends)
# vi /etc/pam.d/ssh

Append following line:
auth required pam_listfile.so item=user sense=allow file=/etc/sshd/sshd.allow onerr=fail

Save and close the file.

Now add all usernames to /etc/sshd/sshd.allow file. Now a user is allowed to login via sshd if they are listed in this file.
# vi /etc/sshd/sshd.allow

Append username per line:
tony
om
rocky

Restart sshd service (optional):
# /etc/init.d/sshd restart

Now if paul try to login using ssh he will get an error:
Permission denied (publickey,keyboard-interactive).

Following log entry recorded into my log file (/var/log/secure or /var/log/auth.log file)
tail -f /var/log/auth.log

Output:

Jul 30 23:07:40 p5www2 sshd[12611]: PAM-listfile: Refused user paul for service ssh
Jul 30 23:07:42 p5www2 sshd[12606]: error: PAM: Authentication failure for paul from 125.12.xx.xx

Understanding the config directives:

  • auth required pam_listfile.so : Name of module required while authenticating users.
  • item=user : Check or specify the username
  • sense=allow : Allow user if existing in specified file
  • file=/etc/sshd/sshd.allow : Name of file which contains the list of user (one user per line)
  • onerr=fail : If filename does not exists or username formatting is not coreect it will not allow to login.

Further reading:

  1. Linux PAM guide for the system administrators’
  2. Sun Solaris PAM site has excellent information for both sys admins and developers
  3. Download the three Linux-PAM Guides, for system administrators, module developers, and application developers.

By default when you add new user to system (/etc/passwd file) it grant shell access. If you are creating new users for POP3 or SMTP (mail server) or FTP then you do not need to grant shell access to a user. Remember as soon as you add a user he/she can login via telnet or ssh. The best way to put Linux shell access restriction is to use special shell called nologin, which politely refuse a login. It displays a message that an account is not available and exits non-zero. It is intended as a replacement shell field for accounts that have been disabled or have other user level access such as ftp, pop3, smtp etc. This is a very common practice followed by ISP or web hosting service provider’s web, mail and FTP server(s).

/sbin/nologin Example

(a) First make sure nologin exists in /etc/shells file (else service such as ftp may not allow login)
# less /etc/shells
If nologin shell does not exist in above shell list, just add /sbin/nologin shell to it:
# echo "/sbin/nologin" >> /etc/shells
If you are using Debian then use following path:
# echo "/usr/sbin/nologin" >> /etc/shells
(b) Block shell access for user vivek (vivek user account must exits):
# usermod -s /sbin/nologin vivek
Debain Linux user modify above command as follows:
# usermod -s /usr/sbin/nologin vivek
Now user vivek’s new login shell is /sbin/nologin. Vivek allowed to use other services such as ftp, pop3 but not shell access via ssh or telnet.

New user accounts

Add a new user called tony with no shell access:
# useradd -s /sbin/nologin tony
Debain / Ubuntu Linux user modify above command as follows:
# useradd -s /usr/sbin/nologin tony

Please note that above method is very easy to use but if you have a large setup. you need to take help of PAM (and may be OpenLDAP / MySQL). I will cover such setup some time later :).

This is Part III in a series on Execute Commands on Multiple Linux or UNIX Servers Simultaneously. The full series is Part I, Part II, and Part III.

In third and final part of this series I will cover expect tool. Expect is a program that talks to other interactive programs according to a script. Expect is useful for running any program which requires interaction between the program and the user. For example

Install expect

Expect comes with special pre installed script called multixterm expect. If you are using Debian Linux then use apt-get as follows :

# apt-get install expect
# apt-get install expectk

If you are using Red hat Linux then use up2date command as follows:

# up2date -i expect

Fedora core (RHEL 5) / CentOS Linux user can use yum:

# yum install expect expectk

You can use ports to install expect under FreeBSD or use following command:

# pkg_add -v -r expect

Please note you can download expect from offical web site.

General syntax of multixterm:

multixterm -xc “command arg1 arg2” server1 server2…
Multixterm creates multiple xterms that can be driven together or separately so that you can execute or run on multiple hosts/servers simultaneously. The following command line starts up two xterms using ssh to the hosts 192.168.1.16 and 192.168.1.11:

$ multixterm -xc "ssh root@%n" 192.168.1.11 192.168.1.16

Where,

  • -xc : The optional -xc argument indicates a command to be run in each named xterm (see -xn). With no -xc argument, the command is the current shell. This means you type command once and it get executed on both ssh hosts/servers.
  • ssh root@%n : ssh is a command to connect remote server with root user. This name will also be substituted for any %n in the command argument.

Debian Linux stores multixterm at /usr/share/doc/expect directory. You need to type commands in multixterm window itself (stdin window). Click on stdin window and type uptime or w command:
For example when I typed the uptime and w command it looked like as follows:

See also: