Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for DevOps Security & Hardening By James Joyner IV · · 9 min read

Security Error Guide: 'GPG error: ... NO_PUBKEY' Repository Signature Verification Failed

Fix apt/yum GPG signature verification failures: diagnose NO_PUBKEY, expired repo keys, missing keyrings, and BADSIG errors, then verify and install keys the right way.

  • #security-hardening
  • #troubleshooting
  • #errors
  • #gpg

Exact Error Message

When package metadata cannot be verified against a trusted key, the package manager refuses the repository. On Debian/Ubuntu (apt):

W: GPG error: https://repo.example.com stable InRelease: The following signatures
couldn't be verified because the public key is not available: NO_PUBKEY 8B48AD6246925553
E: The repository 'https://repo.example.com stable InRelease' is not signed.

On RHEL/Fedora (dnf/yum):

GPG key retrieval failed: [Errno 14] curl#37 ... 
Public key for package-1.2.3.rpm is not installed
The GPG keys listed for the "example" repository are already installed but they are not correct for this package.

What the Error Means

Package managers verify that repository metadata and packages are signed by a key the system trusts. NO_PUBKEY means the signing key is not in the trusted keyring. BADSIG/EXPKEYSIG mean a key is present but the signature is invalid or the key has expired. dnf’s “not correct for this package” means the installed repo key does not match the one that signed the package.

This is a security control working as designed: it refuses to install software it cannot cryptographically attribute to the expected publisher. Engineers hit it after enabling signed repos, rotating a repo’s key, or migrating away from the deprecated global apt-key trust store toward per-repository signed-by keyrings. The correct fix is to obtain and verify the right public key, never to disable verification.

Common Causes

  • Signing key not installed. A new third-party repo was added without importing its public key, so apt/dnf has nothing to verify against.
  • Repo key rotated or expired. The publisher rolled their signing key; the old key in your keyring no longer matches (EXPKEYSIG/KEYEXPIRED).
  • apt-key deprecation. The key lives in the legacy trusted store but the repo line uses signed-by=, or vice versa, so the keyring path is wrong.
  • Wrong keyring path in the .sources/.list entry. signed-by=/etc/apt/keyrings/example.gpg points to a file that does not exist or holds the wrong key.
  • Corrupted or ASCII-armored key in a binary keyring. A .gpg keyring file contains armored text instead of dearmored bytes, so apt cannot read it.
  • Mirror/cache served stale metadata signed by a key the publisher already retired.

How to Reproduce the Error

On a test host, add a signed repository but skip importing its key:

echo 'deb [signed-by=/etc/apt/keyrings/example.gpg] https://repo.example.com stable main' \
  | sudo tee /etc/apt/sources.list.d/example.list
sudo apt-get update
W: GPG error: https://repo.example.com stable InRelease: The following signatures
couldn't be verified because the public key is not available: NO_PUBKEY 8B48AD6246925553

The 16-hex NO_PUBKEY value is the long key ID you must locate and verify before trusting.

Diagnostic Commands

These read-only commands identify which key is missing and let you verify a key before installing it.

# Which key ID is missing? (re-read the apt update output)
sudo apt-get update 2>&1 | grep -iE 'NO_PUBKEY|EXPKEYSIG|BADSIG'

# List keys already in the per-repo keyrings (read-only)
for k in /etc/apt/keyrings/*.gpg /usr/share/keyrings/*.gpg; do \
  echo "== $k =="; gpg --no-default-keyring --keyring "$k" --list-keys 2>/dev/null; done

# Inspect a downloaded key file's fingerprint WITHOUT trusting it
gpg --show-keys --with-fingerprint /tmp/example-key.asc

# Verify a detached signature against a file (read-only)
gpg --verify InRelease.gpg InRelease

# RHEL/Fedora: list installed RPM GPG keys
rpm -q gpg-pubkey --qf '%{NAME}-%{VERSION}-%{RELEASE} %{SUMMARY}\n'

# Confirm the repo definition and its signed-by path
grep -R signed-by /etc/apt/sources.list /etc/apt/sources.list.d/ 2>/dev/null

gpg --show-keys is critical: it prints the fingerprint of a key file so you can compare it against the publisher’s documented fingerprint before adding it to a keyring.

Step-by-Step Resolution

  1. Identify the exact key. Read the NO_PUBKEY/EXPKEYSIG ID from apt update, or the package name from dnf. This tells you which publisher key is required.

  2. Obtain the key over HTTPS from the official source and inspect it before trusting it:

    curl -fsSL https://repo.example.com/gpg.key -o /tmp/example-key.asc
    gpg --show-keys --with-fingerprint /tmp/example-key.asc

    Compare the printed fingerprint against the one published in the vendor’s documentation. Do not proceed if they differ.

  3. Install the key into a per-repository keyring (the modern, scoped approach), dearmoring it to binary:

    sudo install -m 0644 -D /dev/stdin /etc/apt/keyrings/example.gpg \
      < <(gpg --dearmor /tmp/example-key.asc)

    Ensure the .list/.sources entry’s signed-by= points at exactly this file.

  4. For RHEL/Fedora, import the verified key and confirm the repo references it:

    sudo rpm --import https://repo.example.com/RPM-GPG-KEY-example
  5. Handle expiry/rotation by replacing the old key with the publisher’s new one through the same verify-then-install flow; remove the retired key from the keyring.

  6. Re-run sudo apt-get update (or dnf makecache) and confirm the repository now validates with no GPG warnings.

Prevention and Best Practices

  • Always verify a key’s fingerprint against the publisher’s documentation before adding it; never pipe a key straight into the trust store unseen.
  • Use per-repository keyrings with signed-by= instead of the deprecated global apt-key store, so one repo’s key cannot sign for another.
  • Pin repo definitions and keyring paths in configuration management so every host trusts the same verified keys.
  • Monitor for EXPKEYSIG/KEYEXPIRED so you rotate keys before they break apt update fleet-wide.
  • Never disable signature checking (--allow-unauthenticated, gpgcheck=0) to “fix” the error; that removes the protection entirely.
  • The repository is not signed — the metadata signature could not be verified at all.
  • EXPKEYSIG / KEYEXPIRED — a known key has passed its expiry date.
  • unable to get local issuer certificate — a TLS (not GPG) trust failure fetching the key, covered in the security hardening guides.
  • Hash Sum mismatch — corrupted or stale metadata, often from a bad mirror.

Frequently Asked Questions

Can I just add [trusted=yes] to skip verification? No. That disables the security control entirely and lets any party serve packages. Import and verify the correct key instead.

The key is installed but I still get NO_PUBKEY. The repo line’s signed-by= path probably points at a different file than where you installed the key, or the key was armored instead of dearmored. Check the signed-by path and the keyring contents.

Why did this start after a working install? The publisher likely rotated or let their signing key expire. Fetch and verify their current key.

How do I know the key I downloaded is genuine? Compare the gpg --show-keys fingerprint against the fingerprint the vendor publishes on their official site or documentation, ideally over HTTPS.

Is apt-key still safe to use? It is deprecated because it grants global trust. Use a per-repository keyring referenced by signed-by= instead.

Free download · 368-page PDF

Download the Free 500-Prompt DevOps AI Toolkit

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.