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
f75b3f3d
Commit
f75b3f3d
authored
Apr 01, 2017
by
Josh Horwitz
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added host path whitelist to psp
parent
52337d5d
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
187 additions
and
1 deletion
+187
-1
types.go
pkg/apis/extensions/types.go
+4
-0
types.go
pkg/apis/extensions/v1beta1/types.go
+4
-0
provider.go
pkg/security/podsecuritypolicy/provider.go
+9
-0
provider_test.go
pkg/security/podsecuritypolicy/provider_test.go
+40
-1
util.go
pkg/security/podsecuritypolicy/util/util.go
+50
-0
util_test.go
pkg/security/podsecuritypolicy/util/util_test.go
+80
-0
No files found.
pkg/apis/extensions/types.go
View file @
f75b3f3d
...
@@ -884,6 +884,10 @@ type PodSecurityPolicySpec struct {
...
@@ -884,6 +884,10 @@ type PodSecurityPolicySpec struct {
// will not be forced to.
// will not be forced to.
// +optional
// +optional
ReadOnlyRootFilesystem
bool
ReadOnlyRootFilesystem
bool
// AllowedHostPaths is a white list of allowed host path prefixes. Empty indicates that all
// host paths may be used.
// +optional
AllowedHostPaths
[]
string
}
}
// HostPortRange defines a range of host ports that will be enabled by a policy
// HostPortRange defines a range of host ports that will be enabled by a policy
...
...
pkg/apis/extensions/v1beta1/types.go
View file @
f75b3f3d
...
@@ -909,6 +909,10 @@ type PodSecurityPolicySpec struct {
...
@@ -909,6 +909,10 @@ type PodSecurityPolicySpec struct {
// will not be forced to.
// will not be forced to.
// +optional
// +optional
ReadOnlyRootFilesystem
bool
`json:"readOnlyRootFilesystem,omitempty" protobuf:"varint,14,opt,name=readOnlyRootFilesystem"`
ReadOnlyRootFilesystem
bool
`json:"readOnlyRootFilesystem,omitempty" protobuf:"varint,14,opt,name=readOnlyRootFilesystem"`
// AllowedHostPaths is a white list of allowed host path prefixes. Empty indicates that all
// host paths may be used.
// +optional
AllowedHostPaths
[]
string
`json:"allowedHostPaths,omitempty" protobuf:"bytes,15,opt,name=allowedHostPaths"`
}
}
// FS Type gives strong typing to different file systems that are used by volumes.
// FS Type gives strong typing to different file systems that are used by volumes.
...
...
pkg/security/podsecuritypolicy/provider.go
View file @
f75b3f3d
...
@@ -241,6 +241,15 @@ func (s *simpleProvider) ValidatePodSecurityContext(pod *api.Pod, fldPath *field
...
@@ -241,6 +241,15 @@ func (s *simpleProvider) ValidatePodSecurityContext(pod *api.Pod, fldPath *field
allErrs
=
append
(
allErrs
,
field
.
Invalid
(
allErrs
=
append
(
allErrs
,
field
.
Invalid
(
field
.
NewPath
(
"spec"
,
"volumes"
)
.
Index
(
i
),
string
(
fsType
),
field
.
NewPath
(
"spec"
,
"volumes"
)
.
Index
(
i
),
string
(
fsType
),
fmt
.
Sprintf
(
"%s volumes are not allowed to be used"
,
string
(
fsType
))))
fmt
.
Sprintf
(
"%s volumes are not allowed to be used"
,
string
(
fsType
))))
continue
}
if
fsType
==
extensions
.
HostPath
{
if
!
psputil
.
PSPAllowsHostVolumePath
(
s
.
psp
,
v
.
HostPath
.
Path
)
{
allErrs
=
append
(
allErrs
,
field
.
Invalid
(
field
.
NewPath
(
"spec"
,
"volumes"
)
.
Index
(
i
),
string
(
fsType
),
fmt
.
Sprintf
(
"host path %s is not allowed to be used. allowed host paths: %v"
,
v
.
HostPath
.
Path
,
s
.
psp
.
Spec
.
AllowedHostPaths
)))
}
}
}
}
}
}
}
...
...
pkg/security/podsecuritypolicy/provider_test.go
View file @
f75b3f3d
...
@@ -238,6 +238,21 @@ func TestValidatePodSecurityContextFailures(t *testing.T) {
...
@@ -238,6 +238,21 @@ func TestValidatePodSecurityContextFailures(t *testing.T) {
},
},
}
}
failHostPathDirPod
:=
defaultPod
()
failHostPathDirPod
.
Spec
.
Volumes
=
[]
api
.
Volume
{
{
Name
:
"bad volume"
,
VolumeSource
:
api
.
VolumeSource
{
HostPath
:
&
api
.
HostPathVolumeSource
{
Path
:
"/fail"
,
},
},
},
}
failHostPathDirPSP
:=
defaultPSP
()
failHostPathDirPSP
.
Spec
.
Volumes
=
[]
extensions
.
FSType
{
extensions
.
HostPath
}
failHostPathDirPSP
.
Spec
.
AllowedHostPaths
=
[]
string
{
"/foo/bar"
}
failOtherSysctlsAllowedPSP
:=
defaultPSP
()
failOtherSysctlsAllowedPSP
:=
defaultPSP
()
failOtherSysctlsAllowedPSP
.
Annotations
[
extensions
.
SysctlsPodSecurityPolicyAnnotationKey
]
=
"bar,abc"
failOtherSysctlsAllowedPSP
.
Annotations
[
extensions
.
SysctlsPodSecurityPolicyAnnotationKey
]
=
"bar,abc"
...
@@ -308,6 +323,11 @@ func TestValidatePodSecurityContextFailures(t *testing.T) {
...
@@ -308,6 +323,11 @@ func TestValidatePodSecurityContextFailures(t *testing.T) {
psp
:
defaultPSP
(),
psp
:
defaultPSP
(),
expectedError
:
"hostPath volumes are not allowed to be used"
,
expectedError
:
"hostPath volumes are not allowed to be used"
,
},
},
"failHostPathDirPSP"
:
{
pod
:
failHostPathDirPod
,
psp
:
failHostPathDirPSP
,
expectedError
:
"host path /fail is not allowed to be used. allowed host paths: [/foo/bar]"
,
},
"failSafeSysctlFooPod with failNoSysctlAllowedSCC"
:
{
"failSafeSysctlFooPod with failNoSysctlAllowedSCC"
:
{
pod
:
failSafeSysctlFooPod
,
pod
:
failSafeSysctlFooPod
,
psp
:
failNoSysctlAllowedPSP
,
psp
:
failNoSysctlAllowedPSP
,
...
@@ -706,13 +726,28 @@ func TestValidateContainerSecurityContextSuccess(t *testing.T) {
...
@@ -706,13 +726,28 @@ func TestValidateContainerSecurityContextSuccess(t *testing.T) {
hostDirPod
:=
defaultPod
()
hostDirPod
:=
defaultPod
()
hostDirPod
.
Spec
.
Volumes
=
[]
api
.
Volume
{
hostDirPod
.
Spec
.
Volumes
=
[]
api
.
Volume
{
{
{
Name
:
"
ba
d volume"
,
Name
:
"
goo
d volume"
,
VolumeSource
:
api
.
VolumeSource
{
VolumeSource
:
api
.
VolumeSource
{
HostPath
:
&
api
.
HostPathVolumeSource
{},
HostPath
:
&
api
.
HostPathVolumeSource
{},
},
},
},
},
}
}
hostPathDirPod
:=
defaultPod
()
hostPathDirPod
.
Spec
.
Volumes
=
[]
api
.
Volume
{
{
Name
:
"good volume"
,
VolumeSource
:
api
.
VolumeSource
{
HostPath
:
&
api
.
HostPathVolumeSource
{
Path
:
"/foo/bar/baz"
,
},
},
},
}
hostPathDirPSP
:=
defaultPSP
()
hostPathDirPSP
.
Spec
.
Volumes
=
[]
extensions
.
FSType
{
extensions
.
HostPath
}
hostPathDirPSP
.
Spec
.
AllowedHostPaths
=
[]
string
{
"/foo/bar"
}
hostPortPSP
:=
defaultPSP
()
hostPortPSP
:=
defaultPSP
()
hostPortPSP
.
Spec
.
HostPorts
=
[]
extensions
.
HostPortRange
{{
Min
:
1
,
Max
:
1
}}
hostPortPSP
.
Spec
.
HostPorts
=
[]
extensions
.
HostPortRange
{{
Min
:
1
,
Max
:
1
}}
hostPortPod
:=
defaultPod
()
hostPortPod
:=
defaultPod
()
...
@@ -773,6 +808,10 @@ func TestValidateContainerSecurityContextSuccess(t *testing.T) {
...
@@ -773,6 +808,10 @@ func TestValidateContainerSecurityContextSuccess(t *testing.T) {
pod
:
hostDirPod
,
pod
:
hostDirPod
,
psp
:
hostDirPSP
,
psp
:
hostDirPSP
,
},
},
"pass hostDir allowed directory validating PSP"
:
{
pod
:
hostPathDirPod
,
psp
:
hostPathDirPSP
,
},
"pass hostPort validating PSP"
:
{
"pass hostPort validating PSP"
:
{
pod
:
hostPortPod
,
pod
:
hostPortPod
,
psp
:
hostPortPSP
,
psp
:
hostPortPSP
,
...
...
pkg/security/podsecuritypolicy/util/util.go
View file @
f75b3f3d
...
@@ -18,6 +18,7 @@ package util
...
@@ -18,6 +18,7 @@ package util
import
(
import
(
"fmt"
"fmt"
"strings"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/sets"
...
@@ -168,3 +169,52 @@ func UserFallsInRange(id types.UnixUserID, rng extensions.UserIDRange) bool {
...
@@ -168,3 +169,52 @@ func UserFallsInRange(id types.UnixUserID, rng extensions.UserIDRange) bool {
func
GroupFallsInRange
(
id
types
.
UnixGroupID
,
rng
extensions
.
GroupIDRange
)
bool
{
func
GroupFallsInRange
(
id
types
.
UnixGroupID
,
rng
extensions
.
GroupIDRange
)
bool
{
return
id
>=
rng
.
Min
&&
id
<=
rng
.
Max
return
id
>=
rng
.
Min
&&
id
<=
rng
.
Max
}
}
// PSPAllowsHostVolumePath is a utility for checking if a PSP allows the host volume path.
// This only checks the path. You should still check to make sure the host volume fs type is allowed.
func
PSPAllowsHostVolumePath
(
psp
*
extensions
.
PodSecurityPolicy
,
hostPath
string
)
bool
{
if
psp
==
nil
{
return
false
}
// If no allowed paths are specified then allow any path
if
len
(
psp
.
Spec
.
AllowedHostPaths
)
==
0
{
return
true
}
for
_
,
allowedPath
:=
range
psp
.
Spec
.
AllowedHostPaths
{
if
hasPathPrefix
(
hostPath
,
allowedPath
)
{
return
true
}
}
return
false
}
// hasPathPrefix returns true if the string matches pathPrefix exactly, or if is prefixed with pathPrefix at a path segment boundary
// the string and pathPrefix are both normalized to remove trailing slashes prior to checking.
func
hasPathPrefix
(
s
,
pathPrefix
string
)
bool
{
s
=
strings
.
TrimSuffix
(
s
,
"/"
)
pathPrefix
=
strings
.
TrimSuffix
(
pathPrefix
,
"/"
)
// Short circuit if s doesn't contain the prefix at all
if
!
strings
.
HasPrefix
(
s
,
pathPrefix
)
{
return
false
}
pathPrefixLength
:=
len
(
pathPrefix
)
if
len
(
s
)
==
pathPrefixLength
{
// Exact match
return
true
}
if
s
[
pathPrefixLength
:
pathPrefixLength
+
1
]
==
"/"
{
// The next character in s is a path segment boundary
// Check this instead of normalizing pathPrefix to avoid allocating on every call
return
true
}
return
false
}
pkg/security/podsecuritypolicy/util/util_test.go
View file @
f75b3f3d
...
@@ -103,3 +103,83 @@ func TestPSPAllowsFSType(t *testing.T) {
...
@@ -103,3 +103,83 @@ func TestPSPAllowsFSType(t *testing.T) {
}
}
}
}
}
}
func
TestPSPAllowsHostVolumePath
(
t
*
testing
.
T
)
{
tests
:=
map
[
string
]
struct
{
psp
*
extensions
.
PodSecurityPolicy
path
string
allows
bool
}{
"nil psp"
:
{
psp
:
nil
,
path
:
"/test"
,
allows
:
false
,
},
"empty allowed paths"
:
{
psp
:
&
extensions
.
PodSecurityPolicy
{},
path
:
"/test"
,
allows
:
true
,
},
"non-matching"
:
{
psp
:
&
extensions
.
PodSecurityPolicy
{
Spec
:
extensions
.
PodSecurityPolicySpec
{
AllowedHostPaths
:
[]
string
{
"/foo"
},
},
},
path
:
"/foobar"
,
allows
:
false
,
},
"match on direct match"
:
{
psp
:
&
extensions
.
PodSecurityPolicy
{
Spec
:
extensions
.
PodSecurityPolicySpec
{
AllowedHostPaths
:
[]
string
{
"/foo"
},
},
},
path
:
"/foo"
,
allows
:
true
,
},
"match with trailing slash on host path"
:
{
psp
:
&
extensions
.
PodSecurityPolicy
{
Spec
:
extensions
.
PodSecurityPolicySpec
{
AllowedHostPaths
:
[]
string
{
"/foo"
},
},
},
path
:
"/foo/"
,
allows
:
true
,
},
"match with trailing slash on allowed path"
:
{
psp
:
&
extensions
.
PodSecurityPolicy
{
Spec
:
extensions
.
PodSecurityPolicySpec
{
AllowedHostPaths
:
[]
string
{
"/foo/"
},
},
},
path
:
"/foo"
,
allows
:
true
,
},
"match child directory"
:
{
psp
:
&
extensions
.
PodSecurityPolicy
{
Spec
:
extensions
.
PodSecurityPolicySpec
{
AllowedHostPaths
:
[]
string
{
"/foo/"
},
},
},
path
:
"/foo/bar"
,
allows
:
true
,
},
"non-matching parent directory"
:
{
psp
:
&
extensions
.
PodSecurityPolicy
{
Spec
:
extensions
.
PodSecurityPolicySpec
{
AllowedHostPaths
:
[]
string
{
"/foo/bar"
},
},
},
path
:
"/foo"
,
allows
:
false
,
},
}
for
k
,
v
:=
range
tests
{
allows
:=
PSPAllowsHostVolumePath
(
v
.
psp
,
v
.
path
)
if
v
.
allows
!=
allows
{
t
.
Errorf
(
"%s expected PSPAllowsHostVolumePath to return %t but got %t"
,
k
,
v
.
allows
,
allows
)
}
}
}
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