Chapter 23. Enhancing security with the kernel integrity subsystem You can improve the protection of your system by using components of the kernel integrity subsystem. Learn more about the relevant components and their configuration. Note Red Hat products distributed through methods such as RPMs, ISOs, and zip files are signed with cryptographic signatures. The RHEL Kernel keyring system includes certificates for Red Hat product signing keys only. Therefore, to ensure kernels are tamper-proof, you must not use other hash features. 23.1. The kernel integrity subsystem The integrity subsystem is the kernel component that maintains the overall integrity of system data. This subsystem helps in maintaining the system in the same state from the time it was built. Using this subsystem, you can protect executable files, libraries, and configuration files. The kernel integrity subsystem consists of two major components: Integrity Measurement Architecture (IMA) IMA measures file content whenever it is executed or accessed by cryptographically hashing or signing with cryptographic keys. The keys are stored in the kernel keyring subsystem. IMA places the measured values within the kernel's memory space. This prevents users of the system from modifying the measured values. IMA allows local and remote parties to verify the measured values. IMA provides local validation of the current content of files against the values previously stored in the measurement list within the kernel memory. This extension forbids performing any operation on a specific file in case the current and the measures do not match. Extended Verification Module (EVM) EVM protects extended attributes of files (also known as xattr ) related to system security, such as IMA measurements and SELinux attributes. EVM cryptographically hashes their corresponding values or signs them with cryptographic keys. The keys are stored in the kernel keyring subsystem. The kernel integrity subsystem can use the Trusted Platform Module (TPM) to further harden system security. A TPM is a hardware, firmware, or virtual component with integrated cryptographic keys that are built according to the TPM specification by the Trusted Computing Group (TCG) for important cryptographic functions. By providing cryptographic functions from a protected and tamper-proof area of the hardware chip, TPMs are protected from software-based attacks. TPMs provide the following features: Random-number generator Generator and secure storage for cryptographic keys Hashing generator Remote attestation Additional resources Security hardening Basic and advanced configuration of Security-Enhanced Linux (SELinux) 23.2. Trusted and encrypted keys Trusted keys and encrypted keys are an important part of enhancing system security. Trusted and encrypted keys are variable-length symmetric keys generated by the kernel that use the kernel keyring service. You can verify the integrity of the keys, for example, to allow 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 Trusted keys need the Trusted Platform Module (TPM) chip, which is used to both create and encrypt (seal) the keys. Each TPM has a master wrapping key, called the storage root key, which is stored within the TPM itself. Note RHEL 9 supports only TPM 2.0. If you must use TPM 1.2, use RHEL 8. For more information, see the Red Hat Knowledgebase solution Is Trusted Platform Module (TPM) supported by Red Hat? . You can verify the status of TPM 2.0 chip: You can also enable a TPM 2.0 chip and manage the TPM 2.0 device through settings in the machine firmware. In addition to that, you 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. PCR-sealed keys can only be decrypted by the TPM on the system where they were encrypted. However, when you load a PCR-sealed trusted key to a keyring, its associated PCR values are verified. After verification, you can update the key with new or future PCR values, for example, to support booting a new kernel. Also, you can save a single key as multiple blobs, each with a different PCR value. Encrypted keys Encrypted keys do not require a TPM, because 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 security of the encrypted key depends on the user key that was used to encrypt it. 23.3. Working with trusted keys You can improve system security by using the keyctl utility to create, export, load and update trusted keys. Prerequisites Trusted Platform Module (TPM) is enabled and active. See The kernel integrity subsystem and Trusted and encrypted keys . You can verify that your system has a TPM by entering the tpm2_pcrread command. If the output from this command displays several hashes, you have a TPM. Procedure Create a 2048-bit RSA key with an SHA-256 primary storage key with a persistent handle of, for example, 81000001 , by using one of the following utilities: By using the tss2 package: By using the tpm2-tools package: Create a trusted key by using a TPM 2.0 with the syntax of keyctl add trusted <NAME> "new <KEY_LENGTH> keyhandle= <PERSISTENT-HANDLE> [options]" <KEYRING> . In this example, the persistent handle is 81000001 . The command creates a trusted key called kmk with 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). List the current structure of the kernel keyrings: Export the key to a user-space blob by using the serial number of the trusted key: The command uses the pipe subcommand and the serial number of kmk . Load the trusted key from the user-space blob: Create secure encrypted keys that use the TPM-sealed trusted key ( kmk ). Follow this syntax: keyctl add encrypted <NAME> "new [FORMAT] <KEY_TYPE>:<PRIMARY_KEY_NAME> <KEY_LENGTH>" <KEYRING> : Additional resources the keyctl(1) manual page 23.4. Working with encrypted keys You can improve system security on systems where a Trusted Platform Module (TPM) is not available by managing encrypted keys. Encrypted keys, unless sealed by a trusted primary key, inherit the security level of the user primary key (random-number key) used for encryption. Therefore, it is highly recommended to load the primary user key securely, ideally early in the boot process. Procedure Generate a user key by using a random sequence of numbers: The command generates a user key called kmk-user which acts as a primary key and is used to seal the actual encrypted keys. Generate an encrypted key using the primary key from the step: Verification List all keys in the specified user keyring: Additional resources The keyctl(1) manual page 23.5. Enabling IMA and EVM You can enable and configure Integrity measurement architecture (IMA) and extended verification module (EVM) to improve the security of the operating system. Important Always enable EVM together with IMA. Although you can enable EVM alone, EVM appraisal is only triggered by an IMA appraisal rule. Therefore, EVM does not protect file metadata such as SELinux attributes. If file metadata is tampered with offline, EVM can only prevent file metadata changes. It does not prevent file access, such as executing the file. Prerequisites Secure Boot is temporarily disabled. Note When Secure Boot is enabled, the ima_appraise=fix kernel command-line parameter does not work. The securityfs file system is mounted on the /sys/kernel/security/ directory and the /sys/kernel/security/integrity/ima/ directory exists. You can verify where securityfs is mounted by using the mount command: The systemd service manager is patched to support IMA and EVM on boot time. Verify by using the following command: For example: Procedure Enable IMA and EVM in the fix mode for the current boot entry and allow users to gather and update the IMA measurements by adding the following kernel command-line parameters: The command enables IMA and EVM in the fix mode for the current boot entry to gather and update the IMA measurements. The ima_policy=appraise_tcb kernel command-line parameter ensures that the kernel uses the default Trusted Computing Base (TCB) measurement policy and the appraisal step. The appraisal step forbids access to files whose prior and current measures do not match. Reboot to make the changes come into effect. Optional: Verify the parameters added to the kernel command line: Create a kernel master key to protect the EVM key: The kmk is kept entirely in the kernel space memory. The 32-byte long value of the kmk is generated from random bytes from the /dev/urandom file and placed in the user ( @u ) keyring. The key serial number is on the first line of the output. Create an encrypted EVM key based on the kmk : The command uses the kmk to 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 first line of the 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. Search for the kmk and export its unencrypted value into the new directory. Search for the evm-key and export its encrypted value into the new directory. The evm-key has been encrypted by the kernel master key earlier. Optional: View the newly created keys: Optional: If the keys are removed from the keyring, for example after system reboot, you can import the already exported kmk and evm-key instead of creating new ones. Import the kmk . Import the evm-key . Activate EVM. Relabel the whole system. Warning Enabling IMA and EVM without relabeling the system might make the majority of the files on the system inaccessible. Verification Verify that EVM has been initialized: 23.6. Collecting file hashes with integrity measurement architecture In the measurement phase, you can create file hashes and store them as extended attributes ( xattrs ) of those files. With the file hashes, you can generate either an RSA-based digital signature or a Hash-based Message Authentication Code (HMAC-SHA1) and prevent offline tampering attacks on the extended attributes. Prerequisites IMA and EVM are enabled. For more information, see Enabling integrity measurement architecture and extended verification module . A valid trusted key or encrypted key is stored in the kernel keyring. The ima-evm-utils , attr , and keyutils packages are installed. Procedure Create a test file: IMA and EVM ensure that the test_file example file has assigned hash values that are stored as its extended attributes. Inspect the file's extended attributes: The example output shows extended attributes with the IMA and EVM hash values and SELinux context. EVM adds a security.evm extended attribute related to the other attributes. At this point, you can use the evmctl utility on security.evm to generate either an RSA-based digital signature or a Hash-based Message Authentication Code (HMAC-SHA1). Additional resources Security hardening 23.7. Adding IMA signatures to package files To allow the kernel, Keylime, fapolicyd , and debuginfo packages to perform their integrity checks, you need to add IMA signatures to RPM files. After installing the rpm-plugin-ima plug-in, newly installed RPM files automatically have IMA signatures placed in the security.ima extended file attribute. However, you need to reinstall existing packages to obtain IMA signatures. Procedure Install the rpm-plugin-ima plug-in: Reinstall all packages: Verification Confirm that the reinstalled package file has a valid IMA signature. For example, to check the IMA signature of the /usr/bin/bash file, run the following command: Verify the IMA signature of a file with a specified certificate. For example, to check that the IMA signature of /usr/bin/bash is accessible by /usr/share/doc/kernel-keys/USD(uname -r)/ima.cer , run the following command:". 23.8. Enabling kernel runtime integrity monitoring You can enable kernel runtime integrity monitoring that IMA appraisal provides. Prerequisites The kernel installed on your system has version 5.14.0-359 or higher. The dracut package has version 057-43.git20230816 or higher. The keyutils package is installed. The ima-evm-utils package is installed. The files covered by the policy have valid signatures. For instructions, see Adding IMA signatures to package files . Procedure To copy the Red Hat IMA code signing key to the /etc/ima/keys file, run: To add the IMA code signing key to the .ima keyring, run: Depending on your threat model, define an IMA policy in the /etc/sysconfig/ima-policy file. For example, the following IMA policy checks the integrity of both executables and involved memory mapping library files: To load the IMA policy to make sure the kernel accepts this IMA policy, run: To enable the dracut integrity module to automatically load the IMA code signing key and the IMA policy, run: 23.9. Creating custom IMA keys using OpenSSL You can use OpenSSL to generate a CSR for your digital certificates to secure your code. The kernel searches the .ima keyring for a code signing key to verify an IMA signature. Before you add a code signing key to the .ima keyring, you need to ensure that IMA CA key signed this key in the .builtin_trusted_keys or .secondary_trusted_keys keyrings. Prerequisites The custom IMA CA key has the following extensions: the basic constraints extension with the CA boolean asserted. the KeyUsage extension with the keyCertSign bit asserted but without the digitalSignature asserted. The custom IMA code signing key falls under the following criteria: The IMA CA key signed this custom IMA code signing key. The custom key includes the subjectKeyIdentifier extension. Procedure To generate a custom IMA CA key pair, run: Optional: To check the content of the ima_ca.conf file, run: To generate a private key and a certificate signing request (CSR) for the IMA code signing key, run: Optional: To check the content of the ima.conf file, run: Use the IMA CA private key to sign the CSR to create the IMA code signing certificate: 23.10. Deploying a custom signed IMA policy for UEFI systems In the Secure Boot environment, you may want to only load a signed IMA policy signed by your custom IMA key. Prerequisites The MOK list contains the custom IMA key. For guidance, see Enrolling public key on target system by adding the public key to the MOK list . The kernel installed on your system has version 5.14.0-335 or higher. Procedure Enable Secure Boot. Permanently add the ima_policy=secure_boot kernel parameter. For instructions, see Configuring kernel parameters permanently with sysctl . Prepare your IMA policy by running the command: Sign the policy with your custom IMA code signing key by running the command: Load the IMA policy by running the command:

