Using a hardware key for better security: Difference between revisions
No edit summary |
No edit summary |
||
| (One intermediate revision 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 | 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 | 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 46: | Line 46: | ||
An example exchange looks like this: | An example exchange looks like this: | ||
<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" | 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. | ||
| Line 56: | Line 57: | ||
Your identification has been saved in /home/user001/.ssh/id_ed25519_sk | 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 | Your public key has been saved in /home/user001/.ssh/id_ed25519_sk.pub | ||
</syntaxhighlight> | |||
==== Copy your key: ==== | ==== Copy your key: ==== | ||
| Line 63: | Line 65: | ||
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, 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 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. | ||
| Line 82: | Line 85: | ||
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. | ||
First, download and inspect the LaunchAgent plist before loading it: | First, download and inspect the LaunchAgent plist before loading it:<syntaxhighlight lang="bash"> | ||
# 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 | |||
</syntaxhighlight>The content should look like this:<syntaxhighlight lang="xml"><?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></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. | |||
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 <code>$SSH_AUTH_SOCK</code> points to the Homebrew agent socket (not the Apple one) before continuing: | 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: | ||
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:
- Enforce/use a password to unlock your SSH key
- Enforce/use a PIN to unlock the hardware key
- Enforce/use touching the hardware key to get access
This then leads to the following 4 scenarios:
- Use SSH key password, pin and touch for each new SSH session (no SSH agent)
- 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 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-skas 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)