Date Series Part 2 of Building RPMs Tags rpm / gpg


In Part 1 of this series, we set up an RPM build environment with a dedicated user for building RPMs.

Before we actually walk through the steps for building an RPM, we need to create a GPG key to sign the RPMs before they are distributed and installed. Signing RPMs is a good practice and ensures all the installed RPMs in your environment are verified from trusted sources.

In this guide, we will walk through the steps required to create your own RPM GPG signing key, distribute it and import it into a machine's RPM database.


Creating a GPG key requires a certain amount of entropy in order to ensure sufficient randomness. If you are following this guide on a virtual machine, you will need to make sure that the virtual machine has sufficient entropy.

See this post on how to increase the entropy on your virtual machine using rng-tools before continuing.

Additionally, the steps in this guide will be carried out by the makerpm user.

Install Packages

To install the GPG package, run the following:

sudo yum install gnupg2

Create a GPG Key Pair

Use the gpg command to create a new key pair:

gpg --gen-key

The --gen-key option is used interactively. Select the key you want to use. The first option, RSA and RSA, creates an RSA key for digital signing and another RSA key for encryption.

Please select what kind of key you want:
   (1) RSA and RSA (default)
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
Your selection? 1

Next, select the size. The default 2048 bits are sufficient, but if you are feeling particularly paranoid, go for 4096 bits.

RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 2048
Requested keysize is 2048 bits

Next, choose how long the key should be valid. In this example, we choose the default choice, 0, so the key will not expire.

Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 
Key does not expire at all
Is this correct? (y/N) y

Now, you will need to fill out some identifying information about the key, like your name and email. In this example, we leave the Comment field empty. After filling out the fields, you are prompted to confirm the information or change any of the fields before continuing.

GnuPG needs to construct a user ID to identify your key.

Real name: Example Org Signing Key
Email address:
You selected this USER-ID:
    "Example Org Signing Key <>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o

The last step in creating the key pair is to protect your secret key with a passphrase. Note the use of a suggested passphrase and not a password. We recommend using an easy to remember sentence to protect the secret key.

You should now be presented with a curses based prompt to enter and confirm your passphrase.

│ Enter passphrase                                    │
│                                                     │
│                                                     │
│ Passphrase ________________________________________ │
│                                                     │
│   <OK>                             <Cancel>         │

This passphrase prompt is displayed by the pinentry package. If you are in an X environment, whether on a desktop or via SSH with X11 forwarding enabled to a remote server, you may get a GUI version of the passphrase prompt. To get the GUI prompt, however, you will need to have the pinentry-gtk package installed if you are using GNOME and pinentry-qt or pinentry-qt4 if you are using KDE.

After typing your password, the key generation may stall and you may see the following message:

We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.

This has to do with insufficient entropy. Again, see this post on how to increase the entropy on your virtual machine. You may open another terminal to the server you are generating the keys on and install and run rng-tools. Shortly after the rngd daemon is running, the key generation should complete and you should see a message like this:

gpg: key 3D832D1E marked as ultimately trusted
public and secret key created and signed.

gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
pub   2048R/3D832D1E 2015-05-29
      Key fingerprint = 7F50 5CA9 0CD0 DBF1 FAC2  AB46 E5E5 4444 3D83 2D1E
uid                  Example Org Signing Key <>
sub   2048R/D4F51F8B 2015-05-29

Confirming your keys

To list your keys, run the following command:

gpg --list-keys

You will see a listing of all keys. In this example, only a single key is listed, the one we just created from the above steps.

pub   2048R/3D832D1E 2015-05-29
uid                  Example Org Signing Key <>
sub   2048R/D4F51F8B 2015-05-29

Troubleshooting TTY Issues

There is an issue, apparently with the gnupg2 package, where if you su, i.e. switch, to another user, a new pseudo-terminal is not opened for the switched user.

This causes problems since gnupg2 requires permissions to open a tty for the pinentry package, which is responsible for displaying the passphrase prompt to the screen. Therefore, if you run the gpg --gen-key command after switching to a different user, you may see one of the following error messages:

Without X11 Forwarding:

