102

I'd like to allow a user to set up an SSH tunnel to a particular machine on a particular port (say, 5000), but I want to restrict this user as much as possible. (Authentication will be with public/private keypair).

I know I need to edit the relevant ~/.ssh/authorized_keys file, but I'm not sure exactly what content to put in there (other than the public key).

Lorin Hochstein
  • 57,372
  • 31
  • 105
  • 141

10 Answers10

96

On Ubuntu 11.10, I found I could block ssh commands, sent with and without -T, and block scp copying, while allowing port forwarding to go through.

Specifically I have a redis-server on "somehost" bound to localhost:6379 that I wish to share securely via ssh tunnels to other hosts that have a keyfile and will ssh in with:

$ ssh -i keyfile.rsa -T -N -L 16379:localhost:6379 someuser@somehost

This will cause the redis-server, "localhost" port 6379 on "somehost" to appear locally on the host executing the ssh command, remapped to "localhost" port 16379.

On the remote "somehost" Here is what I used for authorized_keys:

cat .ssh/authorized_keys   (portions redacted)

no-pty,no-X11-forwarding,permitopen="localhost:6379",command="/bin/echo do-not-send-commands" ssh-rsa rsa-public-key-code-goes-here keyuser@keyhost

The no-pty trips up most ssh attempts that want to open a terminal.

The permitopen explains what ports are allowed to be forwarded, in this case port 6379 the redis-server port I wanted to forward.

The command="/bin/echo do-not-send-commands" echoes back "do-not-send-commands" if someone or something does manage to send commands to the host via ssh -T or otherwise.

From a recent Ubuntu man sshd, authorized_keys / command is described as follows:

command="command" Specifies that the command is executed whenever this key is used for authentication. The command supplied by the user (if any) is ignored.

Attempts to use scp secure file copying will also fail with an echo of "do-not-send-commands" I've found sftp also fails with this configuration.

I think the restricted shell suggestion, made in some previous answers, is also a good idea. Also, I would agree that everything detailed here could be determined from reading "man sshd" and searching therein for "authorized_keys"

Paul
  • 26,170
  • 12
  • 85
  • 119
  • 1
    While `no-pty` doesn't allow to open interactive seesion it does nothing to prevent command execution, so the user can edit `authorized_keys` file if he has access with something like `ssh server 'sed -i -e s/no-pty// ~/.ssh/authorized_keys'`. – synapse Dec 25 '13 at 14:06
  • 4
    @synapse command="/bin/echo do-not-send-commands", also listed above, is intended to block commands. and provide a message. Did you intend your example to defeat the entire settings above or are you only commenting on no-pty? – Paul Dec 26 '13 at 04:03
  • It bears mentioning that admins are not obligated to grant users ownership of an authorized_keys file or containing directory, nor that it even exists in a users' home directory (assuming ssh server is configured properly for its location) – erik258 Feb 13 '14 at 00:37
  • ?? @DanFarrell would the .ssh/authorized_keys be owned by root, or wheel, or whom? – Andrew Wolfe Nov 23 '15 at 14:35
  • @AndrewWolfe typically, `~user/.ssh/authorized_keys` would be owned by `user`, and `user` would manage the authorized keys used to access the account. SSH is picky about permissions and may impose expectations on `~/.ssh/` and its contents. I did a `sudo chown root: .ssh/authorized_keys` and it seems to have stopped me from logging in, but I know from past experience that the user doesn't have to own that file - `root` can manage it if you'd prefer. – erik258 Nov 24 '15 at 18:34
  • Very useful answer. I would only add that `/sbin/nologin` for an user seems to work fine with `-N` and port forwarding (if all the people connecting to that account should be treated the same way). – Marcin Zajączkowski Jan 20 '18 at 22:43
  • For me, in Ubuntu 19, this method gives the `do-not-send-commands` message when I try to set up the SSH tunnel with `ssh -i PATH_TO_KEYFILE -o ExitOnForwardFailure=yes -L 9229:127.0.0.1:9229 USER@IP sleep 10`. I have tried with `permitopen="localhost:9229"` and `permitopen="127.0.0.1:9229"` – nerdlinger Apr 05 '20 at 14:54
  • @nerdlinger That may not get enough attention as a comment. Perhaps try writing a new question. You might need to post it on askubuntu or serverfault, as I think these kinds of sysadmin questions have become more discouraged on stack overflow. – Paul Apr 06 '20 at 02:19
  • @Paul Good point! https://askubuntu.com/questions/1224352/when-i-set-up-a-user-account-restricted-to-port-forwarding-command-bin-echo – nerdlinger Apr 09 '20 at 11:59
  • Oh and an answer here on https://superuser.com/questions/1539080/when-setting-up-an-ssh-tunnel-user-authorized-keys-directive-command-blocks – nerdlinger Apr 09 '20 at 12:00
