Skip to content

Commit

Permalink
feat(fips-crypto-policies): Make c-p follow FIPS mode automatically
Browse files Browse the repository at this point in the history
For a system that uses crypto-policies to be switched to FIPS mode
correctly, it needs to be

- booted with `fips=1` on the kernel command line
- switched to the FIPS crypto-policy (or a policy derived from it)
- have the fips dracut module enabled

On older systems, there were additional steps, for example, creating
`/etc/system-fips`.

We have repeatedly seen inconsistencies between those different toggles,
either because the user space tooling to switch between those does not
(for reliability, maintainability, and compliance reasons) undo some of
the steps it does when disabling FIPS mode, or because other
installation methods (bootc, containers, image builder) independently do
some of those steps. Eventually, all of these ended with user confusion.

We can avoid this situation by eliminating the difference by treating
the `fips=1` kernel command line switch as a single source of truth, and
making all others follow automatically. This module provides this for
crypto-policies, by adding bind-mounts before pivot if the system has
not already been switched to a FIPS-based crypto-policy.

This requires some support from the crypto-policies package (because it
needs to deal with the bind mounts when a user calls
`update-crypto-policies --set`), so make it a no-op unless

 - `fips=1` is on the kernel command line
 - crypto-policies is installed
 - crypto-policies supports the bind-mounts (indicated by the presence
   of the `default-fips-config` file)
 - the policy isn't already FIPS

These checks should make this safe to add to the initramfs on all
current systems.

The bind-mounts also need to happen in the initramfs already, because
systemd links against OpenSSL, and doing them later means that systemd
will start with an OpenSSL configuration that isn't tailored for FIPS.

See also [1], which adds the user space support to crypto-policies,
along with a systemd service that does the same steps in case dracut
hasn't already done them (which is useful for environments that don't
use an initramfs like containers).

  [1]: https://gitlab.com/redhat-crypto/fedora-crypto-policies/-/merge_requests/191

Signed-off-by: Clemens Lang <[email protected]>
  • Loading branch information
neverpanic committed Aug 8, 2024
1 parent 5d2bda4 commit e9662a1
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 0 deletions.
52 changes: 52 additions & 0 deletions modules.d/01fips-crypto-policies/fips-crypto-policies.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/usr/bin/sh

type getarg > /dev/null 2>&1 || . /lib/dracut-lib.sh

if ! fipsmode=$(getarg fips) || [ "$fipsmode" = "0" ] || [ -z "$fipsmode" ]; then
# Do nothing if not in FIPS mode
exit 0
fi

policyfile=/etc/crypto-policies/config
fipspolicyfile=/usr/share/crypto-policies/default-fips-config
backends=/etc/crypto-policies/back-ends
fipsbackends=/usr/share/crypto-policies/back-ends/FIPS

# When in FIPS mode, check the active crypto policy by reading the
# $root/etc/crypto-policies/config file. If it is not "FIPS", or does not start
# with "FIPS:", automatically switch to the FIPS policy by creating
# bind-mounts.

if ! [ -r "${NEWROOT}${policyfile}" ]; then
# No crypto-policies configured, possibly not a system that uses
# crypto-policies?
exit 0
fi

if ! [ -f "${NEWROOT}${fipspolicyfile}" ]; then
# crypto-policies is too old to deal with automatic bind-mounting of the
# FIPS policy over the normal policy, do not attempt to do the bind-mount.
exit 0
fi

policy=$(cat "${NEWROOT}${policyfile}")

# Remove the largest suffix pattern matching ":*" from the string (i.e., the
# complete list of active policy modules), then check for FIPS. This is part of
# POSIX sh (https://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_02).
if [ "${policy%%:*}" = "FIPS" ]; then
exit 0
fi

# Current crypto policy is not FIPS or FIPS-based, but the system is in FIPS
# mode; this is an inconsistent configuration. Automatically bind-mount a FIPS
# configuration over this.
if ! mount -o bind,ro "${NEWROOT}${fipsbackends}" "${NEWROOT}${backends}"; then
warn "Failed to bind-mount FIPS policy over ${backends} (the system is in FIPS mode, but the crypto-policy is not)."
# If this bind-mount failed, don't attempt to do the other one to avoid
# a system that seems to be in FIPS crypto-policy but actually is not.
exit 0
fi

mount -o bind,ro "${NEWROOT}${fipspolicyfile}" "${NEWROOT}${policyfile}" \
|| warn "Failed to bind-mount FIPS crypto-policy state file over ${policyfile} (the system is in FIPS mode, but the crypto-policy is not)."
27 changes: 27 additions & 0 deletions modules.d/01fips-crypto-policies/module-setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/bash

# called by dracut
check() {
# only enable on systems that use crypto-policies
[ -d "$dracutsysrootdir/etc/crypto-policies" ] && return 0

# include when something else depends on it or it is explicitly requested
return 255
}

# called by dracut
depends() {
return 0
}

# called by dracut
installkernel() {
return 0
}

# called by dracut
install() {
inst_hook pre-pivot 01 "$moddir/fips-crypto-policies.sh"

inst_multiple mount
}

0 comments on commit e9662a1

Please sign in to comment.