I have the following setup in my network:

Internet <--> Bastion <--> Local Network

I have several users and each user is assigned to a specific machine. Or in other words: Each user must have only access to one of those servers. E.g.: User1 --> Machine1, User2 --> Machine2 and so on.

Those users will connect from the outside of my network and I have considered many options how to forward their connects via my bastion host to my network.

Eventually I opted for Match Blocks and forcecommand.

So, my /etc/ssh/sshd_config on bastion looks like this:

Match User User1
        ForceCommand ssh User1@Machine1 $SSH_ORIGINAL_COMMAND

User1 connects to bastion host which automatically establishes a connection with Machine1.

As far as I understood ForceCommand, User1 won't have any real access to the bastion host, because all of his operations will be handled by the match block first, hence rerouted to Machine1. However is this really true? Is this already enough to be a secure setup? The user is jailed on Machine1 anyway, so he won't have many possibilities there.

  • 2
    Remember to get IPv6, so you will have no further need of jump boxes. – Michael Hampton Oct 28 '14 at 19:42

The way I use a bastion host is using ProxyCommand and the -W flag as in this example:

ssh -o ProxyCommand='ssh -W %h:%p user@bastion' user@machine

I use this approach for security reasons. The communication between client and target machine is encrypted and authenticated end-to-end, which means it remains secured even if the bastion is compromised. A compromised bastion host would provide no less security than using ssh end-to-end without a bastion would.

It also eliminates the need to use any agent forwarding. The client can use key based authentication first to access the bastion and then again to access the target host without either of those being provided with an agent connection that could be used to abuse the private key present on the client.

It also limits the code I am dependent on on the bastion host. I don't need to execute any command at all on the bastion. -W implies the no command flag as well as one single port forwarding, this port forwarding is all the bastion host need to permit.

With this approach in mind my recommendation would be to lock down the bastion host as much as possible allowing only commands of the above structure to be used.

The ~/.ssh/authorized_keys file on the bastion could be owned by root (as could all the directories on the path from the root of the file system to it), this reduces the risk it could be modified even if somebody managed to break in as unprivileged user on the bastion host.

In authorized_keys the client's privileges can be limited by using the options command, no-agent-forwarding, no-pty, no-user-rc, no-X11-forwarding, as well as using permitopen to limit port forwardings to only allow access to port 22 on the host that this user is allowed access to.

In principle this approach would be secure even if multiple users share the a single user name on the bastion. But you get slightly more separation by using separate user names on the bastion.

  • It appears that you're invoking ssh binary at the bastion itself. In this case, if the bastion is compromised, the attacker can replace this ssh binary with one which would dump your communications. Since you're not using path in your command-line (such as /usr/bin/ssh), the attacker might do so even without having root access on bastion, by putting it into your home dir and changing PATH (or using alias ssh). Just my 2 cents. – George Y. Jul 20 '16 at 4:57
  • 1
    @GeorgeY. You are wrong. Both ssh commands are running on the client. And that is exactly the point of doing it the way I suggest. The approach mentioned in the question would run ssh on the bastion, which opens a wide range of possible attack vectors. – kasperd Jul 20 '16 at 9:43

You can easily circumvent ForceCommand since it kicks in when you shell has started. This essentially means that your shell rc file is processed first and then ForceCommand if you allow it to get there. Simple exec sh in your shell rc file will spawn up another shell and keep ForceCommand waiting until you exit this shell.

So bottom line; if user can somehow edit his shell rc (say .bashrc) via ftp, sftp, scp or some other way, then ForceCommand is not really something to rely on.

  • Ok I will try that. None of those users does have access to the bastion host to do any file alterations. They only have access to the destination host where they could alter the .bashrc. But I hope I understand you right, that you relate to the bastion host? – Dr.Elch Oct 26 '14 at 23:09
  • 1
    That's only a problem if the user is able to log into the system to change the bashrc file. If these accounts are not intended to be used normally, then they can be owned by root, with the directory and almost all files owned by root. Check the rules around ownership of .ssh files, but certainly things like .bashrc need not be writeable. – mc0e Oct 27 '14 at 9:35
  • Yes @Dr.Elch indeed, I was referring to security on bastion host. You can also consider; chattr +i to set shell rc as immutable and disable users from changing shell for them selves as option. – Hrvoje Špoljar Oct 27 '14 at 10:10

I imagine that's fine most of the time, but the problem with security is the things noone has gotten around to thinking about yet. There are no guarantees.

Like for instance for a long time noone had thought too hard about the way functions could be created from environment variables in bash, but recently people realised that could be subverted, and one of the effects of that was that ForceCommand could be gotten around (at least as implemented in the authorized_keys file) if the users' shell was bash. Bash got fixed, and hopefully your version is up to date, but stuff like this happens.

I'm not entirely sure whether defining ForceCommand is effectively the same as defining those commands in the authorized_keys files. I haven't looked that closely.


Make the .bashrc owned by root:usergrp but still readable by the sshd running as the user logging in. Set perms/owner on $HOME disallowing creating new files by the user. This way root controls contents of .bashrc , letting it do what it needs, but the user itself cannot change those settings, or permissions on files/dirs that would indirectly allow them to change the contents of .bashrc.

  • how about not assigning any home dir to that user on the bastion server? – Dr.Elch Oct 27 '14 at 1:02
  • Where are you going to store the .bashrc with commands you want it to run then? – Marcin Oct 27 '14 at 13:27
  • On the bastion server the forcecommand that forwards the connection to the real host is defined in the sshd_config. Hence, I don't need to specify any more commands on that bastion host, right? – Dr.Elch Oct 27 '14 at 13:41

I have another idea. For each user on the bastion server you can define their shell in /etc/passwd to be a bash script that simply runs ssh user1@machine1, user2@machine2, etc. This way you'll ensure that they don't have any valid shell on the server itself and that they simply connect to the machine that they should be connecting to.

  • Have you tried this? This idea occurred to me and I'm wondering how well it works. – William Pietri Apr 21 '15 at 14:31

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.