20

You'll probably want to set the user's shell to the restricted shell. Unset the PATH variable in the user's ~/.bashrc or ~/.bash_profile, and they won't be able to execute any commands. Later on, if you decide you want to allow the user(s) to execute a limited set of commands, like less or tail for instance, then you can copy the allowed commands to a separate directory (such as /home/restricted-commands) and update the PATH to point to that directory.

Jason Day
  • 8,809
  • 1
  • 41
  • 46
  • 1
    But that doesn't prevent the user from specifying a different command on the ssh command line, like `ssh use@host "/bin/bash"`, does it? – Fritz Aug 31 '15 at 10:31
  • Yes, it does, assuming that `user@host` has rbash as the shell. See [The Restricted Shell](http://www.gnu.org/software/bash/manual/html_node/The-Restricted-Shell.html) – Jason Day Aug 31 '15 at 13:23
  • Okay, I tried it and you are right. Since the specified command is executed by the login shell, executing `/bin/bash` fails because it contains slashes. – Fritz Sep 01 '15 at 17:29
  • 3
    Although it should be said that allowing `less` is probably a bad idea, because from there you can escape to an unrestricted shell with `!/bin/bash`. See http://pen-testing.sans.org/blog/2012/06/06/escaping-restricted-linux-shells/comment-page-1/ for other examples. So allowing individual commands should be done very, very carefully, if at all. – Fritz Sep 01 '15 at 17:33
17

Besides authorized_keys option like no-X11-forwarding, there actually is exactly one you are asking for: permitopen="host:port". By using this option, the user may only set up a tunnel to the specified host and port.

For the details of the AUTHORIZED_KEYS file format refer to man sshd.

marbu
  • 171
  • 1
  • 3
  • 13
    You'll need to also specify "no-pty" as part of the option set. If you use "permitopen" only, then you'll restrict tunnels to the given host/port ... but you'll still allow interactive shells. – John Hart Aug 14 '12 at 19:53
  • Does restricting port forwarding with permitopen also lock down the kind of tunnel device forwarding that ssh -w asks for? – flabdablet May 29 '14 at 19:20
  • 5
    @JohnHart: `no-pty` doesn't restrict shell access either, you'll still get to the shell, it just won't show you the prompt; You can still give commands and see the output just fine. You need the `command="..."` option if you want to restrict shell access from `.ssh/authorized_keys`. – Aleksi Torhamo Jan 01 '15 at 20:35
9

My solution is to provide the user who only may be tunneling, without an interactive shell, to set that shell in /etc/passwd to /usr/bin/tunnel_shell.

Just create the executable file /usr/bin/tunnel_shell with an infinite loop.

#!/bin/bash
trap '' 2 20 24
clear
echo -e "\r\n\033[32mSSH tunnel started, shell disabled by the system administrator\r\n"
while [ true ] ; do
sleep 1000
done
exit 0

Fully explained here: http://blog.flowl.info/2011/ssh-tunnel-group-only-and-no-shell-please/

Daniel W.
  • 31,164
  • 13
  • 93
  • 151
  • 9
    CTRL+Z will escape from the script giving you full access to bash... Try adding "trap '' 20" (without quotes) at very beginning of script – Big Papoo Oct 01 '13 at 08:50
  • 1
    thanks for the hint, I added trapping of some interrupt signals – Daniel W. Oct 30 '13 at 16:48
  • 1
    I just use /bin/cat for a "shell". Seems to work fine. Not aware of any exploits against cat, and even if you did find some input pattern that manages to crash it, your ssh session would just terminate. – flabdablet May 29 '14 at 19:17
  • 5
    @BigPapoo: Did you actually test it? I can't see where it would escape to. If you're in a shell and you run `tunnel_shell`, you'll have `shell -> /bin/bash tunnel_shell` so you can of course escape back to the shell, but if you've set `tunnel_shell` *as* the user's shell, you'll only have `/bin/bash tunnel_shell` running, with no shell to escape to, as far as I can see. I tested it and couldn't escape with ctrl-z. If you *did* try it and could escape, could you post the setup? Likewise, if you know of any documentation that says that it should work like that, could you post that? – Aleksi Torhamo Jan 01 '15 at 21:00
5

Here you have a nice post that I found useful: http://www.ab-weblog.com/en/creating-a-restricted-ssh-user-for-ssh-tunneling-only/

The idea is: (with the new restricted username as "sshtunnel")

useradd sshtunnel -m -d /home/sshtunnel -s /bin/rbash
passwd sshtunnel

Note that we use rbash (restricted-bash) to restrict what the user can do: the user cannot cd (change directory) and cannot set any environment variables.

Then we edit the user's PATH env variable in /home/sshtunnel/.profile to nothing - a trick that will make bash not find any commands to execute:

PATH=""

Finally we disallow the user to edit any files by setting the following permissions:

chmod 555 /home/sshtunnel/
cd /home/sshtunnel/
chmod 444 .bash_logout .bashrc .profile
Benjamin Hodgson
  • 42,952
  • 15
  • 108
  • 157
juanmf
  • 2,002
  • 2
  • 26
  • 28
3

If you want to do allow access only for a specific command -- like svn -- you can also specify that command in the authorized keys file:

command="svnserve -t",no-port-forwarding,no-pty,no-agent-forwarding,no-X11-forwarding [KEY TYPE] [KEY] [KEY COMMENT]

From http://svn.apache.org/repos/asf/subversion/trunk/notes/ssh-tricks

joseph_morris
  • 705
  • 6
  • 13
3

I'm able to set up the authorized_keys file with the public key to log in. What I'm not sure about is the additional information I need to restrict what that account is allowed to do. For example, I know I can put commands such as:

no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding

You would want a line in your authorized_keys file that looks like this.

permitopen="host.domain.tld:443",no-pty,no-agent-forwarding,no-X11-forwardi
ng,command="/bin/noshell.sh" ssh-rsa AAAAB3NzaC.......wCUw== zoredache 
gdelfino
  • 11,053
  • 6
  • 44
  • 48
Zoredache
  • 37,543
  • 7
  • 45
  • 61
0

I made a C program which looks like this:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
void sig_handler(int signo)
{
    if (signo == SIGHUP)
        exit(0);
}

int main()
{
    signal(SIGINT, &sig_handler);
    signal(SIGTSTP, &sig_handler);

    printf("OK\n");
    while(1)
        sleep(1);
    exit(0);
}

I set the restricted user's shell to this program.

I don't think the restricted user can execute anything, even if they do ssh server command, because the commands are executed using the shell, and this shell does not execute anything.

-1

See this post on authenticating public keys.

The two main things you need to remember are:

  1. Make sure you chmod 700 ~/.ssh
  2. Append the public key block to authorized-keys
Nathaniel Ford
  • 20,545
  • 20
  • 91
  • 102
Michael Pryor
  • 25,046
  • 18
  • 72
  • 90
-3

You will generate a key on the users machine via whatever ssh client they are using. pUTTY for example has a utility to do this exact thing. It will generate both a private and public key.

The contents of the public key file generated will be placed in the authorized_keys file.

Next you need to make sure that the ssh client is configured to use the private key that generated the public key. It's fairly straight forward, but slightly different depending on the client being used.

palehorse
  • 26,407
  • 4
  • 40
  • 48