Directing an SSH agent socket (UNIX domain socket) into a podman container, is as easy as 1-2-mount, so I erroneously assumed that doing similarly for GPG would be as easy. It wasn’t, at least for me.
I rose at 06:00 and yelled Eureka! at 15:05 local time. It took me so long because I tried to follow GNU documentation which speaks of using extra-socket
. To cut a far too long story short, on the Debian host I’m doing this none of that business worked: the gpg-agent
was just not creating the UNIX domain socket where I configured it to.
What I then did was to completely deactivate system’d socket activation for GPG: stop and disable the service and the socket activations. The main reason: changes in the unit file for the service, e.g. --extra-socket
, weren’t being applied.
Then I launched the daemon manually and began looking at some logs. (No, I’m not a guru, but I hoped I’d see lots of things; omg did I.)
$ gpg-agent --daemon --debug-level guru > /tmp/glog 2>&1
Slowly but surely, after downloading the source to GPG and looking at what the agent does, it dawns on me that something magic is happening, and I blame either the distro and/or systemd. Be that as it may, the debian files in /usr/share/doc don’t mention anything about deactivating the extra socket, so shrug.
What I can’t get to work at all are the settings in ~/.gnupg/gpg-agent.conf
, so I ignore that.
Anyway, I’m a bit further, but not really much, but it’s clear that it’s not gpg-agent’s fault.
Enough rambling, as I can’t remember all I’ve done, let me jot down how I solved the puzzle:
I reactivated all the systemd stuff, and everything’s back to normal. gpg-agent is creating the files in /run/user/1003/gnupg/
and when I try to kick the agent by decrypting a file on the host, the following files are created
$ gpgconf --kill gpg-agent
$ rm -r /run/user/1003/gnupg/
$ gpg --batch --use-agent --decrypt project/vault_passphrase.gpg
$ ls -l /run/user/1003/gnupg/
total 0
srwx------ 1 jpm staff 0 Apr 16 12:58 S.gpg-agent
srwx------ 1 jpm staff 0 Apr 16 12:58 S.gpg-agent.browser
srwx------ 1 jpm staff 0 Apr 16 12:58 S.gpg-agent.extra
srwx------ 1 jpm staff 0 Apr 16 12:58 S.gpg-agent.ssh
So be it. That’s where the sockets are. :shrug: (Note, I’m displeased, but :shrug:)
Now back to podman. The intention is to carry a socket across, so that the container can access my agent. This is the magic incantation:
--container-volume-mount /run/user/1003/gnupg/S.gpg-agent:/root/.gnupg/S.gpg-agent:Z
When the container launches (target user is root), my agent socket (user 1003) is mounted at /root/.gnupg
in the target, and the root user there has access to it.
This actually works, and I want this to be able to provide encrypted vault secrets.
Total overkill, and half a day’s worth of smoke arising from the top of my skull, but if somebody asks “can it?”, I can answer: “yes, it can!”
The actual fun begins then, with Ansible accessing the vault, configured in an ansible.cfg
for the project:
[defaults]
vault_password_file = vault_pass.sh
The vault_pass.sh
program which is taken across in the ansible-runner project now does this (output to stderr so that it’s carried back to the host which invoked ansible-runner
):
gpg --list-keys >&2 # will create the .gnupg directory
cat > ~/.gnupg/gpg.conf <<EOF1
use-agent
EOF1
cat << EOF2 | gpg --import -
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQGNBGYc9KgBDACm0FOP70HFdSfGVL9W8X0HkasdTxYrz5RWJmM+Z3oxBZEpzAuP
4572CAdZC4MS/8B/ABlnojJBegrATySNu+fB7wHURKkz4BOEnF3oobJQoj+PYOT4
...
rzkFQg==
=xTtx
-----END PGP PUBLIC KEY BLOCK-----
EOF2
gpg --homedir /root/.gnupg --batch --use-agent --decrypt vault_passphrase.gpg
echo "Outta here" >&2
Output (stdout) from gpg
is consumed by Ansible to unlock vault secrets.
And yes, this does function:
$ ansible-runner run \
--container-volume-mount /run/user/1003/gnupg/S.gpg-agent:/root/.gnupg/S.gpg-agent:Z \
. -p v1.yml
gpg: keybox '/root/.gnupg/pubring.kbx' created
gpg: /root/.gnupg/trustdb.gpg: trustdb created
gpg: key 353C430586B83FE5: public key "JP Ansible (Runner Vault tests) <jp@example>" import
ed
gpg: WARNING: server 'gpg-agent' is older than us (2.2.40 < 2.3.3)
gpg: Note: Outdated servers may lack important security fixes.
gpg: Note: Use the command "gpgconf --kill all" to restart them.
gpg: Total number processed: 1
gpg: imported: 1
gpg: encrypted with rsa3072 key, ID 3F9FC1C9EA3FE42F, created 2024-04-15
"JP Ansible (Runner Vault tests) <jp@example>"
gpg: WARNING: server 'gpg-agent' is older than us (2.2.40 < 2.3.3)
gpg: Note: Outdated servers may lack important security fixes.
gpg: Note: Use the command "gpgconf --kill all" to restart them.
gpg: problem with fast path key listing: IPC parameter error - ignored
Outta here
PLAY [Vault test] **************************************************************
TASK [ping] ********************************************************************
ok: [w00]
TASK [Can we unvault this var?] ************************************************
ok: [w00] => {
"msg": "The cow jumped over the moon."
}
The variable was unvaulted.
One important bit: the socket activation of gpg-agent only occasionally triggers the pinentry program on the host; I’ve noticed it works smoothest if I do so myself by decrypting a file on the host. (I’m not now feeling up to how to configure TTLs on the agent-cached secrets; I hope that’s more straightforward than what I dug into today.)
Moo.
Update
In desperation I thought I’d see what happens when gpg-agent finds a file in the place it wants to create a directory. I wish I hadn’t done that, but see for yourselves. The result is what I’ve spent 3/4 of a day trying to accomplish.
Yeah, my use of man gpg-agent
at the end is sarcastic. I could have written worse: info gnupg
Update2
I download the Debian source package for gpg-agent, and therein I do a grep -ri run.user .
. To be fair, they’ve documented it somewhat:
Users who don’t want systemd to manage their gpg-agent in this way for all future sessions should do:
systemctl --user mask --now gpg-agent.service gpg-agent.socket gpg-agent-ssh.socket gpg-agent-extra.socket gpg-agent-browser.socket
The reason I didn’t find that sentence yesterday? I looked in /usr/share/doc/gnupg
. Beginner error. It’s in /usr/share/doc/gpg-agent
(list of files). Sighs.
But there’s no word on the fallback to $HOME/.gnupg
that I can find.