Skip to content
Latchkey

gpg --encrypt -r: Encrypt Secrets to a Recipient

gpg --encrypt -r encrypts data so only the holders of the named recipient keys can read it.

A common pattern is encrypting a secrets bundle to the CI key in the repo, then decrypting it on the runner. -r selects the recipient by their public key.

What it does

gpg --encrypt encrypts the input to one or more recipient public keys named with --recipient (-r); only the matching secret keys can decrypt it. With --symmetric instead, it encrypts with a passphrase and no key at all.

Common usage

Terminal
# public-key encryption to a recipient
gpg --encrypt --recipient ci@example.com --armor secrets.env
# multiple recipients
gpg --encrypt -r alice@example.com -r bob@example.com secrets.env
# passphrase-only (symmetric), non-interactive
gpg --batch --symmetric --cipher-algo AES256 \
  --passphrase "$KEY" --pinentry-mode loopback secrets.env

Options

FlagWhat it does
--encrypt / -eEncrypt to recipient public keys
--recipient <id> / -rAdd a recipient (repeatable)
--symmetric / -cEncrypt with a passphrase instead of a key
--armor / -aASCII-armor the ciphertext
--cipher-algo <name>Choose the symmetric cipher, e.g. AES256
--trust-model alwaysEncrypt without prompting about recipient trust

In CI

When encrypting to an imported recipient key whose owner trust is unset, gpg prompts "use this key anyway?" and hangs. Add --trust-model always (or set owner trust) so the encrypt step never blocks. For passphrase-only secrets, --symmetric with --batch --pinentry-mode loopback keeps it non-interactive.

Common errors in CI

"gpg: <id>: skipped: No public key" means the recipient key is not imported. "gpg: <id>: There is no assurance this key belongs to the named user" followed by a hang is the trust prompt; add --trust-model always. With --symmetric, a no-TTY passphrase prompt raises "Inappropriate ioctl for device"; use loopback.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →