[arch-general] gpg-agent, ssh keys, and systemd --user
How can I get gpg-agent to work with ssh keys? The following script that I’ve put in /etc/profile.d sets it up, but I’d like to move my user daemons (such as gpg-agent) over to systemd --user. $ cat gpg-agent.sh #!/bin/sh envfile="${HOME}/.gnupg/gpg-agent.env" if test -f "$envfile" && kill -0 $(grep GPG_AGENT_INFO "$envfile" | cut -d: -f 2) 2>/dev/null; then eval "$(cat "$envfile")" else eval "$(gpg-agent --daemon --enable-ssh-support --write-env-file "$envfile")" fi export GPG_AGENT_INFO I’ve written the following user service, and it should do the same thing, but it doesn’t seem to work: $ cat ~/.config/systemd/user/gpg-agent.service [Unit] Description=GnuPG private key agent Wants=environment.target Before=environment.target IgnoreOnIsolate=true [Service] Type=forking Environment=GPG_ENVFILE=%t/gpg-agent.info ExecStart=/usr/bin/gpg-agent --daemon --enable-ssh-support --use-standard-socket --write-env-file ${GPG_ENVFILE} ExecStartPost=/bin/sh -c "xargs systemctl --user set-environment < ${GPG_ENVFILE}" ExecStopPost=/bim/rm %t/gpg-agent.info Restart=on-abort [Install] WantedBy=default.target Both the script and the service file start gpg, create an environment file, and export the variables. But for some reason, gpg-agent doesn’t store keys or anything if run as a service. I don’t know why. Can anyone help?
systemd --user runs in its own separate login/cgroup. I doubt environmental variables set with `systemctl --user set-environment` going to be available outside of that login/cgroup. I doubt they're even made available to anything outside of future processes spawned by systemctl. So it'll all depend on how you're using user sessions. Anyhow... Not quite the same thing and a bit of shameless self promotion, but you could try envoy <https://github.com/vodik/envoy> Create the following user sessions in ~/.config/systemd/user envoy.socket: [Socket] ListenStream=@/vodik/envoy [Install] WantedBy=sockets.target and envoy.service: [Unit] Description=Envoy agent monitor [Service] ExecStart=/usr/bin/envoyd -t gpg-agent StandardOutput=syslog StandardError=syslog [Install] WantedBy=vodik.target Also=envoy.socket Enable the socket and then all you need to put is `source <(envoy -p)` in your shell rc/profile. More details are available on github page. Sorry about the poor state of the documentation if its confusing. Its the last thing i need to work on now. On Wed, Apr 10, 2013 at 9:21 AM, Robbie Smith <zoqaeski@gmail.com> wrote:
How can I get gpg-agent to work with ssh keys? The following script that I’ve put in /etc/profile.d sets it up, but I’d like to move my user daemons (such as gpg-agent) over to systemd --user.
$ cat gpg-agent.sh #!/bin/sh
envfile="${HOME}/.gnupg/gpg-agent.env" if test -f "$envfile" && kill -0 $(grep GPG_AGENT_INFO "$envfile" | cut -d: -f 2) 2>/dev/null; then eval "$(cat "$envfile")" else eval "$(gpg-agent --daemon --enable-ssh-support --write-env-file "$envfile")" fi export GPG_AGENT_INFO
I’ve written the following user service, and it should do the same thing, but it doesn’t seem to work:
$ cat ~/.config/systemd/user/gpg-agent.service [Unit] Description=GnuPG private key agent Wants=environment.target Before=environment.target IgnoreOnIsolate=true
[Service] Type=forking Environment=GPG_ENVFILE=%t/gpg-agent.info ExecStart=/usr/bin/gpg-agent --daemon --enable-ssh-support --use-standard-socket --write-env-file ${GPG_ENVFILE} ExecStartPost=/bin/sh -c "xargs systemctl --user set-environment < ${GPG_ENVFILE}" ExecStopPost=/bim/rm %t/gpg-agent.info Restart=on-abort
[Install] WantedBy=default.target
Both the script and the service file start gpg, create an environment file, and export the variables. But for some reason, gpg-agent doesn’t store keys or anything if run as a service. I don’t know why.
Can anyone help?
On 11/04/13 15:11, Simon Gomizelj wrote:
systemd --user runs in its own separate login/cgroup. I doubt environmental variables set with `systemctl --user set-environment` going to be available outside of that login/cgroup. I doubt they're even made available to anything outside of future processes spawned by systemctl.
So it'll all depend on how you're using user sessions. Anyhow...
This might be it. But what’s confused me is that the variables are written to that info file, and I should be able to export them manually by adding something like this to my ~/.zshrc: if (( $+commands[gpg-agent] )); then local InfoFile=/run/user/$(id -u)/gpg-agent.info if [[ -s $InfoFile ]]; then eval "$(cat $InfoFile)" fi unset InfoFile fi Strangely enough, this doesn’t seem to work. What’s the difference between exporting variables in /etc/profile.d/ and ~/.zshrc?
On 2013-04-11 at 22:50 +1000, Robbie Smith wrote:
if (( $+commands[gpg-agent] )); then local InfoFile=/run/user/$(id -u)/gpg-agent.info if [[ -s $InfoFile ]]; then eval "$(cat $InfoFile)" fi unset InfoFile fi
Strangely enough, this doesn’t seem to work. What’s the difference between exporting variables in /etc/profile.d/ and ~/.zshrc?
First, `/etc/profile` and therefore `/etc/profile.d` is sourced by login shells and `~/.zshrc` sourced by interactive Z shells, Thus an interactive login Z shell reads both. See the "STARTUP/SHUTDOWN FILES" section in man:zsh(1). Second, you aren't "exporting" anything. The gpg-agent env-file is an environment file consisting of one variable assignment per line. When you source the file the shell sets these variables just as shell variables. They are only available to the current shell process. To make them available to child process as environment variables you have to export them. The simplest way to do all this probably would be: export $(< "$InfoFile") And third, a couple of other remarks.
if (( $+commands[gpg-agent] )); then local InfoFile=/run/user/$(id -u)/gpg-agent.info
The runtime directory is available in the environment variable XDG_RUNTIME_DIR. You can just use local InfoFile=$XDG_RUNTIME_DIR/gpg-agent.info Or if you don't want to rely on that: local InfoFile=${XDG_RUNTIME_DIR:-/run/user/${UID:-$(id -u)}}/gpg-agent.info
if [[ -s $InfoFile ]]; then eval "$(cat $InfoFile)" fi unset InfoFile fi
Don't read a file with cat and the evaluate the output. Just let the shell source the file directly: source "$InfoFile" HTH, Sebastian
Robbie Smith wrote in message <5165674E.4080001@gmail.com>:
I’ve written the following user service, and it should do the same thing, but it doesn’t seem to work:
$ cat ~/.config/systemd/user/gpg-agent.service [Unit] Description=GnuPG private key agent Wants=environment.target Before=environment.target IgnoreOnIsolate=true
So your question has been answered, but in case anyone is interested I run a setup pretty similar to yours, except that I also launch a user service for ssh-agent (because gpg-agent does not yet know how to handle ECDSA ssh keys :-() $ cat gpg-agent.service [Unit] Description=gpg-agent ConditionFileIsExecutable=/usr/bin/gpg-agent [Service] ExecStart=/usr/bin/gpg-agent --daemon --use-standard-socket Type=forking Restart=always [Install] WantedBy=basic.target $ cat ssh-agent.service [Unit] Description=ssh-agent ConditionFileIsExecutable=/usr/bin/ssh-agent [Service] ExecStart=/usr/bin/ssh-agent -d -a %t/ssh_auth_sock Restart=always [Install] WantedBy=basic.target So after ssh-agent is launched, it is just a matter of exporting the right environment variable: [ -z "$SSH_AUTH_SOCK" ] && export SSH_AUTH_SOCK="${XDG_RUNTIME_DIR:-/run/user/${UID:-$(id -u)}}/ssh_auth_sock" As for gpg-agent, you can't tell him where to put his socket, but at least using "--use-standard-socket" he will use a socket in a standard place. You then just need to tell gpg to look for an agent listening to this socket: $ cat ~/.gnupg/gpg.conf [...] use-agent $ cat ~/.gnupg/gpg-agent.conf use-standard-socket
On 15/04/13 19:00, Damien Robert wrote:
Robbie Smith wrote in message <5165674E.4080001@gmail.com>:
I’ve written the following user service, and it should do the same thing, but it doesn’t seem to work:
$ cat ~/.config/systemd/user/gpg-agent.service [Unit] Description=GnuPG private key agent Wants=environment.target Before=environment.target IgnoreOnIsolate=true
So your question has been answered, but in case anyone is interested I run a setup pretty similar to yours, except that I also launch a user service for ssh-agent (because gpg-agent does not yet know how to handle ECDSA ssh keys :-()
$ cat gpg-agent.service [Unit] Description=gpg-agent ConditionFileIsExecutable=/usr/bin/gpg-agent
[Service] ExecStart=/usr/bin/gpg-agent --daemon --use-standard-socket Type=forking Restart=always
[Install] WantedBy=basic.target
$ cat ssh-agent.service [Unit] Description=ssh-agent ConditionFileIsExecutable=/usr/bin/ssh-agent
[Service] ExecStart=/usr/bin/ssh-agent -d -a %t/ssh_auth_sock Restart=always
[Install] WantedBy=basic.target
So after ssh-agent is launched, it is just a matter of exporting the right environment variable: [ -z "$SSH_AUTH_SOCK" ] && export SSH_AUTH_SOCK="${XDG_RUNTIME_DIR:-/run/user/${UID:-$(id -u)}}/ssh_auth_sock"
As for gpg-agent, you can't tell him where to put his socket, but at least using "--use-standard-socket" he will use a socket in a standard place. You then just need to tell gpg to look for an agent listening to this socket:
$ cat ~/.gnupg/gpg.conf [...] use-agent $ cat ~/.gnupg/gpg-agent.conf use-standard-socket
The issue I’m getting is that these unit files (or my variants thereof) do not work for me. The agents are starting, and the environment variables exist, but none of my programs (ssh-add, git, etc) can access them, so I continuously get asked the passphrase for the private keys.
participants (4)
-
Damien Robert
-
Robbie Smith
-
Sebastian Schwarz
-
Simon Gomizelj