The use of SSH Agent Forwarding, enables us to simplify the re-use of SSH keys. From your desktop environment it is possible to traverse through multiple hosts over SSH. However, this method comes with an inherent risk where the agent can be hijacked. This means a malicious actor could use the SSH keys to compromise downstream hosts, oblivious to the original users knowledge.
In this post, I will cover a simple way to protect against SSH Agent Hijacking. Also, I will detail what it takes to configure a system-wide agent that runs under Gnome.
Confirmation of SSH Key Usage
To protect yourself from SSH Agent Hijacking it is highly advisable that when you add your ssh keys to the ssh-agent, that you specify the - c option of the ssh-add command. An excerpt from the man page below, explains the usage of the -c option.
-c Indicates that added identities should be subject to confirmation before being used for authentication. Confirmation is performed by ssh-askpass(1). Successful confirmation is signaled by a zero exit status from ssh-askpass(1), rather than text entered into the requester.
Agent forwarding is always somewhat potentially harmful, but this potential can be limited a great deal via the -c option.
Implementation of System-Wide SSH Agent
Below are the steps that will achieve our objective. This tutorial is for the Gnome Desktop Environment on Fedora. This covers only the classic Gnome Session under X and not applicable to usage on Wayland.
Starting Gnome via the ssh-agent Process
For us to achieve system-wide usage of the ssh-agent the Gnome Session needs to be started with the ssh-agent process. The following file will ensure the Gnome Desktop Environment is started as such:
# cat << EOF > /etc/X11/xinit/Xclients.d/Xclients.gnome-session.sh #!/bin/sh exec -l $SHELL -c "$SSH_AGENT gnome-session" EOF
and make this file executable:
# chmod +x /etc/X11/xinit/Xclients.d/Xclients.gnome-session.sh
On the next login, the Gnome Session will be running under ssh-agent.
Disabling Gnome SSH Keyring
Next we have to disable the ssh part of the Gnome Keyring Agent as this does not support the ssh-add -c option.
cp /usr/share/applications/gnome-keyring-ssh.desktop ~/.config/autostart/gnome-keyring-ssh.desktop
Make sure the Autostart directive is set to false. Add this line if it does not exist.
Again, this will not take effect until the next login. This completes the system configuration for the system-wide ssh agent.
SSH Key Confirmation Zenity Script
We now write a Zenity script that will ask for confirmation when the SSH Key is to be used. Successful confirmation is signaled by a zero exit status from this script. You could also install the openssh-askpass program, however this is the approach I have always used.
cat << EOF > ~/bin/ask-pass.sh #!/bin/sh zenity --window-icon=warning --width="200" --height="100" \ --question --title="Confirm Key Usage" --text="WARNING: \ There has been a request to the ssh-agent program to access your \ private key.\n\nShould this request be authorized?" EOF chmod +x ~/bin/ask-pass.sh
We can test this script now and view the exit status with echo $?. In this first instance, we click “Yes” to mimic the confirmation of the key usage. The result is “0” as expected from the man page explanation.
$ ~/bin/ask-pass.sh $ echo $? 0
In this second instance, we choose “No”, which gives us an exit status of “1”.
$ ~/bin/ask-pass.sh $ echo $? 1
Setting the $SSH_ASKPASS Variable
For openssh to access this script we need to set the environment variable in .bash_profile.
SSH_ASKPASS=$HOME/bin/ask-pass.sh export SSH_ASKPASS
Again, this will not take effect until the next login.
Workaround for Fedora 29+
Starting from Fedora 29, openssh no longer picks up on this environment variable, don’t ask my why, I have no idea. But this is very easily set right by placing our Zenity script where openssh expects to find it.
# cp ~/bin/ask-pass.sh /usr/libexec/openssh/ssh-askpass
Testing “ssh-agent -c” Configuration.
After logging out and back in again, we are already to go to test this configuration.
Let us first confirm the ssh-agent is running under Gnome.
$ ssh-add -l The agent has no identities.
If you receive an error say that the agent cannot be connected, have a look at /etc/X11/xinit/Xclients.d/Xclients.gnome-session.sh. This is most likely the cause of the error. Make sure it is executable.
Now we will add a key with the -c directive.
$ ssh-add -c ~/.ssh/rsa.key Enter passphrase for ~/.ssh/rsa.key (will confirm each use): Identity added: ~/.ssh/rsa.key (~/.ssh/rsa.key) The user must confirm each use of the key
The Identity has been added if you provided the correct passphrase for the key. This can be confirmed by listing the keys that the agent is storing.
$ ssh-add -l 4096 SHA256:8kjhkeh0kjf3/shkjhdkliousabdskhtiolqkrejbdk ~/.ssh/rsa.key (RSA)
Without further ado, let us log into a remote server that we have placed our public keys in the authorized_keys file of that server.
ssh -A email@example.com
We will be prompted to confirm the key usage with the Zenity pop-up window.
As explained above, clicking “Yes” will result in an exit status of “0” allowing usage of the key.
That completes the tutorial part of this post.
SSH Agent Hijacking is a very interesting subject, therefore I have included some links below so that you can read up more on this subject, if you wish to do so.