Chapter 22. Enhancing security with the kernel integrity subsystem
You can increase the protection of your system by utilizing components of the kernel integrity subsystem. The following sections introduce the relevant components and provide guidance on their configuration.
22.1. The kernel integrity subsystem
The integrity subsystem is a part of the kernel which is responsible for maintaining the overall system’s data integrity. This subsystem helps to keep the state of a certain system the same from the time it was built thereby it prevents undesired modification on specific system files from users.
The kernel integrity subsystem consists of two major components:
- Integrity Measurement Architecture (IMA)
- Measures files' content whenever it is executed or opened. Users can change this behavior by applying custom policies.
- Places the measured values within the kernel’s memory space thereby it prevents any modification from the users of the system.
- Allows local and remote parties to verify the measured values.
- Extended Verification Module (EVM)
- Protects files' extended attributes (also known as xattr) that are related to the system’s security, like IMA measurements and SELinux attributes, by cryptographically hashing their corresponding values.
Both IMA and EVM also contain numerous feature extensions that bring additional functionality. For example:
- Provides local validation of the current file’s content against the values previously stored in the measurement file within the kernel memory. This extension forbids any operation to be performed over a specific file in case the current and the previous measure do not match.
- EVM Digital Signatures
- Allows digital signatures to be used through cryptographic keys stored into the kernel’s keyring.
The feature extensions complement each other, but you can configure and use them independently of one another.
The kernel integrity subsystem can harness the Trusted Platform Module (TPM) to harden the system security even more. TPM is a specification by the Trusted Computing Group (TCG) for important cryptographic functions. TPMs are usually built as dedicated hardware that is attached to the platform’s motherboard and prevents software-based attacks by providing cryptographic functions from a protected and tamper-proof area of the hardware chip. Some of the TPM features are:
- Random-number generator
- Generator and secure storage for cryptographic keys
- Hashing generator
- Remote attestation
22.2. Integrity measurement architecture
Integrity Measurement Architecture (IMA) is a component of the kernel integrity subsystem. IMA aims to maintain the contents of local files. Specifically, IMA measures, stores, and appraises files' hashes before they are accessed, which prevents the reading and execution of unreliable data. Thereby, IMA enhances the security of the system.
22.3. Extended verification module
Extended Verification Module (EVM) is a component of the kernel integrity subsystem, which monitors changes in files' extended attributes (xattr). Many security-oriented technologies, including Integrity Measurement Architecture (IMA), store sensitive file information, such as content hashes, in the extended attributes. EVM creates another hash from these extended attributes and from a special key, which is loaded at boot time. The resulting hash is validated every time the extended attribute is used. For example, when IMA appraises the file.
RHEL 9 accepts the special encrypted key under the
evm-key keyring. The key was created by a master key held in the kernel keyrings.
22.4. Trusted and encrypted keys
The following section introduces trusted and encrypted keys as an important part of enhancing system security.
Trusted and encrypted keys are variable-length symmetric keys generated by the kernel that utilize the kernel keyring service. The fact that this type of keys never appear in the user space in an unencrypted form means that their integrity can be verified, which in turn means that they can be used, for example, by the extended verification module (EVM) to verify and confirm the integrity of a running system. User-level programs can only access the keys in the form of encrypted blobs.
Trusted keys need a hardware component: the Trusted Platform Module (TPM) chip, which is used to both create and encrypt (seal) the keys. The TPM seals the keys using a 2048-bit RSA key called the storage root key (SRK).
To use a TPM 1.2 specification, enable and activate it through a setting in the machine firmware or by using the
tpm_setactive command from the
tpm-tools package of utilities. Also, the
TrouSers software stack needs to be installed and the
tcsd daemon needs to be running to communicate with the TPM (dedicated hardware). The
tcsd daemon is part of the
TrouSers suite, which is available through the
trousers package. The more recent and backward incompatible TPM 2.0 uses a different software stack, where the
ibm-tss utilities provide access to the dedicated hardware.
In addition to that, the user can seal the trusted keys with a specific set of the TPM’s platform configuration register (PCR) values. PCR contains a set of integrity-management values that reflect the firmware, boot loader, and operating system. This means that PCR-sealed keys can only be decrypted by the TPM on the same system on which they were encrypted. However, once a PCR-sealed trusted key is loaded (added to a keyring), and thus its associated PCR values are verified, it can be updated with new (or future) PCR values, so that a new kernel, for example, can be booted. A single key can also be saved as multiple blobs, each with different PCR values.
Encrypted keys do not require a TPM, as they use the kernel Advanced Encryption Standard (AES), which makes them faster than trusted keys. Encrypted keys are created using kernel-generated random numbers and encrypted by a master key when they are exported into user-space blobs. The master key is either a trusted key or a user key. If the master key is not trusted, the encrypted key is only as secure as the user key used to encrypt it.
22.5. Working with trusted keys
The following section describes how to create, export, load or update trusted keys with the
keyctl utility to improve the system security.
For the 64-bit ARM architecture and IBM Z, the
trustedkernel module needs to be loaded. For more information on how to load kernel modules, see Managing kernel modules.
- Trusted Platform Module (TPM) needs to be enabled and active. For more information about TPM see, The kernel integrity subsystem and Trusted and encrypted keys.
To create a trusted key using a TPM, execute:
# keyctl add trusted <name> "new <key_length> [options]" <key_ring>
Based on the syntax, construct an example command as follows:
# keyctl add trusted kmk "new 32" @u 642500861
The command creates a trusted key called
kmkwith the length of 32 bytes (256 bits) and places it in the user keyring (
@u). The keys may have a length of 32 to 128 bytes (256 to 1024 bits).
To list the current structure of the kernel keyrings:
# keyctl show Session Keyring -3 --alswrv 500 500 keyring: _ses 97833714 --alswrv 500 -1 \_ keyring: _uid.1000 642500861 --alswrv 500 500 \_ trusted: kmk
To export the key to a user-space blob, execute:
# keyctl pipe 642500861 > kmk.blob
The command uses the
pipesubcommand and the serial number of
To load the trusted key from the user-space blob, use the
addsubcommand with the blob as an argument:
# keyctl add trusted kmk "load `cat kmk.blob`" @u 268728824
Create secure encrypted keys based on the TPM-sealed trusted key:
# keyctl add encrypted <pass:quotes[name]> "new [format] <pass:quotes[key_type]>:<pass:quotes[primary_key_name]> <pass:quotes[keylength]>" <pass:quotes[key_ring]>
Based on the syntax, generate an encrypted key using the already created trusted key:
# keyctl add encrypted encr-key "new trusted:kmk 32" @u 159771175
The command uses the TPM-sealed trusted key (
kmk), produced in the previous step, as a primary key for generating encrypted keys.
22.6. Working with encrypted keys
The following section describes managing encrypted keys to improve the system security on systems where a Trusted Platform Module (TPM) is not available.
For the 64-bit ARM architecture and IBM Z, the
encrypted-keyskernel module needs to be loaded. For more information on how to load kernel modules, see Managing kernel modules.
Use a random sequence of numbers to generate a user key:
# keyctl add user kmk-user "$(dd if=/dev/urandom bs=1 count=32 2>/dev/null)" @u 427069434
The command generates a user key called
kmk-userwhich acts as a primary key and is used to seal the actual encrypted keys.
Generate an encrypted key using the primary key from the previous step:
# keyctl add encrypted encr-key "new user:kmk-user 32" @u 1012412758
Optionally, list all keys in the specified user keyring:
# keyctl list @u 2 keys in keyring: 427069434: --alswrv 1000 1000 user: kmk-user 1012412758: --alswrv 1000 1000 encrypted: encr-key
Keep in mind that encrypted keys that are not sealed by a trusted primary key are only as secure as the user primary key (random-number key) that was used to encrypt them. Therefore, the primary user key should be loaded as securely as possible and preferably early during the boot process.
- Kernel Key Retention Service
22.7. Enabling integrity measurement architecture and extended verification module
Integrity measurement architecture (IMA) and extended verification module (EVM) belong to the kernel integrity subsystem and enhance the system security in various ways. The following section describes how to enable and configure IMA and EVM to improve the security of the operating system.
Verify that the
securityfsfilesystem is mounted on the
/sys/kernel/security/directory and the
# mount … securityfs on /sys/kernel/security type securityfs (rw,nosuid,nodev,noexec,relatime) …
Verify that the
systemdservice manager is already patched to support IMA and EVM on boot time:
# dmesg | grep -i -e EVM -e IMA [ 0.000000] Command line: BOOT_IMAGE=(hd0,msdos1)/vmlinuz-5.14.0-1.el9.x86_64 root=/dev/mapper/rhel-root ro crashkernel=auto resume=/dev/mapper/rhel-swap rd.lvm.lv=rhel/root rd.lvm.lv=rhel/swap rhgb quiet [ 0.000000] kvm-clock: cpu 0, msr 23601001, primary cpu clock [ 0.000000] Using crashkernel=auto, the size chosen is a best effort estimation. [ 0.000000] Kernel command line: BOOT_IMAGE=(hd0,msdos1)/vmlinuz-5.14.0-1.el9.x86_64 root=/dev/mapper/rhel-root ro crashkernel=auto resume=/dev/mapper/rhel-swap rd.lvm.lv=rhel/root rd.lvm.lv=rhel/swap rhgb quiet [ 0.911527] ima: No TPM chip found, activating TPM-bypass! [ 0.911538] ima: Allocated hash algorithm: sha1 [ 0.911580] evm: Initialising EVM extended attributes: [ 0.911581] evm: security.selinux [ 0.911581] evm: security.ima [ 0.911582] evm: security.capability [ 0.911582] evm: HMAC attrs: 0x1 [ 1.715151] systemd: systemd 239 running in system mode. (+PAM +AUDIT +SELINUX +IMA -APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD +IDN2 -IDN +PCRE2 default-hierarchy=legacy) [ 3.824198] fbcon: qxldrmfb (fb0) is primary device [ 4.673457] PM: Image not found (code -22) [ 6.549966] systemd: systemd 239 running in system mode. (+PAM +AUDIT +SELINUX +IMA -APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD +IDN2 -IDN +PCRE2 default-hierarchy=legacy)
Add the following kernel command line parameters:
# grubby --update-kernel=/boot/vmlinuz-$(uname -r) --args="ima_policy=appraise_tcb ima_appraise=fix evm=fix"
The command enables IMA and EVM in the fix mode for the current boot entry and allows users to gather and update the IMA measurements.
ima_policy=appraise_tcbkernel command line parameter ensures that the kernel uses the default Trusted Computing Base (TCB) measurement policy and the appraisal step. The appraisal part forbids access to files, whose prior and current measures do not match.
- Reboot to make the changes come into effect.
- Optionally, verify that the parameters have been added to the kernel command line:
# cat /proc/cmdline BOOT_IMAGE=(hd0,msdos1)/vmlinuz-5.14.0-1.el9.x86_64 root=/dev/mapper/rhel-root ro crashkernel=auto resume=/dev/mapper/rhel-swap rd.lvm.lv=rhel/root rd.lvm.lv=rhel/swap rhgb quiet ima_policy=appraise_tcb ima_appraise=fix evm=fix
Create a kernel master key to protect the EVM key:
# keyctl add user kmk "$(dd if=/dev/urandom bs=1 count=32 2> /dev/null)" @u 748544121
The kernel master key (
kmk) is kept entirely in the kernel space memory. The 32-byte long value of the kernel master key
kmkis generated from random bytes from the
/dev/urandomfile and placed in the user (
@u) keyring. The key serial number is on the second line of the previous output.
Create an encrypted EVM key based on the
# keyctl add encrypted evm-key "new user:kmk 64" @u 641780271
The command uses
kmkto generate and encrypt a 64-byte long user key (named
evm-key) and places it in the user (
@u) keyring. The key serial number is on the second line of the previous output.Important
It is necessary to name the user key as evm-key because that is the name the EVM subsystem is expecting and is working with.
Create a directory for exported keys:
# mkdir -p /etc/keys/
Search for the
kmkkey and export its value into a file:
# keyctl pipe $(keyctl search @u user kmk) > /etc/keys/kmk
The command places the unencrypted value of the kernel master key (
kmk) into a file of previously defined location (
Search for the
evm-keyuser key and export its value into a file:
# keyctl pipe $(keyctl search @u encrypted evm-key) > /etc/keys/evm-key
The command places the encrypted value of the user
evm-keykey into a file of arbitrary location. The
evm-keyhas been encrypted by the kernel master key earlier.
Optionally, view the newly created keys:
# keyctl show Session Keyring 974575405 --alswrv 0 0 keyring: _ses 299489774 --alswrv 0 65534 \_ keyring: _uid.0 748544121 --alswrv 0 0 \_ user: kmk 641780271 --alswrv 0 0 \_ encrypted: evm-key
You should be able to see a similar output.
# echo 1 > /sys/kernel/security/evm
Optionally, verify that EVM has been initialized:
# dmesg | tail -1 […] evm: key initialized
22.8. Collecting file hashes with integrity measurement architecture
The first level of operation of integrity measurement architecture (IMA) is the measurement phase, which allows to create file hashes and store them as extended attributes (xattrs) of those files. The following section describes how to create and inspect the files' hashes.
- Enable integrity measurement architecture (IMA) and extended verification module (EVM) as described in Enabling integrity measurement architecture and extended verification module.
Verify that the
keyutilspackages are already installed:
# yum install ima-evm-utils attr keyutils Updating Subscription Management repositories. This system is registered to Red Hat Subscription Management, but is not receiving updates. You can use subscription-manager to assign subscriptions. Last metadata expiration check: 0:58:22 ago on Fri 14 Feb 2020 09:58:23 AM CET. Package ima-evm-utils-1.1-5.el8.x86_64 is already installed. Package attr-2.4.48-3.el8.x86_64 is already installed. Package keyutils-1.5.10-7.el8.x86_64 is already installed. Dependencies resolved. Nothing to do. Complete!
Create a test file:
# echo <Test_text> > test_file
IMA and EVM ensure that the example file
test_fileis assigned hash values, which are stored as its extended attributes.
Inspect extended attributes of the file:
# getfattr -m . -d test_file # file: test_file security.evm=0sAnDIy4VPA0HArpPO/EqiutnNyBql security.ima=0sAQOEDeuUnWzwwKYk+n66h/vby3eD security.selinux="unconfined_u:object_r:admin_home_t:s0"
The previous example output shows extended attributes related to SELinux and the IMA and EVM hash values. EVM actively adds a
security.evmextended attribute and detects any offline tampering to xattrs of other files such as
security.imathat are directly related to content integrity of files. The value of the
security.evmfield is in Hash-based Message Authentication Code (HMAC-SHA1), which was generated with the