Customize GuixSD: Use Stock SSH Agent Everywhere!
I frequently use SSH. Since I don't like typing my password all the
time, I use an SSH agent. Originally I used the GNOME Keyring as my
SSH agent, but recently I've switched to using the
OpenSSH. I accomplished this by doing the following two things:
Replace the default GNOME Keyring with a custom-built version that disables the SSH agent feature.
Start my desktop session with OpenSSH's
ssh-agentso that it's always available to any applications in my desktop session.
Below, I'll show you in detail how I did this. In addition to being
useful for anyone who wants to use OpenSSH's
ssh-agent in GuixSD, I
hope this example will help to illustrate how GuixSD enables you to
customize your entire system to be just the way you want it!
The Problem: GNOME Keyring Can't Handle My SSH Keys
On GuixSD, I like to use the GNOME desktop environment. GNOME is just one of the various desktop environments that GuixSD supports. By default, the GNOME desktop environment on GuixSD comes with a lot of goodies, including the GNOME Keyring, which is GNOME's integrated solution for securely storing secrets, passwords, keys, and certificates.
The GNOME Keyring has many useful features. One of those is its SSH
This feature allows you to use the GNOME Keyring as an SSH agent.
This means that when you invoke a command like
ssh-add, it will add
the private key identities to the GNOME Keyring. Usually this is
quite convenient, since it means that GNOME users basically get an SSH
agent for free!
Unfortunately, up until GNOME 3.28 (the current
the GNOME Keyring's SSH agent implementation was not as complete as
the stock SSH agent from OpenSSH. As a result, earlier versions of
GNOME Keyring did not support many use
cases. This was a
problem for me, since GNOME Keyring couldn't read my modern SSH keys.
To make matters worse, by design the SSH agent for GNOME Keyring and
OpenSSH both use the same environment variables (e.g.,
SSH_AUTH_SOCK). This makes it difficult to use OpenSSH's
ssh-agent everywhere within my GNOME desktop environment.
Happily, starting with GNOME 3.28, GNOME Keyring delegates all SSH agent functionality to the stock SSH agent from OpenSSH. They have removed their custom implementation entirely. This means that today, I could solve my problem simply by using the most recent version of GNOME Keyring. I'll probably do just that when the new release gets included in Guix. However, when I first encountered this problem, GNOME 3.28 hadn't been released yet, so the only option available to me was to customize GNOME Keyring or remove it entirely.
In any case, I'm going to show you how I solved this problem by
modifying the default GNOME Keyring from the Guix package collection.
The same ideas can be used to customize any package, so hopefully it
will be a useful example. And what if you don't use GNOME, but you do
want to use OpenSSH's
ssh-agent? In that case, you may still need
to customize your GuixSD system a little bit. Let me show you how!
~/.xsession and a Custom GNOME Keyring
The goal is to make OpenSSH's
ssh-agent available everywhere when we
log into our GNOME desktop session. First, we must arrange for
ssh-agent to be running whenever we're logged in.
There are many ways to accomplish this. For example, I've seen people
implement shell code in their shell's start-up files which basically
manages their own
ssh-agent process. However, I prefer to just
ssh-agent once and not clutter up my shell's start-up files
with unnecessary code. So that's what we're going to do!
ssh-agent in Your
By default, GuixSD uses the SLiM desktop manager. When you log in, SLiM presents you with a menu of so-called "desktop sessions", which correspond to the desktop environments you've declared in your operating system declaration. For example, if you've added the gnome-desktop-service to your operating system declaration, then you'll see an option for GNOME at the SLiM login screen.
You can further customize your desktop session with the
file. The contract for this file in GuixSD is the same as it is for
many GNU/Linux distributions: if it exists, then it will be
The arguments passed to it will be the command line invocation that
would normally be executed to start the desktop session that you
selected from the SLiM login screen. Your
~/.xsession is expected
to do whatever is necessary to customize and then start the specified
desktop environment. For example, when you select GNOME from the SLiM
login screen, your
~/.xsession file will basically be executed like
this (for the exact execution mechanism, please refer to the source
code linked above):
$ ~/.xsession gnome-session
The upshot of all this is that the
~/.xsession is an ideal place
to set up your SSH agent! If you start an SSH agent in your
~/.xsession file, you can have the SSH agent available everywhere,
automatically! Check it out: Put this into your
and make the file executable:
#!/run/current-system/profile/bin/bash exec ssh-agent "$@"
When you invoke
ssh-agent in this way, it executes the specified
program in an environment where commands like
ssh-add just work. It
does this by setting environment variables such as
which programs like
ssh-add find and use automatically. Because
GuixSD allows you to customize your desktop session like this, you can
use any SSH agent you want in any desktop environments that you want,
Of course, if you're using GNOME Keyring version 3.27 or earlier (like
I was), then this isn't quite enough. In that case, the SSH agent
feature of GNOME Keyring will override the environment variables set
ssh-agent, so commands like
ssh-add will wind up
communicating with the GNOME Keyring instead of the
launched in your
~/.xsession. This is bad because, as previously
mentioned, GNOME Keyring version 3.27 or earlier doesn't support as
many uses cases as OpenSSH's
How can we work around this problem?
Customize the GNOME Keyring
One heavy-handed solution would be to remove GNOME Keyring entirely. That would work, but then you would lose out on all the other great features that it has to offer. Surely we can do better!
The GNOME Keyring documentation
explains that one
way to disable the SSH agent feature is to include the
--disable-ssh-agent configure flag when building it. Thankfully,
Guix provides some ways to customize software in exactly this way!
Conceptually, we "just" have to do the following two things:
Customize the existing
gnome-desktop-serviceuse our custom
Create a Custom GNOME Keyring Package
Let's begin by defining a custom
gnome-keyring package, which we'll
gnome-keyring-sans-ssh-agent. With Guix, we can do this in
less than ten lines of code:
(define-public gnome-keyring-sans-ssh-agent (package (inherit gnome-keyring) (name "gnome-keyring-sans-ssh-agent") (arguments (substitute-keyword-arguments (package-arguments gnome-keyring) ((#:configure-flags flags) `(cons "--disable-ssh-agent" ,flags))))))
Don't worry if some of that code is unclear at first. I'll clarify it now!
In Guix, a
<package> record like the one above is defined by a macro
define-record-type* (defined in the file guix/records.scm in
It's similar to an SRFI-9
inherit feature of this macro is very useful: it creates a new
copy of an existing record, overriding specific fields in the new copy
In the above, we define
gnome-keyring-sans-ssh-agent to be a copy of
gnome-keyring package, and we use
inherit to change the
arguments fields in that new copy. We also use the
substitute-keyword-arguments macro (defined in the file
guix/utils.scm in the Guix
--disable-ssh-agent to the list of configure
defined in the
gnome-keyring package. The effect of this is to
define a new GNOME Keyring package that is built exactly the same as
the original, but in which the SSH agent is disabled.
I'll admit this code may seem a little opaque at first, but all code
does when you first learn it. Once you get the hang of things, you
can customize packages any way you can imagine. If you want to learn
more, you should read the docstrings for the
substitute-keyword-arguments macros in the Guix source code. It's
also very helpful to
grep the source code to see examples of how
these macros are used in practice. For example:
$ # Search the currently installed Guix for the current user. $ grep -r substitute-keyword-arguments ~/.config/guix/latest $ # Search the Guix Git repository, assuming you've checked it out here. $ grep -r substitute-keyword-arguments ~/guix
Use the Custom GNOME Keyring Package
OK, we've created our own custom GNOME Keyring package. Great! Now, how do we use it?
In GuixSD, the GNOME desktop environment is treated as a system
make GNOME use our custom GNOME Keyring package, we must somehow
gnome-desktop-service (defined in the file
to use our custom package. How do we do customize a service?
Generally, the answer depends on the service. Thankfully, many of
GuixSD's services, including the
gnome-desktop-service, follow a
similar pattern. In this case, we "just" need to pass a custom
<gnome-desktop-configuration> record to the
procedure in our operating system declaration, like this:
(operating-system ... (services (cons* (gnome-desktop-service #:config my-gnome-desktop-configuration) %desktop-services)))
cons* procedure just adds the GNOME desktop service to the
%desktop-services list, returning the new list. For details, please
refer to the the Guile
Now the question is: what should
Well, if we examine the definition of this record type in the Guix
we see the following:
(define-record-type* <gnome-desktop-configuration> gnome-desktop-configuration make-gnome-desktop-configuration gnome-desktop-configuration (gnome-package gnome-package (default gnome)))
gnome package referenced here is a "meta" package: it exists
only to aggregate many GNOME packages together, including
gnome-keyring. To see its
we can simply invoke
guix edit gnome, which opens the file where
the package is
(define-public gnome (package (name "gnome") (version (package-version gnome-shell)) (source #f) (build-system trivial-build-system) (arguments '(#:builder (mkdir %output))) (propagated-inputs ;; TODO: Add more packages according to: ;; <https://packages.debian.org/jessie/gnome-core>. `(("adwaita-icon-theme" ,adwaita-icon-theme) ("baobab" ,baobab) ("font-cantarell" ,font-cantarell) [... many packages omitted for brevity ...] ("gnome-keyring" ,gnome-keyring) [... many packages omitted for brevity ...] (synopsis "The GNU desktop environment") (home-page "https://www.gnome.org/") (description "GNOME is the graphical desktop for GNU. It includes a wide variety of applications for browsing the web, editing text and images, creating documents and diagrams, playing media, scanning, and much more.") (license license:gpl2+)))
Apart from being a little long, this is just a normal package
We can see that
gnome-keyring is included in the list of
propagated-inputs. So, we need to create a replacement for the
gnome package that uses our
gnome-keyring. The following package definition accomplishes
(define-public gnome-sans-ssh-agent (package (inherit gnome) (name "gnome-sans-ssh-agent") (propagated-inputs (map (match-lambda ((name package) (if (equal? name "gnome-keyring") (list name gnome-keyring-sans-ssh-agent) (list name package)))) (package-propagated-inputs gnome)))))
As before, we use
inherit to create a new copy of the
package that overrides the original
fields. Since Guix packages are just defined using good old scheme,
we can use existing language features like
to manipulate the list of propagated inputs. The effect of the above
is to create a new package that is the same as the
gnome package but
gnome-keyring-sans-ssh-agent instead of
Now that we have
gnome-sans-ssh-agent, we can create a custom
<gnome-desktop-configuration> record and pass it to the
gnome-desktop-service procedure as follows:
(operating-system ... (services (cons* (gnome-desktop-service #:config (gnome-desktop-configuration (gnome-package gnome-sans-ssh-agent))) %desktop-services)))
Wrapping It All Up
Finally, you need to run the following commands as
root to create
and boot into the new system
MY-CONFIG with the path to the customized operating system
# guix system reconfigure MY-CONFIG # reboot
After you log into GNOME, any time you need to use SSH, the stock SSH
agent from OpenSSH that you started in your
~/.xsession file will be
used instead of the GNOME Keyring's SSH agent. It just works! Note
that it still works even if you select a non-GNOME desktop session
(like XFCE) at the SLiM login screen, since the
~/.xsession is not
tied to any particular desktop session,
In the unfortunate event that something went wrong and things just aren't working when you reboot, don't worry: with GuixSD, you can safely roll back to the previous system generation via the usual mechanisms. For example, you can run this from the command line to roll back:
# guix system roll-back # reboot
This is one of the great benefits that comes from the fact that Guix
follows the functional software deployment
However, note that because the
~/.xsession file (like many files in
your home directory) is not managed by Guix, you must manually undo
the changes that you made to it in order to roll back fully.
I hope this helps give you some ideas for how you can customize your
own GuixSD system to make it exactly what you want it to be. Not only
can you customize your desktop session via your
but Guix also provides tools for you to modify any of the default
packages or services to suit your specific needs.
To the extent possible under law, Chris Marusich has waived all copyright and related or neighboring rights to this article, "Customize GuixSD: Use Stock SSH Agent Everywhere!". This work is published from: United States.
The views expressed in this article are those of Chris Marusich and do not necessarily reflect the views of his past, present, or future employers.
About GNU Guix
GNU Guix is a transactional package manager for the GNU system. The Guix System Distribution or GuixSD is an advanced distribution of the GNU system that relies on GNU Guix and respects the user's freedom.
In addition to standard package management features, Guix supports transactional upgrades and roll-backs, unprivileged package management, per-user profiles, and garbage collection. Guix uses low-level mechanisms from the Nix package manager, except that packages are defined as native Guile modules, using extensions to the Scheme language. GuixSD offers a declarative approach to operating system configuration management, and is highly customizable and hackable.
GuixSD can be used on an i686, x86_64 and armv7 machines. It is also possible to use Guix on top of an already installed GNU/Linux system, including on mips64el and aarch64.