Contrary to a popular belief, the Ledger Nano S is not only designed to secure crypto currencies. It can also be used to generate and store private SSH keys, which makes it the most secure way to protect them.

Being both slightly paranoid, a Ledger employee and a heavy SSH user, I didn't want to rely on my computer to store my private keys anymore. That's why I decided to move everything on my Nano S. The most annoying thing with generating a set of new key pairs is that I had to change every public key I use on my servers and on Github. I wanted to derive my new keys from the Ledger secure element stored private key instead of reusing keys that might have already been compromised.

Installing the SSH Application on the Ledger Nano S

Before you can use the Ledger Nano S to generate and store your SSH keys, you need to install the SSH application.

Plug and unlock your Ledger Nano S before you launch the Ledger Manager. On the application panel, click on the Show developer items link, then scroll until you see the SSH/GPG Agent application.

Install the SSH/PGP Agent application, and when asked, click on your Ledger Nano S right button to authorise the Manager to process. You're done!

Install the Ledger Agent Python Command Line Tools

Open your favorite terminal application and make sure you have Python 3 and pip3 running on your computer.

$ which python3

/usr/local/bin/python3

$ which pip3

/usr/local/bin/pip3

If you don't have Python3 yet, don't panic and install it. I'm using Mac OS X with Homebrew, so I just need to type:

$ brew install python3

To have the command line tools communicate with the Ledger Nano S, you also need the libusb to be installed. On Mac OS X, just type:

$ brew install libusb

You can now use pip3 to install the Ledger Agent:

$ pip3 install ledger_agent

You're done with the installation, it's now time to generate your first SSH key.

Generate your First SSH Key on the Ledger Nano S

Plug and unlock your Ledger Nano S if you have unplugged it since you installed the SSH/GPG Agent application. Scroll through the applications, and select SSH/GPG Agent pressing both Nano S buttons.

Once the app launched, your Ledger Nano S should display SSH/PGP Agent.

Switch back to your terminal, and run:

$ ledger-agent user@host

Where user is your usual SSH user and host the host you want to connect to.

You will be asked to confirm the operation on the Ledger Nano S.

Accept and switch back to your terminal. You now have the SSH public key for the user and the host you previously selected.

ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBGQsHbGxSf6M+S3aA1lRjsrZ+Q/RZNr4Ma0qBkFzNrOx6BR2f8RZJW/wV4pJSdUYXMp6ItEXXvdW8CM0wQT4NDc= <ssh://user@host|nist256p1>

Cut past the whole string into your server ~/.ssh/authorized_keys file, you're now ready to use SSH with your newly generated key.

$ ledger-agent -c user@host

Before connecting, you need to accept the use of your key on the Ledger Nano S.

Then accept to authenticate your user.

Using the Ledger Agent shell wide

Using the Ledger Agent to connect to SSH is not the most practical thing ever. Thankfully, it is possible to use it as a traditional SSH agent so you can use it with the SSH client, git, and many more.

After the first key generation, the Ledger Agent printed a classic SSH ECDSA public key along with a string between <>.

<ssh://user@host|nist256p1>

This string is a Ledger Agent identity. Add it to a file, for example ~/.ssh/ledger.conf, then run the Ledger Agent again:

$ echo "<ssh://user@host|nist256p1>" >> ~/.ssh/ledger.conf

$ ledger-agent ~/.ssh/ledger.conf -s -v

2018-04-07 19:19:38,241 INFO identity #0: <ssh://user@host|nist256p1> [__init__.py:208]

2018-04-07 19:19:38,259 INFO running '/bin/zsh' with {'SSH_AUTH_SOCK': '/var/folders/4r/1nrw0lls4rqdq52xkvdcj7vm0000gn/T/trezor-ssh-agent-ib39yy', 'SSH_AGENT_PID': '29715'} [server.py:119]

This spawns a new shell with an SSH Agent using all the identities stored into the ledger.conf file. That way, you can simply run.

$ ssh user@host

This will use the SSH key stored into the Ledger Nano S without the need of using the ledger-agent. It also works with git, and everything using SSH such as mosh.

Don't launch the ledger-agent from your .bashrc or .zshrc since it will spawn another and another… in an infinite loop.

As I don't want to spawn 2 zsh process every time I open a terminal, I changed my iTerm2 profile to spawn a shell from the Ledger Agent at startup in place of a plain Zsh:

Automation, Because we're Lazy

I wouldn't be a system engineer if I wasn't a lazy ass. That's why I've written a small shell script to do all the work for me (available on Github under the MIT License).

This script:

Generates a new key for your user@host.

Adds the new identity to the ~/.ssh/ledger.conf file

Adds the new host to your ~/.ssh/config file

Reloads the Ledger Agent with all your identities (in the current shell only)

#!/bin/bash LEDGER_BIN=$(which ledger-agent)

LEDGER_HOST="${1}"

LEDGER_CONF="${HOME}/.ssh/ledger.conf" if [ -z "${LEDGER_HOST}" ]; then

echo "Usage: ${0} user@host"

echo exiting

exit 1

fi echo "Generating the private key, please confirm on the Nano S..." key=$(ledger-agent ${LEDGER_HOST}) echo "${key}" | cut -f 3 -d ' ' >> ${LEDGER_CONF} echo "Adding ${LEDGER_HOST} to your ssh config"

ssh_host=$(echo ${LEDGER_HOST} | cut -f 2 -d '@')

ssh_user=$(echo ${LEDGER_HOST} | cut -f 1 -d '@')

echo "Host ${ssh_host}

HostName ${ssh_host}

Port 22

User ${ssh_user}

PreferredAuthentications publickey " >> ${HOME}/.ssh/config echo "Your new public key is now into your clipboard!"

echo "${key}" | cut -f 1,2 -d ' ' | pbcopy echo "Now reloading the Ledger agent"

${LEDGER_BIN} ${LEDGER_CONF} -v -s exit 0

That's all folks, your private keys are now secure!