# Build and Sign RPM package and repo
Table of Contents
Hi there!
Welcome to geekcoding101.com!
I have two decades years of working experiences on Linux. There are many things I have come across, but I want to say, building package for Linux is something you couldn’t avoid at all in your work or study!
I have summarized the steps/tricks in this article, hope you will find it useful!
Enjoy!
Create unsigned rpm
I will first demonstrate how to create unsigned rpm.
Create Folder Structure
First step is creating folder structure.
If you don’t specify top_dir in ~/.rpmmacros (It’s a config file), then it will use ~/rpmbuild by default
cd ~mkdir rpmbuildcd rpmbuildmkdir BUILD BUILDROOT SOURCES SRPMS RPMS SPECSCreate SPEC file for unsigned rpm
Now we can work on the spec file SPECS/rpm-no-sig.spec:
# cat SPECS/rpm-no-sig.specName: rpm-no-sigVersion: 1.0Release: 1Summary: This is a unsigned rpm.
Vendor: Geekcoding101License: Copyright (c) 2021
BuildArch: noarchBuildRoot: %{_tmppath}/%{name}-%{version}
Packager: Geekcoding101
Source0: %{name}-%{version}.tar.gz%define INSTALL_DIR /usr/lib/unsigned-rpm/%define INSTALL_FILE rpm-helper-unsigned.py
%description%{Summary}This package provides rpm gpgcheck demo.
%prep%setup -q
%installrm -rf %{buildroot}install --directory %{buildroot}/%{INSTALL_DIR}install -m 0755 %{INSTALL_FILE} %{buildroot}/%{INSTALL_DIR}
%cleanrm -rf %{buildroot}
%files%defattr(-,root,root,-)%{INSTALL_DIR}%{INSTALL_DIR}/%{INSTALL_FILE}%exclude %{INSTALL_DIR}/*.pyc%exclude %{INSTALL_DIR}/*.pyo
%doc
%changelog* Sun Jan 21 2021 - Geekcoding101- Initial commit.
%postCreate a dummy source file for unsigned rpm
Use a dummy py file to be packed into the rpm: rpm-helper-unsigned.py:
#!/usr/bin/env python
import sysimport osimport re
def main(): print("This is from unsigned rpm.")
if __name__ == '__main__': main()Create a folder: mkdir <rpm-name>-<version>
For example:
cd ~mkdir rpm-no-sig-1.0Then put rpm-helper-unsigned.py under it.
Then make gz file for the folder:
tar cf rpm-no-sig-1.0.tar rpm-no-sig-1.0gzip rpm-no-sig-1.0.tarYou will get file rpm-no-sig-1.0.tar.gz.
Move it to SOURCES folder.
When building rpm, it will recognize this gz file and extract it automatically.
Build rpm-no-sig.rpm
Run command: rpmbuild -ba SPECS/rpm-no-sig.spec
Example:
# rpmbuild -ba SPECS/rpm-no-sig.specwarning: bogus date in %changelog: Sun Jan 21 2021 - Geekcoding101Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.ut6Q5z+ umask 022+ cd /root/rpmbuild/BUILD+ cd /root/rpmbuild/BUILD+ rm -rf rpm-no-sig-1.0+ /usr/bin/gzip -dc /root/rpmbuild/SOURCES/rpm-no-sig-1.0.tar.gz+ /usr/bin/tar -xf -+ STATUS=0+ '[' 0 -ne 0 ']'+ cd rpm-no-sig-1.0+ /usr/bin/chmod -Rf a+rX,u+w,g-w,o-w .+ exit 0Executing(%install): /bin/sh -e /var/tmp/rpm-tmp.UOxKuK+ umask 022+ cd /root/rpmbuild/BUILD+ '[' /root/rpmbuild/BUILDROOT/rpm-no-sig-1.0-1.x86_64 '!=' / ']'+ rm -rf /root/rpmbuild/BUILDROOT/rpm-no-sig-1.0-1.x86_64++ dirname /root/rpmbuild/BUILDROOT/rpm-no-sig-1.0-1.x86_64+ mkdir -p /root/rpmbuild/BUILDROOT+ mkdir /root/rpmbuild/BUILDROOT/rpm-no-sig-1.0-1.x86_64+ cd rpm-no-sig-1.0+ rm -rf /root/rpmbuild/BUILDROOT/rpm-no-sig-1.0-1.x86_64+ install --directory /root/rpmbuild/BUILDROOT/rpm-no-sig-1.0-1.x86_64//usr/lib/unsigned-rpm/+ install -m 0755 rpm-helper-unsigned.py /root/rpmbuild/BUILDROOT/rpm-no-sig-1.0-1.x86_64//usr/lib/unsigned-rpm/+ '[' noarch = noarch ']'+ case "${QA_CHECK_RPATHS:-}" in+ /usr/lib/rpm/check-buildroot+ /usr/lib/rpm/redhat/brp-compress+ /usr/lib/rpm/redhat/brp-strip /usr/bin/strip+ /usr/lib/rpm/redhat/brp-strip-comment-note /usr/bin/strip /usr/bin/objdump+ /usr/lib/rpm/redhat/brp-strip-static-archive /usr/bin/strip+ /usr/lib/rpm/brp-python-bytecompile /usr/bin/python 1+ /usr/lib/rpm/redhat/brp-python-hardlink+ /usr/lib/rpm/redhat/brp-java-repack-jarsProcessing files: rpm-no-sig-1.0-1.noarchwarning: File listed twice: /usr/lib/unsigned-rpm/rpm-helper-unsigned.pyProvides: rpm-no-sig = 1.0-1Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(FileDigests) <= 4.6.0-1 rpmlib(PartialHardlinkSets) <= 4.0.4-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1Requires: /usr/bin/envChecking for unpackaged file(s): /usr/lib/rpm/check-files /root/rpmbuild/BUILDROOT/rpm-no-sig-1.0-1.x86_64Wrote: /root/rpmbuild/SRPMS/rpm-no-sig-1.0-1.src.rpmWrote: /root/rpmbuild/RPMS/noarch/rpm-no-sig-1.0-1.noarch.rpmExecuting(%clean): /bin/sh -e /var/tmp/rpm-tmp.w4KHSg+ umask 022+ cd /root/rpmbuild/BUILD+ cd rpm-no-sig-1.0+ rm -rf /root/rpmbuild/BUILDROOT/rpm-no-sig-1.0-1.x86_64+ exit 0You will get RPMS/noarch/rpm-no-sig-1.0-1.noarch.rpm
Check MD5: rpm -Kv <rpm file>
Example:
# rpm -Kv RPMS/noarch/rpm-no-sig-1.0-1.noarch.rpmRPMS/noarch/rpm-no-sig-1.0-1.noarch.rpm: Header SHA1 digest: OK (84bd6662874a27ccd5cd3247ef7a4107c1919f54) MD5 digest: OK (198ab02bd5765c383c57dbe113551af0)Backup this rpm to somewhere else.
Create signed rpm
Create SPEC file for signed rpm
The spec file SPECS/rpm-with-sig.spec:
# cat SPECS/rpm-with-sig.specName: rpm-with-sigVersion: 1.0Release: 1Summary: This is a signed rpm.
Vendor: Geekcoding101License: Copyright (c) 2021
BuildArch: noarchBuildRoot: %{_tmppath}/%{name}-%{version}
Packager: Geekcoding101
Source0: %{name}-%{version}.tar.gz%define INSTALL_DIR /usr/lib/signed-rpm/%define INSTALL_FILE rpm-helper-signed.py
%description%{Summary}This package provides rpm gpgcheck demo.
%prep%setup -q
%installrm -rf %{buildroot}install --directory %{buildroot}/%{INSTALL_DIR}install -m 0755 %{INSTALL_FILE} %{buildroot}/%{INSTALL_DIR}
%cleanrm -rf %{buildroot}
%files%defattr(-,root,root,-)%{INSTALL_DIR}%{INSTALL_DIR}/%{INSTALL_FILE}%exclude %{INSTALL_DIR}/*.pyc%exclude %{INSTALL_DIR}/*.pyo
%doc
%changelog* Sun Jan 21 2021 - Geekcoding101- Initial commit.
%postCreate a dummy source file for signed rpm
Use a dummy py file to be packed into the rpm: rpm-helper-signed.py. You can just reuse the one in above and change the print message accordingly.
Create a folder: cd ~ && mkdir <rpm-name>-<version>
Example: cd ~ && mkdir rpm-with-sig-1.0
Move rpm-helper-signed.py into the folder.
Also create the gz file with same process.
Example:
tar cf rpm-with-sig-1.0.tar rpm-with-sig-1.0gzip rpm-with-sig-1.0.tarYou will get file rpm-with-sig-1.0.tar.gz.
Remove rpm-no-sig-1.0.tar.gz from SOURCES folder. Move rpm-with-sig-1.0.tar.gz into SOURCES.
Generate GPG key and Build rpm-with-sig.rpm
-
Generate a gpg key for signing the rpm:
gpg --gen-key -
Check the new keys on your system:
gpg --fingerprintgpg --list-keys-
Update ~/.rpmmacros to specify which key to be used for signing:
%_gpg_name <secret key's last 8 digits> -
Build the rpm:
rpmbuild -ba SPECS/rpm-with-sig.spec -
You will get
RPMS/noarch/rpm-with-sig-1.0-1.noarch.rpm -
Sign the rpm:
rpm --addsign RPMS/noarch/rpm-with-sig-1.0-1.noarch.rpm -
Now you can check MD5 again:
rpm -Kv <rpm file>Example:
# rpm -Kv ../rpm-with-sig-1.0-1.noarch.rpm../rpm-with-sig-1.0-1.noarch.rpm: Header V4 RSA/SHA1 Signature, key ID 1ddb39c6: NOKEY Header SHA1 digest: OK (64fc89cf3eb3054e6316a77f4b22c183221ab13d) V4 RSA/SHA1 Signature, key ID 1ddb39c6: NOKEY MD5 digest: OK (fadae5f41bb0c939edbe865a974fce4c)-
You might see “NOKEY” in above output, because we didn’t import the key into OS.
-
Export your key:
gpg --export -a <last_8_dig_of_your_pub_key> > PUB_KEY_SIGNING_RPM -
Import it into RPM’s database:
rpm --import PUB_KEY_SIGNING_RPM -
Now you can check MD5 again:
rpm -Kv rpm-with-sig-1.0-1.noarch.rpmExample:
# rpm -Kv ../rpm-with-sig-1.0-1.noarch.rpm../rpm-with-sig-1.0-1.noarch.rpm: Header V4 RSA/SHA1 Signature, key ID 1ddb39c6: OK Header SHA1 digest: OK (64fc89cf3eb3054e6316a77f4b22c183221ab13d) V4 RSA/SHA1 Signature, key ID 1ddb39c6: OK MD5 digest: OK (fadae5f41bb0c939edbe865a974fce4c)Creating repo database/conf for unsigned rpm
Create repo database for the rpm-no-sig rpm
cd ~mkdir unsigned_repo_with_rpm_no_sigcp rpm-no-sig-1.0-1.noarch.rpm unsigned_repo_with_rpm_no_sigcreaterepo --database unsigned_repo_with_rpm_no_sig/Example:
# createrepo --database unsigned_repo_with_rpm_no_sig/Spawning worker 0 with 1 pkgsSpawning worker 1 with 0 pkgsSpawning worker 2 with 0 pkgsSpawning worker 3 with 0 pkgsWorkers FinishedSaving Primary metadataSaving file lists metadataSaving other metadataGenerating sqlite DBsSqlite DBs completeCreate repo conf file for unsigned repo
# cat /etc/yum.repos.d/rpm-no-sig.repo[RPM-NO-SIG]name=rpm no sig repositorybaseurl=file:///root/unsigned_repo_with_rpm_no_sigenabled=1gpgcheck=0localpkg_gpgcheck=0repo_gpgcheck=0skip_if_unavailable=1Creating signed repo database/conf/gpg for signed rpm
Generate GPG key and Create repo for the rpm-with-sig rpm
cd ~mkdir signed_repo_with_rpm_with_sigcp rpm-with-sig-1.0-1.noarch.rpm signed_repo_with_rpm_with_sigcreaterepo --database signed_repo_with_rpm_with_sig/Generate a new gpg key for signing the repo: gpg --gen-key Create asc file:
gpg --detach-sign --armor -r Ox<secret key's last 8 digits fingerprint> signed_repo_with_rpm_with_sig/repodata/repomd.xmlIt will generate signed_repo_with_rpm_with_sig/repodata/repomd.xml.asc.
Create repo conf file for signed repo
# cat /etc/yum.repos.d/rpm-with-sig.repo[RPM-WITH-SIG]name=rpm with sig repositorybaseurl=file:///root/signed_repo_with_rpm_with_sigenabled=1gpgcheck=1localpkg_gpgcheck=1repo_gpgcheck=1skip_if_unavailable=1RPM/YUM relevant GPG knowlege
There are two types of GPG keyrings used on RPM-based systems:
-
RPM’s GPG keyring. This keyring is used for verifying signatures on RPM packages. This can be check by
gpgwithout specifyinghomedir. -
YUM’s GPG keyring. This keyring is used for verifying signatures on repository metadata. There is one keyring per repository on the system. Once scanned the repo by
yum repolist, you could find the gpg folder like this:/var/lib/yum/repos/x86_64/7/<your_repo_name>/gpgdir. You could usegpgcommandADD/LIST/DELETEkeys as below:
sudo gpg --homedir /var/lib/yum/repos/x86_64/7/<your_repo_name>/gpgdir --delete-key <keyid>YUM clean up
yum clean all will not remove everything. In order to do a real clean, you could try this:
yum clean allrm -fr /var/lib/yum/repos/x86_64/7/<your_repo_name>rm -fr /var/cache/yum/x86_64/7/<your_repo_name>Yum commands references
yum install <rpm name>yum install <path of the rpm>yum clean allyum clean metadatayum-config-manageryum-config-manager <rpm name>Q/A
Can’t remove keys from RPM due to duplicate entries
You might hit problem that there are duplicate entries in rpm -qa gpg-pub* with same fingerprints.
rpm -e gpg-pubkey-xxxx can’t remove any.
You should use rpm -e --all-matches gpg-pubkey-xxxx
All right!
That’s all for my sharing today!
Hope you find it useful!
Bye!