GPG version: 2.2.23
Docker version 20.10.5

I am playing around with GPG on my laptop and trying to reuse it inside docker container.

The docker container is simply a PHP-FPM alpine image. I have simple PHP CLI tool which encrypt/decrypts data with GPG. I exported the GPG from host and imported it inside container. The problem though, I always need to provide passphrase for PHP to decrypt the data. I would like to avoid passphrase in container for sake of security.

Further I discovered the gpg-agent with gpg-preset-passphrase and preconfigured it inside the container, but later on found that this isn't optimal, because once I restart the container or destroy it, I will need to start gpg-agent and set passphrase again.

So, I was wondering, is there a way to pass gpg-agent with cached passphrase inside docker and so docker would reuse it to encrypt/decrypt the data?

I know there is possibility to reuse ssh-agent inside docker, but couldn't really find a way to do the same for GPG.

Or maybe there is a better/secure way of doing it?


I would say the resolution was very simple.


First of all, you need to start gpg-agent:

gpg-agent --verbose --daemon --log-file /tmp/gpg-agent.log --allow-preset-passphrase --default-cache-ttl=31536000

This will start gpg-agent in background. You can verify that it is running:

ps aux | grep gpg

Now you need to use gpg-preset-passphrase to preset passphrase for the private key. gpg-preset-passphrase is not located in the /usr/local/bin, so you need to find it:

sudo find / -name gpg-preset-passphrase

In my case it was /usr/local/Cellar/gnupg/2.3.1_1/libexec/gpg-preset-passphrase, so now run the following command to find out private KEYID:

gpg-connect-agent 'keyinfo --list' /bye

Sample output:

S KEYINFO 4B86D9FBE0D9617C6EB4B42015C9B2AC8XXXXXXX D - - - P - - -
S KEYINFO 8960D3408E09A1A111AA862DBFB1B16CFXXXXXXX D - - - P - - -

In my case it is two keys, choose one of the KEY IDs.

echo "your-secret-passphrase" | /your/path/to/gpg-preset-passphrase --verbose --preset 4B86D9FBE0D9617C6EB4B42015C9B2AC8XXXXXXX

Replace your-secret-passphrase with your password, /your/path/to/ with your path and 4B86D9FBE0D9617C6EB4B42015C9B2AC8XXXXXXX with your own KEYID.

Now run the following command again to verify that passphrase was set successfully:

gpg-connect-agent 'keyinfo --list' /bye

If you see "1" near the KEYID you've chosen, it means passphrase set successfully.

Let's verify by doing encrypt and decrypt:

echo "hello" | gpg --armor --encrypt --recipient email@example.com | gpg --decrypt

Replace email@example.com with your email.

GPG Agent Forwarding via SSH

Add the following to your ~/.ssh/config

Host gpgtunnel
    User user
    HostName server-ip
    Port 22
    RemoteForward /root/.gnupg/S.gpg-agent /home/user/.gnupg/S.gpg-agent
    IdentityFile ~/.ssh/id_rsa

RemoteForward has the following signature: <remote path> <local path>. You can find location of local path by running:

gpgconf --list-dir agent-extra-socket

ssh to you server and find remote path by running:

gpgconf --list-dir agent-socket

Some note about S.gpg-agent vs S.gpg-agent.extra. S.gpg-agent allows to do export of the private key and other manipulation with keys, where is S.gpg-agent.extra is a very limit version which allows only encrypt/decrypt operation.

Now you need to export public key to remote sever, you can use the following command:

gpg --export email@example.com | ssh -p 22 user@remote-server gpg --import

Replace email@example.com with your GPG email.

Ensure you have imported public key successfully:

ssh -p 22 user@remote-server gpg -k


Now try to run ssh gpgtunnel and do encrypt/decrypt on the server. Now server should be able to reuse your local gpg-agent socket.

echo "hello" | gpg --armor --encrypt --recipient gpg.for.testing.in.docker@example.com | gpg --decrypt

If for some reason this doesn't work, you may run the following SSH command from your local computer:

ssh -fNT gpgtunnel

This will put SSH to background (-f flag). Now ssh gpgtunnel normally and retry encrypt/decrypt command from above again.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.