Fix SELinux mismatch metrics

DesiredStateOfWorld must remember both
- the effective SELinux label to apply as a mount option (non-empty for
  RWOP volumes, empty otherwise)
- and the label that _would_ be used if the mount option would be used by
  all access modes.

Mismatch warning metrics must be generated from the second label.
This commit is contained in:
Jan Safranek 2023-03-09 14:15:58 +01:00
parent 771c9be291
commit 48ea6a3f3a

View File

@ -206,12 +206,23 @@ type volumeToMount struct {
// Usually this value reflects size recorded in pv.Spec.Capacity // Usually this value reflects size recorded in pv.Spec.Capacity
persistentVolumeSize *resource.Quantity persistentVolumeSize *resource.Quantity
// seLinuxFileLabel is desired SELinux label on files on the volume. If empty, then // effectiveSELinuxMountFileLabel is the SELinux label that will be applied to the volume using mount options.
// If empty, then:
// - either the context+label is unknown (assigned randomly by the container runtime)
// - or the volume plugin responsible for this volume does not support mounting with -o context
// - or the volume is not ReadWriteOncePod
// - or the OS does not support SELinux
// In all cases, the SELinux context does not matter when mounting the volume.
effectiveSELinuxMountFileLabel string
// originalSELinuxLabel is the SELinux label that would be used if SELinux mount was supported for all access modes.
// For RWOP volumes it's the same as effectiveSELinuxMountFileLabel.
// It is used only to report potential SELinux mismatch metrics.
// If empty, then:
// - either the context+label is unknown (assigned randomly by the container runtime) // - either the context+label is unknown (assigned randomly by the container runtime)
// - or the volume plugin responsible for this volume does not support mounting with -o context // - or the volume plugin responsible for this volume does not support mounting with -o context
// - or the OS does not support SELinux // - or the OS does not support SELinux
// In all cases, the SELinux context does not matter when mounting the volume. originalSELinuxLabel string
seLinuxFileLabel string
} }
// The pod object represents a pod that references the underlying volume and // The pod object represents a pod that references the underlying volume and
@ -307,23 +318,25 @@ func (dsw *desiredStateOfWorld) AddPodToVolume(
} }
} }
} }
effectiveSELinuxMountLabel := seLinuxFileLabel
if !util.VolumeSupportsSELinuxMount(volumeSpec) { if !util.VolumeSupportsSELinuxMount(volumeSpec) {
// Clear SELinux label for the volume with unsupported access modes. // Clear SELinux label for the volume with unsupported access modes.
klog.V(4).InfoS("volume does not support SELinux context mount, clearing the expected label", "volume", volumeSpec.Name()) klog.V(4).InfoS("volume does not support SELinux context mount, clearing the expected label", "volume", volumeSpec.Name())
seLinuxFileLabel = "" effectiveSELinuxMountLabel = ""
} }
if seLinuxFileLabel != "" { if seLinuxFileLabel != "" {
seLinuxVolumesAdmitted.Add(1.0) seLinuxVolumesAdmitted.Add(1.0)
} }
vmt := volumeToMount{ vmt := volumeToMount{
volumeName: volumeName, volumeName: volumeName,
podsToMount: make(map[types.UniquePodName]podToMount), podsToMount: make(map[types.UniquePodName]podToMount),
pluginIsAttachable: attachable, pluginIsAttachable: attachable,
pluginIsDeviceMountable: deviceMountable, pluginIsDeviceMountable: deviceMountable,
volumeGidValue: volumeGidValue, volumeGidValue: volumeGidValue,
reportedInUse: false, reportedInUse: false,
desiredSizeLimit: sizeLimit, desiredSizeLimit: sizeLimit,
seLinuxFileLabel: seLinuxFileLabel, effectiveSELinuxMountFileLabel: effectiveSELinuxMountLabel,
originalSELinuxLabel: seLinuxFileLabel,
} }
// record desired size of the volume // record desired size of the volume
if volumeSpec.PersistentVolume != nil { if volumeSpec.PersistentVolume != nil {
@ -337,9 +350,9 @@ func (dsw *desiredStateOfWorld) AddPodToVolume(
} else { } else {
// volume exists // volume exists
if pluginSupportsSELinuxContextMount { if pluginSupportsSELinuxContextMount {
if seLinuxFileLabel != vol.seLinuxFileLabel { if seLinuxFileLabel != vol.originalSELinuxLabel {
// TODO: update the error message after tests, e.g. add at least the conflicting pod names. // TODO: update the error message after tests, e.g. add at least the conflicting pod names.
fullErr := fmt.Errorf("conflicting SELinux labels of volume %s: %q and %q", volumeSpec.Name(), vol.seLinuxFileLabel, seLinuxFileLabel) fullErr := fmt.Errorf("conflicting SELinux labels of volume %s: %q and %q", volumeSpec.Name(), vol.originalSELinuxLabel, seLinuxFileLabel)
supported := util.VolumeSupportsSELinuxMount(volumeSpec) supported := util.VolumeSupportsSELinuxMount(volumeSpec)
if err := handleSELinuxMetricError(fullErr, supported, seLinuxVolumeContextMismatchWarnings, seLinuxVolumeContextMismatchErrors); err != nil { if err := handleSELinuxMetricError(fullErr, supported, seLinuxVolumeContextMismatchWarnings, seLinuxVolumeContextMismatchErrors); err != nil {
return "", err return "", err
@ -499,7 +512,7 @@ func (dsw *desiredStateOfWorld) VolumeExists(
// and mounted with new SELinux mount options for pod B. // and mounted with new SELinux mount options for pod B.
// Without SELinux, kubelet can (and often does) reuse device mounted // Without SELinux, kubelet can (and often does) reuse device mounted
// for A. // for A.
return vol.seLinuxFileLabel == seLinuxMountContext return vol.effectiveSELinuxMountFileLabel == seLinuxMountContext
} }
return true return true
} }
@ -515,7 +528,7 @@ func (dsw *desiredStateOfWorld) PodExistsInVolume(
} }
if feature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) { if feature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) {
if volumeObj.seLinuxFileLabel != seLinuxMountOption { if volumeObj.effectiveSELinuxMountFileLabel != seLinuxMountOption {
// The volume is in DSW, but with a different SELinux mount option. // The volume is in DSW, but with a different SELinux mount option.
// Report it as unused, so the volume is unmounted and mounted back // Report it as unused, so the volume is unmounted and mounted back
// with the right SELinux option. // with the right SELinux option.
@ -573,7 +586,7 @@ func (dsw *desiredStateOfWorld) GetVolumesToMount() []VolumeToMount {
ReportedInUse: volumeObj.reportedInUse, ReportedInUse: volumeObj.reportedInUse,
MountRequestTime: podObj.mountRequestTime, MountRequestTime: podObj.mountRequestTime,
DesiredSizeLimit: volumeObj.desiredSizeLimit, DesiredSizeLimit: volumeObj.desiredSizeLimit,
SELinuxLabel: volumeObj.seLinuxFileLabel, SELinuxLabel: volumeObj.effectiveSELinuxMountFileLabel,
}, },
} }
if volumeObj.persistentVolumeSize != nil { if volumeObj.persistentVolumeSize != nil {