Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
158f17b9
Commit
158f17b9
authored
Jun 06, 2017
by
Quintin Lee
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
PodSecurityPolicy should respect and validate user-supplied RunAsNonRoot fields.
parent
8df56da4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
138 additions
and
82 deletions
+138
-82
provider.go
pkg/security/podsecuritypolicy/provider.go
+1
-1
provider_test.go
pkg/security/podsecuritypolicy/provider_test.go
+70
-60
nonroot.go
pkg/security/podsecuritypolicy/user/nonroot.go
+9
-3
nonroot_test.go
pkg/security/podsecuritypolicy/user/nonroot_test.go
+58
-18
No files found.
pkg/security/podsecuritypolicy/provider.go
View file @
158f17b9
...
@@ -165,7 +165,7 @@ func (s *simpleProvider) CreateContainerSecurityContext(pod *api.Pod, container
...
@@ -165,7 +165,7 @@ 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
// 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
// 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 UID will be checked.
// or, if runAsUser is not set, the image UID will be checked.
if
s
.
psp
.
Spec
.
RunAsUser
.
Rule
==
extensions
.
RunAsUserStrategyMustRunAsNonRoot
{
if
s
c
.
RunAsNonRoot
==
nil
&&
s
.
psp
.
Spec
.
RunAsUser
.
Rule
==
extensions
.
RunAsUserStrategyMustRunAsNonRoot
{
nonRoot
:=
true
nonRoot
:=
true
sc
.
RunAsNonRoot
=
&
nonRoot
sc
.
RunAsNonRoot
=
&
nonRoot
}
}
...
...
pkg/security/podsecuritypolicy/provider_test.go
View file @
158f17b9
...
@@ -112,76 +112,86 @@ func TestCreatePodSecurityContextNonmutating(t *testing.T) {
...
@@ -112,76 +112,86 @@ func TestCreatePodSecurityContextNonmutating(t *testing.T) {
}
}
func
TestCreateContainerSecurityContextNonmutating
(
t
*
testing
.
T
)
{
func
TestCreateContainerSecurityContextNonmutating
(
t
*
testing
.
T
)
{
// Create a pod with a security context that needs filling in
untrue
:=
false
createPod
:=
func
()
*
api
.
Pod
{
tests
:=
[]
struct
{
return
&
api
.
Pod
{
security
*
api
.
SecurityContext
Spec
:
api
.
PodSpec
{
}{
Containers
:
[]
api
.
Container
{{
{
nil
},
SecurityContext
:
&
api
.
SecurityContext
{},
{
&
api
.
SecurityContext
{
RunAsNonRoot
:
&
untrue
}},
}},
},
}
}
}
// Create a PSP with strategies that will populate a blank security context
for
_
,
tc
:=
range
tests
{
createPSP
:=
func
()
*
extensions
.
PodSecurityPolicy
{
// Create a pod with a security context that needs filling in
uid
:=
types
.
UnixUserID
(
1
)
createPod
:=
func
()
*
api
.
Pod
{
return
&
extensions
.
PodSecurityPolicy
{
return
&
api
.
Pod
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Spec
:
api
.
PodSpec
{
Name
:
"psp-sa"
,
Containers
:
[]
api
.
Container
{{
Annotations
:
map
[
string
]
string
{
SecurityContext
:
tc
.
security
,
seccomp
.
AllowedProfilesAnnotationKey
:
"*"
,
}},
seccomp
.
DefaultProfileAnnotationKey
:
"foo"
,
},
},
},
}
Spec
:
extensions
.
PodSecurityPolicySpec
{
}
DefaultAddCapabilities
:
[]
api
.
Capability
{
"foo"
},
RequiredDropCapabilities
:
[]
api
.
Capability
{
"bar"
},
// Create a PSP with strategies that will populate a blank security context
RunAsUser
:
extensions
.
RunAsUserStrategyOptions
{
createPSP
:=
func
()
*
extensions
.
PodSecurityPolicy
{
Rule
:
extensions
.
RunAsUserStrategyMustRunAs
,
uid
:=
types
.
UnixUserID
(
1
)
Ranges
:
[]
extensions
.
UserIDRange
{{
Min
:
uid
,
Max
:
uid
}},
return
&
extensions
.
PodSecurityPolicy
{
},
ObjectMeta
:
metav1
.
ObjectMeta
{
SELinux
:
extensions
.
SELinuxStrategyOptions
{
Name
:
"psp-sa"
,
Rule
:
extensions
.
SELinuxStrategyMustRunAs
,
Annotations
:
map
[
string
]
string
{
SELinuxOptions
:
&
api
.
SELinuxOptions
{
User
:
"you"
},
seccomp
.
AllowedProfilesAnnotationKey
:
"*"
,
},
seccomp
.
DefaultProfileAnnotationKey
:
"foo"
,
// these are pod mutating strategies that are tested above
},
FSGroup
:
extensions
.
FSGroupStrategyOptions
{
Rule
:
extensions
.
FSGroupStrategyRunAsAny
,
},
},
SupplementalGroups
:
extensions
.
SupplementalGroupsStrategyOptions
{
Spec
:
extensions
.
PodSecurityPolicySpec
{
Rule
:
extensions
.
SupplementalGroupsStrategyRunAsAny
,
DefaultAddCapabilities
:
[]
api
.
Capability
{
"foo"
},
RequiredDropCapabilities
:
[]
api
.
Capability
{
"bar"
},
RunAsUser
:
extensions
.
RunAsUserStrategyOptions
{
Rule
:
extensions
.
RunAsUserStrategyMustRunAs
,
Ranges
:
[]
extensions
.
UserIDRange
{{
Min
:
uid
,
Max
:
uid
}},
},
SELinux
:
extensions
.
SELinuxStrategyOptions
{
Rule
:
extensions
.
SELinuxStrategyMustRunAs
,
SELinuxOptions
:
&
api
.
SELinuxOptions
{
User
:
"you"
},
},
// these are pod mutating strategies that are tested above
FSGroup
:
extensions
.
FSGroupStrategyOptions
{
Rule
:
extensions
.
FSGroupStrategyRunAsAny
,
},
SupplementalGroups
:
extensions
.
SupplementalGroupsStrategyOptions
{
Rule
:
extensions
.
SupplementalGroupsStrategyRunAsAny
,
},
// mutates the container SC by defaulting to true if container sets nil
ReadOnlyRootFilesystem
:
true
,
},
},
// mutates the container SC by defaulting to true if container sets nil
}
ReadOnlyRootFilesystem
:
true
,
},
}
}
}
pod
:=
createPod
()
pod
:=
createPod
()
psp
:=
createPSP
()
psp
:=
createPSP
()
provider
,
err
:=
NewSimpleProvider
(
psp
,
"namespace"
,
NewSimpleStrategyFactory
())
provider
,
err
:=
NewSimpleProvider
(
psp
,
"namespace"
,
NewSimpleStrategyFactory
())
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatalf
(
"unable to create provider %v"
,
err
)
t
.
Fatalf
(
"unable to create provider %v"
,
err
)
}
}
sc
,
_
,
err
:=
provider
.
CreateContainerSecurityContext
(
pod
,
&
pod
.
Spec
.
Containers
[
0
])
sc
,
_
,
err
:=
provider
.
CreateContainerSecurityContext
(
pod
,
&
pod
.
Spec
.
Containers
[
0
])
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatalf
(
"unable to create container security context %v"
,
err
)
t
.
Fatalf
(
"unable to create container security context %v"
,
err
)
}
}
// The generated security context should have filled in missing options, so they should differ
// The generated security context should have filled in missing options, so they should differ
if
reflect
.
DeepEqual
(
sc
,
&
pod
.
Spec
.
Containers
[
0
]
.
SecurityContext
)
{
if
reflect
.
DeepEqual
(
sc
,
&
pod
.
Spec
.
Containers
[
0
]
.
SecurityContext
)
{
t
.
Error
(
"expected created security context to be different than container's, but they were identical"
)
t
.
Error
(
"expected created security context to be different than container's, but they were identical"
)
}
}
// Creating the provider or the security context should not have mutated the psp or pod
// Creating the provider or the security context should not have mutated the psp or pod
if
!
reflect
.
DeepEqual
(
createPod
(),
pod
)
{
if
!
reflect
.
DeepEqual
(
createPod
(),
pod
)
{
diffs
:=
diff
.
ObjectDiff
(
createPod
(),
pod
)
diffs
:=
diff
.
ObjectDiff
(
createPod
(),
pod
)
t
.
Errorf
(
"pod was mutated by CreateContainerSecurityContext. diff:
\n
%s"
,
diffs
)
t
.
Errorf
(
"pod was mutated by CreateContainerSecurityContext. diff:
\n
%s"
,
diffs
)
}
}
if
!
reflect
.
DeepEqual
(
createPSP
(),
psp
)
{
if
!
reflect
.
DeepEqual
(
createPSP
(),
psp
)
{
t
.
Error
(
"psp was mutated by CreateContainerSecurityContext"
)
t
.
Error
(
"psp was mutated by CreateContainerSecurityContext"
)
}
}
}
}
}
...
...
pkg/security/podsecuritypolicy/user/nonroot.go
View file @
158f17b9
...
@@ -41,8 +41,9 @@ func (s *nonRoot) Generate(pod *api.Pod, container *api.Container) (*types.UnixU
...
@@ -41,8 +41,9 @@ func (s *nonRoot) Generate(pod *api.Pod, container *api.Container) (*types.UnixU
// Validate ensures that the specified values fall within the range of the strategy. Validation
// Validate ensures that the specified values fall within the range of the strategy. Validation
// of this will pass if either the UID is not set, assuming that the image will provided the UID
// of this will pass if either the UID is not set, assuming that the image will provided the UID
// or if the UID is set it is not root. In order to work properly this assumes that the kubelet
// or if the UID is set it is not root. Validation will fail if RunAsNonRoot is set to false.
// performs a final check on runAsUser or the image UID when runAsUser is nil.
// In order to work properly this assumes that the kubelet performs a final check on runAsUser
// or the image UID when runAsUser is nil.
func
(
s
*
nonRoot
)
Validate
(
pod
*
api
.
Pod
,
container
*
api
.
Container
)
field
.
ErrorList
{
func
(
s
*
nonRoot
)
Validate
(
pod
*
api
.
Pod
,
container
*
api
.
Container
)
field
.
ErrorList
{
allErrs
:=
field
.
ErrorList
{}
allErrs
:=
field
.
ErrorList
{}
securityContextPath
:=
field
.
NewPath
(
"securityContext"
)
securityContextPath
:=
field
.
NewPath
(
"securityContext"
)
...
@@ -51,8 +52,13 @@ func (s *nonRoot) Validate(pod *api.Pod, container *api.Container) field.ErrorLi
...
@@ -51,8 +52,13 @@ func (s *nonRoot) Validate(pod *api.Pod, container *api.Container) field.ErrorLi
allErrs
=
append
(
allErrs
,
field
.
Invalid
(
securityContextPath
,
container
.
SecurityContext
,
detail
))
allErrs
=
append
(
allErrs
,
field
.
Invalid
(
securityContextPath
,
container
.
SecurityContext
,
detail
))
return
allErrs
return
allErrs
}
}
if
container
.
SecurityContext
.
RunAsNonRoot
!=
nil
&&
*
container
.
SecurityContext
.
RunAsNonRoot
==
false
{
detail
:=
fmt
.
Sprintf
(
"RunAsNonRoot must be true for container %s"
,
container
.
Name
)
allErrs
=
append
(
allErrs
,
field
.
Invalid
(
securityContextPath
.
Child
(
"runAsNonRoot"
),
*
container
.
SecurityContext
.
RunAsNonRoot
,
detail
))
return
allErrs
}
if
container
.
SecurityContext
.
RunAsUser
!=
nil
&&
*
container
.
SecurityContext
.
RunAsUser
==
0
{
if
container
.
SecurityContext
.
RunAsUser
!=
nil
&&
*
container
.
SecurityContext
.
RunAsUser
==
0
{
detail
:=
fmt
.
Sprintf
(
"running with the root UID is forbidden by the pod security policy %s"
,
container
.
Name
)
detail
:=
fmt
.
Sprintf
(
"running with the root UID is forbidden by the pod security policy
for container
%s"
,
container
.
Name
)
allErrs
=
append
(
allErrs
,
field
.
Invalid
(
securityContextPath
.
Child
(
"runAsUser"
),
*
container
.
SecurityContext
.
RunAsUser
,
detail
))
allErrs
=
append
(
allErrs
,
field
.
Invalid
(
securityContextPath
.
Child
(
"runAsUser"
),
*
container
.
SecurityContext
.
RunAsUser
,
detail
))
return
allErrs
return
allErrs
}
}
...
...
pkg/security/podsecuritypolicy/user/nonroot_test.go
View file @
158f17b9
...
@@ -52,30 +52,70 @@ func TestNonRootGenerate(t *testing.T) {
...
@@ -52,30 +52,70 @@ func TestNonRootGenerate(t *testing.T) {
func
TestNonRootValidate
(
t
*
testing
.
T
)
{
func
TestNonRootValidate
(
t
*
testing
.
T
)
{
goodUID
:=
types
.
UnixUserID
(
1
)
goodUID
:=
types
.
UnixUserID
(
1
)
badUID
:=
types
.
UnixUserID
(
0
)
badUID
:=
types
.
UnixUserID
(
0
)
untrue
:=
false
unfalse
:=
true
s
,
err
:=
NewRunAsNonRoot
(
&
extensions
.
RunAsUserStrategyOptions
{})
s
,
err
:=
NewRunAsNonRoot
(
&
extensions
.
RunAsUserStrategyOptions
{})
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatalf
(
"unexpected error initializing NewMustRunAs %v"
,
err
)
t
.
Fatalf
(
"unexpected error initializing NewMustRunAs %v"
,
err
)
}
}
container
:=
&
api
.
Container
{
tests
:=
[]
struct
{
SecurityContext
:
&
api
.
SecurityContext
{
container
*
api
.
Container
RunAsUser
:
&
badUID
,
expectedErr
bool
msg
string
}{
{
container
:
&
api
.
Container
{
SecurityContext
:
&
api
.
SecurityContext
{
RunAsUser
:
&
badUID
,
},
},
expectedErr
:
true
,
msg
:
"in test case %d, expected errors from root uid but got none: %v"
,
},
{
container
:
&
api
.
Container
{
SecurityContext
:
&
api
.
SecurityContext
{
RunAsUser
:
&
goodUID
,
},
},
expectedErr
:
false
,
msg
:
"in test case %d, expected no errors from non-root uid but got %v"
,
},
{
container
:
&
api
.
Container
{
SecurityContext
:
&
api
.
SecurityContext
{
RunAsNonRoot
:
&
untrue
,
},
},
expectedErr
:
true
,
msg
:
"in test case %d, expected errors from RunAsNonRoot but got none: %v"
,
},
{
container
:
&
api
.
Container
{
SecurityContext
:
&
api
.
SecurityContext
{
RunAsNonRoot
:
&
unfalse
,
RunAsUser
:
&
goodUID
,
},
},
expectedErr
:
false
,
msg
:
"in test case %d, expected no errors from non-root uid but got %v"
,
},
{
container
:
&
api
.
Container
{
SecurityContext
:
&
api
.
SecurityContext
{
RunAsNonRoot
:
&
unfalse
,
RunAsUser
:
&
badUID
,
},
},
expectedErr
:
true
,
msg
:
"in test case %d, expected errors from root uid but got %v"
,
},
},
}
}
errs
:=
s
.
Validate
(
nil
,
container
)
for
i
,
tc
:=
range
tests
{
if
len
(
errs
)
==
0
{
errs
:=
s
.
Validate
(
nil
,
tc
.
container
)
t
.
Errorf
(
"expected errors from root uid but got none"
)
if
(
len
(
errs
)
==
0
)
==
tc
.
expectedErr
{
}
t
.
Errorf
(
tc
.
msg
,
i
,
errs
)
}
container
.
SecurityContext
.
RunAsUser
=
&
goodUID
errs
=
s
.
Validate
(
nil
,
container
)
if
len
(
errs
)
!=
0
{
t
.
Errorf
(
"expected no errors from non-root uid but got %v"
,
errs
)
}
container
.
SecurityContext
.
RunAsUser
=
nil
errs
=
s
.
Validate
(
nil
,
container
)
if
len
(
errs
)
!=
0
{
t
.
Errorf
(
"expected no errors from nil uid but got %v"
,
errs
)
}
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment