11

We have bastion server B. We need to SSH from A through B to C, using private key.

What is the better option:

  • Put the private SSH key on server B. We read that it's a bad idea to do that in a production environment.

    From here:

    Never place your SSH private keys on the bastion instance. Instead, use SSH agent forwarding to connect first to the bastion and from there to other instances in private subnets. This lets you keep your SSH private key just on your computer.

  • Use SSH agent forwarding. For setting up agent forwarding, I need to allow TCP Forwarding. When setting up agent forwarding, a socket file is created on the forwarding host, which is the mechanism by which the key can be forwarded to the destination. In the Bastion settings at AWS:

    TCP forward: Setting this value to true will enable TCP forwarding (SSH tunneling). This can be very useful but it is also a security risk, so we recommend that you keep the default (disabled) setting unless required

    Also from here:

    SSH Agent Forwarding considered harmful

What is better? What about the alternative from the second link: ProxyCommand, I understand it helps with the socket file issue, but still I think I have to enable TCP forwarding, so is it secure enough?

user2503775
  • 223
  • 3
  • 9
  • 2
    With ProxyCommand you don't need to enable TCP forwarding. The forwarding is done by ssh on the intermediate host. – wurtel Mar 14 '19 at 10:53
  • Thanks. Were the configuration file should be? in my computer or in the Bastion? – user2503775 Mar 14 '19 at 10:55
  • On your local system, where you will be entering the `ssh hostb` command, so that it can lookup hostb in the local config and know that it needs to connect through hosta. It couldn't do that if you put the config on hosta... – wurtel Mar 14 '19 at 10:58
  • Where the private key of server C will be stored? also in my comp? I'm using keepass with keeAgent – user2503775 Mar 14 '19 at 11:00
  • 2
    I’m afraid you’re confusing **TCP forwarding** with **Agent forwarding**. They are different things. – MLu Mar 14 '19 at 11:02
  • @user2503775 yes, you simply need to have all keys on your local computer where Keepass is running. Then follow the 2nd link with the `ProxyCommand` or even simpler use `ProxyJump`, it does something which I qualify as similar to ProxyCommand but the syntax is even easier. – Huygens Mar 14 '19 at 11:04
  • You don't store the private key of server C anywhere, you need to put the public key of your identity in the `authorized_keys` file on server C. – wurtel Mar 14 '19 at 11:04

3 Answers3

14

Use ProxyCommand or ProxyJump

I would recommend to use ProxyCommand (or even better ProxyJump as the syntax is easier but requires openssh 7.3+ I think on the client side), and you do not need to deploy private key on the Bastion, everything stays local.

Example with ProxyJump

On your client computer you write a file under ~/.ssh/config with a similar content to bellow:

Host bastion
  HostName bastion.example.com
  User bastion-user
  Port 22
  IdentityFile ~/.ssh/id_bastion

Host srvC
  HostName srvC.local
  User server-user
  IdentityFile ~/.ssh/id_protected_lan
  ProxyJump bastion

Then doing ssh srvC will connect you to C via B (bastion) without Agent Forwarding nor deploying the private key to the bastion.

In the above example, "bastion" is an alias to your Bastion host and srvC is an alias to your server C. In the HostName you need to put either IPs or real fully qualified domain name for your hosts. For the users, you need to update the User for the correct login name on the Bastion and server C. Finally the IdentityFile is optional if you use a local agent (e.g. KeeAgent or ssh-agent), but if it is not running then it will also work and ask you for each key passphrases.

Deploying the public keys

Of course you need to deploy the public keys to both bastion and srvC. You can use (the $ sign is just to illustrate the prompt, do not type it):

$ ssh-copy-id -i ~/.ssh/id_bastion.pub \
   -o PreferredAuthentications=password \
   -o PubkeyAuthentication=no \
   bastion
$ ssh-copy-id -i ~/.ssh/id_protected_lan.pub \
   -o PreferredAuthentications=password \
   -o PubkeyAuthentication=no \
   srvC

Note: the above will work only if password authentication is still allowed. After the above deployment and verifying that everything work as intended, you should disallow password authentication on the 2 servers.

Example with ProxyCommand instead of ProxyJump

If you have an older version of OpenSSH which does not support ProxyJump (on the client side), then replace:

ProxyJump bastion

by

ProxyCommand ssh -q -W %h:%p bastion

As far as I understood, this is similar.

Huygens
  • 1,678
  • 2
  • 19
  • 36
  • Thank you! I work with linux, but we have some team members working on windows. It should work there as well, isn't it? – user2503775 Mar 14 '19 at 11:32
  • Which SSH client are they going to use? OpenSSH (via WSL, or cygwin or etc.) or PuTTY (or another tool based on PuTTY) like MobaXterm? – Huygens Mar 14 '19 at 11:37
  • Some of them use PuTTy and others use ssh via Git Shell. – user2503775 Mar 14 '19 at 11:39
  • @user2503775 I have never tried it with PuTTY, but it seems to be possible using the ProxyCommand approach, see here: https://stackoverflow.com/a/28937185 – Huygens Mar 14 '19 at 11:43
  • If using Git Shell or WSL, this will work as on Linux and described above. – Huygens Mar 14 '19 at 11:43
  • 1
    Thank you very much for the detailed answer! – user2503775 Mar 14 '19 at 11:48
  • I'm getting an error when trying to call ssh srvC: `channel 0: open failed: administratively prohibited: open failed. stdio forwarding failed. ssh_exchange_identification: Connection closed by remote host`. Do you have an idea why? At secure log I see: `refused local port forward: originator 127.0.0.1 port 65535, target *app-ip* port 22` – user2503775 Mar 17 '19 at 10:43
  • When trying the second option `proxyCommand` I'm getting only this: `ssh_exchange_identification: Connection closed by remote host`. I'm also using google authenticator on the bastion. – user2503775 Mar 17 '19 at 11:24
  • Hi @user2503775, the Proxy* commands are building a sort of tunnel through the bastion machine. It seems that this tunnel is prohibited "administratively", so within the `sshd_config` file (or in the `authorized_keys` file). I guess it is the bastion ssh configuration which has this feature. You should define the PermitOpen and AllowTCPForwarding (not AllowAgentForwarding) to proper value. The latter should be set to `yes` while the former could be set to `any` or better `IP:PORT` with the IP and PORT of your target server (srvC). https://man.openbsd.org/sshd_config.5#PermitOpen – Huygens Mar 17 '19 at 12:02
  • But the first comment to the answer says: `With ProxyCommand you don't need to enable TCP forwarding` – user2503775 Mar 17 '19 at 13:35
  • @user2503775 There are 2 different things: TCP and Agent forwarding. In the AWS Bastion link you provided, they warn against using Agent Forwarding not TCP Forwarding (as your quote seems to mention). TCP Forwarding is a completely different thing, there is no Unix socket involved, it is not about the agent authentication, etc.. This was being confused in your first version of the question and the comment you refer to used either the same wording or was also confused. – Huygens Mar 17 '19 at 13:45
  • If @wurtel meant Agent Forwarding then his comment is correct (albeit using the wrong terminology) if he really meant TCP forwarding, then his comment is incorrect. Check the ssh manuals, Agent and TCP forwarding have different options and explanations. I hope this clarifies things. – Huygens Mar 17 '19 at 13:45
  • Try first setting `AllowTCPForwarding` to yes and then `PermitOpen` to any. If that works, refer to the sshd_config manual pages to restrict those settings (like I was suggesting). This should work. – Huygens Mar 17 '19 at 13:47
  • Thanks. I will try that. B.T.W - I'm not confusing! I know the second link warns about agent Forwarding, please read again the end of my question. I also quoted Amazon, who said `TCP forward: Setting this value to true will enable TCP forwarding (SSH tunneling). ... but it is also a security risk, so we recommend that you keep the default (disabled) setting unless required`. – user2503775 Mar 18 '19 at 06:27
  • That's why I asked in the end of my question: `What about the alternative from the second link: ProxyCommand, I understand it helps with the socket file issue, but still I think I have to enable TCP forwarding, so is it secure enough?` – user2503775 Mar 18 '19 at 06:27
  • Still getting the same error also after adding `AllowTCPForwarding` and `PermitOpen` – user2503775 Mar 18 '19 at 10:25
  • Hi @user2503775, I will try to reply to your newly opened question. But the above technique works, it is not something I read, it is something I'm doing every day :-) There must be something else that blocks. – Huygens Mar 18 '19 at 19:41
5

I saw the answer about ProxyJump. Let's talk about ProxyCommand.

But wait, wait! I can write to you how to hack the server that uses Agent forwarding, that would be much easier to understand the difference!

Let's hack!

For the basic steps: you can read my post here

Basic steps are the following:

  1. Create bastion users
  2. Disable root login
  3. Block hacking attempts
  4. Change port
  5. Configure firewall
  6. Configure SELinux

