How to encrypt with GPG in CI

George Shuklin
OpsOps
Published in
2 min readFeb 14, 2022

There is a rather unpleasant problem: if you ever tried to encrypt message (or file) with gpg in a CI/CD pipeline, you get a rather annoying error:

gpg: 123456789ABCDEF: There is no assurance this key belongs to the named usergpg: cannot open '/dev/tty': No such device or address

In CI/CD environment there is a rather low chance to understand what’s going on.

If you have /dev/tty (which you don’t have in CI/CD), you can read the rest of the message, which explain the problem a bit more:

sub  rsa4096/123456789ABCDEF 2022-22-22 Some One <some@example.com>
Primary key fingerprint: 0102 0304 0506 0708 090A 0B0C
Subkey fingerprint: 0D0E 0F10 1112 1314 1516 1718
It is NOT certain that the key belongs to the person named
in the user ID. If you *really* know what you are doing,
you may answer the next question with yes.
Use this key anyway? (y/N)

Yes, GPG is paranoid about keys and do not want to encrypt with random key. The proper way to solve this problem on desktop is to mark key as trusted via pgp trust database.

The problem is that CI/CD is not a desktop and pipeline finishes as soon as job done, so there is no special ‘trust’ there.

Stackoverflow is full of rather non-satisfying answers proposing different way of adding keys into trusted database, etc.

I found a better way. We can control trust model of gpg. The one we want is either ‘tofu’ or ‘always’:

echo test | gpg --encrypt --armor --yes --encrypt-to -r 123456789ABCDEF --trust-model always-----BEGIN PGP MESSAGE-----
...

Success.

You may wonder where I got a public key to encrypt to into CI/CD. The most simple way is to import it, or use existing (known to CI via secrets) key.

For GH Actions I used this: crazy-max/ghaction-import-gpg@v4

--

--

George Shuklin
OpsOps

I work at Servers.com, most of my stories are about Ansible, Ceph, Python, Openstack and Linux. My hobby is Rust.