Commands:
cat /sys/class/tpm/tpm0/tpm_version_major 2
TPM_DEVICE=/dev/tpm0 tsscreateprimary -hi o -st Handle 80000000 TPM_DEVICE=/dev/tpm0 tssevictcontrol -hi o -ho 80000000 -hp 81000001
tpm2_createprimary --key-algorithm=rsa2048 --key-context=key.ctxt name-alg: value: sha256 raw: 0xb ... sym-keybits: 128 rsa: xxxxxx... tpm2_evictcontrol -c key.ctxt 0x81000001 persistentHandle: 0x81000001 action: persisted
keyctl add trusted kmk "new 32 keyhandle=0x81000001" @u 642500861
keyctl show Session Keyring -3 --alswrv 500 500 keyring: ses 97833714 --alswrv 500 -1 \ keyring: uid.1000 642500861 --alswrv 500 500 \ trusted: kmk
keyctl pipe 642500861 > kmk.blob
keyctl add trusted kmk "load `cat kmk.blob`" @u 268728824
keyctl add encrypted encr-key "new trusted:kmk 32" @u 159771175
keyctl add user kmk-user "USD(dd if=/dev/urandom bs=1 count=32 2>/dev/null)" @u 427069434
keyctl add encrypted encr-key "new user:kmk-user 32" @u 1012412758
keyctl list @u 2 keys in keyring: 427069434: --alswrv 1000 1000 user: kmk-user 1012412758: --alswrv 1000 1000 encrypted: encr-key
mount securityfs on /sys/kernel/security type securityfs (rw,nosuid,nodev,noexec,relatime)
grep < options > pattern < files >
dmesg | grep -i -e EVM -e IMA -w [ 0.943873] ima: No TPM chip found, activating TPM-bypass! [ 0.944566] ima: Allocated hash algorithm: sha256 [ 0.944579] ima: No architecture policies found [ 0.944601] evm: Initialising EVM extended attributes: [ 0.944602] evm: security.selinux [ 0.944604] evm: security.SMACK64 (disabled) [ 0.944605] evm: security.SMACK64EXEC (disabled) [ 0.944607] evm: security.SMACK64TRANSMUTE (disabled) [ 0.944608] evm: security.SMACK64MMAP (disabled) [ 0.944609] evm: security.apparmor (disabled) [ 0.944611] evm: security.ima [ 0.944612] evm: security.capability [ 0.944613] evm: HMAC attrs: 0x1 [ 1.314520] systemd[1]: systemd 252-18.el9 running in system mode (+PAM +AUDIT +SELINUX -APPARMOR +IMA +SMACK +SECCOMP +GCRYPT +GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS -FIDO2 +IDN2 -IDN -IPTC +KMOD +LIBCRYPTSETUP +LIBFDISK +PCRE2 -PWQUALITY +P11KIT -QRENCODE +TPM2 +BZIP2 +LZ4 +XZ +ZLIB +ZSTD -BPF_FRAMEWORK +XKBCOMMON +UTMP +SYSVINIT default-hierarchy=unified) [ 1.717675] device-mapper: core: CONFIG_IMA_DISABLE_HTABLE is disabled. Duplicate IMA measurements will not be recorded in the IMA log. [ 4.799436] systemd[1]: systemd 252-18.el9 running in system mode (+PAM +AUDIT +SELINUX -APPARMOR +IMA +SMACK +SECCOMP +GCRYPT +GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS -FIDO2 +IDN2 -IDN -IPTC +KMOD +LIBCRYPTSETUP +LIBFDISK +PCRE2 -PWQUALITY +P11KIT -QRENCODE +TPM2 +BZIP2 +LZ4 +XZ +ZLIB +ZSTD -BPF_FRAMEWORK +XKBCOMMON +UTMP +SYSVINIT default-hierarchy=unified)
grubby --update-kernel=/boot/vmlinuz-USD(uname -r) --args="ima_policy=appraise_tcb ima_appraise=fix evm=fix"
cat /proc/cmdline BOOT_IMAGE=(hd0,msdos1)/vmlinuz-5.14.0-1.el9.x86_64 root=/dev/mapper/rhel-root ro crashkernel=1G-4G:192M,4G-64G:256M,64G-:512M 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
keyctl add user kmk "USD(dd if=/dev/urandom bs=1 count=32 2> /dev/null)" @u 748544121
keyctl add encrypted evm-key "new user:kmk 64" @u 641780271
mkdir -p /etc/keys/
keyctl pipe USD(keyctl search @u user kmk) > /etc/keys/kmk
keyctl pipe USD(keyctl search @u encrypted evm-key) > /etc/keys/evm-key
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 ls -l /etc/keys/ total 8 -rw-r--r--. 1 root root 246 Jun 24 12:44 evm-key -rw-r--r--. 1 root root 32 Jun 24 12:43 kmk
keyctl add user kmk "USD(cat /etc/keys/kmk)" @u 451342217
keyctl add encrypted evm-key "load USD(cat /etc/keys/evm-key)" @u 924537557
echo 1 > /sys/kernel/security/evm
find / -fstype xfs -type f -uid 0 -exec head -n 1 '{}' >/dev/null \;
dmesg | tail -1 [... ] evm: key initialized
echo < Test_text > > test_file
getfattr -m . -d test_file file: test_file security.evm=0sAnDIy4VPA0HArpPO/EqiutnNyBql security.ima=0sAQOEDeuUnWzwwKYk+n66h/vby3eD
dnf install rpm-plugin-ima -y
dnf reinstall '*' -y
getfattr -m security.ima -d /usr/bin/bash
'security.ima=0sAwIE0zIESQBnMGUCMFhf0iBeM7NjjhCCHVt4/ORx1eCegjrWSHzFbJMCsAhR9bYU2hNGjiWUYT2IIqWaaAIxALFGUkqGP5vDLuxQXibO9g7HFcfyZzRBY4rbKPsXcAIZRtDHVS5dQBZqM3hyS5v1MA=='
evmctl ima_verify -k /usr/share/doc/kernel-keys/USD(uname -r)/ima.cer /usr/bin/bash
'key 1: d3320449 /usr/share/doc/kernel-keys/5.14.0-359.el9.x86-64/ima.cer /usr/bin/bash:' verification is OK
mkdir -p /etc/keys/ima cp /usr/share/doc/kernel-keys/USD(uname -r)/ima.cer /etc/ima/keys
keyctl padd asymmetric RedHat-IMA %:.ima < /etc/ima/keys/ima.cer
PROC_SUPER_MAGIC = 0x9fa0 dont_appraise fsmagic=0x9fa0 SYSFS_MAGIC = 0x62656572 dont_appraise fsmagic=0x62656572 DEBUGFS_MAGIC = 0x64626720 dont_appraise fsmagic=0x64626720 TMPFS_MAGIC = 0x01021994 dont_appraise fsmagic=0x1021994 RAMFS_MAGIC dont_appraise fsmagic=0x858458f6 DEVPTS_SUPER_MAGIC=0x1cd1 dont_appraise fsmagic=0x1cd1 BINFMTFS_MAGIC=0x42494e4d dont_appraise fsmagic=0x42494e4d SECURITYFS_MAGIC=0x73636673 dont_appraise fsmagic=0x73636673 SELINUX_MAGIC=0xf97cff8c dont_appraise fsmagic=0xf97cff8c SMACK_MAGIC=0x43415d53 dont_appraise fsmagic=0x43415d53 NSFS_MAGIC=0x6e736673 dont_appraise fsmagic=0x6e736673 EFIVARFS_MAGIC dont_appraise fsmagic=0xde5e81e4 CGROUP_SUPER_MAGIC=0x27e0eb dont_appraise fsmagic=0x27e0eb CGROUP2_SUPER_MAGIC=0x63677270 dont_appraise fsmagic=0x63677270 appraise func=BPRM_CHECK appraise func=FILE_MMAP mask=MAY_EXEC
echo /etc/sysconfig/ima-policy > /sys/kernel/security/ima/policy echo USD? 0
echo 'add_dracutmodules+=" integrity "' > /etc/dracut.conf.d/98-integrity.conf dracut -f
openssl req -new -x509 -utf8 -sha256 -days 3650 -batch -config ima_ca.conf -outform DER -out custom_ima_ca.der -keyout custom_ima_ca.priv
cat ima_ca.conf [ req ] default_bits = 2048 distinguished_name = req_distinguished_name prompt = no string_mask = utf8only x509_extensions = ca [ req_distinguished_name ] O = YOUR_ORG CN = YOUR_COMMON_NAME IMA CA emailAddress = YOUR_EMAIL [ ca ] basicConstraints=critical,CA:TRUE subjectKeyIdentifier=hash authorityKeyIdentifier=keyid:always,issuer keyUsage=critical,keyCertSign,cRLSign
openssl req -new -utf8 -sha256 -days 365 -batch -config ima.conf -out custom_ima.csr -keyout custom_ima.priv
cat ima.conf [ req ] default_bits = 2048 distinguished_name = req_distinguished_name prompt = no string_mask = utf8only x509_extensions = code_signing [ req_distinguished_name ] O = YOUR_ORG CN = YOUR_COMMON_NAME IMA signing key emailAddress = YOUR_EMAIL [ code_signing ] basicConstraints=critical,CA:FALSE keyUsage=digitalSignature subjectKeyIdentifier=hash authorityKeyIdentifier=keyid:always,issuer
openssl x509 -req -in custom_ima.csr -days 365 -extfile ima.conf -extensions code_signing -CA custom_ima_ca.der -CAkey custom_ima_ca.priv -CAcreateserial -outform DER -out ima.der
evmctl ima_sign /etc/sysconfig/ima-policy -k < PATH_TO_YOUR_CUSTOM_IMA_KEY > Place your public certificate under /etc/keys/ima/ and add it to the .ima keyring
keyctl padd asymmetric CUSTOM_IMA1 %:.ima < /etc/ima/keys/my_ima.cer
echo /etc/sysconfig/ima-policy > /sys/kernel/security/ima/policy echo USD? 0