If apt update throws warnings about invalid signature verification and NO_PUBKEY, you may need to migrate from using the deprecated system keyring to using a ‘signed-by’ attribute in your apt repo definition file.
Here are examples of errors you might see when doing an ‘apt update’.
W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: http://linux.dropbox.com/ubuntu disco Release: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY FC918B335044912E W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: https://cli.github.com/packages stable InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 23F3D4EA75716059 W: Failed to fetch https://cli.github.com/packages/dists/stable/InRelease The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 23F3D4EA75716059
If these are valid keys in the deprecated system keyring (they exist and are not expired), you can export them from the system keyring and then reference their path in the ‘signed-by’ attribute of the apt repo definition file to resolve the issue.
Identify all NO_PUBKEY warnings
First, we will parse the warnings from ‘apt update’ to construct a list of repository URL and hexadecimal key id that need to be addressed.
# show list of public keys not found in apt sudo apt update 2>&1 # isolate keys referenced in apt warnings keylist=$(sudo apt update 2>&1 | grep -Po '^W.* NO_PUBKEY \K(.*)') echo -e "keys mentioned in apt warnings:\n$keylist" # isolate repo url referenced in warnings repolist=$(sudo apt update 2>&1 | grep -Po "(error:|fetch) (http|https):\/\/\K([^ \/]*)") echo -e "repos mentioned in apt warnings:\n$repolist" # make sure keylist and repolist have same count of items # if these do not match, grep is not parsing correctly (do not continue) [[ $(echo "$repolist" | wc -l) -eq $(echo "$keylist" | wc -l) ]] && echo "OK same count" || echo "ERROR keylist and repolist do not have same count"
Validate keys found in deprecated system keyring
Then we want to validate that all the hexadecimal key ids identified are actually in the system keyring, and are both valid and not expired.
# package for dumping gpg key details sudo apt install -y pgpdump # show whether key can be found in legacy system keyring COUNTER=1 for key in $keylist; do keyname=$(echo $repolist | cut -d' ' -f $COUNTER); gpg --export $key 1>/dev/null; [[ $? -eq 0 ]] && echo "OK $key for $keyname found in system keyring" || echo "NOTFOUND $key for $keyname not in system keyring"; ((COUNTER+=1)); done # show whether key in legacy system keyring has expired COUNTER=1 for key in $keylist; do keyname=$(echo $repolist | cut -d' ' -f $COUNTER); echo -e "\n==Expiration for $key used by $keyname"; gpg --export $key | pgpdump | grep expiration -A1; [[ $? -ne 0 ]] && echo "n/a no expiration set"; ((COUNTER+=1)); done
If the key is NOT found in the deprecated system keyring or is expired, you have one of two choices.
Option#1: Fetch from keyserver
The key may be distributed to a standard keyserver. You can try fetching and importing it into the deprecated system keyring.
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys $key
Alternate key servers include: pgpkeys.mit.edu, pool.sks-keyservers.net
Option#2: Manually search for key on internet, download
See my previous article here on searching duckduckgo.com to find the gpg key for a remote repository, under the section “Find newest PGP key”.
The downloaded file can be added to the deprecated system keyring using apt-key.
sudo apt-key add <filePath>
Export from system keyring to independent file
Export from the deprecated system keyring to the recommended implementation, which is an independent file under “/usr/share/keyrings”.
# export gpg key from deprecated trusted keyring to /usr/share/keyrings COUNTER=1 for key in $keylist; do keyname=$(echo $repolist | cut -d' ' -f $COUNTER); echo "exporting $key as /usr/share/keyrings/$keyname.gpg"; gpg --export $key | sudo tee /usr/share/keyrings/$keyname.gpg 1>/dev/null; ((COUNTER+=1)); done # MUST set permissions for files sudo chmod 644 /usr/share/keyrings/*
In the above command, we export to a binary .gpg format. If we had dearmored the file (‘-a’ flag) into a PGP public key text file, then we would have saved with the ‘.asc’ suffix instead.
If the files in ‘/usr/share/keyrings’ do not have at least mode 644, apt will continue to throw a NO_PUBKEY error.
Modify apt repo definition files
Finally, we need to add a ‘signed-by’ attribute to each apt repository definition file that references these remote URL.
NOTE: This script only shows you what strings to add to your files, you still need to manually add them. It does NOT modify any files.
# show 'signed-by' value that needs to be added to apt repo url files for repo in $repolist; do echo -e "\nTODO ADD '[arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/$repo.gpg]' to these files:";grep -srl "$repo" /etc/apt | grep -Ev "save|distUpgrade|~"; done
The ‘signed-by’ attribute goes inside square brackets right after the initial ‘deb’, with the syntax shown below.
deb [arch=xxx, signed-by=/usr/share/keyrings/xxx.gpg] https://repoURL dist component
Validate resolution
Check apt update again and the warnings should be gone.
sudo apt update
Deleting key from system keyring
As an optional step, you can now delete the key from the deprecated system keyring.
# optional step for key in $keylist; do sudo apt-key del $key; done
REFERENCES
debian.org, current scheme for package signature checks
askubuntu.com, script for finding all legacy keys and converting to new format
askubuntu.com, finding the signing key for a ppa launchpad
itfoss.com, explanation of legacy keyrings, dearmor, deprecation of ‘apt-key’
omgubuntu.co.uk – fix apt-key deprecation error with export and dearmor
ubuntu man pages, apt-key deprecated in Ubuntu 21
jeffmotoretta.ca – why apt-key is deprecated
NOTES
Check if the developers have loaded newer key into keyserver
curl -s "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x${hexid}" | pgpdump | grep -E "User ID -|expiration" -A1