There are many aspects to reducing a Linux server's security risks. Protecting the integrity and confidentiality of data is certainly important, and it's also essential to ensure the system is configured properly to manage the server. One aspect of this configuration to consider is Secure Boot.
What is Secure Boot?
Secure Boot is a protocol that enables a safe and trusted path during the Linux boot process. It verifies that the code the firmware loads on a motherboard is the code that the user intends for the computer to load. In other words, it verifies that malicious code hasn't been inserted (by a rootkit or similar mechanism) in place of the kernel that the user has installed.
Secure Boot is part of the Unified Extensible Firmware Interface (UEFI). The protocol defines a process that prevents the loading of unsigned drivers, boot loaders, or kernel modules (or those with unacceptable digital signatures). When Secure Boot is enabled, system boot loaders, the Red Hat Enterprise Linux kernel, and all kernel modules must be cryptographically signed with a private key. This allows them to be authenticated with the corresponding public key.
Module signing makes it harder to load a suspicious module into the kernel. The kernel does the module signature verification. Module signing currently supports the RSA public key encryption standard. To check whether a system uses Secure Boot mode, use the mokutil
command:
$ mokutil --sb-state
Sign a kernel module
When signing a standalone kernel module, a public and private X.509 key pair is used to digitally sign kernel modules on a Secure Boot system. The private key is used to sign the kernel module, and the corresponding public key is added to the Secure Boot Machine Owner Key (MOK) to validate the signed module.
First, create a configuration file for key pair generation:
$ sudo cat << EOF >> x509.genkey
[ req ]
default_bits = 4096
distinguished_name = req_distinguished_name
prompt = no
x509_extensions = myexts
[ req_distinguished_name ]
O = ModuleType
CN = ModuleType module signing key
[ myexts ]
basicConstraints=critical,CA:FALSE
keyUsage=digitalSignature
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid
EOF
Create an X.509 public and private key pair using the openssl
command:
$ openssl req -x509 -new -nodes -utf8 -sha256 -days 36500 \
-batch -config x509.genkey -outform DER \
-out signing_key.x509 \
-keyout signing_key.priv
The signing_key.x509
file is the public key, and the signing_key.priv
is the private key.
Install the keys
Now that you have your key pair, you must add the public key to the MOK list:
$ mokutil --import signing_key.x509
Password: XXX
Now, reboot your system. When Linux boots on a UEFI-based system with Secure Boot enabled, the kernel imports the keys in the MOK list into the system keyring.
A list of choices is displayed:
Continue boot
Enroll MOK
…
[ Download the free guide to implementing DevSecOps. ]
Choose the Enroll MOK option. Next, a different list of choices is displayed:
View
Continue
Choose Continue
You're prompted to enroll the key. Choose Yes, enter the key password, and allow the system to reboot.
The system reboots, and the new key is added to the system keyring.
Query the system keyring
You can use the keyctl
and mokutil
commands to gather information about the key you added to your system's keyring:
$ sudo keyctl list %:.platform
1 key in keyring:
556121735: ---lswrv 0 0 asymmetric: Secure Boot CA 5: dd7e654ae88f…
You can display a more verbose variation of the information with:
$ mokutil -l
The kernel console output shows the keys loaded into the system keyring:
$ dmesg | grep 'integrity: Loaded
Sign a kernel module
If you develop original kernel modules, you must digitally sign them so that they can load into the kernel with modprobe
.
First, create a sample module and save it to a file called hello-1.c
:
/*
* hello-1.c - The simplest kernel module.
*/
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
MODULE_LICENSE ("GPL v2");
int init_module(void)
{
/* printk is the kernel message logging facility */
printk(KERN_INFO "Hello world 1.\n");
/* A non 0 return means init_module failed; module can't be loaded. */
return 0;
}
void cleanup_module(void)
{
printk(KERN_INFO "Goodbye world 1.\n");
}
Next, create a Makefile
for the hello-1.c
sample module:
obj-m += hello-1.o
all:
make -C /lib/modules/\$(shell uname -r)/build M=\$(PWD) modules
clean:
make -C /lib/modules/\$(shell uname -r)/build M=\$(PWD) clean
[ Find out about the new features in RHEL 9. ]
Now build the module:
$ make
Use the sign-file
utility to sign the module with the imported MOK key.
$ /usr/src/kernels/$(uname -r)/scripts/sign-file sha256 \
signing_key.priv \
signing_key.x509 \
my_module.ko
The sign-file
command computes and appends the signature directly to the ELF image in your kernel module file. You cannot display the signature with an ELF utility, but you can use the modinfo
utility to display information about your module's signature.
$ modinfo my_module.ko
filename: ~/kernel-module/hello-1.ko
license: GPL v2
rhelversion: 9.0
srcversion: 0ADA50D36BA76F1D1018A81
depends:
retpoline: Y
name: hello_1
vermagic: 5.14.0-70.5.1.el9_0.x86_64 SMP preempt mod_unload modversions
You can now load your hello-1.c
kernel module with the modprobe
command.
Sign a SystemTap module
SystemTap translates probes into C code, builds a module, and loads the resulting module into a running Linux kernel. On a Secure Boot system, you must sign the module. There are two methods for signing a SystemTap module. One method uses a SystemTap compile server, and the other does not use a compile server.
Sign a module without a compile server
Starting with SystemTap 4.7, you can sign a module without a compile server, which is similar to the standalone module method used above. The SystemTap command is stap
, and the option --sign-module
signs a module. If there is no SystemTap MOK key in the system MOK database, then SystemTap creates a key to be imported (using OpenSSL) and instructs you to reboot the system.
Create an X.509 public and private key pair:
$ sudo stap --sign-module -e 'probe syscall.read { printf("%s (%s)\n", name, argstr)}'
Generating an RSA private key
writing new private key to '/DIR/.systemtap/ssl/server/moks/stap-server.VGpxGW/signing_key.priv'
There is no machine owner key (MOK) in common with this system.
This command has failed because there's no MOK key pair available yet. That's normal when using stap
to generate a key pair because the MOK can't be set up until a key pair exists. You'll run the same command later after adding the MOK to the keychain.
Use the following command to import a MOK into this system:
$ sudo mokutil --import /DIR/.systemtap/ssl/server/moks/67:c4:f4:b1:f8:e5:01:de:a1:a0:a7:c3:09:94:b0:10:17:bb:97:e2/signing_key.x509
Reboot, and add the public key to the MOK list again:
$ sudo mokutil –import /DIR/.systemtap/ssl/server/moks/67:c4:f4:b1:f8:e5:01:de:a1:a0:a7:c3:09:94:b0:10:17:bb:97:e2/signing_key.x509
Add the key to the system keyring (as you did above).
Reboot your system and import the SystemTap key as prompted. When SystemTap is invoked again, the SystemTap module is signed and loaded:
$ sudo stap --sign-module -e 'probe syscall.read { printf("%s (%s)\n", name, argstr)}'
SystemTap keeps the SystemTap key used to sign the module in the directory /DIR/.systemtap/ssl/server/moks/{FINGERPRINT}/
(where {FINGERPRINT}
is the actual fingerprint you see listed, such as f3:9e:bb:a5:cb:78:9f:1a:da:e9:0c:a5:3d:a4:cf:6e:a1:a3:79:7b
). You can see the public key with the openssl
command:
$ sudo openssl x509 -text -inform der -in
/DIR/.systemtap/ssl/server/moks/<FINGERPRINT>/signing_key.x509
You can use keyctl
or mokutil
to see the system keyring.
Sign a module with a compile server
You can also use the SystemTap compile server (you can read about it with man stap-server
) to sign a module. The SystemTap compile server listens for connections from stap clients on a secure SSL network port and accepts requests to run the stap
frontend to build SystemTap modules. The client sends the server a list of the SystemTap keys in the system keyring. If there is no matching SystemTap key, then your computer prompts you to import the key and reboot.
Create an X.509 public and private key pair:
$ stap --list-servers=all
Systemtap Compile Server Status for 'all'
host=fedora 35.local address=192.168.122.127 port=1234 sysinfo="5.14.10-300.fc35.x86_64 x86_64" version=4.7 certinfo="00:bb:39:5d:75" mok_fingerprints="f2:b8:48:74:d6:38:f3:90:a1:bd:2f:da:bf:dd:3b:93:fd:c3:de:b7
$ stap -e 'probe begin {println("Hello From Server");exit()}' \
--use-server=fedora 35:1234
Server: No matching machine owner key (MOK) available on the server to sign the module.
Server: The server has no machine owner key (MOK) in common with this
system. Use the following command to import a server MOK into this
system, then reboot:
$ sudo mokutil --import signing_key.x509
Add the public key to the MOK list as instructed:
$ sudo mokutil –import signing_key.x509
Add the key to your system keyring, and then reboot. Import the SystemTap key when prompted.
If there is a matching SystemTap key, the compile server builds and signs the module, which SystemTap runs on the client system:
$ stap -e 'probe begin {println("Hello From Server");exit()}' \
--use-server=fedora 35:1234`
Hello From Server
Know your binaries
Digitally signing files is an excellent way to verify the identity of binaries that need to run on your system. With signature verification, it's not an option for an attacker to swap out an important module just by giving it the correct name and placing it in the right location. Consider whether to start using Secure Boot on your systems and digitally sign your work.
About the author
Stan Cox works in Red Hat's platform tools group on performance tools,
primarily SystemTap and Dyninst. Stan came to Red Hat when it
acquired Cygnus, where he worked on the gcc compiler.
More like this
Browse by channel
Automation
The latest on IT automation for tech, teams, and environments
Artificial intelligence
Updates on the platforms that free customers to run AI workloads anywhere
Open hybrid cloud
Explore how we build a more flexible future with hybrid cloud
Security
The latest on how we reduce risks across environments and technologies
Edge computing
Updates on the platforms that simplify operations at the edge
Infrastructure
The latest on the world’s leading enterprise Linux platform
Applications
Inside our solutions to the toughest application challenges
Original shows
Entertaining stories from the makers and leaders in enterprise tech
Products
- Red Hat Enterprise Linux
- Red Hat OpenShift
- Red Hat Ansible Automation Platform
- Cloud services
- See all products
Tools
- Training and certification
- My account
- Customer support
- Developer resources
- Find a partner
- Red Hat Ecosystem Catalog
- Red Hat value calculator
- Documentation
Try, buy, & sell
Communicate
About Red Hat
We’re the world’s leading provider of enterprise open source solutions—including Linux, cloud, container, and Kubernetes. We deliver hardened solutions that make it easier for enterprises to work across platforms and environments, from the core datacenter to the network edge.
Select a language
Red Hat legal and privacy links
- About Red Hat
- Jobs
- Events
- Locations
- Contact Red Hat
- Red Hat Blog
- Diversity, equity, and inclusion
- Cool Stuff Store
- Red Hat Summit