Skip to content

Commit 97c79df

Browse files
authored
Merge pull request kubernetes#127981 from jsafrane/selinux-changepolicy
1710: Implement SELinuxChangePolicy
2 parents b240c51 + 09afd66 commit 97c79df

File tree

87 files changed

+1896
-1064
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

87 files changed

+1896
-1064
lines changed

api/openapi-spec/swagger.json

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/openapi-spec/v3/api__v1_openapi.json

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/openapi-spec/v3/apis__apps__v1_openapi.json

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/openapi-spec/v3/apis__batch__v1_openapi.json

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/api/pod/util.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,8 @@ func GetValidationOptionsFromPodSpecAndMeta(podSpec, oldPodSpec *api.PodSpec, po
393393
opts.AllowRelaxedEnvironmentVariableValidation = useRelaxedEnvironmentVariableValidation(podSpec, oldPodSpec)
394394
opts.AllowRelaxedDNSSearchValidation = useRelaxedDNSSearchValidation(oldPodSpec)
395395

396+
opts.AllowOnlyRecursiveSELinuxChangePolicy = useOnlyRecursiveSELinuxChangePolicy(oldPodSpec)
397+
396398
if oldPodSpec != nil {
397399
// if old spec has status.hostIPs downwardAPI set, we must allow it
398400
opts.AllowHostIPsField = opts.AllowHostIPsField || hasUsedDownwardAPIFieldPathWithPodSpec(oldPodSpec, "status.hostIPs")
@@ -723,6 +725,7 @@ func dropDisabledFields(
723725

724726
dropPodLifecycleSleepAction(podSpec, oldPodSpec)
725727
dropImageVolumes(podSpec, oldPodSpec)
728+
dropSELinuxChangePolicy(podSpec, oldPodSpec)
726729
}
727730

728731
func dropPodLifecycleSleepAction(podSpec, oldPodSpec *api.PodSpec) {
@@ -1361,3 +1364,34 @@ func imageVolumesInUse(podSpec *api.PodSpec) bool {
13611364

13621365
return false
13631366
}
1367+
1368+
func dropSELinuxChangePolicy(podSpec, oldPodSpec *api.PodSpec) {
1369+
if utilfeature.DefaultFeatureGate.Enabled(features.SELinuxChangePolicy) || seLinuxChangePolicyInUse(oldPodSpec) {
1370+
return
1371+
}
1372+
if podSpec == nil || podSpec.SecurityContext == nil {
1373+
return
1374+
}
1375+
podSpec.SecurityContext.SELinuxChangePolicy = nil
1376+
}
1377+
1378+
func seLinuxChangePolicyInUse(podSpec *api.PodSpec) bool {
1379+
if podSpec == nil || podSpec.SecurityContext == nil {
1380+
return false
1381+
}
1382+
return podSpec.SecurityContext.SELinuxChangePolicy != nil
1383+
}
1384+
1385+
func useOnlyRecursiveSELinuxChangePolicy(oldPodSpec *api.PodSpec) bool {
1386+
if utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMount) {
1387+
// All policies are allowed
1388+
return false
1389+
}
1390+
1391+
if seLinuxChangePolicyInUse(oldPodSpec) {
1392+
// The old pod spec has *any* policy: we need to keep that object update-able.
1393+
return false
1394+
}
1395+
// No feature gate + no value in the old object -> only Recursive is allowed
1396+
return true
1397+
}

pkg/api/pod/util_test.go

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import (
2525
"github.com/google/go-cmp/cmp"
2626
"github.com/stretchr/testify/assert"
2727
"github.com/stretchr/testify/require"
28+
"k8s.io/component-base/featuregate"
29+
"k8s.io/utils/ptr"
2830

2931
v1 "k8s.io/api/core/v1"
3032
"k8s.io/apimachinery/pkg/api/resource"
@@ -3901,3 +3903,142 @@ func TestDropImageVolumes(t *testing.T) {
39013903
})
39023904
}
39033905
}
3906+
3907+
func TestDropSELinuxChangePolicy(t *testing.T) {
3908+
podRecursive := &api.Pod{
3909+
Spec: api.PodSpec{
3910+
SecurityContext: &api.PodSecurityContext{
3911+
SELinuxChangePolicy: ptr.To(api.SELinuxChangePolicyRecursive),
3912+
},
3913+
},
3914+
}
3915+
podMountOption := &api.Pod{
3916+
Spec: api.PodSpec{
3917+
SecurityContext: &api.PodSecurityContext{
3918+
SELinuxChangePolicy: ptr.To(api.SELinuxChangePolicyMountOption),
3919+
},
3920+
},
3921+
}
3922+
podNull := &api.Pod{
3923+
Spec: api.PodSpec{
3924+
SecurityContext: &api.PodSecurityContext{
3925+
SELinuxChangePolicy: nil,
3926+
},
3927+
},
3928+
}
3929+
3930+
tests := []struct {
3931+
name string
3932+
oldPod *api.Pod
3933+
newPod *api.Pod
3934+
gates []featuregate.Feature
3935+
wantPod *api.Pod
3936+
}{
3937+
{
3938+
name: "no old pod, new pod with Recursive, all features disabled",
3939+
oldPod: nil,
3940+
newPod: podRecursive,
3941+
gates: nil,
3942+
wantPod: podNull,
3943+
},
3944+
{
3945+
name: "no old pod, new pod with MountOption, all features disabled",
3946+
oldPod: nil,
3947+
newPod: podMountOption,
3948+
gates: nil,
3949+
wantPod: podNull,
3950+
},
3951+
{
3952+
name: "old pod with Recursive, new pod with Recursive, all features disabled",
3953+
oldPod: podRecursive,
3954+
newPod: podRecursive,
3955+
gates: nil,
3956+
wantPod: podRecursive,
3957+
},
3958+
{
3959+
name: "old pod with MountOption, new pod with Recursive, all features disabled",
3960+
oldPod: podMountOption,
3961+
newPod: podRecursive,
3962+
gates: nil,
3963+
wantPod: podRecursive,
3964+
},
3965+
{
3966+
name: "no old pod, new pod with Recursive, SELinuxChangePolicy feature enabled",
3967+
oldPod: nil,
3968+
newPod: podRecursive,
3969+
gates: []featuregate.Feature{features.SELinuxChangePolicy},
3970+
wantPod: podRecursive,
3971+
},
3972+
{
3973+
name: "no old pod, new pod with MountOption, SELinuxChangePolicy feature enabled",
3974+
oldPod: nil,
3975+
newPod: podMountOption,
3976+
gates: []featuregate.Feature{features.SELinuxChangePolicy},
3977+
wantPod: podMountOption,
3978+
},
3979+
{
3980+
name: "old pod with Recursive, new pod with Recursive, SELinuxChangePolicy feature enabled",
3981+
oldPod: podRecursive,
3982+
newPod: podRecursive,
3983+
gates: []featuregate.Feature{features.SELinuxChangePolicy},
3984+
wantPod: podRecursive,
3985+
},
3986+
{
3987+
name: "old pod with MountOption, new pod with Recursive, SELinuxChangePolicy feature enabled",
3988+
oldPod: podMountOption,
3989+
newPod: podRecursive,
3990+
gates: []featuregate.Feature{features.SELinuxChangePolicy},
3991+
wantPod: podRecursive,
3992+
},
3993+
// In theory, SELinuxMount does not have any effect on dropping SELinuxChangePolicy field, but for completeness:
3994+
{
3995+
name: "no old pod, new pod with Recursive, SELinuxChangePolicy + SELinuxMount features enabled",
3996+
oldPod: nil,
3997+
newPod: podRecursive,
3998+
gates: []featuregate.Feature{features.SELinuxChangePolicy, features.SELinuxMount},
3999+
wantPod: podRecursive,
4000+
},
4001+
{
4002+
name: "no old pod, new pod with MountOption, SELinuxChangePolicy + SELinuxMount features enabled",
4003+
oldPod: nil,
4004+
newPod: podMountOption,
4005+
gates: []featuregate.Feature{features.SELinuxChangePolicy, features.SELinuxMount},
4006+
wantPod: podMountOption,
4007+
},
4008+
{
4009+
name: "old pod with Recursive, new pod with Recursive, SELinuxChangePolicy + SELinuxMount features enabled",
4010+
oldPod: podRecursive,
4011+
newPod: podRecursive,
4012+
gates: []featuregate.Feature{features.SELinuxChangePolicy, features.SELinuxMount},
4013+
wantPod: podRecursive,
4014+
},
4015+
{
4016+
name: "old pod with MountOption, new pod with Recursive, SELinuxChangePolicy + SELinuxMount features enabled",
4017+
oldPod: podMountOption,
4018+
newPod: podRecursive,
4019+
gates: []featuregate.Feature{features.SELinuxChangePolicy, features.SELinuxMount},
4020+
wantPod: podRecursive,
4021+
},
4022+
}
4023+
for _, tc := range tests {
4024+
t.Run(tc.name, func(t *testing.T) {
4025+
4026+
for _, gate := range tc.gates {
4027+
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, gate, true)
4028+
}
4029+
4030+
oldPod := tc.oldPod.DeepCopy()
4031+
newPod := tc.newPod.DeepCopy()
4032+
DropDisabledPodFields(newPod, oldPod)
4033+
4034+
// old pod should never be changed
4035+
if diff := cmp.Diff(oldPod, tc.oldPod); diff != "" {
4036+
t.Errorf("old pod changed: %s", diff)
4037+
}
4038+
4039+
if diff := cmp.Diff(tc.wantPod, newPod); diff != "" {
4040+
t.Errorf("new pod changed (- want, + got): %s", diff)
4041+
}
4042+
})
4043+
}
4044+
}