gpg-agent[5569]: directory `/home/makerpm/.gnupg/private-keys-v1.d' created
gpg-agent[5569]: command get_passphrase failed: Operation cancelled
gpg: cancelled by user
gpg: Key generation canceled.

With X11 Forwarding:

X11 connection rejected because of wrong authentication.
xprop:  unable to open display 'localhost:10.0'
X11 connection rejected because of wrong authentication.

(pinentry-gtk-2:10602): Gtk-WARNING **: cannot open display: localhost:10.0
gpg-agent[10601]: can't connect server: ec=4.16383
gpg-agent[10601]: can't connect to the PIN entry module: End of file
gpg-agent[10601]: command get_passphrase failed: No pinentry
gpg: problem with the agent: No pinentry
gpg: Key generation canceled.

# Workaround

In order to work around the above TTY issue, you will need to use X11 forwarding when switching to a different user. To do this, you need an export file in root's .xauth directory.

First, switch to root:

su -

Then, create an export file with the user you want to switch to, for example, user1:

cd $HOME
mkdir -p .xauth
echo "user1" >> .xauth/export

Switch to user1:

su - user1

Now, if you try to generate gpg keys, pinentry will present the passphrase prompt.

Distributing the Public Key

If you plan to distribute custom built RPMs to multiple or even all machines in your environment, you will need to distribute the public key to all machines and import it into each machine's local RPM database.

Export the Signing Key

We need to export the signing key into ASCII armored output, which is a form of binary-to-text encoding. We need the name of the key in order to export it.

Get a list of keys:

gpg --list-keys

The output, as seen above, should similar to the following:

pub   2048R/3D832D1E 2015-05-29
uid                  Example Org Signing Key <>
sub   2048R/D4F51F8B 2015-05-29

The name is in the uid line, before the email address. In this case, it is Example Org Signing Key. Use gpg to export this key in ASCII armored output to a file:

gpg --export -a "Example Org Signing Key" > RPM-GPG-KEY-example-org-signing-key

The resulting file, RPM-GPG-KEY-example-org-signing-key, is the RPM signing key that we can distribute to other machines.

Importing the Key into the RPM database

On RHEL 6 and its clones, the default location on the filesystem for RPM GPG keys are /etc/pki/rpm-gpg. Use your tool of choice, such as scp, rsync, Puppet, Ansible, etc., to copy the file to any remote machine where you will install custom RPMs signed with this key.

If SELinux is in Enforcing mode, be sure that the TYPE in the target security context is cert_t. Use the ls command to view the SELinux context of the key file

ls -lZ /etc/pki/rpm-gpg/RPM-GPG-KEY-example-org-signing-key

The output should look something similar to the following:

-rw-r--r--. root root unconfined_u:object_r:cert_t:s0 /etc/pki/rpm-gpg/RPM-GPG-KEY-example-org-signing-key

Lastly, import the key into the RPM database on all machines where you copied the key. This command will not return any output and exit with return code 0.

rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-example-org-signing-key

Verify Key Import

To verify that the key has been imported, we can search the RPM database. First, we need the public GPG key id. In the output of gpg --list-keys, the public key id is found in the pub line. It is the 8 hex digits after the slash. The size of the key, 2048, and the algorithm, R for RSA, is shown before the slash on the pub line.

pub   2048R/3D832D1E 2015-05-29

Then, use the rpm command to find the public key.

rpm -qa gpg-pubkey\*

The output will show all GPG keys that have been imported into the RPM database. You should see your public key ID, in lowercase, in one of the pubkeys listed:


Finally, use rpm command again to see more information about the key:

rpm -qi gpg-pubkey-3d832d1e-556873e0

The output should look similar to the following:

Name        : gpg-pubkey                   Relocations: (not relocatable)
Version     : 3d832d1e                          Vendor: (none)
Release     : 556873e0                      Build Date: Fri 29 May 2015 08:13:22 PM EDT
Install Date: Fri 29 May 2015 08:13:22 PM EDT      Build Host: localhost
Group       : Public Keys                   Source RPM: (none)
Size        : 0                                License: pubkey
Signature   : (none)
Summary     : gpg(Example Org Signing Key <>)
Description :


You now have an RPM GPG key that you can use sign and verify custom RPMs. In Part 3 of this guide, we will look at various ways of building RPMs.


comments powered by Disqus