Using a hardware key for better security: Difference between revisions

From HPCwiki
Jump to navigation Jump to search
Prins0891 (talk | contribs)
No edit summary
Haars0011 (talk | contribs)
No edit summary
 
(2 intermediate revisions by the same user not shown)
Line 3: Line 3:
With that key, you can implement multifactor authentication for your SSH connections.
With that key, you can implement multifactor authentication for your SSH connections.


Depending on you choices and setup, you can make it very secure, so that without the key, pin and password your SSH key won't be able to be used.
Depending on your choices and setup, you can make it very secure, so that without the key, pin and password your SSH key won't be able to be used.


The steps below are adaptations of https://developers.yubico.com/SSH/Securing_SSH_with_FIDO2.html  
The steps below are adaptations of https://developers.yubico.com/SSH/Securing_SSH_with_FIDO2.html  
Line 10: Line 10:
There are different levels of security you can apply, each being more secure, but also introducing an extra step before you have an active session.
There are different levels of security you can apply, each being more secure, but also introducing an extra step before you have an active session.


There a three "interactions" that can be used:
There are three "interactions" that can be used:


# Enforce/use a password to unlock your SSH key
# Enforce/use a password to unlock your SSH key
Line 22: Line 22:
# Use pin and touch for each new SSH session (use SSH agent for password)
# Use pin and touch for each new SSH session (use SSH agent for password)
# Use touch for each new SSH session (use SSH agent for password, but no PIN enforcement in key)
# Use touch for each new SSH session (use SSH agent for password, but no PIN enforcement in key)
# Use SSH key password and touch for first SSH session (pass in SSH agent, no PIN and touch enforcement in key)
# Use SSH key password for each new SSH session (use SSH agent to cache passphrase; no PIN or touch required per-session)


The last one is the least intrusive, and as an attacker would need physical access to your device to circumvent your security, this is probably fine for most people.
The last one is the least intrusive, and as an attacker would need physical access to your device to circumvent your security, this is probably fine for most people.
Line 39: Line 39:
The options are:
The options are:


* <code>-t ed25519-sk</code> : Type of key, this is the more secure option
* <code>-t ed25519-sk</code> : Type of key, this is the more secure option. If your hardware key does not support ed25519-sk, use <code>-t ecdsa-sk</code> as a fallback.
* <code>-O resident</code> : Store the SSH key on your hardware key, makes it easier to use on another machine
* <code>-O resident</code> : Store the SSH key on your hardware key, makes it easier to use on another machine
* <code>-O no-touch-required</code> : No need to touch the hardware key every time
* <code>-O no-touch-required</code> : No need to touch the hardware key every time
* <code>-O application=ssh:anunna.wur.nl</code> : identifier for the key on your hardware key
* <code>-O application=ssh:anunna</code> : identifier for the key on your hardware key
* <code>-C "[Your comment to identify this key on the server]"</code> : identifier for the key on the server
* <code>-C "[Your comment to identify this key on the server]"</code> : identifier for the key on the server


An example exchange looks like this:
An example exchange looks like this:
  user001@LAPTOP:~ % ssh-keygen -t ed25519-sk -O resident -O no-touch-required -O application=ssh:anunna -C "first.lastname@wur.nl"
<syntaxhighlight lang="bash">
  user001@LAPTOP:~$ ssh-keygen -t ed25519-sk -O resident -O no-touch-required -O application=ssh:anunna -C "first.lastname@wur.nl"
  Generating public/private ed25519-sk key pair.
  Generating public/private ed25519-sk key pair.
  You may need to touch your authenticator to authorize key generation.
  You may need to touch your authenticator to authorize key generation.
  Enter PIN for authenticator:
  Enter PIN for authenticator:
  You may need to touch your authenticator again to authorize key generation.
  You may need to touch your authenticator again to authorize key generation.
  Enter file in which to save the key (/Users/user001/.ssh/id_ed25519_sk):
  Enter file in which to save the key (/home/user001/.ssh/id_ed25519_sk):
  Enter passphrase for "/Users/user001/.ssh/id_ed25519_sk" (empty for no passphrase):
  Enter passphrase for "/home/user001/.ssh/id_ed25519_sk" (empty for no passphrase):
  Enter same passphrase again:
  Enter same passphrase again:
  Your identification has been saved in /Users/user001/.ssh/id_ed25519_sk
  Your identification has been saved in /home/user001/.ssh/id_ed25519_sk
  Your public key has been saved in /Users/user001/.ssh/id_ed25519_sk.pub
  Your public key has been saved in /home/user001/.ssh/id_ed25519_sk.pub
