gpg-agent and systemd

Hello folks,

I am trying to setup mbsync (for keeping a local copy of mails) on Leap 42.3. I have configured mbsync to use gpg to decrypt the passwords associated with my email accounts. I also have configured gpg with gpg-agent. When opening a Plasma session, I am prompted for my passphrase to unlock my gpg key. After that, I can

 mbsync -Va

in a terminal without entering my passphrase again.

However, I also want mbsync to be launched every 3 minutes in the background, and I followed the Arch wiki to create a set of systemd files (https://wiki.archlinux.org/index.php/Mbsync).

I have a service and a timer file, with

  • in /etc/systemd/system/mbsync@.service
[Unit]
Description=Mailbox synchronization service for user %I

[Service]
Type=oneshot
ExecStart=/usr/bin/mbsync -Va
ExecStartPost=/usr/bin/notmuch new
User=%i
StandardOutput=syslog
StandardError=syslog
  • and in /etc/systemd/system/mbsync@.timer
[Unit]
Description=Mailbox synchronization timer

[Timer]
OnBootSec=300
OnUnitActiveSec=180
Persistent=false
Unit=mbsync@%i.service

[Install]
WantedBy=timers.target

This does not work, and I have these entries in journalctl:

gpg-agent[6237]: command get_passphrase failed: End of file
gpg: problem with the agent: End of file
gpg: decryption failed: No secret key

I suppose this is a permission problem, and that the services are run by “someone” else than me, am I right ? How can I fix this ?

Thanks a lot for your help !

bests,

This is all new to me, but when you unlock something when you login in a Plasma session, that has of course nothing to do with something that runs in the background. You can understand that already when you understand that the background job will run regardless if somebody is loged in in the system (CLI, or Gnome, or KDE, or whatever) or not

The unlocking is IMHO for that particular session. not for everybody that happens to be on the system in whatever form on the same time.

I ran this:


% printenv | grep GPG
GPG_AGENT_INFO=/tmp/gpg-jKYjVd/S.gpg-agent:5439:1

If you were to run the same command, and then set GPG_AGENT_INFO in the environment of your script, that would probably work for a while. But it would stop working when you logout, because gpg-agent would be stopped on your logout.

Arch uses a newer “gpg”, where gpg-agent is started when first required. So maybe that still works. OpenSUSE Tumbleweed also uses that newer “gpg”.

I’m not clear on what you are doing, so I don’t know if my hints are helpful. Best is for background mail processes to not need access to your gpg key, and then the problem doesn’t arise.

Hello guys,

After some reading, I finally found a solution to the problem, using user systemd unit files. For reference, if someone is interested, here is how it is done.

Exactly, but that is the intended behaviour, as I do not want to fetch mails when I’m not logged in. However, I should be able to do that when logged in, without being prompted for a passphrase, and for that, I need to tell gpg-agent to write GPG_AGENT_INFO somewhere.

My setup is the following, with the systemd related files being placed in ~/.config/systemd/user/

  • First, I start gpg-agent with gpg-agent.service (ssh support for other purposes), with the --write-env-file option:

[Unit]
Description=gpg-agent Daemon with SSH Support

[Service]
Type=forking
ExecStart=/usr/bin/gpg-agent --quiet --daemon --enable-ssh-support --write-env-file "${HOME}/.gnupg/gpg-agent-info"
Restart=on-success

[Install]
WantedBy=default.target

  • Then, mbsync.service is used to fetch mails, with a custom fetch_mail.sh script (see below):

[Unit]
Description=Mailbox synchronization service for user

[Service]
Type=oneshot
ExecStart=${HOME}/bin/fetch_mail.sh
StandardOutput=syslog
StandardError=syslog

The important point is that fetch_mail.sh will read the file gpg-agent created with the following code:


if  -f "${HOME}/.gnupg/gpg-agent-info" ]; then
    . "${HOME}/.gnupg/gpg-agent-info"
    export GPG_AGENT_INFO
fi

  • And the timer file mbsync.timer is used to activate mbsync.service every 3 minutes:

[Unit]
Description=Mailbox synchronization timer

[Timer]
OnBootSec=300
OnUnitActiveSec=180
Persistent=false
Unit=mbsync.service

[Install]
WantedBy=default.target

  • Everything is activated with the following commands:

systemctl --user daemon-reload
systemctl --user enable mbsync.timer
systemctl --user enable gpg-agent.service
systemctl --user start gpg-agent.service
systemctl --user start mbsync.timer

Now, everything works as intended :slight_smile:

Thanks !

Nice example of systemd usage on the user level.

Thanks so much for posting this.

Good to hear you got a solution working, but…

  1. Is there some reason why you didn’t put your custom systemd Unit files in the standard location instead of in your home directory
/etc/systemd/user/
  1. Ordinarily, it’s not necessary to execute the systemd commands in your last step specifying a User, without specifiying a User those commands should execute “daemon reload” against all Unit files and the others simply modify and start the specific Unit files.

TSU

This is just to separate what belongs only to the user to system-wide files. Besides, this setup does not require root access.

I think using daemon-reload without the --user flag works as well, but I’m not sure if with the files put in ~/.config/systemd/user/ not specifying --user will work. However, I have an empirical and very experimental knowledge on systemd, so I may be mistaking there :slight_smile:

You’re welcome :slight_smile: Besides, as I have an habit of changing / reinstalling my system and losing some tweaks, at least now I know this is somewhere on the Web !

bests,

Because he wants to organize this as a normal user for the normal user. Thus he has no access to changing things in /etc.

This is IMHO an example how an “end-user” can make use of the features of systemd.

Reading

man systemd

–system, --user
For --system, tell systemd to run a system instance, even if the process ID is not 1, i.e. systemd is not run as init process. --user does the opposite, running a user instance even if the process ID is 1. Normally it should not be necessary to pass these options, as systemd automatically detects the mode it is started in. These options are hence of little use except for debugging. Note that it is not supported booting and maintaining a full system with systemd running in --system mode, but PID not 1. In practice, passing --system explicitly is only useful in conjunction with --test.

which means, as you say, that sytemd will detect it is executed by a user.

You should be commended for successfully implementing two custom services for your solution.

Note that the locations for custom systemd system and user Unit files are in different locations.

system

/etc/systemd/system/

User

/etc/systemd/user/

When a system boots up, these two locations are scanned first, and if any Unit file has the same name as in the default location, then these found in subdirectories of /etc/systemd/ will over-ride. Of course, if your Unit file has a unique name, then there is nothing to over-ride.

TSU

A FYI for anyone interested in diving deeper into systemd/User,

https://wiki.archlinux.org/index.php/Systemd/User

Includes a full description why systemd Unit files might be deployed in different places.

TSU

I think the advantage of my setup is that it is completely portable on systems where the user does not have root access.

Thanks for the link, I’ll dive into it as soon as I can. I didn’t know much about systemd before, but the ability to fully use its capacities on a user level is very interesting !

As a side thought: systemd could completely replace cron jobs, right ?

Use Google with: cron systemd