SSH Configuration
What is ssh
SSH stands for Secure SHell and provides a Secure (remote) connection over an unsecure channel (internet).
The connection can open:
- command line interface (most common)
- tunnel ports (we’ll see how to use that later for web servers ;) -> reasonably fast) (
-L local_socket:host:hostport
) - X11 sessions (useful for passing application windows thorugh the ssh connection -> can be slow) (
-X
more secure or-Y
-> assumed trusted -> bypasses checks)
Connection
The easiest way to connect to a machine is by typing
ssh USERNAME@MACHINENAME
see SIP for a list of machines names
This will prompt you with the username’s password.
This is the “basic” form of authentification, behinds the scenes ssh
generates a pair of keys which are passed between the server and host (see Wikipedia for more information) it is possible to manually generate these and no longer have to provide the username’s password, see ssh keys.
Options
As with most command line tools there are certain options that can be specified here are some useful commands.
X server
ssh -X USERNAME@MACHINENAME
From the manual pages:
X11 forwarding should be enabled with caution. Users with the ability to bypass file permissions on the remote host (for the user’s X authorization database) can access
the local X11 display through the forwarded connection. An attacker may then be able to perform activities such as keystroke monitoring.
For this reason, X11 forwarding is subjected to X11 SECURITY extension restrictions by default.
ssh -Y USERNAME@MACHINENAME
This command bypasses the security set above. USE WITH CAUTION
Tunnel ports
Port tunneling is used to connect ports on a remote machine to ports on the localhost. For example when running Jupyter it uses port 8888, if running Jupyter locally then you navigate to http://localhost:8888
to open the webpage. If you run Jupyter on a accessible (all ports) server (inside local network on on the web) then you can acess jupyter via http://MACHINENAME:8888
. However what happens when the server is not directly accessible from the outside, for example you need to go via a gateway (jump) server to access the server? In this case you can use port tunnelling.
The below example connects to a target_server
via a gateway_server
by using the -J
option. It then connects a localport
to the target_server’s port. So for example if we run jupyter on target_server:8888
then run ssh ... -L 8765:target_server:8888
we can now navigate to http://localhost:8765
and via ssh magic we see, in a secure manner, what is happening on the port 8888
of the target server.
ssh -v -N USERNAME_ON_TARGET_SERVER@TARGET_SERVER -J USERNAME_ON_GATEWAY_SERVER@GATEWAY_SERVER -L LOCALPORT:TARGET_SERVER:TARGET_SERVER_PORT
ssh keys
As we saw above in Connection the easiest (and default) way to login is using a password, we also saw that by doing this an automatic pairs of keys are created.
An alternative (and less hassle) way of doing this is by creating these keys manually then copying them to the different servers. The servers will no longer prompt for the username’s password. Passwordless connections only work as long as the machine you are connecting from has the corresponding private key. NEVER SHARE YOUR PRIVATE KEY, LIKE NEVER EVER EVER
For extra security you can add a password to the private key file, this is for the file and not server dependant, meaning that you only have to remember one password.
Setup
Create ssh pair
If you already have an ssh key pair generated you can skip this step (ls -al ~/.ssh
you are looking for a pair with a .pub
file if you aren’t sure just create a new one)
I could rewrite all the steps but frankly there is no point in reinventing the wheel so check out this documentation, you need to do Generating a new ssh key AND Adding your ssh key to ssh-agent (but you do not need to the last step - Add the ssh key to your gihub account) —> GitHub Documentation
Copy public key to server
You have to carry out this step FOR EVERY server you wish to connect to.
Direct access
If you have direct acess (the server is publically visible) you can run:
ssh-copy-id username_on_server@servername
Server behind a jump server (behind gateway)
If you want to access a target_server
that is behind a gateway_server
(so not publically visible) then you need to use the -o ProxyJump=
command which sets up the jump via the proxys server
ssh-copy-id -o ProxyJump=username_on_gateway_server@gateway_server username_on_target_server@target_server
Test
You should now be able to execute
ssh username@servername
And only be prompted for you ssh key password (if you set one)
ssh config
Its great being able to login to all these different machines remotely but it can be time consuming to write all those commands out and also annoying to always pass via the gateway.
Good news there is a way around that!
Create config file
If the file doesn’t exist create ~/.ssh/config
Default options
We can set some defaul options that will be used for all hosts (*
).
- AddKeysToAgent: Automatically adds keys to the default agent -> Doc
- IdentityFile: This is the default ssh key file that should be used for all hosts (you can change this on a per host basis if needed). It is perfectly fine to have the same ssh private key for multiple servers, if a server is hacked this does not allow hackers access to the other servers.
Host *
AddKeysToAgent yes
IdentityFile ~/.ssh/id_ed25519
~/.ssh/id_ed25519
is the default value when following the instructions in the guide above, if this is not your default ssh key or you do not have a default ssh key do not use this line
Publicly accessible server
This is the simpliest configuration where the server is publically accesible. The following example should be appended to ~/.ssh/config
Host SHORTCUT_NAME
Hostname SERVER_ADDRESS
User YOUR_USERNAME_ON_THE_SERVER
With this configuration we are able to use the SHORTCUT_NAME
instead of YOUR_USERNAME_ON_THE_SERVER@SERVER_ADDRESS
. This means that:
ssh YOUR_USERNAME_ON_THE_SERVER@SERVER_ADDRESS
becomes:
ssh SHORTCUT_NAME
Server behind Gateway
As we saw before certain servers may reside behind a gateway and are not publically accessible.
Before we either had to
ssh user1@server1
Then from server1
ssh user2@server2
to access the server in two steps or
ssh user2@server2 -J user1@server1
to access the server in a one liner. This sort of configuration can also be automated inside the config file.
Host GATEWAY_SERVER_SHORT_NAME
Hostname GATEWAY_SERVER_ADDRESS
User GATEWAY_SERVER_USERNAME
Host TARGET_SERVER_SHORT_NAME
Hostname TARGET_SERVER
User TARGET_SERVER_USERNAME
ProxyJump GATEWAY_SERVER_SHORT_NAME
This allows us to wirte:
ssh TARGET_SERVER_SHORT_NAME
To directly access the server behind the gateway.
Port Tunnelling
As we saw above via ssh it is possible to connect remote ports to local ports to interact with services running on a remote machine. To do this we use the LocalForward
keyword.
Host SERVER
Hostname SERVER_ADDRESS
User SERVER_USERNAME
LocalForward 8111 127.0.0.1:8080
127.0.0.1 is the loopback address in other words it means the servers itself or localhost on the server
This connects the port 8111
on your localmachine to the port 8080
on the server meaning that you can navigate to http://localhost:8111
and see what is actually on http://localhost:8080
of the server.
This is useful when a port on a server is not publically visible.
Opening Remote Windows
To open remote windows the ForwardX11
(-X) or ForwardX11Trusted
keywords should be used. If the target server is behind a jump server only use this keyword on the target server. Options are yes
or no
(default)
For Mac users ensure XQuartz is installed else X11 windows can not be passed through.
brew install --cask xquartz
Host SERVER
Hostname SERVER_ADDRESS
User SERVER_USERNAME
ForwardX11 yes
Conclusion
- Setup SSH keys using GitHub Documentation.
- Copy the ssh key to a server via
ssh-copy-id username_on_server@servername
or
ssh-copy-id -o ProxyJump=username_on_gateway_server@gateway_server username_on_target_server@target_server
- create a
~/.ssh/config
similar to:
Host *
AddKeysToAgent yes
IdentityFile ~/.ssh/id_ed25519
Host GATEWAY_SERVER_SHORTNAME
Hostname GATEWAY_SERVER_ADDRESS
User GATEWAY_SERVER_USERNAME
Host PRIVATE_SERVER_SHORTNAME
Hostname PRIVATE_SERVER_ADDRESS
User PRIVATE_SERVER_USERNAME
ForwardX11 yes
ProxyJump GATEWAY_SERVER_SHORTNAME
LocalForward LOCAL_PORT 127.0.0.1:REMOTE_PORT
LocalForward
allows port tunnelling.
ForwardX11
or ForwardX11Trusted
allows passing windows through the connection