</syntaxhighlight>


==== Copy your key: ====
==== Copy your key: ====
To be able to log in, the server will have to have the public part of your key.
To be able to log in, the server will have to have the public part of your key.


For that, copy the contents of your public key, in my case <code>/Users/user001/.ssh/id_ed25519_sk.pub</code> to <code>$HOME/.ssh/authorized_keys</code>
For that, copy the contents of your public key, in my case <code>/home/user001/.ssh/id_ed25519_sk.pub</code> to <code>$HOME/.ssh/authorized_keys</code>


To allow touchless entry, we'll need to tell the SSH daemon to allow that:
To allow touchless entry, we'll need to tell the SSH daemon to allow that:
<syntaxhighlight lang="bash">
  # Copy over key
  # Copy over key
  ssh login.anunna.wur.nl "umask 0077; mkdir -p ~/.ssh; echo 'no-touch-required $(cat ~/.ssh/id_ed25519_sk.pub)' >> ~/.ssh/authorized_keys"
  ssh login.anunna.wur.nl "umask 0077; mkdir -p ~/.ssh; echo 'no-touch-required $(cat ~/.ssh/id_ed25519_sk.pub)' >> ~/.ssh/authorized_keys"
  # Check for key
  # Check for key
  ssh login.anunna.wur.nl 'tail -1 .ssh/authorized_keys'
  ssh login.anunna.wur.nl 'tail -1 .ssh/authorized_keys'
 
</syntaxhighlight>
==== Key use ====
==== Key use ====
On the machine that you created the key, there will be a stub file added to point ssh-agent to the hardware key, so that machine should work out of the box.
On the machine that you created the key, a stub file will have been added to point ssh-agent to the hardware key. If the SSH agent was already running at the time of key creation, you may need to run <code>ssh-add ~/.ssh/id_ed25519_sk</code> once to load it manually.


On other machines, you can load the private SSH key from the hardware key with
On other machines, you can load the private SSH key from the hardware key with (requires OpenSSH ≥ 8.3):
  ssh-add -K  
  ssh-add -K  
After this all, you should be able to login without issue.
After this all, you should be able to login without issue.
Line 80: Line 83:
So:
So:
  brew install openssh
  brew install openssh
Besides that, you will have to replace the MacOS ssh-agent with the one from openssh:
Besides that, you will have to replace the MacOS ssh-agent with the one from openssh.
# Download the plist
 
