Using GPG inside a container
Sometimes I use GPG to encrypt secrets used by applications.
This has the advantage that most software have one way or another of accessing GPG
so it also help sharing secrets between tools.
For example sharing the same data file between Ansible and Terraform rather than using different methods.
This also maintains one source of truth.
The downside is of course setting up a keychain on each machine that needs access.
There is also the extra step of doing this over and over in a container like Docker or Kubernetes.
This is one possibility to address it:
- mount the encrypted files: GPG secret key, ownertrust ID, public key
(only the secret key is sensitive really but I like to keep them together)
- mount the public keys we may want to encrypt for
- get the GPG passphrase so we can decrypt our key
- get the keygrip so we know which key is ours TODO: put it in the private key pair file
Initialise the keychain at the start of your process or inside an init container.
We don’t want to have both the GPG_PASSPHRASE and the seret key it decrypt stored in the same place;
this is why eventually the GPG_PASSPHRASE is passed as an environment variable.
It could just as well be another mount point , but I don’t like having secrets “on disk”.
[[ ! $# -eq 2 ]] && usage
gpg_private_keyfile=$1
gpg_ownertrust_file=$2
[[ ! -f ${gpg_private_keyfile} ]] && die "file not found:" ${gpg_private_keyfile}
[[ ! -f ${gpg_ownertrust_file} ]] && die "file not found:" ${gpg_ownertrust_file}
[[ -z ${GPG_PASSPHRASE} ]] && die "GPG_PASSPHASE environment variable not set."
[[ -z ${GPG_KEYGRIP} ]] && die "GPG_KEYGRIP environment variable not set."
info "Importing GPG private key"
gpg --batch --import ${gpg_private_keyfile}
info "Importing GPG ownertrust"
gpg --import-ownertrust ${gpg_ownertrust_file}
warn "Restarting gpg-agent"
gpgconf --kill gpg-agent
gpg-agent --daemon --allow-preset-passphrase --max-cache-ttl 3600
info "Importing GPG passphrase"
/usr/libexec/gpg-preset-passphrase --preset --passphrase ${GPG_PASSPHRASE} ${GPG_KEYGRIP}
info "Current GPG keys"
gpg --with-colons -K
We start our Pod by mounting all the secrets and not so secrets data files
from ConfigMap and Secret and send the Passphrase via environment. TODO: change this
---
apiVersion: v1
kind: Pod
metadata:
name: worker
spec:
imagePullSecrets:
- name: docker-registry-creds
containers:
- name: worker
image: "ansible:latest"
imagePullPolicy: Always
tty: true
command:
- cat
volumeMounts:
- mountPath: /tmpfs/.secrets
name: gpg-keyring
- mountPath: /tmpfs/gpg-public-keys
name: gpg-public-keys
env:
- name: GPG_PASSPHRASE
valueFrom:
secretKeyRef:
name: gpg-keyring
key: passphrase
- name: GPG_KEYGRIP
valueFrom:
secretKeyRef:
name: gpg-keyring
key: keygrip
volumes:
- name: gpg-keyring
secret:
secretName: gpg-keyring
- name: gpg-public-keys
configMap:
name: gpg-public-keys