-
Notifications
You must be signed in to change notification settings - Fork 194
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
pkg/subscriptions: Modernize FIPS mounts #2174
base: main
Are you sure you want to change the base?
pkg/subscriptions: Modernize FIPS mounts #2174
Conversation
/etc/system-fips is deprecated in CentOS Stream 9 and has been removed from CentOS Stream 10. UBI8 containers still contain /etc/system-fips -> /run/secrets/system-fips, but UBI9 containers do not, so creating /run/secrets/system-fips on UBI9 (or later) does not serve a useful purpose. See [1, 2]. Instead of checking /etc/system-fips to determine whether FIPS mode is enabled on the host, read /proc/sys/crypto/fips_enabled, which works for all supported RHEL versions and likely even earlier. In CentOS 10 Stream, the crypto-policies package does now contain /usr/share/crypto-policies/default-fips-config, which is meant to serve as a file to bind-mount over /etc/crypto-policies/config when in FIPS mode [3]. Manual creation of this file is thus no longer required in containers/common for modern containers. Using this file as a source also enables improvements in crypto-policies tooling which will now - unmount the two bind mounts when a user manually changes the policy using update-crypto-policies --set, something which was previously broken in containers because /etc/crypto-policies/config was a read-only bind-mount, and - unmount and restore the two bind-mounts when the crypto-policies package is updated. The crypto-policies package will only do these steps if the the bind mounts for crypto-policies use the /usr/share/crypto-policies/default-fips-config file as source, so it makes sense for containers/common to switch to that. [1]: https://gitlab.com/redhat-crypto/fedora-crypto-policies/-/merge_requests/111 [2]: https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/9.0_release_notes/deprecated_functionality#deprecated-functionality_security [3]: https://gitlab.com/redhat-crypto/fedora-crypto-policies/-/commit/04ceadccfc07e5946b08157d06ca5c0d5a229d92 Closes: containers#2130 Related: https://issues.redhat.com/browse/CRYPTO-13556 Signed-off-by: Clemens Lang <[email protected]>
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: neverpanic The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if err := addFIPSModeSubscription(&subscriptionMounts, containerRunDir, mountPoint, mountLabel, uid, gid); err != nil { | ||
logrus.Errorf("Adding FIPS mode subscription to container: %v", err) | ||
// Enable FIPS mode in crypto-policies if /proc/sys/crypto/fips_enabled on the host contains "1" | ||
if fips_enabled, err := ioutil.ReadFile("/proc/sys/crypto/fips_enabled"); err == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ioutil.ReadFile
function is deprecated. I would use os.ReadFile
.
// Enable FIPS mode in crypto-policies if /proc/sys/crypto/fips_enabled on the host contains "1" | ||
if fips_enabled, err := ioutil.ReadFile("/proc/sys/crypto/fips_enabled"); err == nil { | ||
if strings.TrimSpace(string(fips_enabled)) == "1" { | ||
if err := addFIPSMounts(&subscriptionMounts, containerRunDir, mountPoint, mountLabel, uid, gid); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please reduce the nesting of if statements.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(I don’t really mind three if
s nested, but extracting the whole condition, incl. the disableFips
part, into a separate helper function would be nice.)
// In the event of restart, it is possible for the FIPS mode file to already exist | ||
if err := fileutils.Exists(fipsFile); errors.Is(err, os.ErrNotExist) { | ||
file, err := os.Create(fipsFile) | ||
fipsFileHost := filepath.Join(mountPoint, "etc/system-fips") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The following if
statement should create a separate function that checks whether $container/etc/system-fips
exists and whether it is a symlink to /run/secrets/system-fips
with reduced if
nesting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(For me, the more relevant benefit is having the else logrus.…
conditions much closer to the triggering cause, rather than just nesting per se. A separate function with early exits would make that easier to structure.)
destPolicyConfig := "/etc/crypto-policies/config" | ||
srcPolicyConfigOnHost := filepath.Join(mountPoint, srcPolicyConfig) | ||
|
||
err := fileutils.Exists(srcPolicyConfigOnHost) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be part of the following if
statement.
|
||
// /usr/share/crypto-policies/default-fips-config does not exist, let's create it ourselves | ||
cryptoPoliciesConfigFile := filepath.Join(containerRunDir, "fips-config") | ||
file, err := os.Create(cryptoPoliciesConfigFile) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead, create a file, write to it, and close the file. You can use os.WriteFile
. This should reduce the amount of code. Then you can use: os.Chown
logrus.Errorf("Adding FIPS mode bind mounts to container: %v", err) | ||
} | ||
} else { | ||
logrus.Debug("/proc/sys/crypto/fips_enabled does not contain '1', not adding FIPS mode bind mounts") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it worth logging the value here?
file, err := os.Create(fipsFile) | ||
fipsFileHost := filepath.Join(mountPoint, "etc/system-fips") | ||
if fileutils.Lexists(fipsFileHost) != nil { | ||
fipsFileTarget, err := filepath.EvalSymlinks(fipsFileHost) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This conceptually allows an attacker to set up /etc/system-fips
inside the container to be a symlink with ../../
… to break out of the container and refer to hosts’ files.
Yes, we actually only compare the fipsFileTarget
text without referring to the possibly-unwanted file, but, still…
In other words, either we care about the specific symlink text, and we can just Readlink
(probably not), or we care about where the symlink evaluates, whatever its form, and in that case ..
in the /
directory of the container should be evaluated correctly (restricted to the containers’ root).
(https://github.com/cyphar/filepath-securejoin is used for that purpose in some parts of the codebase.)
// Enable FIPS mode in crypto-policies if /proc/sys/crypto/fips_enabled on the host contains "1" | ||
if fips_enabled, err := ioutil.ReadFile("/proc/sys/crypto/fips_enabled"); err == nil { | ||
if strings.TrimSpace(string(fips_enabled)) == "1" { | ||
if err := addFIPSMounts(&subscriptionMounts, containerRunDir, mountPoint, mountLabel, uid, gid); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(I don’t really mind three if
s nested, but extracting the whole condition, incl. the disableFips
part, into a separate helper function would be nice.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn’t actually review the substance of the PR, whether the code correctly handles all relevant versions of the OSes and behaviors.
Just looking at the mechanism, all the filepath.Join(mountPoint, …)
in this file make me worried about symlink breakouts. There might not be much actually wrong there (at worst, I guess, triggering an an audit message about a DAC or SELinux permission violation by the container runtime when checking for presence of an out-of-contaienr file), but that’s just one small refactor away from disaster.
I do appreciate that almost all of that is pre-existing and not directly relevant to this PR.
I noticed this last week when I looked at this PR and reported this internally so yes this is an pre existing issue, fix in #2185 |
I'm on PTO until Oct 14, I'll fix the comments after that. |
/etc/system-fips
is deprecated in CentOS Stream 9 and has been removed from CentOS Stream 10. UBI8 containers still contain/etc/system-fips -> /run/secrets/system-fips
, but UBI9 containers do not, so creating/run/secrets/system-fips
on UBI9 (or later) does not serve a useful purpose. See [1, 2].Instead of checking
/etc/system-fips
to determine whether FIPS mode is enabled on the host, read/proc/sys/crypto/fips_enabled
, which works for all supported RHEL versions and likely even earlier.In CentOS 10 Stream, the crypto-policies package does now contain
/usr/share/crypto-policies/default-fips-config
, which is meant to serve as a file to bind-mount over/etc/crypto-policies/config
when in FIPS mode [3]. Manual creation of this file is thus no longer required in containers/common for modern containers. Using this file as a source also enables improvements in crypto-policies tooling which will nowupdate-crypto-policies --set
, something which was previously broken in containers because/etc/crypto-policies/config
was a read-only bind-mount, and/usr/share/crypto-policies/default-fips-config
file as source, so it makes sense for containers/common to switch to that.
Closes: #2130
Related: https://issues.redhat.com/browse/CRYPTO-13556