curl --silent --output ~/Library/LaunchAgents/com.homebrew.ssh-agent.plist <nowiki>https://gist.githubusercontent.com/partikus/cd45013b1274af8ae63b17030d89176c/raw/d34dfae3872dec38137e8a51780fbcb95380034c/com.homebrew.ssh-agent.plist</nowiki>
First, download and inspect the LaunchAgent plist before loading it:<syntaxhighlight lang="bash">
# Get the plist
# disable the default ssh-agent
curl --output ~/Library/LaunchAgents/com.homebrew.ssh-agent.plist https://gist.githubusercontent.com/partikus/cd45013b1274af8ae63b17030d89176c/raw/d34dfae3872dec38137e8a51780fbcb95380034c/com.homebrew.ssh-agent.plist  
launchctl disable gui/$UID/com.openssh.ssh-agent
# Review the file contents before proceeding
launchctl stop gui/$UID/com.openssh.ssh-agent
cat ~/Library/LaunchAgents/com.homebrew.ssh-agent.plist
</syntaxhighlight>The content should look like this:<syntaxhighlight lang="xml"><?xml version="1.0" encoding="UTF-8"?>
# enable the homebrew ssh-agent  
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
launchctl bootstrap gui/$UID ~/Library/LaunchAgents/com.homebrew.ssh-agent.plist
<plist version="1.0">
<dict>
# verify installation (you should see com.homebrew.ssh-agent)
<key>Label</key>
launchctl list | grep ssh
<string>com.homebrew.ssh-agent</string>
If there are issues with the MacOS ssh-agent, try a reboot, do another verify, and only the homebrew one should be present.
<key>ProgramArguments</key>
<array>
<string>/bin/sh</string>
<string>-c</string>
<!-- We reuse SSH_AUTH_SOCK from com.openssh.ssh-agent -->
<string>rm -f $SSH_AUTH_SOCK; exec /opt/homebrew/bin/ssh-agent -D -a $SSH_AUTH_SOCK</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist></syntaxhighlight>Then load it and disable the Apple agent:<syntaxhighlight lang="bash">
# enable the homebrew ssh-agent  
launchctl bootstrap gui/$UID ~/Library/LaunchAgents/com.homebrew.ssh-agent.plist
 
# disable the default ssh-agent
launchctl disable gui/$UID/com.openssh.ssh-agent
launchctl stop gui/$UID/com.openssh.ssh-agent
 
# verify installation (you should see com.homebrew.ssh-agent)
launchctl list | grep ssh
</syntaxhighlight>If there are issues with the MacOS ssh-agent, try a reboot, do another verify, and only the homebrew one should be present.


After this, open a new terminal , and follow the Linux flow.
After this, open a new terminal. Verify that <code>$SSH_AUTH_SOCK</code> points to the Homebrew agent socket (not the Apple one) before continuing:
echo $SSH_AUTH_SOCK
Then follow the Linux flow above.


=== Windows ===
=== Windows ===
(needs to be filled by a Windows user)
(needs to be filled by a Windows user)

Latest revision as of 14:16, 25 March 2026

WUR employees can get a Yubikey hardware key for free at the servicedesk in Forum.

With that key, you can implement multifactor authentication for your SSH connections.

Depending on your choices and setup, you can make it very secure, so that without the key, pin and password your SSH key won't be able to be used.

The steps below are adaptations of https://developers.yubico.com/SSH/Securing_SSH_with_FIDO2.html

Different levels of security/annoyance

There are different levels of security you can apply, each being more secure, but also introducing an extra step before you have an active session.

There are three "interactions" that can be used:

  1. Enforce/use a password to unlock your SSH key
  2. Enforce/use a PIN to unlock the hardware key
  3. Enforce/use touching the hardware key to get access


This then leads to the following 4 scenarios:

  1. Use SSH key password, pin and touch for each new SSH session (no SSH agent)
  2. Use pin and touch for each new SSH session (use SSH agent for password)
  3. Use touch for each new SSH session (use SSH agent for password, but no PIN enforcement in key)
  4. Use SSH key password for each new SSH session (use SSH agent to cache passphrase; no PIN or touch required per-session)

The last one is the least intrusive, and as an attacker would need physical access to your device to circumvent your security, this is probably fine for most people.

This is thus the scenario that we'll describe below in detail.

For scenario 1 & 2, add -O verify-required to the ssh-keygen command to enforce PIN enforcement in key.

For scenarios 1, 2 & 3, do not add -O no-touch-required to the ssh-keygen command to enforce touch enforcement in key.

Linux

Create your key:

(do this on your laptop or desktop)

ssh-keygen -t ed25519-sk -O resident -O no-touch-required -O application=ssh:anunna -C "[Your comment to identify this key on the server]"

The options are:

  • -t ed25519-sk : Type of key, this is the more secure option. If your hardware key does not support ed25519-sk, use -t ecdsa-sk as a fallback.
  • -O resident : Store the SSH key on your hardware key, makes it easier to use on another machine
  • -O no-touch-required : No need to touch the hardware key every time
  • -O application=ssh:anunna : identifier for the key on your hardware key
  • -C "[Your comment to identify this key on the server]" : identifier for the key on the server