How to use AgentForwarding

-Create config in ~/.ssh/config

  Host bast
        Hostname BASTION_IP
        ForwardAgent yes
        User bastion

-Add your authentification key to ssh-agent

ssh-add ~/.ssh/name_rsa

-Connect to bastion hos

ssh bast

-Connect application server from the bastion

 ssh app@IP -p PORT

Hacking!

You may, well, ask me the question:

  • Is my server secure? And the answer is quite simple:

    • NO!
  • Why?

    • Because you are using SSH Agent forwarding!
  • And where is the problem?

    • Because Agent forwarding is dangerous and it's consider considered harmful.
  • Why?

    • Let's explain everything inside out: When you connect bastion host your glorious ssh-agent is forwarded. It means that the socket will be set up so that someone may use this socket data to access your servers. Imagine that your bastion server is compromised, If someone has sufficient permissions on your Linux server he/she will just use your socket info. As a result, all your server can be accessed. I know the window of compromise is very small because it depends on how much time you are connected to the bastion host. But do you really want to the risk when you have other options like ProxyCommand? Hence, just use ProxyCommand!

How to hack servers if you compromised bastion host?

Track Target

In /tmp directory you may see something like that:

[root@localhost tmp]# ll
total 12
drwx------  2 bastion bastion 4096 Sep  7 17:35 ssh-mKX88v0Vlo

Let's open the temporary file

[root@localhost tmp]# cd ssh-mKX88v0Vlo/
[root@localhost ssh-mKX88v0Vlo]# ll
total 0
srwxr-xr-x 1 bastion bastion 0 Sep  7 17:35 agent.10507

Let's see connections to this process id.

netstat -nxp | grep  10507

result:

unix  [ ]   STREAM     CONNECTED     501384   10507/sshd: bastion

and who is connected?

lsof -i -a -p 10507

result:

COMMAND  PID   USER  FD  TYPE DEVICE SIZE/OFF NODE NAME
sshd    10507 bastion  3u  IPv4 501301  0t0  TCP *IP*:ssh->*IP*:8279 (ESTABLISHED)

We can also see socket files:

cd /proc/10507/fd/
ls

result:

lrwx------ 1 root root 64 Sep  7 17:46 0 -> /dev/null
lrwx------ 1 root root 64 Sep  7 17:46 1 -> /dev/null
lrwx------ 1 root root 64 Sep  7 17:46 10 -> /dev/ptmx
lrwx------ 1 root root 64 Sep  7 17:46 14 -> /dev/ptmx
lrwx------ 1 root root 64 Sep  7 17:46 15 -> /dev/ptmx
lrwx------ 1 root root 64 Sep  7 17:46 2 -> /dev/null
lrwx------ 1 root root 64 Sep  7 17:46 3 -> socket:[501994]
lrwx------ 1 root root 64 Sep  7 17:46 4 -> socket:[502069]
lrwx------ 1 root root 64 Sep  7 17:46 5 -> socket:[502072]
l-wx------ 1 root root 64 Sep  7 17:46 6 -> /run/systemd/sessions/1836.ref
lr-x------ 1 root root 64 Sep  7 17:46 7 -> pipe:[502079]
l-wx------ 1 root root 64 Sep  7 17:46 8 -> pipe:[502079]
lrwx------ 1 root root 64 Sep  7 17:46 9 -> socket:[502080]

And what happens when client will be connected to remote server? let's see:

lrwx------ 1 root root 64 Sep  7 17:46 0 -> /dev/null
lrwx------ 1 root root 64 Sep  7 17:46 1 -> /dev/null
lrwx------ 1 root root 64 Sep  7 17:46 10 -> /dev/ptmx
lrwx------ 1 root root 64 Sep  7 17:48 11 -> socket:[502267]
lrwx------ 1 root root 64 Sep  7 17:46 14 -> /dev/ptmx
lrwx------ 1 root root 64 Sep  7 17:46 15 -> /dev/ptmx
lrwx------ 1 root root 64 Sep  7 17:46 2 -> /dev/null
lrwx------ 1 root root 64 Sep  7 17:46 3 -> socket:[501994]
lrwx------ 1 root root 64 Sep  7 17:46 4 -> socket:[502069]
lrwx------ 1 root root 64 Sep  7 17:46 5 -> socket:[502072]
l-wx------ 1 root root 64 Sep  7 17:46 6 -> /run/systemd/sessions/1836.ref
lr-x------ 1 root root 64 Sep  7 17:46 7 -> pipe:[502079]
l-wx------ 1 root root 64 Sep  7 17:46 8 -> pipe:[502079]
lrwx------ 1 root root 64 Sep  7 17:46 9 -> socket:[502080]

