You’d like to restrict what an incoming SSH user or script can do.*
Edit the ~/.ssh/authorized_keys file, use SSH forced commands, and optionally disable unnecessary SSH features.
For example, suppose you want to allow an rsync process without also allowing interactive use.
First, you need to figure out exactly what command is being run on the remote side.
Create a key and add a forced command to tell you.
Edit the ~/.ssh/authorized_keys file and add:
1 |
command="/bin/echo Command was: $SSH_ORIGINAL_COMMAND" |
before the key. It will look something like this, all on one line:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
command="/bin/echo Command was: $SSH_ORIGINAL_COMMAND" ssh-dss AAAAB3NzaC1kc3MAAAEBANpgvvTslst2m0ZJA0ayhh1Mqa3aWwU3kfv0m9+myFZ9veFsxM7IVxIjWfAlQh3jp lY+Q78fMzCTiG+ZrGZYn8adZ9yg5/ wAC03KXm2vKt8LfTx6I+qkMR7v15NI7tZyhxGah5qHNehReFWLuk7JXCtRrzRvWMdsHc/ L2SA1Y4fJ9Y9FfVlBdE1Er+ZIuc5xIlO6D1HFjKjt3wjbAal+oJxwZJaupZ0Q7N47uwMslmc5ELQBRNDsaoqF RKlerZASPQ5P+AH/+Cxa/fCGYwsogXSJJ0H5S7+QJJHFze35YZI/ +A1D3BIa4JBf1KvtoaFr5bMdhVAkChdAdMjo96xhbdEAAAAVAJSKzCEsrUo3KAvyUO8KVD6e0B/NAAAA/3u/ Ax2TIB/M9MmPqjeH67Mh5Y5NaVWuMqwebDIXuvKQQDMUU4EPjRGmS89Hl8UKAN0Cq/C1T+OGzn4zrbE06CO/ Sm3SRMP24HyIbElhlWV49sfLR05Qmh9fRl1s7ZdcUrxkDkr2J6on5cMVB9M2nIl90IhRVLd5RxP01u81yqvhv E61ORdA6IMjzXcQ8ebuD2R733O37oGFD7e2O7DaabKKkHZIduL/zFbQkzMDK6uAMP8ylRJN0fUsqIhHhtc// 16OT2H6nMU09MccxZTFUfqF8xIOndElP6um4jXYk5Q30i/CtU3TZyvNeWVwyGwDi4wg2jeVe0YHU2Rh/ ZcZpwAAAQEAv2O86701U9sIuRijp8sO4h13eZrsE5rdn6aul/mkm+xAlO+WQeDXR/ ONm9BwVSrNEmIJB74tEJL3qQTMEFoCoN9Kp00Ya7Qt8n4gZ0vcZlI5u+cgyd1mKaggS2SnoorsRlb2Lh/ Hpe6mXus8pUTf5QT8apgXM3TgFsLDT+3rCt40IdGCZLaP+UDBuNUSKfFwCru6uGoXEwxaL08Nv1wZOc19qrc0 Yzp7i33m6i3a0Z9Pu+TPHqYC74QmBbWq8U9DAo+7yhRIhq/ fdJzk3vIKSLbCxg4PbMwx2Qfh4dLk+L7wOasKnl5//W+RWBUrOlaZ1ZP1/azsK0Ncygno/0F1ew== This is my new key |
Now execute your command and see what the result is.
1 2 |
$ ssh remote_host 'ls -l /etc' Command was: ls -l /etc |
Now, the problem with this approach is that it will break a program like rsync that depends on having the STDOUT/STDIN channel all to itself.
1 2 3 4 |
$ rsync -avzL -e ssh remote_host:/etc . protocol version mismatch -- is your shell clean? (see the rsync man page for an explanation) rsync error: protocol incompatibility (code 2) at compat.c(64) |
But we can work around that by modifying our forced command as follows:
1 |
command="/bin/echo Command was: $SSH_ORIGINAL_COMMAND >> ~/ssh_command" |
So on the client side we try again:
1 2 3 |
$ rsync -avzL -e ssh 192.168.99.56:/etc . rsync: connection unexpectedly closed (0 bytes received so far) [receiver] rsync error: error in rsync protocol data stream (code 12) at io.c(420) |
And on the remote host side we now have:
1 2 |
$ cat ../ssh_command Command was: rsync --server --sender -vlLogDtprz . /etc |
So we can update our forced command as necessary.
Two other things we can do are to set a from host restriction and disable SSH commands.
The host restriction specifies the hostname or IP address of the source host.
Disabling commands is also pretty intuitive:
1 |
no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty |
So when we put it all together, it looks like this (still all on one giant line):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,from="local_ client",command="rsync --server --sender -vlLogDtprz . /etc" ssh-dss AAAAB3NzaC1kc3MAAAEBANpgvvTslst2m0ZJA0ayhh1Mqa3aWwU3kfv0m9+myFZ9veFsxM7IVxIjWfAlQh3jp lY+Q78fMzCTiG+ZrGZYn8adZ9yg5/ wAC03KXm2vKt8LfTx6I+qkMR7v15NI7tZyhxGah5qHNehReFWLuk7JXCtRrzRvWMdsHc/ L2SA1Y4fJ9Y9FfVlBdE1Er+ZIuc5xIlO6D1HFjKjt3wjbAal+oJxwZJaupZ0Q7N47uwMslmc5ELQBRNDsaoqF RKlerZASPQ5P+AH/+Cxa/fCGYwsogXSJJ0H5S7+QJJHFze35YZI/ +A1D3BIa4JBf1KvtoaFr5bMdhVAkChdAdMjo96xhbdEAAAAVAJSKzCEsrUo3KAvyUO8KVD6e0B/NAAAA/3u/ Ax2TIB/M9MmPqjeH67Mh5Y5NaVWuMqwebDIXuvKQQDMUU4EPjRGmS89Hl8UKAN0Cq/C1T+OGzn4zrbE06CO/ Sm3SRMP24HyIbElhlWV49sfLR05Qmh9fRl1s7ZdcUrxkDkr2J6on5cMVB9M2nIl90IhRVLd5RxP01u81yqvhv E61ORdA6IMjzXcQ8ebuD2R733O37oGFD7e2O7DaabKKkHZIduL/zFbQkzMDK6uAMP8ylRJN0fUsqIhHhtc// 16OT2H6nMU09MccxZTFUfqF8xIOndElP6um4jXYk5Q30i/CtU3TZyvNeWVwyGwDi4wg2jeVe0YHU2Rh/ ZcZpwAAAQEAv2O86701U9sIuRijp8sO4h13eZrsE5rdn6aul/mkm+xAlO+WQeDXR/ ONm9BwVSrNEmIJB74tEJL3qQTMEFoCoN9Kp00Ya7Qt8n4gZ0vcZlI5u+cgyd1mKaggS2SnoorsRlb2Lh/ Hpe6mXus8pUTf5QT8apgXM3TgFsLDT+3rCt40IdGCZLaP+UDBuNUSKfFwCru6uGoXEwxaL08Nv1wZOc19qrc0 Yzp7i33m6i3a0Z9Pu+TPHqYC74QmBbWq8U9DAo+7yhRIhq/ fdJzk3vIKSLbCxg4PbMwx2Qfh4dLk+L7wOasKnl5//W+RWBUrOlaZ1ZP1/azsK0Ncygno/0F1ew== This is my new key |
If you have any problems with ssh, the -v option is very helpful. ssh -v or ssh -v -v
will almost always give you at least a clue about what’s going wrong.
Give them a try when things are working to get an idea of what their output looks like.
If you’d like to be a little more open about what the key can and can’t do, look into
the OpenSSH Restricted Shell rssh (http://www.pizzashack.org/rssh/), which supports scp, sftp, rdist, rsync, and cvs.
You’d think restrictions like these would be very easy, but it turns out they are not.
The problem has to do with the way SSH (and the r-commands before it) actually
work.
It’s a brilliant idea and it works very well, except that it’s hard to limit.
To vastly oversimplify it, you can think of SSH as connecting your local STDOUT to
STDIN on the remote side and the remote STDOUT to your local STDIN.
So all things like scp or rsync do is stream bytes from the local machine to the remote machine as if over a pipe.
But that very flexibility precludes SSH from being able to restrict interactive access while allowing scp.
There’s no difference. And that’s why you can’t put lots of echo and debugging statements in your bash configuration files that output will intermingle with the byte stream and cause havoc.
So how does rssh work? It provides a wrapper that you use instead of a default login
shell (like bash) in /etc/passwd.
That wrapper determines what it will and will not allow, but with much more flexibility than a plain old SSH-restricted command.