Blog.

Howto Secure Shell easily from the terminal

Marco Franssen

Marco Franssen /

10 min read1882 words

Cover Image for Howto Secure Shell easily from the terminal

I see many struggle when it comes to using Secure Shell in a comfortable way. Many are installing unneeded applications like Putty on Windows for example. Just like I did 4 years ago. Over the years I have been working a lot on servers where there was no GUI available and learned a lot doing that. I would like to share my tips and tricks so you can also be empowered by just sticking to the terminal on your OS or simply using Git Bash on Windows.

What is SSH

The SSH protocol (also referred to as Secure Shell) is a method for secure remote login from one computer to another. It provides several alternative options for strong authentication, and it protects the communications security and integrity with strong encryption. It is a secure alternative to the non-protected login protocols (such as telnet, rlogin) and insecure file transfer methods (such as FTP).

SSH key

Too ease the way you access servers or use Git I always recommend to create an SSH key. This reduces the amount of times you need to enter credentials and it adds a small layer of additional security by having the need for this (physical) ssh key file on available. To generate an SSH key you simply run the following command from your terminal or Git Bash when on Windows. Ensure to protect the key with a password, so no one can abuse it, when you loose or leak it somewhere. In general you can go with the default location.

terminal
$ ssh-keygen -t rsa -b 4096 -C marco.franssen@my-email.com
Generating public/private rsa key pair.
Enter file in which to save the key (/users/marco/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in ~/.ssh/id_rsa.
Your public key has been saved in ~/.ssh/id_rsa.pub.
The key fingerprint is:
30:a5:c1:7a:bb:00:bf:7c:24:b7:4d:f1:d6:3d:e5:7e marco.franssen@my-email.com

To break it down.

  • -t rsa => a key of type rsa (encryption format)
  • -b 4096 => use an encryption length of 4096 bytes long. Lower lengths are as of this writing considered insecure.
  • -C marco.franssen@my-email.com => a comment to document your key.

SSH Agent

Next up you do want to configure an SSH Agent, which will help us in a couple of ways. First of all we won't continuously be prompted to enter the password for our key. The SSH Agent will cache our key for the lifetime of the SSH-Agent, or until you remove the key from the agent. Secondly it will allow us to do something called SSH Agent Forwarding. More on that later. Lets first have a look on how to enable an SSH agent on your machine.

MacOS

On MacOS the easiest to setup an SSH Agent is by installing keychain (Not to be confused with keychain shipped natively with your Mac). Easiest to install keychain is by using Homebrew.

terminal
brew install keychain

Once keychain is installed we will add the following to our ~/.bash_profile.

~/.bash_profile
eval keychain --eval --agents ssh --inherit any id_rsa
source $HOME/.keychain/$HOSTNAME-sh

This will launch our ssh agent and cache our id_rsa key whenever we launch a terminal. Only the first time you will be prompted to enter a password for your key.

Windows

On Windows I assume you are using Git Bash. You can install Git via Chocolatey (I don't like downloading installers manually and clicking through them manually).

Powershell
choco install -y git

Then we will add a small config file to instruct Git Bash to launch an SSH Agent. Following script is a Bash script that automatically executes when openening Git Bash. Important is to name and place the file exactly as mentioned below. Inside your users home directory.

declare -x SSH_ENV="$HOME/.ssh/environment"

# start the ssh-agent
function start_agent {
    echo "Initializing new SSH agent..."
    # spawn ssh-agent
    ssh-agent | sed 's/^echo/#echo/' > "${SSH_ENV}"
    echo succeeded
    chmod 600 "${SSH_ENV}"
    . "${SSH_ENV}" > /dev/null
    ssh-add
}

# test for identities
function test_identities {
    # test whether standard identities have been added to the agent already
    ssh-add -l | grep "The agent has no identities" > /dev/null
    if [ $? -eq 0 ]; then
        ssh-add
        # $SSH_AUTH_SOCK broken so we start a new proper agent
        if [ $? -eq 2 ];then
            start_agent
        fi
    fi
}

# check for running ssh-agent with proper $SSH_AGENT_PID
if [ -n "$SSH_AGENT_PID" ]; then
    ps -f -u "${USERNAME}" | grep "$SSH_AGENT_PID" | grep ssh-agent > /dev/null
    if [ $? -eq 0 ]; then
        test_identities
    fi
else
    if [ -f "$SSH_ENV" ]; then
        . "$SSH_ENV" > /dev/null
    fi
    ps -f -u "${USERNAME}" | grep "$SSH_AGENT_PID" | grep ssh-agent > /dev/null
    if [ $? -eq 0 ]; then
        test_identities
    else
        start_agent
    fi
fi

Now having this in place for every new terminal we open we simply will have the Agent with a loaded ssh-key available. Only the first terminal you open will request you to enter the password for your ssh key. Now you can simply git clone, git push and git pull without the need to enter passwords. You will first have to upload your key to your Git Server as described in the section Authorize your Key though. If you can bring up the patience please continue reading before trying to authorize your key.

SSH Config

Next we add a ~/.ssh/config file. In this file I define some Hosts which allow me easy access to the servers using an easy to remember name. Host defines an alias you can use for your server, name it to be easy remembered or describe your server. The hostname is the ip address or dns record on which the server can be accessed. The port in general is port number 22, unless your server admin changed it. Next we can define user which will be used as the user to login to the server.

~/.ssh/config
Host nas
    Hostname 192.168.0.20
    Port 2200
    User marco

Host raspberry
    Hostname 192.168.0.33
    User pi

# Host proxy-example-via-nas
#    HostName raspberry
#    ProxyCommand ssh nas -W %h:%p

Host *
   Port 22
   ForwardAgent=yes
   IdentityFile ~/.ssh/id_rsa

The Host * applies the defined settings for all the other hosts, so we don't have to repeat the setting everywhere. The forward agent option allows us to use our key also on the server during our session. This has as an advantage that you will never have the need to store SSH keys on the server. This means a potential hacker could only have access to your SSH key during the time you have an active session. Using the forward agent option you can do things like hopping to other servers which also have your key authorized or you can do things like git clone on the server using the ssh-key on your client.

Furthermore you can use # to make comments in the file, for the sake of documenting your own things. In above example I commented a configuration that would allow us to use an automated SSH hop via my nas host to the raspberry. E.g. this can be very usefull if there is only a single server publicly exposed (bastion server) and the rest of your servers are behind a firewall in a private network. Using this approach we can still directly access those servers by connecting to the alias that applies the SSH hop strategy.

Authorize your key

Now we have ~/.ssh/config in place we can very easily SSH into servers. The only thing remaining is to authorize our SSH Key on the server(s). This can be done manually by going onto the server and updating the file ~/.ssh/authorized_keys or simply by using the ssh-copy-id command that will allow us to do this in an easier way.

terminal
$ ssh-copy-id raspberry
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
pi@192.168.0.33's password:

Number of key(s) added:        1

Now try logging into the machine, with:   "ssh 'raspberry'"
and check to make sure that only the key(s) you wanted were added

For Git this usually boils down to upload your public key on your Git provider profile. E.g.:

To copy your key on MacOS you simple do following command:

cat ~/.ssh/id_rsa.pub | pbcopy

This will read the contents from your public key and put it on the clipboard.

On Windows in your Git Bash you simply do the following:

cat ~/.ssh/id_rsa.pub | clip

Please be sure to never share your private key (~/.ssh/id_rsa) anywhere.

Now on your profile page simply paste your key (ctrl+v or command+v) to authorize it and give it a description. E.g.: Key on my Macbook Pro. To verify if you have access you can run following command on your terminal / Git Bash.

$ ssh -T git@github.com
Hi marcofranssen! You've successfully authenticated, but GitHub does not provide shell access.

Done

Now with all these things in place we can simply run commands in the form of ssh <your alias>. Please also try the following to ensure you have access to your SSH Agent on the server itself.

terminal
$ ssh-add -l
4096 SHA256:X3LpX9VnhhGsJa2eEReYr50nQP3izSX9I4Nqj3L18kh /Users/marco/.ssh/id_rsa (RSA)
$ ssh raspberry
pi@raspberry:$ ssh-add -l
4096 SHA256:X3LpX9VnhhGsJa2eEReYr50nQP3izSX9I4Nqj3L18kh /Users/marco/.ssh/id_rsa (RSA)

You can see on my client I have my key loaded in the ssh-agent. Then when I ssh into the raspberry I'm running this command again. As you can see on the raspberry my key is also accessible via the Agent Forwarding. You can see this based on the fingerprint as well from the key file location, which is the location of the key on my client.

Bonus

Thank you for reading my blogpost. If you made it till here you captured my nice little autocompletion Bonus, which is my present to you for making it to the end.

~/.bash_profile
# autocomplete ssh hosts configured in ~/.ssh/config

_ssh()
{
    local cur prev opts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    opts=$(grep '^Host' ~/.ssh/config | grep -v '[?*]' | cut -d ' ' -f 2-)

    COMPREPLY=( $(compgen -W "$opts" -- ${cur}) )
    return 0
}
complete -F _ssh ssh
complete -F _ssh scp
complete -F _ssh ssh-copy-id

Above function will simply grep all the lines starting with Host. Now when you type either ssh, scp or ssh-copy-id it will autcomplete based on your aliases. This way when having a huge amount of hosts you can simply autocomplete their names by using the shell autocompletion feature. Shell autocompletion is triggered when you hit the tab key on your keyboard twice.

E.g.:

$ ssh r<tab><tab>
raspberry

References

Please leave me a comment and share on Social media with your friends.

You have disabled cookies. To leave me a comment please allow cookies at functionality level.

More Stories

Cover Image for Signing Docker images using Docker Content Trust

Signing Docker images using Docker Content Trust

Marco Franssen

Marco Franssen /

In this blog I want to introduce you to the concept of signing Docker images. Signing your docker images will add some layer of trust to your images. This can guarantee a consumer of your image that this image is for sure published by you and hasn't been tampered with by others. You might already used PGP to sign your Git commits. In this blogpost I shown a nice way of setting PGP signing keys using Krypton that adds 2FA. In practice Docker image signing is the same concept. If this all soun…

Cover Image for Secure 2FA SSH and PGP using Krypton

Secure 2FA SSH and PGP using Krypton

Marco Franssen

Marco Franssen /

In this blogpost I want to show you how easy it is to setup SSH and PGP key securily without even having them on your laptop. Instead we will have those keys on our mobile device. Yes, I hear you thinking…. Wutt, but, but, but, whaat! No worries bear with me, I walk you through it an will even explain you some magic behind the Krypton commands which we are about to use, so you will have a fully transparant understanding on Krypton. First of all you shouldn't worry about the safety of your ke…

Cover Image for Manage Go tools via Go modules

Manage Go tools via Go modules

Marco Franssen

Marco Franssen /

In this blog I will cover how I'm managing and versioning the tools my Go projects depend on. Go Modules are available since Go 1.11. Using Go Modules you can manage the dependencies for your project. You can compare it to NPM in Nodejs projects or Maven in Java project or Nuget in .NET projects. In general Go Modules are used to manage your compile time dependencies. However in my projects I also like to manage the tools required for Continuous Integration in my projects. To ensure all devel…

Cover Image for Install fresh Raspbian image on your Raspberry Pi - part 2

Install fresh Raspbian image on your Raspberry Pi - part 2

Marco Franssen

Marco Franssen /

In the previous blog of this series I explained the basics of getting a fresh installation of Raspbian on your Rapberry Pi including SSH access and configuration of a static IP for your Wifi. In this blog we are going to have a look at tweaking it a little further to get a better commandline experience and have some more tooling available to operate your Raspberry Pi. Admin experience and tooling On any server I will most likely always work with Git and Vim. I have many of my bash scripts an…