An example exchange looks like this:

 user001@LAPTOP:~$ ssh-keygen -t ed25519-sk -O resident -O no-touch-required -O application=ssh:anunna -C "first.lastname@wur.nl"
 Generating public/private ed25519-sk key pair.
 You may need to touch your authenticator to authorize key generation.
 Enter PIN for authenticator:
 You may need to touch your authenticator again to authorize key generation.
 Enter file in which to save the key (/home/user001/.ssh/id_ed25519_sk):
 Enter passphrase for "/home/user001/.ssh/id_ed25519_sk" (empty for no passphrase):
 Enter same passphrase again:
 Your identification has been saved in /home/user001/.ssh/id_ed25519_sk
 Your public key has been saved in /home/user001/.ssh/id_ed25519_sk.pub

Copy your key:

To be able to log in, the server will have to have the public part of your key.

For that, copy the contents of your public key, in my case /home/user001/.ssh/id_ed25519_sk.pub to $HOME/.ssh/authorized_keys

To allow touchless entry, we'll need to tell the SSH daemon to allow that:

 # Copy over key
 ssh login.anunna.wur.nl "umask 0077; mkdir -p ~/.ssh; echo 'no-touch-required $(cat ~/.ssh/id_ed25519_sk.pub)' >> ~/.ssh/authorized_keys"
 # Check for key
 ssh login.anunna.wur.nl 'tail -1 .ssh/authorized_keys'

Key use

On the machine that you created the key, a stub file will have been added to point ssh-agent to the hardware key. If the SSH agent was already running at the time of key creation, you may need to run ssh-add ~/.ssh/id_ed25519_sk once to load it manually.

On other machines, you can load the private SSH key from the hardware key with (requires OpenSSH ≥ 8.3):

ssh-add -K 

After this all, you should be able to login without issue.

MacOS

For MacOS, we can mostly do the same as for Linux, except that we will have to install openssh, as the default SSH stack doesn't work with hardware keys.

So:

brew install openssh

Besides that, you will have to replace the MacOS ssh-agent with the one from openssh.

First, download and inspect the LaunchAgent plist before loading it:

# Get the plist
curl --output ~/Library/LaunchAgents/com.homebrew.ssh-agent.plist https://gist.githubusercontent.com/partikus/cd45013b1274af8ae63b17030d89176c/raw/d34dfae3872dec38137e8a51780fbcb95380034c/com.homebrew.ssh-agent.plist 
# Review the file contents before proceeding
cat ~/Library/LaunchAgents/com.homebrew.ssh-agent.plist

The content should look like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Label</key>
	<string>com.homebrew.ssh-agent</string>
	<key>ProgramArguments</key>
	<array>
		<string>/bin/sh</string>
		<string>-c</string>
		<!-- We reuse SSH_AUTH_SOCK from com.openssh.ssh-agent -->
		<string>rm -f $SSH_AUTH_SOCK; exec /opt/homebrew/bin/ssh-agent -D -a $SSH_AUTH_SOCK</string>
	</array>
	<key>RunAtLoad</key>
	<true/>
</dict>
</plist>

Then load it and disable the Apple agent:

# enable the homebrew ssh-agent 
launchctl bootstrap gui/$UID ~/Library/LaunchAgents/com.homebrew.ssh-agent.plist

# disable the default ssh-agent
launchctl disable gui/$UID/com.openssh.ssh-agent
launchctl stop gui/$UID/com.openssh.ssh-agent

# verify installation (you should see com.homebrew.ssh-agent)
launchctl list | grep ssh

If there are issues with the MacOS ssh-agent, try a reboot, do another verify, and only the homebrew one should be present.

After this, open a new terminal. Verify that $SSH_AUTH_SOCK points to the Homebrew agent socket (not the Apple one) before continuing:

echo $SSH_AUTH_SOCK

Then follow the Linux flow above.

Windows

(needs to be filled by a Windows user)