Skip to content

Commit

Permalink
scc: set container nonroot=true if the pod/container RunAsUser is non…
Browse files Browse the repository at this point in the history
…-zero

PodSecurity admission requires the non-zero flag to be set no matter
the container/pod UID.
  • Loading branch information
stlaz committed Jun 15, 2022
1 parent 29f4c54 commit 4d7bed8
Show file tree
Hide file tree
Showing 2 changed files with 164 additions and 3 deletions.
18 changes: 15 additions & 3 deletions pkg/securitycontextconstraints/sccmatching/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,21 @@ func (s *simpleProvider) CreateContainerSecurityContext(pod *api.Pod, container
// if we're using the non-root strategy set the marker that this container should not be
// run as root which will signal to the kubelet to do a final check either on the runAsUser
// or, if runAsUser is not set, the image
if sc.RunAsNonRoot() == nil && sc.RunAsUser() == nil && s.scc.RunAsUser.Type == securityv1.RunAsUserStrategyMustRunAsNonRoot {
nonRoot := true
sc.SetRunAsNonRoot(&nonRoot)
// Alternatively, also set the RunAsNonRoot to true in case the UID value is non-nil and non-zero
// to more easily satisfy the requirements of upstream PodSecurity admission "restricted" profile
if sc.RunAsNonRoot() == nil {
nonRoot := false
if runAsUser := sc.RunAsUser(); runAsUser == nil {
if s.scc.RunAsUser.Type == securityv1.RunAsUserStrategyMustRunAsNonRoot {
nonRoot = true
}
} else if *runAsUser != 0 {
nonRoot = true
}

if nonRoot {
sc.SetRunAsNonRoot(&nonRoot)
}
}

caps, err := s.capabilitiesStrategy.Generate(pod, container)
Expand Down
149 changes: 149 additions & 0 deletions pkg/securitycontextconstraints/sccmatching/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/stretchr/testify/require"

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/equality"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/diff"
"k8s.io/apimachinery/pkg/util/validation/field"
Expand Down Expand Up @@ -932,6 +933,154 @@ func TestGenerateContainerSecurityContextReadOnlyRootFS(t *testing.T) {
}
}

func TestGenerateNonRootSecurityContextOnNonZeroRunAsUser(t *testing.T) {
userSCC := defaultSCC()
var minRange int64 = 100
var maxRange int64 = 900
userSCC.RunAsUser = securityv1.RunAsUserStrategyOptions{
Type: securityv1.RunAsUserStrategyMustRunAsRange,
UIDRangeMin: &minRange,
UIDRangeMax: &maxRange,
}

rootMinSCC := defaultSCC()
var rootUID int64 = 0
rootMinSCC.RunAsUser = securityv1.RunAsUserStrategyOptions{
Type: securityv1.RunAsUserStrategyMustRunAsRange,
UIDRangeMin: &rootUID,
UIDRangeMax: &maxRange,
}

nonRootSCC := defaultSCC()
nonRootSCC.RunAsUser = securityv1.RunAsUserStrategyOptions{
Type: securityv1.RunAsUserStrategyMustRunAsNonRoot,
}

var useruid int64 = 500
containerUserPod := defaultPod()
containerUserPod.Spec.Containers[0].SecurityContext.RunAsUser = &useruid

podUserPod := defaultPod()
podUserPod.Spec.SecurityContext.RunAsUser = &useruid

zeroPodUserPod := defaultPod()
zeroPodUserPod.Spec.SecurityContext.RunAsUser = &rootUID

zeroContainerUserPod := defaultPod()
zeroContainerUserPod.Spec.Containers[0].SecurityContext.RunAsUser = &rootUID

zeroPodUserPodNonRootSCC := zeroPodUserPod.DeepCopy()
zeroContainerUserPodNonRootSCC := zeroContainerUserPod.DeepCopy()

falseVal := false
trueVal := true
tests := map[string]struct {
pod *api.Pod
scc *securityv1.SecurityContextConstraints
expectedSC *api.SecurityContext
}{
"generate non-zero user": {
pod: defaultPod(),
scc: userSCC,
expectedSC: &api.SecurityContext{
RunAsUser: &minRange,
RunAsNonRoot: &trueVal,
Privileged: &falseVal,
},
},
"generate zero user": {
pod: defaultPod(),
scc: rootMinSCC,
expectedSC: &api.SecurityContext{
RunAsUser: &rootUID,
RunAsNonRoot: nil,
Privileged: &falseVal,
},
},
"nonzero user set on pod level": {
pod: podUserPod,
scc: userSCC,
expectedSC: &api.SecurityContext{
RunAsUser: nil,
RunAsNonRoot: &trueVal,
Privileged: &falseVal,
},
},
"nonzero user set on container level": {
pod: containerUserPod,
scc: userSCC,
expectedSC: &api.SecurityContext{
RunAsUser: &useruid,
RunAsNonRoot: &trueVal,
Privileged: &falseVal,
},
},
"zero user set on pod level": {
pod: zeroPodUserPod,
scc: rootMinSCC,
expectedSC: &api.SecurityContext{
RunAsUser: nil,
RunAsNonRoot: nil,
Privileged: &falseVal,
},
},
"zero user set on container level": {
pod: zeroContainerUserPod,
scc: rootMinSCC,
expectedSC: &api.SecurityContext{
RunAsUser: &rootUID,
RunAsNonRoot: nil,
Privileged: &falseVal,
},
},
"no user set, nonroot SCC": {
pod: defaultPod(),
scc: nonRootSCC,
expectedSC: &api.SecurityContext{
RunAsUser: nil,
RunAsNonRoot: &trueVal,
Privileged: &falseVal,
},
},
"zero user set on pod level, nonroot SCC": {
pod: zeroPodUserPodNonRootSCC,
scc: nonRootSCC,
expectedSC: &api.SecurityContext{
RunAsUser: nil,
RunAsNonRoot: nil,
Privileged: &falseVal,
},
},
"zero user set on container level, nonroot SCC": {
pod: zeroContainerUserPodNonRootSCC,
scc: nonRootSCC,
expectedSC: &api.SecurityContext{
RunAsUser: &rootUID,
RunAsNonRoot: nil,
Privileged: &falseVal,
},
},
}

for k, v := range tests {
provider, err := NewSimpleProvider(v.scc)
if err != nil {
t.Errorf("%s unable to create provider %v", k, err)
continue
}
sc, err := provider.CreateContainerSecurityContext(v.pod, &v.pod.Spec.Containers[0])
if err != nil {
t.Errorf("%s unable to create container security context %v", k, err)
continue
}

if !equality.Semantic.DeepEqual(v.expectedSC, sc) {
t.Errorf("%s expected security context does not match the actual: %s", k, diff.ObjectDiff(v.expectedSC, sc))
}

}
}

func defaultSCC() *securityv1.SecurityContextConstraints {
return &securityv1.SecurityContextConstraints{
ObjectMeta: metav1.ObjectMeta{
Expand Down

0 comments on commit 4d7bed8

Please sign in to comment.