pkg/apis/core/types.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3684,6 +3684,22 @@ const (
36843684
SupplementalGroupsPolicyStrict SupplementalGroupsPolicy = "Strict"
36853685
)
36863686

3687+
// PodSELinuxChangePolicy defines how the container's SELinux label is applied to all volumes used by the Pod.
3688+
type PodSELinuxChangePolicy string
3689+
3690+
const (
3691+
// Recursive relabeling of all Pod volumes by the container runtime.
3692+
// This may be slow for large volumes, but allows mixing privileged and unprivileged Pods sharing the same volume on the same node.
3693+
SELinuxChangePolicyRecursive PodSELinuxChangePolicy = "Recursive"
3694+
// MountOption mounts all eligible Pod volumes with `-o context` mount option.
3695+
// This requires all Pods that share the same volume to use the same SELinux label.
3696+
// It is not possible to share the same volume among privileged and unprivileged Pods.
3697+
// Eligible volumes are in-tree FibreChannel and iSCSI volumes, and all CSI volumes
3698+
// whose CSI driver announces SELinux support by setting spec.seLinuxMount: true in their
3699+
// CSIDriver instance. Other volumes are always re-labelled recursively.
3700+
SELinuxChangePolicyMountOption PodSELinuxChangePolicy = "MountOption"
3701+
)
3702+
36873703
// PodSecurityContext holds pod-level security attributes and common container settings.
36883704
// Some fields are also present in container.securityContext. Field values of
36893705
// container.securityContext take precedence over field values of PodSecurityContext.
@@ -3820,6 +3836,32 @@ type PodSecurityContext struct {
38203836
// Note that this field cannot be set when spec.os.name is windows.
38213837
// +optional
38223838
AppArmorProfile *AppArmorProfile
3839+
// seLinuxChangePolicy defines how the container's SELinux label is applied to all volumes used by the Pod.
3840+
// It has no effect on nodes that do not support SELinux or to volumes does not support SELinux.
3841+
// Valid values are "MountOption" and "Recursive".
3842+
//
3843+
// "Recursive" means relabeling of all files on all Pod volumes by the container runtime.
3844+
// This may be slow for large volumes, but allows mixing privileged and unprivileged Pods sharing the same volume on the same node.
3845+
//
3846+
// "MountOption" mounts all eligible Pod volumes with `-o context` mount option.
3847+
// This requires all Pods that share the same volume to use the same SELinux label.
3848+
// It is not possible to share the same volume among privileged and unprivileged Pods.
3849+
// Eligible volumes are in-tree FibreChannel and iSCSI volumes, and all CSI volumes
3850+
// whose CSI driver announces SELinux support by setting spec.seLinuxMount: true in their
3851+
// CSIDriver instance. Other volumes are always re-labelled recursively.
3852+
// "MountOption" value is allowed only when SELinuxMount feature gate is enabled.
3853+
//
3854+
// If not specified and SELinuxMount feature gate is enabled, "MountOption" is used.
3855+
// If not specified and SELinuxMount feature gate is disabled, "MountOption" is used for ReadWriteOncePod volumes
3856+
// and "Recursive" for all other volumes.
3857+
//
3858+
// This field affects only Pods that have SELinux label set, either in PodSecurityContext or in SecurityContext of all containers.
3859+
//
3860+
// All Pods that use the same volume should use the same seLinuxChangePolicy, otherwise some pods can get stuck in ContainerCreating state.
3861+
// Note that this field cannot be set when spec.os.name is windows.
3862+
// +featureGate=SELinuxChangePolicy
3863+
// +optional
3864+
SELinuxChangePolicy *PodSELinuxChangePolicy
38233865
}
38243866

38253867
// SeccompProfile defines a pod/container's seccomp profile settings.

pkg/apis/core/v1/zz_generated.conversion.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)