This guide walks through packaging a FlexLM license manager as an RPM on RHEL9, generating a FIPS-compliant GPG key to sign it, distributing the public key for verification, and wiring up a systemd service so the license daemon can start automatically.
Prerequisites
- A RHEL9 build host (does not need to be the same host the RPM will be instaled on) that is in FIPS mode
- Root or sudo access
- The FlexLM vendor daemon and lmgrd binaries
1. Install RPM Build Dependencies
sudo dnf install rpm-build rpmdevtools rpmlint gnupg2 systemd-rpm-macros
After installing the required development tools, create a standard build tree in your home directory to work out of.
rpmdev-setuptree
This creates ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
2. Generate a FIPS-Compliant GPG Signing Key
RHEL9’s FIPS mode restricts you to FIPS-approved primitives. For GPG, that means RSA keys and SHA-256 or stronger for digests.
Confirm FIPS status first:
fips-mode-setup --check
# This should return Enabled. Enable FIPS if not enabled.
Set your GPG preferences to enforce FIPS-approved algorithms before key generation. Create or edit ~/.gnupg/gpg.conf
mkdir -p ~/.gnupg && chmod 700 ~/.gnupg
cat >> ~/.gnupg/gpg.conf << 'EOF'
personal-digest-preferences SHA256
cert-digest-algo SHA256
default-preference-list SHA512 SHA384 SHA256 AES256 AES192 AES ZLIB BZIP2 ZIP Uncompressed
EOF
Now generate the key
gpg --full-generate-key
When prompted, chose the following:
- Key Type: RSA And RSA (Default)
- Key Size: 4096
- Expiration: 1-2 years is common
- Name/Email/Comment: Use identity tied to the packaging team
- Example: FlexLM Package Signing ([email protected])
- Passphrase: required, store it in a secrets manager for build credentials.
Verify the key was created with an approved algorithm and digest:
gpg --list-keys --with-colors | grep pub
gpg --edit-key "FlexLM Package Signing" showpref quit
You will want to see RSA4096 and SHA256/SHA512 in the output, not DSA or SHA-1.
3. Export and Distribute the Public Key
Export the public key so consuming systems can verify the RPM’s signature:
gpg --export -a "FlexLM Package Signing" > RPM-GPG-KEY-flexlm-packaging
On any system that will install the RPM, import the public key into the RPM database so rpm/dnf can validate the signature:
rpm --import RPM-GPG-KEY-flexlm-packaging
4. Configure rpmbuild to Sign With Your Key
Edit ~/.rpmmacros to add the following:
cat >> ~/.rpmmacros << EOF
%_signature gpg
%_gpg_name FlexLM Package Signing
%_gpg_path %{getenv:HOME}/.gnupg
%_gpgbin /usr/bin/gpg2
%__gpg_sign_cmd %{__gpg} gpg --batch --no-verbose --no-armor --digest-algo sha256 --pinentry-mode loopback --passphrase-fd 3 --no-secmem-warning -u "%{_gpg_name}" -sbo %{__signature_filename} %{__plaintext_filename}
EOF
The –digest-algo sha256 flag is the important part here because it forces the signature digest to a FIPS-approved algorithm redardless of the GPG’s defaults on the build host.
5. Stage the FlexLM Files
Lay out the source tree that the RPM package will need. A typical install looks like this:
mkdir -p ~/rpmbuild/SOURCES/flexlm-1.0/opt/flexlm/{bin,licenses,logs}
Copy in the vendor-supplied binaries and any supporting files.
cp lmgrd ~/rpmbuild/SOURCES/flexlm-1.0/opt/flexlm/bin/
cp vendor_daemon ~/rpmbuild/SOURCES/flexlm-1.0/opt/flexlm/bin/
chmod 755 ~/rpmbuild/SOURCES/flexlm-1.0/opt/flexlm/bin/*
Create the systemd unit file in the same staging tree so it gets packaged as source:
mkdir -p ~/rpmbuild/SOURCES/flexlm-1.0/systemd
cat > ~/rpmbuild/SOURCES/flexlm-1.0/systemd/flexlm.service << 'EOF'
[Unit]
Description=FlexLM License Manager
After=network.target
[Service]
Type=forking
ExecStart=/opt/flexlm/bin/lmgrd -c /opt/flexlm/licenses/license.dat -l /opt/flexlm/logs/lmgrd.log
ExecStop=/opt/flexlm/bin/lmutil lmdown -c /opt/flexlm/licenses/license.dat -q
Restart=on-failure
User=flexlm
Group=flexlm
[Install]
WantedBy=multi-user.target
EOF
Be sure to adjust the user and group fields to what service account will be used (do not run as root).
Tar it up so it matches what the spec file’s %prep stage expects:
cd ~/rpmbuild/SOURCES
tar czf flexlm-1.0.tar.gz flexlm-1.0
6. Write the Spec File
Create ~/rpmbuild/SPECS/flexlm.spec
Name: flexlm
Version: 1.0
Release: 1%{?dist}
Summary: FlexLM License Manager
License: Proprietary
URL: https://internal.example.com/packaging/flexlm
Source0: flexlm-1.0.tar.gz
BuildRequires: systemd-rpm-macros
Requires: systemd
Requires: glibc
Requires(pre): shadow-utils
%{?systemd_requires}
%description
Packages the FlexLM license manager (lmgrd and vendor daemon) along with
a systemd unit for automatic startup and management.
%prep
%setup -q
%install
mkdir -p %{buildroot}/opt/flexlm/{bin,licenses,logs}
mkdir -p %{buildroot}%{_unitdir}
cp -p opt/flexlm/bin/* %{buildroot}/opt/flexlm/bin/
cp -p opt/flexlm/licenses/* %{buildroot}/opt/flexlm/licenses/
install -m 644 systemd/flexlm.service %{buildroot}%{_unitdir}/flexlm.service
%pre
getent group flexlm >/dev/null || groupadd -r flexlm
getent passwd flexlm >/dev/null || useradd -r -g flexlm -d /opt/flexlm -s /sbin/nologin flexlm
%post
%systemd_post flexlm.service
%preun
%systemd_preun flexlm.service
%postun
%systemd_postun_with_restart flexlm.service
%files
%attr(755, flexlm, flexlm) /opt/flexlm/bin/*
%attr(644, flexlm, flexlm) /opt/flexlm/licenses/*
%dir %attr(755, flexlm, flexlm) /opt/flexlm/logs
%{_unitdir}/flexlm.service
%changelog
* Mon Aug 17 2026 Packaging Team <[email protected]> - 1.0-1
- Initial FlexLM RPM with systemd unit and FIPS-signed package
A few notes on this spec:
- %{?systemd_requires} and the %systemd_post/%systemd_preun/%systemd_postun_with_restart macros handle enabling, disabling, and restarting the unit correctly across install, upgrade, and removal, you don’t need to call systemctl by hand in the scriptlets
- %pre creates a dedicated system account so lmgrd never runs as root
- Adjust Requires: to match whatever runtime libraries your specific vendor daemon links against, check with ldd vendor_daemon on the build host if you’re not sure
7. Build the RPM
cd ~/rpmbuild/SPECS
rpmbuild -ba flexlm.spec
This produces both the binary RPM and SRPM under ~/rpmbuild/RPMS/x86_64/ and ~/rpmbuild/SRPMS/
Lint it before signing:
rpmlint ~/rpmbuild/RPMS/x86_64/flexlm-1.0-1.*.rpm
8. Sign the RPM
rpm --addsign ~/rpmbuild/RPMS/x86_64/flexlm-1.0-1.*.rpm
You’ll be prompted for the key’s passphrase. Since the ~/.rpmmacros config from Step 4 was already established, the resulting signature is FIPS-compliant.
9. Verify the Signature
On the build host or any system that has the imported key:
rpm -K ~/rpmbuild/RPMS/x86_64/flexlm-1.0-1.*.rpm
You should see something like rsa sha256 (md5) pgp md5 OK or similar, confirming both the digest and signature check pass. If the importing system hasn’t run rpm –import on your public key, this will report the signature as unknown.
10. Install and Enable the Service
sudo dnf install ~/rpmbuild/RPMS/x86_64/flexlm-1.0-1.*.rpm
sudo systemctl enable --now flexlm.service
sudo systemctl status flexlm.service
At this point, FlexLM is packaged, signed with a FIPS-approved key and digest, installable through your normal RPM tooling, and managed by systemd like any other service on the box, including automatic start on boot if you leave it enabled.
Closing Remarks
It’s fair to ask why you would go through all of this instead of just dropping the vendor binaries on a box and running lmgrd by hand. The short answer is that wrapping FlexLM in an RPM turns a one-off manual install into something that’s repeatable, auditable, and manageable at scale.
- Standardization. Every host gets FlexLM installed the same way, in the same location, owned by the same service account, with the same permissions. No drift between how one admin set it up versus another.
- Simplified updates and rollbacks. A new vendor daemon or license file becomes a version bump and a dnf update, not a manual copy-and-hope. rpm -q gives you an instant answer to what version is running where, and downgrading is just as clean if a new release causes problems.
- Consistent lifecycle management. The %pre, %post, %preun, and %postun scriptlets mean the service account, systemd unit, and file permissions get created, enabled, and cleaned up the same way every single time, whether it’s install, upgrade, or reomval.
- Signature Verification. Because the package is signed, anyone installing it can verify it came from your packaging process untampered.
- Easier compliance story. For FIPS and STIG-compliant environments, having a signed package with a documented build process is much easier to point to during an audit than “someone SCP’d the binaries over and ran a script”.