We can even see if socket file is used using netstat:

unix  3 [ ]  STREAM  CONNECTED  502267  10561/sshd: 
                     bastion  /tmp/ssh-oVoMXC6vb8/agent.10561
unix  3  [ ] STREAM     CONNECTED     502072   10561/sshd:  bastion 

Steal Socket info and IP address

Now we need to steal the socket information while the session of bastion host is open. Oh, we also need destination server IP, so just use netstat:

netstat -tn

The final step to use the forwarded socket file

eval "$(ssh-agent -s)"
SSH_AUTH_SOCK=/tmp/ssh-EAKxOdL4fl/agent.10507

Check if the key is loaded.

ssh-add -l

result should be something like that:

2048 SHA256:2Psdl..B5KQ /home/usr/.ssh/name_rsa (RSA)

Server is hacked, how to fix the security problem?

Proxy command

Host app
    Hostname *.*.*.*
    IdentityFile ~/.ssh/your_rsa
    User *******
    Port ****
    ProxyCommand ssh -W %h:%p bast

Host bast
     Hostname *.*.*.*
     ForwardAgent no
     User ******

For basic operations: how to transfer files via the servers (from client to server, server to client), you can read on my post here

Conclusion

  • If you use bastion host, don't use AgentForwarding but use ProxyCommand
  • Always use non-root user for authentification
  • Use a firewall and block all unnecessary connections.
  • Use SELinux (In general)
  • Block the IP address who tries to log in several times with incorrect credentials
  • If it's not necessary don't give sudo permission to the user
  • Monitor your server
  • Update your server for security patches

More information, see my blog. Additionally I have some screeenshots, so it may be helpfull for you.

grep
  • 161
  • 1
  • 6
  • Thank you very much! actually, we use also google authenticator upon login. – user2503775 Mar 17 '19 at 08:10
  • I'm getting an error when trying to call ssh app: `channel 0: open failed: administratively prohibited: open failed. stdio forwarding failed. `. Do you have an idea why?. At secure log I see: `refused local port forward: originator 127.0.0.1 port 65535, target *app-ip* port 22` – user2503775 Mar 17 '19 at 10:42
  • Cool info. A small advice to improve readability of your answer. Do not copy/paste the content of your blog here. Provide the link and just a summary. Then highlight the real answer part (which for you is using ProxyCommand). I saw you kind of tried it at the beginning but given the copy/paste part it was kind of confusing. Anyway +1 – Huygens Mar 17 '19 at 13:24
  • @user2503775 It should be a different problem, not related ssh-agent forwarding/proxy command. Let's open a new question with logs. – grep Mar 17 '19 at 16:09
  • I did: https://serverfault.com/questions/958768/ssh-through-bastion-host-gives-open-failed-connect-failed-connection-timed-ou – user2503775 Mar 18 '19 at 11:04
  • Can you try to 1. enter the bastion via the SSH and then try to connect the final server. It looks like a connection problem - not related to proxy command or agent forwarding. Or just disable firewall and see if it works. – grep Mar 19 '19 at 05:52
4

Simply use SSH agent forwarding like most others do.

  • The keys will be in ssh agent on your laptop.
  • You login to bastion, authenticated through the agent.
  • From there login to you target host, with authentication request forwarded back to your laptop.

Advantage: there are no keys stored on the bastion that can be misused.

Hope that helps :)

MLu
  • 23,798
  • 5
  • 54
  • 81
  • Hi, that is basically what the OP describes in his/her second bullet. I advise you check the second link provided in the question. – Huygens Mar 14 '19 at 11:02
  • @Huygens true I noticed now. I overloked that as he mixes together TCP forwarding with Agent forwarding. – MLu Mar 14 '19 at 11:05
  • Indeed this is mixed up :-) – Huygens Mar 14 '19 at 11:13
  • It's not mixed. I understand the difference. I edited the question to make it clear. – user2503775 Mar 14 '19 at 11:26
  • I wrote an answer, how to hack agent forwarding (There is no key but there is socket open). Generally, agent forwarding is okay because the possibility to steal the keys is very low - first of all, you must hack bastion host. Anyway you can see my answer: https://serverfault.com/a/958466/476642 – grep Mar 15 '19 at 15:46