During keyring
configuration for the Nextcloud client (see the Linux: the Nextcloud client, qtkeychain and the “The name org.freedesktop.secrets was not provided by any .service files” error post) – I decided to clean up the mess in my SSH keys, as I have a lot of them and sometimes authentication became just pain.
In general to make this simpler one can use system-wide storage like gnome-keyring
or KeeyPassXC, but we will speak about them in the next post.
Today, let’s discuss ssh-agent
and how to use it to manage password-protected RSA keys for SSH authentication without such a backends.
Examples below performed on an Arch Linux installation with some additional tests Manjaro Linux with Budgie DE.
- ssh-agent
- Running the agent
- Examples
- A key generation
- Checking SSH-key’s password
- ssh-copy-id – copy a key to a remote host
- ssh-add
- Could not open a connection to your authentication agent
- Adding a key
- Checking keys
- Deleting key(s)
- Automatically adding keys to ssh-agent
- Running ssh-agent with multitype terminals
- ~/.bashrc
- systemd
- ~/.xinitrc
ssh-agent
[ssh-agent](https://www.ssh.com/ssh/agent)
is intended to manage a user’s SSH keys and their passwords to avoid the necessity to enter a key’s password each time you need to log in a remote host using such a key for your authentication.
Running the agent
Just perform:
$ ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-dMDE5mED77tM/agent.436347; export SSH_AUTH_SOCK;
SSH_AGENT_PID=436348; export SSH_AGENT_PID;
echo Agent pid 436348;
For clients, such as ssh-client or git, they need to know the following variables:
-
SSH_AGENT_PID
: a startedssh-agent
PID, that will be sued for example to kill it withssh-agent -k
-
SSH_AUTH_SOCK
: a path to a UNIX socket file which will be used to communicate to thessh-agent
from clients (ssh
,git
, etc)
To run an agent without displaying these variables and to apply them – do the next:
$ eval $(ssh-agent) > /dev/null
There are few various ways to run the agent, we will take a closer look at the Running ssh-agent with multitype terminals part.
Examples
Let’s take an overview of ssh-agent
basic usage.
A key generation
Create a new key:
$ ssh-keygen -t rsa -b 2048 -f /home/setevoy/.ssh/test-key -C "Testing key" -P pass
Generating public/private rsa key pair.
Your identification has been saved in /home/setevoy/.ssh/test-key.
Your public key has been saved in /home/setevoy/.ssh/test-key.pub.
The key fingerprint is:
SHA256:pTyrGtk1hnNHB6b8ilp5jRe1+K4KrLHg50yUGilApLY Testing key
The key's randomart image is:
+---[RSA 2048]----+
|.o o |
|o . o . |
|o. o o o |
|o .. . o = + . |
|.Eo o o S = . |
| . + + B O o |
| o = B = o . |
| . +.B + . . |
| .oB.. ..... |
+----[SHA256]-----+
Options here:
-
-t
: type, RSA -
-b
: a key’s length in bits (by default 3072 for RSA) -
-f
: a path to the key’s file (by default~/.ssh/id_rsa
) -
-C
: a comment for the key (by default username@hostname) -
-P
: a key’s password
Checking SSH-key’s password
To check a password for a key you can use thessh-keygen
with -y
to display information about this key, and this will ask you to enter this key’s password:
$ ssh-keygen -y -f /home/setevoy/.ssh/test-key
Enter passphrase:
ssh-rsa AAAAB***gud2vedL/V Testing key
ssh-copy-id
– copy a key to a remote host
You can copy a key manually, by getting its public part from the test-key.pub file:
$ cat .ssh/test-key.pub
ssh-rsa AAAAB***gud2vedL/V Testing key
And by adding it to the ~/.ssh/authorized_keys
on a target host.
Another way, the recommended one, is to use an ssh-copy-id
utility which will do the same but also will keep an eye on folders/files permissions – the most frequent problem during SSH RSA-based authentification:
$ ssh-copy-id -i /home/setevoy/.ssh/test-key setevoy@rtfm.co.ua
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/setevoy/.ssh/test-key.pub"
/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
setevoy@rtfm.co.ua's password:
Number of key(s) added: 1
Now try logging into the machine, with: "ssh 'setevoy@rtfm.co.ua'"
and check to make sure that only the key(s) you wanted were added.
Now you can log in using this key:
$ ssh setevoy@rtfm.co.ua -i .ssh/test-key
Enter passphrase for key '.ssh/test-key':
Linux rtfm-do-production 4.9.0-8-amd64 #1 SMP Debian 4.9.144-3.1 (2019-02-19) x86_64
...
setevoy@rtfm-do-production:~$
ssh-add
Okay, so now we do have a password-protected RSA key for SSH authentication.
But during each SSH-login, you’ll have to enter its password again and again and this will be a real pain when using a lot of connections and keys.
To avoid this issue – add a key to the ssh-agent
using ssh-add
.
Check if it is running:
$ ps aux | grep ssh-agent
setevoy 1322 0.0 0.0 5796 456 ? Ss Nov30 0:00 ssh-agent -s
setevoy 1324 0.0 0.0 5796 2160 ? Ss Nov30 0:00 ssh-agent -s
...
Could not open a connection to your authentication agent
The most common problem is when ssh-add
is not able to connect to an agent:
$ ssh-add
Could not open a connection to your authentication agent.
At first – check if it’s PID is set from the SSH_AGENT_PID
, or by checking the $SSH_AUTH_SOCK
variable as all communication is gone via the socket-file specified by this variable:
$ test -z $SSH_AGENT_PID; echo $?
0
Here is it empty, because thessh-agent
was started in another terminal instance (we will speak soon how to handle it).
For now – kill all already running instances:
$ killall ssh-agent
And run an agent’s instance anew:
$ eval $(ssh-agent -s)
Agent pid 452333
We are using the-s
option as not everybody will do the steps above from the exactly bash
shell and eval
to apply the strings from the agent’s output (export SSH_AUTH_SOCK
).
Check again:
$ test -z $SSH_AGENT_PID; echo $?
1
And ssh-add
:
$ ssh-add -l
The agent has no identities.
All done here.
Adding a key
Run:
$ ssh-add /home/setevoy/.ssh/test-key
Enter passphrase for /home/setevoy/.ssh/test-key:
Identity added: /home/setevoy/.ssh/test-key (Testing key)
Checking keys
Use the -l
option to check which keys are already loaded to an agent’s instance:
$ ssh-add -l
2048 SHA256:pTyrGtk1hnNHB6b8ilp5jRe1+K4KrLHg50yUGilApLY Testing key (RSA)
Deleting key(s)
Use -d
to delete one key:
$ ssh-add -d .ssh/test-key
Identity removed: .ssh/test-key (Testing key)
And -D
to delete all keys at once:
$ ssh-add -D
All identities removed.
Automatically adding keys to ssh-agent
To make ssh
(and git
for example) adding used keys to an ssh-agent
without the necessity to run ssh-add
manually you can add the AddKeysToAgent
parameter to theв ~/.ssh/config
and specify one of the following options – yes, confirm or ask (см. SSH_ASKPASS
):
$ head -1 .ssh/config
AddKeysToAgent yes
Let’s check – there is nothing added at this moment:
$ ssh-add -l
The agent has no identities.
Make a connection, enter a key’s password:
$ ssh -i .ssh/test-key setevoy@rtfm.co.ua
Enter passphrase for key '.ssh/test-key':
...
setevoy@rtfm-do-production:~$
Disconnect, and check keys in the agent now:
setevoy@rtfm-do-production:~$ logout
Connection to rtfm.co.ua closed.
$ ssh-add -l
2048 SHA256:pTyrGtk1hnNHB6b8ilp5jRe1+K4KrLHg50yUGilApLY Testing key (RSA)
On the next connection – the ssh
client will use the key from the agent and will not ask you for the key’s password again:
$ ssh -i .ssh/test-key setevoy@rtfm.co.ua
...
setevoy@rtfm-do-production:~$
Running ssh-agent
with multitype terminals
Another big question is what to do when you have few bash-sessions, for example in various terminals’ tabs, as it will not has the $SSH_AUTH_SOCK
variable set and an ssh client will not be able to communicate with an already running ssh-agent
instance.
I.e. when you’ll run ssh-add
in a new terminal – you’ll see the already mentioned “Could not open a connection to your authentication agent” error:
$ ssh-add -l
Could not open a connection to your authentication agent.
~/.bashrc
There is a few ways to make the initialization of the variables during new bash session initialization, for example, you can add the following to your ~/.bashrc
:
if [ -z "$SSH_AUTH_SOCK" ] ; then
eval `ssh-agent -s`
ssh-add /home/setevoy/.ssh/test-key
fi
But in this case, each bash-sessions will has its own ssh-agent running, which is not a problem but maybe not what you’d like to have.
Another way could be the following code added to the ~/.bashrc
:
ssh-add -l &>/dev/null
if [ "$?" == 2 ]; then
test -r ~/.ssh-agent-env && \
eval "$(<~/.ssh-agent-env)" >/dev/null
ssh-add -l &>/dev/null
if [ "$?" == 2 ]; then
(umask 066; ssh-agent > ~/.ssh-agent-env)
eval "$(<~/.ssh-agent-env)" >/dev/null
ssh-add /home/setevoy/.ssh/test-key
fi
fi
Here (see response codes in the ssh-agent
documentation)):
- try to execute
ssh-add -l
, and redirect output to the/dev/null
- check returned code of the previous command:
- if it is == 2 (error connect to an agent):
- check if
~/.ssh-agent-env
is present and available for reading, read it and pass its output to thebash
- retry
ssh-add -l
- if code still 2:
- create the
~/.ssh-agent-env
file with the 660 permissions (read-write for an owner only) - start
ssh-agent
and redirects its output into the.ssh-agent-env
file - read the
.ssh-agent-env
content and pass it via a pipe to thebash
- run
ssh-add /home/setevoy/.ssh/test-key
- create the
Not a bad solution, and in this way all our sessions will use the same agent, although some guides suggesting to have different agents for personal and work usage
systemd
Another solution could be to create a dedicated systemd
service by adding a unit file and by running ssh-agent
as a systemd
service, see the Arch Wiki for the details.
Create a directory if not added yet:
mkdir -p .config/systemd/user/
And create a ~/.config/systemd/user/ssh-agent.service
file there:
[Unit]
Description=SSH key agent
[Service]
Type=simple
Environment=SSH_AUTH_SOCK=%t/ssh-agent.socket
ExecStart=/usr/bin/ssh-agent -D -a $SSH_AUTH_SOCK
[Install]
WantedBy=default.target
Next, Wiki told about the ~/.pam_environment
file for variables, but in my current case I have Openbox and usually set variables via .config/openbox/autostart
file:
$ head -2 .config/openbox/autostart
# ssh-agent.service
SSH_AUTH_SOCK="${XDG_RUNTIME_DIR}/ssh-agent.socket"
By the way, recalled about about such a thing as setting default values in BASH – BASH: переменные — передача значений по-умолчанию ${var:-defaultvalue}, замена значений — ${var:+alternatevalue} и сообщений — ${var:?message} (Rus)
Now, stop all agents running:
$ killall ssh-agent
Check the $XDG_RUNTIME_DIR
variable value:
$ echo $XDG_RUNTIME_DIR
/run/user/1000
For now, set the $SSH_AUTH_SOCK
variable manually:
$ SSH_AUTH_SOCK="${XDG_RUNTIME_DIR}/ssh-agent.socket"
And run an agent via systemctl --user
:
$ systemctl --user start ssh-agent
Check it:
$ systemctl --user status ssh-agent
● ssh-agent.service - SSH key agent
Loaded: loaded (/home/setevoy/.config/systemd/user/ssh-agent.service; disabled; vendor preset: enabled)
Active: active (running) since Sun 2019-12-01 09:15:18 EET; 2s ago
Main PID: 497687 (ssh-agent)
CGroup: /user.slice/user-1000.slice/user@1000.service/ssh-agent.service
└─497687 /usr/bin/ssh-agent -D -a /run/user/1000/ssh-agent.socket
Dec 01 09:15:18 setevoy-arch-pc systemd[670]: Started SSH key agent.
Dec 01 09:15:19 setevoy-arch-pc ssh-agent[497687]: SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket; export SSH_AUTH_SOCK;
A socket’s variable:
$ echo $SSH_AUTH_SOCK
/run/user/1000/ssh-agent.socket
And try ssh-add
:
$ ssh-add -l
The agent has no identities.
“It works!” (c)
You can add to autostart now:
$ systemctl --user enable ssh-agent
Created symlink /home/setevoy/.config/systemd/user/default.target.wants/ssh-agent.service → /home/setevoy/.config/systemd/user/ssh-agent.service.
~/.xinitrc
One more way you can use is by adding the agent’s start to the~/.xinitrc
.
In this case, when you’ll execute the startx
(for example, as in my case, when I have no any login manager, and X.Org is started manually by entering the startx
in the console) – at first, an agent will be started and the – an Openbox session, see the documentation:
$ cat ~/.xinitrc
eval $(ssh-agent) &
exec openbox-session
Also, as already mentioned at the very beginning of this post, there other implementations for the key’s backends that can be used alongside or instead of the ssh-agent
– kind of “wrappers” that will be or “proxy” requests from an ssh client to an ssh-agent
‘s instance, or will fully replace the ssh-agent itself and will store keys and passwords themselves, but we will speak about them in a following post(s?)..
Similar posts
- 01/30/2015 Linux: sftp с авторизацией по RSA-ключу
- 09/27/2016 SSH: ssh-copy-id – Permission denied
- 10/21/2017 SSH: подключение в приватную сеть через Bastion и немного про Multiplexing
- 05/26/2017 C: libssh – пример SSH-“клиента”
Top comments (0)