Skip to content

GPG / PGP Signing

Use QCecuring-managed GPG keys for signing Git commits, tags, RPM packages, DEB packages, and other artifacts — with private keys protected in HSM.


┌──────────────┐ ┌──────────────────┐ ┌──────────────┐
│ GPG CLI │──────►│ QCecuring Agent │──────►│ QCecuring │
│ / git │ │ (PKCS#11 / │ │ Platform │
│ │ │ gpg-agent) │ │ │
└──────────────┘ └──────────────────┘ └──────────────┘
┌──────────────┐
│ HSM │
│ (Private │
│ Keys) │
└──────────────┘

Key points:

  • GPG private keys are stored in the HSM, never exported
  • Signing operations are proxied through the QCecuring Agent
  • Integration via PKCS#11 token or custom gpg-agent socket
  • Compatible with standard GPG workflows and tooling

Step 1: Generate or Import GPG Key in QCecuring

Section titled “Step 1: Generate or Import GPG Key in QCecuring”
  1. Navigate to Keys → Generate in the QCecuring platform
  2. Select key type: GPG / PGP
  3. Configure key parameters:
ParameterRecommended Value
AlgorithmRSA 4096 or Ed25519
UsageSign, Certify
Expiration2 years
User IDYour Name <email@example.com>
SubkeysSigning subkey (recommended)
  1. Click Generate — the key is created in the HSM
Terminal window
# Export your existing private key (for import into QCecuring)
gpg --export-secret-keys --armor KEY_ID > private-key.asc
# Import via QCecuring CLI
qcecuring-agent gpg import \
--key-file private-key.asc \
--label "Developer Signing Key"
# Securely delete the exported key file
shred -u private-key.asc
Terminal window
# Export the public key from QCecuring
qcecuring-agent gpg export-public \
--key-id "ABCD1234..." \
--output public-key.asc
# Import into local GPG keyring (public part only)
gpg --import public-key.asc

Install the PKCS#11 smart card daemon bridge:

Terminal window
# Install gnupg-pkcs11-scd
sudo apt install gnupg-pkcs11-scd # Debian/Ubuntu
sudo yum install gnupg-pkcs11-scd # RHEL/CentOS

Configure ~/.gnupg/gnupg-pkcs11-scd.conf:

# QCecuring PKCS#11 provider
providers qcecuring
provider-qcecuring-library /usr/lib/qcecuring-pkcs11.so
log-file /tmp/gnupg-pkcs11-scd.log

Configure ~/.gnupg/gpg-agent.conf:

scdaemon-program /usr/bin/gnupg-pkcs11-scd

Restart the agent:

Terminal window
gpgconf --kill gpg-agent
gpg --card-status

Use the QCecuring agent as a drop-in gpg-agent replacement:

Terminal window
# Configure QCecuring as the GPG agent
qcecuring-agent gpg configure \
--api-url https://platform.qcecuring.com \
--key-id "ABCD1234..."
# This creates/updates ~/.gnupg/gpg-agent.conf
# and sets up the agent socket

Verify the configuration:

Terminal window
# List available keys through the agent
gpg --list-secret-keys
# Should show your QCecuring-managed key with a ">" indicator
# sec> ed25519 2024-01-15 [SC] [expires: 2026-01-15]
# ABCD1234EFGH5678...
# uid [ultimate] Your Name <email@example.com>
# ssb> ed25519 2024-01-15 [S]

Step 3: Sign Git Commits with Managed Keys

Section titled “Step 3: Sign Git Commits with Managed Keys”
Terminal window
# Set the signing key
git config --global user.signingkey ABCD1234EFGH5678
# Enable commit signing by default
git config --global commit.gpgsign true
# Enable tag signing by default
git config --global tag.gpgsign true
# (Optional) Set GPG program if using a custom path
git config --global gpg.program gpg
Terminal window
# Sign a commit (automatic if commit.gpgsign = true)
git commit -S -m "feat: add new feature"
# Sign a tag
git tag -s v1.0.0 -m "Release v1.0.0"
# Verify a signed commit
git log --show-signature -1
# Verify a signed tag
git tag -v v1.0.0
Terminal window
# Export public key for GitHub/GitLab
gpg --armor --export ABCD1234EFGH5678
# Add to:
# GitHub: Settings → SSH and GPG keys → New GPG key
# GitLab: Preferences → GPG Keys

