Restricting SSH

Restricting SSH access to specific commands

Create usual user on destination server. Make sure it have no password and no expiration set (hint: look into /etc/shadow). This disable remote login using password authentication schema. Check that root can do "su" to it.

Prepare authorized_keys makes magic:

# su - sshruser
$ mkdir -m700 .ssh
$ cat > .ssh/authorized_keys << EOF
#
# This user is restricted to run some commands only.
# using "command" parameter mandatory. This also disallow sftp/scp.
#
command="/usr/local/bin/0000 $SSH_ORIGINAL_COMMAND" ssh-rsa AAAAB3NzaC1yc2EAAAAB
wAAAIEA14L/6GyIiK1AeOiyPTkYmZvl1q4aSvuiA7Wsn7oKL8AUQsiaov8Xu6oVx6WOr1Zsp9Ii3C+ry
J4BZY87++tUgkQFvpf3FiXHFV+q2dYTdIocYC4+MdZYRNgwG+hyzsSN61pZ08PgTPJIVJGqO2Z22xE2Z
elGO+fQfmn0TCJSE= remoteuser@remoteserver
EOF
$

As you see, the SSH public key prepended with command directive. Lets prepare /usr/local/bin/0000 script:

# cat > /usr/local/bin/0000 << EOF
#!/bin/sh

# Log full command
echo "$0" "$@" | logger -t remssh

# Strip previous "sudo -u appuser" :
while [ 'x'"$1" != "xALLOWED-COMMAND" ] ; do
        shift || break
done

[ 'x'"$1" = 'x' ] && { echo "Not allowed command" ; exit 1 ; }

# Additional security level sat by sudo:
sudo -u appuser $(echo $@ | sed -e 's/"//g' )
EOF
# chmod +x /usr/local/bin/0000

Checking

Not suprise, that ALLOWED-COMMAND works; let's see other tries:

$ ssh sshruser@sshserver id
Not allowed command
$ sftp sshruser@sshserver   
Connecting to sshserver...
Received message too long 1315927072
$ scp /bin/bash sshruser@sshserver:/tmp/
Not allowed command

Restricting SSH for SFTP only

Clone SSH service that will use another, its own sshd_config. Example of mine:

# egrep -v "^$|^#" /etc/ssh/sshd_sftp_config
Port 1234
PermitRootLogin no
AuthorizedKeysFile      .ssh/authorized_keys
PasswordAuthentication no
UsePAM yes
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
UsePrivilegeSeparation sandbox          # Default for new installations.
ChrootDirectory /srv/www/https/%u
Subsystem       sftp    internal-sftp
ForceCommand internal-sftp -u 002

Create user without password and without login shell:

# SFTPUSER=mysftpuser
# useradd -c "SFTP user" -m -s /bin/false $SFTPUSER
# eval H=~$SFTPUSER
# mkdir -v -m700 $H/.ssh
# cat > $H/.ssh/authorized_keys
        PASTE HERE USER'S PUBLIC SSH KEY.
        GENERATE NEW ONE SOMEWHERE, IF USER DOES NOT HAVE IT - see next commands.
        Press Ctrl-D after pasted.

#####Example to generate SSH key somewhere on linux:
## ssh-keygen -b 2048 -C $SFTPUSER@$(hostname -f) -f /tmp/$SFTPUSER@$(hostname -f)
## cp /tmp/$SFTPUSER@$(hostname -f) $H/.ssh/authorized_keys
#####Send private key /tmp/$SFTPUSER@$(hostname -f) to user.

# chown -R $SFTPUSER $H

Paste SSH public key into his .ssh/authorized_keys file and care about ownership and permissions.

Create directory structure to keep uploaded files:

# mkdir /srv/www/https/$SFTPUSER
# mkdir /srv/www/https/$SFTPUSER/uploads
# chown $SFTPUSER /srv/www/https/$SFTPUSER/uploads
Checking:
$ ssh -p 1234 sftp-server
X11 forwarding request failed on channel 0
This service allows sftp connections only.
Connection to sftp-server closed.
$ scp -P 1234 sftp-server:/etc/passwd /tmp/
protocol error: mtime.sec not present
$ scp -P 1234 /etc/passwd sftp-server:/tmp/
This service allows sftp connections only.
$ sftp -P 1234 sftp-server
Connected to sftp-server.
sftp> pwd
Remote working directory: /
sftp> ls
uploads
sftp> bye

Restricting the origin of key

Let's assume that your environment is controlled by Ansible tower, and you want to protect such a powerful SSH key with additional options.

The man 8 sshd describes format of .ssh/authorized_keys and names available options. Here is an example of additional restrictions that may be useful for such a control station:

from="10.0.0.*,!host1,*.co.uk",restrict,pty ssh-rsa AAAAB3NzaC1...

Updated on Thu Sep 13 11:20:19 IDT 2012 More documentations here