======Multiple systemd SSH Agents====== ---- This works great on my Debian Bullseye / i3wm system. I don't see why this wouldn't work on other distros / DEs but YMMV. =====Create a ssh-agent systemd service template===== * To enable agent creation for **all users**, create ''%%/etc/systemd/user/ssh-agent@.service%%'': - Create directory structure: sudo mkdir -p /etc/systemd/user/ - Create the service file: cat << EOF | sudo tee /etc/systemd/user/ssh-agent@.service [Unit] Description=SSH authentication agent for %I Before=default.target [Service] Type=simple Environment=SSH_AUTH_SOCK=%t/%i-agent.socket ExecStart=/usr/bin/ssh-agent -D -a %t/%i-agent.socket SuccessExitStatus=2 [Install] WantedBy=default.target # vim: ft=dosini ts=2 sts=2 sw=2 sr et EOF * To enable agent creation for **only you**, create ''%%~/.config/systemd/user/ssh-agent@.service%%'': - Create directory structure: mkdir -p ~/.config/systemd/user/ - Create the service file: cat << EOF > ~/.config/systemd/user/ssh-agent@.service [Unit] Description=SSH authentication agent for %I Before=default.target [Service] Type=simple Environment=SSH_AUTH_SOCK=%t/%i-agent.socket ExecStart=/usr/bin/ssh-agent -D -a %t/%i-agent.socket SuccessExitStatus=2 [Install] WantedBy=default.target # vim: ft=dosini ts=2 sts=2 sw=2 sr et EOF * Enabling creation for all users **does NOT** mean that all users can access //your// agent, it just means that they can create //their own// agents! ---- =====Administration===== ====Manage the ssh-agent service==== * Start and enable the agent as your regular user (and similar for the other agent(s)): systemctl --user enable --now ssh-agent@.service * Check status of the ssh-agent service: systemctl --user status ssh-agent@.service * Stop the ssh-agent service: systemctl --user stop ssh-agent@.service ===Naming the ssh-agent services=== * Whatever name you use for each service will be included in the name of the agent's socket. * For example, if we named one ''%%foo%%'' and another ''%%bar%%'': systemctl --user enable --now ssh-agent@foo.service systemctl --user enable --now ssh-agent@bar.service * We would have two new socket files: "$XDG_RUNTIME_DIR/foo-agent.socket" "$XDG_RUNTIME_DIR/bar-agent.socket" ---- =====Set a default ssh-agent===== * Create an environment variable in your preferred startup file (eg ''%%~/.profile%%'', ''%%~/.bash_profile%%'', etc): socketpath="$XDG_RUNTIME_DIR/-agent.socket" if [ -S "$socketpath" ]; then export SSH_AUTH_SOCK="$socketpath" fi ---- =====Configure SSH to use the agent===== * Use the **IdentityAgent** directive and add the SSH agent socket in your ''%%~/.ssh/config%%'': Host myhost ... AddKeysToAgent yes IdentityAgent "/run/user/%i/-agent.socket" IdentitiesOnly yes * **ForwardAgent** can be configured to forward the agent in ''%%~/.ssh/config%%'': Host myhost ... AddKeysToAgent yes ForwardAgent "/run/user/%i/-agent.socket" IdentityAgent "/run/user/%i/-agent.socket" IdentitiesOnly yes * Leaving those unconfigured, the hosts will use whatever ''%%$SSH_AUTH_SOCK%%'' is set to by default. ---- ====Manage the keys in the ssh-agent==== * For the default ssh-agent, running only the commands will work: * Add keys to the agent: ssh-add ~/.ssh/ed_25519 * List keys in the ssh-agent: ssh-add -L * Clear keys from the agent: ssh-add -D * Prepend the command with the environment variable to access other ssh-agents: * Add keys to the agent: SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/-agent.socket" ssh-add ~/.ssh/work * List keys in the ssh-agent: SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/-agent.socket" ssh-add -L * Clear keys from the agent: SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/-agent.socket" ssh-add -D Configuring **IdentityAgent** and **AddKeysToAgent** in ''%%~/.ssh/config%%'' will automatically add the key to the correct agent when you use it. ---- =====Gotchas===== * Debian auto-starts a ssh-agent at login. * Comment or remove the line in ''%%/etc/X11/Xsession.options%%'' to stop it from starting: sudo sed -i 's/^use-ssh-agent$/# use-ssh-agent/g' /etc/X11/Xsession.options * ''%%ssh-add -L%%'' will only list keys in ''%%$SSH_AUTH_SOCK%%''. * Specify the ssh-agent by passing the variable: SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/-agent.socket" ssh-add -L * If using ssh-askpass, add the following to the service file: # DISPLAY required for ssh-askpass to work Environment=DISPLAY=:0 * ssh-agent exits with code 2 which results in 'failed' state on stop and I found 2 options to remedy this: * Inform systemd that a successful exit status is ''2'': SuccessExitStatus=2 * Prefix the ExecStart with a ''%%-%%'' to suppress this behavior: ExecStart=-/usr/bin/ssh-agent -D -a %t/%i-agent.socket * //Currently untested//: Enable linger for users who need the agents to be active while not logged in: loginctl enable-linger * https://manpages.debian.org/bullseye/systemd/loginctl.1.en.html#User_Commands ---- =====Example===== After following the steps above, as an example I'll create a "default" agent for my everyday ssh keys and a "work" agent for my work ssh keys. ===Create "Default" SSH Agent=== * Start and enable the "default" ssh-agent: systemctl --user enable --now ssh-agent@ssh.service * Check status: systemctl --user status ssh-agent@ssh.service * Configure environment for the "default" agent: cat << EOF >> ~/.profile socketpath="$XDG_RUNTIME_DIR/ssh-agent.socket" if [ -S "$socketpath" ]; then export SSH_AUTH_SOCK="$socketpath" fi EOF * Source the file to load the variable: source ~/.profile * Add keys to "Default" agent: ssh-add ~/.ssh/key * List keys in "Default" agent: ssh-add -L ===Create "Work" Agent=== * Start and enable a "work" agent: systemctl --user enable --now ssh-agent@work.service * Check the status: systemctl --user status ssh-agent@work.service * Add entries for work machines: Host work-workmachine-1 HostName XX.XX.XX.XX ForwardAgent "/run/user/%i/work-agent.socket" ProxyJump work-jump * Add wildcard entry for work machines at **bottom** of ''%%~/.ssh/config%%'': Host work-* User username IdentityFile "%d/.ssh/work" IdentityAgent "/run/user/%i/work-agent.socket" * Add keys to "Work" agent: SSH_AUTH_SOCK="XDG_RUNTIME_DIR/work-agent.socket" ssh-add ~/.ssh/work * List keys in "Work" agent: SSH_AUTH_SOCK="XDG_RUNTIME_DIR/work-agent.socket" ssh-add -L Configuring **IdentityAgent** and **AddKeysToAgent** in ''%%~/.ssh/config%%'' will add the key to the correct agent when you first use it. ---- =====Bonus Tip===== * You can create a ''%%ssh%%'' directory in your ''%%$XDG_RUNTIME_DIR%%'' to contain the agent socket files. * This is a good opportunity to make use of systemd's ''%%tmpfiles.d%%'' to create the directory at boot. * Create directory to hold the config files: mkdir -p ~/.local/share/user-tmpfiles.d * Create a configuration file: cat << EOF > ~/.local/share/user-tmpfiles.d/ssh-config.conf d %t/ssh 0700 - - - EOF * Create the directory: systemd-tmpfiles --user --create * Enable the tmpfiles service so it creates the directory at boot: systemctl --user enable --now systemd-tmpfiles-setup.service * Enable the cleanup timer: systemctl --user enable --now systemd-tmpfiles-clean.timer * Edit the paths in the files above to add the ''%%ssh%%'' dir. For example: Environment=SSH_AUTH_SOCK=%t/ssh/ssh-agent.socket For multi-user systems, make sure to add/configure files in ''%%/etc/skel%%'' so the agent dependencies are set up during user creation. ---- =====Conclusion===== That's the general idea and should get your system set up with as many ssh-agents as you would ever want to create. Enjoy! ---- =====Links===== * https://manpages.debian.org/stable/openssh-client/ssh-agent.1.en.html * https://manpages.debian.org/stable/systemd/systemd.service.5.en.html#SERVICE_TEMPLATES * https://manpages.debian.org/stable/systemd/systemd.unit.5.en.html#SPECIFIERS * https://manpages.debian.org/stable/openssh-client/ssh-agent.1.en.html * https://manpages.debian.org/stable/openssh-client/ssh_config.5.en.html * https://manpages.debian.org/stable/openssh-client/ssh-add.1.en.html * https://manpages.debian.org/stable/systemd/tmpfiles.d.5.en.html * https://manpages.debian.org/stable/systemd/systemd-tmpfiles.8.en.html * https://wikitech.wikimedia.org/wiki/Managing_multiple_SSH_agents * https://unix.stackexchange.com/a/623559