Configure RPM macros for GPG signing:

~/.rpmmacros
%_signature gpg
%_gpg_name Your Name <email@example.com>
%__gpg /usr/bin/gpg

Sign RPM packages:

Terminal window
# Sign a single RPM
rpm --addsign mypackage-1.0-1.x86_64.rpm
# Sign multiple RPMs
rpm --addsign *.rpm
# Verify RPM signature
rpm --checksig mypackage-1.0-1.x86_64.rpm

Import the public key for verification on target systems:

Terminal window
# Export public key in RPM-compatible format
gpg --export --armor ABCD1234EFGH5678 > RPM-GPG-KEY-yourorg
# Import on target systems
sudo rpm --import RPM-GPG-KEY-yourorg

Sign Debian packages with dpkg-sig:

Terminal window
# Sign a .deb package
dpkg-sig --sign builder mypackage_1.0-1_amd64.deb
# Verify signature
dpkg-sig --verify mypackage_1.0-1_amd64.deb

Sign APT repository metadata with gpg:

Terminal window
# Sign Release file for APT repository
gpg --default-key ABCD1234EFGH5678 \
--armor --detach-sign \
--output Release.gpg Release
# Create InRelease (clearsigned)
gpg --default-key ABCD1234EFGH5678 \
--clearsign \
--output InRelease Release

Terminal window
# Verify the latest commit
git verify-commit HEAD
# Verify a specific commit
git verify-commit abc1234
# Verify a tag
git verify-tag v1.0.0
# Show signature in log
git log --show-signature --oneline -5
Terminal window
# Verify a detached signature
gpg --verify file.sig file
# Verify a clearsigned file
gpg --verify signed-file.asc
# Check key details
gpg --list-keys --keyid-format long ABCD1234EFGH5678
Terminal window
# Check RPM signature
rpm --checksig mypackage-1.0-1.x86_64.rpm
# Verbose verification
rpm -Kv mypackage-1.0-1.x86_64.rpm

name: Signed Release
on:
push:
tags: ['v*']
jobs:
release:
runs-on: self-hosted # QCecuring Agent installed
steps:
- uses: actions/checkout@v4
- name: Configure GPG
run: |
qcecuring-agent gpg configure \
--key-id ${{ secrets.GPG_KEY_ID }}
- name: Build RPM
run: ./build-rpm.sh
- name: Sign RPM
run: rpm --addsign dist/*.rpm
- name: Verify Signatures
run: rpm --checksig dist/*.rpm
- name: Upload Release
uses: softprops/action-gh-release@v1
with:
files: dist/*.rpm

IssueCauseResolution
No secret keyGPG cannot reach QCecuring agentVerify agent is running: qcecuring-agent status
Unusable secret keyPKCS#11 module not loadedCheck gnupg-pkcs11-scd.conf path
signing failed: No pinentryMissing pinentry programInstall pinentry-curses or configure --batch mode
Git commit not showing as verifiedPublic key not uploaded to hostingAdd public key to GitHub/GitLab settings
RPM --addsign hangsWaiting for passphraseConfigure %__gpg_sign_cmd with --batch --pinentry-mode loopback
card error from gpgAgent socket misconfiguredRun gpgconf --kill gpg-agent and restart
Key not found after importKey ID mismatchUse gpg --list-keys to verify the correct key ID

  • Use Ed25519 keys for new deployments (faster, smaller signatures)
  • Set key expiration dates and rotate before expiry
  • Use signing subkeys — keep the primary key for certification only
  • Upload public keys to key servers and Git hosting platforms
  • Enable commit.gpgsign = true globally for all developers
  • Use separate keys for personal commits and CI/CD automation
  • Audit signing operations in the QCecuring platform