How to restrict ssh port forwarding, without denying it?

Suppose I have created an account whose login shell is actually a script which does not permit an interactive login, and only allows a very limited, specific set of commands to be remotely executed.

Nevertheless, ssh allows the user of this account to forward ports, which is a hole.

Now, the twist is that I actually want that account to set up a specific port forwarding configuration when the ssh session is established. But it must be impossible configure arbitrary port forwarding.

(It is an acceptable solution if the permitted port forwarding configuration is unconditionally established as part of the every session.)


Solution 1:

Turns out, OpenSSH has a feature for this, for restricting -L style opens on the server side. The feature is available in two ways.

  1. In the server configuration file there is a PermitOpen option. This option can be used to specify hosts and ports for which forwards can be established. This option can be used inside a Match block, so it can be restricted by user, group, or hostname or IP address pattern.

  2. In an authorized_keys file, options can be associated with a particular key. There is a permitopen option which works similarly to the server-config one.

Notes/Limitations:

  • The option AllowTcpForwarding disables all forwarding in both directions, preventing listening ports from being set up on the server, as well as active forwards.

  • There is no PermitOpen access control for -R style connections. This is probably okay. What it means is that the users can use ssh to open various non-privileged ports for listening on the server. Where these connect to on the other side of the SSH connection is the client's problem. If we restrict forwarding in the -L direction, the user has no way of using those -R ports (at least not through ssh, if that user is not able to create an arbitrary interactive session).

  • There doesn't seem to be a way to create an empty list of permitted opens, to prevent users from making any -L style connections whatsoever. However, a workaround is to use a harmless, nonexistent or impossible host name, such as the empty string. Concretely, permitopen=":1234" does the trick.