vendor update for CSI 0.3.0

This commit is contained in:
gman
2018-07-18 16:47:22 +02:00
parent 6f484f92fc
commit 8ea659f0d5
6810 changed files with 438061 additions and 193861 deletions

View File

@ -17,7 +17,7 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/security/podsecuritypolicy",
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/apis/policy:go_default_library",
"//pkg/security/podsecuritypolicy/apparmor:go_default_library",
"//pkg/security/podsecuritypolicy/capabilities:go_default_library",
"//pkg/security/podsecuritypolicy/group:go_default_library",
@ -39,7 +39,7 @@ go_test(
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/apis/core/v1:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/apis/policy:go_default_library",
"//pkg/security/apparmor:go_default_library",
"//pkg/security/podsecuritypolicy/seccomp:go_default_library",
"//pkg/security/podsecuritypolicy/util:go_default_library",

View File

@ -16,7 +16,7 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/security/podsecuritypolicy/capabilities",
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/apis/policy:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
],
@ -28,7 +28,7 @@ go_test(
embed = [":go_default_library"],
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/apis/policy:go_default_library",
],
)

View File

@ -22,7 +22,7 @@ import (
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation/field"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/apis/policy"
)
// defaultCapabilities implements the Strategy interface
@ -100,7 +100,7 @@ func (s *defaultCapabilities) Validate(pod *api.Pod, container *api.Container, c
}
allowedAdd := makeCapSet(s.allowedCaps)
allowAllCaps := allowedAdd.Has(string(extensions.AllowAllCapabilities))
allowAllCaps := allowedAdd.Has(string(policy.AllowAllCapabilities))
if allowAllCaps {
// skip validation against allowed/defaultAdd/requiredDrop because all capabilities are allowed by a wildcard
return allErrs

View File

@ -21,7 +21,7 @@ import (
"testing"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/apis/policy"
)
func TestGenerateAdds(t *testing.T) {
@ -278,7 +278,7 @@ func TestValidateAdds(t *testing.T) {
},
},
"no required, all allowed, container requests valid": {
allowedCaps: []api.Capability{extensions.AllowAllCapabilities},
allowedCaps: []api.Capability{policy.AllowAllCapabilities},
containerCaps: &api.Capabilities{
Add: []api.Capability{"foo"},
},

View File

@ -21,7 +21,7 @@ import (
"k8s.io/apimachinery/pkg/util/errors"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/apis/policy"
"k8s.io/kubernetes/pkg/security/podsecuritypolicy/apparmor"
"k8s.io/kubernetes/pkg/security/podsecuritypolicy/capabilities"
"k8s.io/kubernetes/pkg/security/podsecuritypolicy/group"
@ -39,7 +39,7 @@ func NewSimpleStrategyFactory() StrategyFactory {
return &simpleStrategyFactory{}
}
func (f *simpleStrategyFactory) CreateStrategies(psp *extensions.PodSecurityPolicy, namespace string) (*ProviderStrategies, error) {
func (f *simpleStrategyFactory) CreateStrategies(psp *policy.PodSecurityPolicy, namespace string) (*ProviderStrategies, error) {
errs := []error{}
userStrat, err := createUserStrategy(&psp.Spec.RunAsUser)
@ -77,15 +77,7 @@ func (f *simpleStrategyFactory) CreateStrategies(psp *extensions.PodSecurityPoli
errs = append(errs, err)
}
var unsafeSysctls []string
if ann, found := psp.Annotations[extensions.SysctlsPodSecurityPolicyAnnotationKey]; found {
var err error
unsafeSysctls, err = extensions.SysctlsFromPodSecurityPolicyAnnotation(ann)
if err != nil {
errs = append(errs, err)
}
}
sysctlsStrat := createSysctlsStrategy(unsafeSysctls)
sysctlsStrat := createSysctlsStrategy(sysctl.SafeSysctlWhitelist(), psp.Spec.AllowedUnsafeSysctls, psp.Spec.ForbiddenSysctls)
if len(errs) > 0 {
return nil, errors.NewAggregate(errs)
@ -106,13 +98,13 @@ func (f *simpleStrategyFactory) CreateStrategies(psp *extensions.PodSecurityPoli
}
// createUserStrategy creates a new user strategy.
func createUserStrategy(opts *extensions.RunAsUserStrategyOptions) (user.RunAsUserStrategy, error) {
func createUserStrategy(opts *policy.RunAsUserStrategyOptions) (user.RunAsUserStrategy, error) {
switch opts.Rule {
case extensions.RunAsUserStrategyMustRunAs:
case policy.RunAsUserStrategyMustRunAs:
return user.NewMustRunAs(opts)
case extensions.RunAsUserStrategyMustRunAsNonRoot:
case policy.RunAsUserStrategyMustRunAsNonRoot:
return user.NewRunAsNonRoot(opts)
case extensions.RunAsUserStrategyRunAsAny:
case policy.RunAsUserStrategyRunAsAny:
return user.NewRunAsAny(opts)
default:
return nil, fmt.Errorf("Unrecognized RunAsUser strategy type %s", opts.Rule)
@ -120,11 +112,11 @@ func createUserStrategy(opts *extensions.RunAsUserStrategyOptions) (user.RunAsUs
}
// createSELinuxStrategy creates a new selinux strategy.
func createSELinuxStrategy(opts *extensions.SELinuxStrategyOptions) (selinux.SELinuxStrategy, error) {
func createSELinuxStrategy(opts *policy.SELinuxStrategyOptions) (selinux.SELinuxStrategy, error) {
switch opts.Rule {
case extensions.SELinuxStrategyMustRunAs:
case policy.SELinuxStrategyMustRunAs:
return selinux.NewMustRunAs(opts)
case extensions.SELinuxStrategyRunAsAny:
case policy.SELinuxStrategyRunAsAny:
return selinux.NewRunAsAny(opts)
default:
return nil, fmt.Errorf("Unrecognized SELinuxContext strategy type %s", opts.Rule)
@ -132,21 +124,21 @@ func createSELinuxStrategy(opts *extensions.SELinuxStrategyOptions) (selinux.SEL
}
// createAppArmorStrategy creates a new AppArmor strategy.
func createAppArmorStrategy(psp *extensions.PodSecurityPolicy) (apparmor.Strategy, error) {
func createAppArmorStrategy(psp *policy.PodSecurityPolicy) (apparmor.Strategy, error) {
return apparmor.NewStrategy(psp.Annotations), nil
}
// createSeccompStrategy creates a new seccomp strategy.
func createSeccompStrategy(psp *extensions.PodSecurityPolicy) (seccomp.Strategy, error) {
func createSeccompStrategy(psp *policy.PodSecurityPolicy) (seccomp.Strategy, error) {
return seccomp.NewStrategy(psp.Annotations), nil
}
// createFSGroupStrategy creates a new fsgroup strategy
func createFSGroupStrategy(opts *extensions.FSGroupStrategyOptions) (group.GroupStrategy, error) {
func createFSGroupStrategy(opts *policy.FSGroupStrategyOptions) (group.GroupStrategy, error) {
switch opts.Rule {
case extensions.FSGroupStrategyRunAsAny:
case policy.FSGroupStrategyRunAsAny:
return group.NewRunAsAny()
case extensions.FSGroupStrategyMustRunAs:
case policy.FSGroupStrategyMustRunAs:
return group.NewMustRunAs(opts.Ranges, fsGroupField)
default:
return nil, fmt.Errorf("Unrecognized FSGroup strategy type %s", opts.Rule)
@ -154,11 +146,11 @@ func createFSGroupStrategy(opts *extensions.FSGroupStrategyOptions) (group.Group
}
// createSupplementalGroupStrategy creates a new supplemental group strategy
func createSupplementalGroupStrategy(opts *extensions.SupplementalGroupsStrategyOptions) (group.GroupStrategy, error) {
func createSupplementalGroupStrategy(opts *policy.SupplementalGroupsStrategyOptions) (group.GroupStrategy, error) {
switch opts.Rule {
case extensions.SupplementalGroupsStrategyRunAsAny:
case policy.SupplementalGroupsStrategyRunAsAny:
return group.NewRunAsAny()
case extensions.SupplementalGroupsStrategyMustRunAs:
case policy.SupplementalGroupsStrategyMustRunAs:
return group.NewMustRunAs(opts.Ranges, supplementalGroupsField)
default:
return nil, fmt.Errorf("Unrecognized SupplementalGroups strategy type %s", opts.Rule)
@ -170,7 +162,7 @@ func createCapabilitiesStrategy(defaultAddCaps, requiredDropCaps, allowedCaps []
return capabilities.NewDefaultCapabilities(defaultAddCaps, requiredDropCaps, allowedCaps)
}
// createSysctlsStrategy creates a new unsafe sysctls strategy.
func createSysctlsStrategy(sysctlsPatterns []string) sysctl.SysctlsStrategy {
return sysctl.NewMustMatchPatterns(sysctlsPatterns)
// createSysctlsStrategy creates a new sysctls strategy.
func createSysctlsStrategy(safeWhitelist, allowedUnsafeSysctls, forbiddenSysctls []string) sysctl.SysctlsStrategy {
return sysctl.NewMustMatchPatterns(safeWhitelist, allowedUnsafeSysctls, forbiddenSysctls)
}

View File

@ -17,7 +17,7 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/security/podsecuritypolicy/group",
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/apis/policy:go_default_library",
"//pkg/security/podsecuritypolicy/util:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
],
@ -30,7 +30,7 @@ go_test(
"runasany_test.go",
],
embed = [":go_default_library"],
deps = ["//pkg/apis/extensions:go_default_library"],
deps = ["//pkg/apis/policy:go_default_library"],
)
filegroup(

View File

@ -21,20 +21,20 @@ import (
"k8s.io/apimachinery/pkg/util/validation/field"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/apis/policy"
psputil "k8s.io/kubernetes/pkg/security/podsecuritypolicy/util"
)
// mustRunAs implements the GroupStrategy interface
type mustRunAs struct {
ranges []extensions.GroupIDRange
ranges []policy.IDRange
field string
}
var _ GroupStrategy = &mustRunAs{}
// NewMustRunAs provides a new MustRunAs strategy based on ranges.
func NewMustRunAs(ranges []extensions.GroupIDRange, field string) (GroupStrategy, error) {
func NewMustRunAs(ranges []policy.IDRange, field string) (GroupStrategy, error) {
if len(ranges) == 0 {
return nil, fmt.Errorf("ranges must be supplied for MustRunAs")
}
@ -70,7 +70,7 @@ func (s *mustRunAs) Validate(_ *api.Pod, groups []int64) field.ErrorList {
for _, group := range groups {
if !s.isGroupValid(group) {
detail := fmt.Sprintf("%d is not an allowed group", group)
detail := fmt.Sprintf("group %d must be in the ranges: %v", group, s.ranges)
allErrs = append(allErrs, field.Invalid(field.NewPath(s.field), groups, detail))
}
}

View File

@ -17,20 +17,22 @@ limitations under the License.
package group
import (
"k8s.io/kubernetes/pkg/apis/extensions"
"strings"
"testing"
"k8s.io/kubernetes/pkg/apis/policy"
)
func TestMustRunAsOptions(t *testing.T) {
tests := map[string]struct {
ranges []extensions.GroupIDRange
ranges []policy.IDRange
pass bool
}{
"empty": {
ranges: []extensions.GroupIDRange{},
ranges: []policy.IDRange{},
},
"ranges": {
ranges: []extensions.GroupIDRange{
ranges: []policy.IDRange{
{Min: 1, Max: 1},
},
pass: true,
@ -50,23 +52,23 @@ func TestMustRunAsOptions(t *testing.T) {
func TestGenerate(t *testing.T) {
tests := map[string]struct {
ranges []extensions.GroupIDRange
ranges []policy.IDRange
expected []int64
}{
"multi value": {
ranges: []extensions.GroupIDRange{
ranges: []policy.IDRange{
{Min: 1, Max: 2},
},
expected: []int64{1},
},
"single value": {
ranges: []extensions.GroupIDRange{
ranges: []policy.IDRange{
{Min: 1, Max: 1},
},
expected: []int64{1},
},
"multi range": {
ranges: []extensions.GroupIDRange{
ranges: []policy.IDRange{
{Min: 1, Max: 1},
{Min: 2, Max: 500},
},
@ -108,54 +110,53 @@ func TestGenerate(t *testing.T) {
func TestValidate(t *testing.T) {
tests := map[string]struct {
ranges []extensions.GroupIDRange
groups []int64
pass bool
ranges []policy.IDRange
groups []int64
expectedError string
}{
"nil security context": {
ranges: []extensions.GroupIDRange{
ranges: []policy.IDRange{
{Min: 1, Max: 3},
},
expectedError: "unable to validate empty groups against required ranges",
},
"empty groups": {
ranges: []extensions.GroupIDRange{
ranges: []policy.IDRange{
{Min: 1, Max: 3},
},
expectedError: "unable to validate empty groups against required ranges",
},
"not in range": {
groups: []int64{5},
ranges: []extensions.GroupIDRange{
ranges: []policy.IDRange{
{Min: 1, Max: 3},
{Min: 4, Max: 4},
},
expectedError: "group 5 must be in the ranges: [{1 3} {4 4}]",
},
"in range 1": {
groups: []int64{2},
ranges: []extensions.GroupIDRange{
ranges: []policy.IDRange{
{Min: 1, Max: 3},
},
pass: true,
},
"in range boundary min": {
groups: []int64{1},
ranges: []extensions.GroupIDRange{
ranges: []policy.IDRange{
{Min: 1, Max: 3},
},
pass: true,
},
"in range boundary max": {
groups: []int64{3},
ranges: []extensions.GroupIDRange{
ranges: []policy.IDRange{
{Min: 1, Max: 3},
},
pass: true,
},
"singular range": {
groups: []int64{4},
ranges: []extensions.GroupIDRange{
ranges: []policy.IDRange{
{Min: 4, Max: 4},
},
pass: true,
},
}
@ -165,11 +166,14 @@ func TestValidate(t *testing.T) {
t.Errorf("error creating strategy for %s: %v", k, err)
}
errs := s.Validate(nil, v.groups)
if v.pass && len(errs) > 0 {
if v.expectedError == "" && len(errs) > 0 {
t.Errorf("unexpected errors for %s: %v", k, errs)
}
if !v.pass && len(errs) == 0 {
t.Errorf("expected no errors for %s but got: %v", k, errs)
if v.expectedError != "" && len(errs) == 0 {
t.Errorf("expected errors for %s but got: %v", k, errs)
}
if v.expectedError != "" && len(errs) > 0 && !strings.Contains(errs[0].Error(), v.expectedError) {
t.Errorf("expected error for %s: %v, but got: %v", k, v.expectedError, errs[0])
}
}
}

View File

@ -22,7 +22,7 @@ import (
"k8s.io/apimachinery/pkg/util/validation/field"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/apis/policy"
psputil "k8s.io/kubernetes/pkg/security/podsecuritypolicy/util"
"k8s.io/kubernetes/pkg/securitycontext"
)
@ -36,7 +36,7 @@ const (
// simpleProvider is the default implementation of Provider.
type simpleProvider struct {
psp *extensions.PodSecurityPolicy
psp *policy.PodSecurityPolicy
strategies *ProviderStrategies
}
@ -44,7 +44,7 @@ type simpleProvider struct {
var _ Provider = &simpleProvider{}
// NewSimpleProvider creates a new Provider instance.
func NewSimpleProvider(psp *extensions.PodSecurityPolicy, namespace string, strategyFactory StrategyFactory) (Provider, error) {
func NewSimpleProvider(psp *policy.PodSecurityPolicy, namespace string, strategyFactory StrategyFactory) (Provider, error) {
if psp == nil {
return nil, fmt.Errorf("NewSimpleProvider requires a PodSecurityPolicy")
}
@ -144,7 +144,7 @@ func (s *simpleProvider) DefaultContainerSecurityContext(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 UID will be checked.
if sc.RunAsNonRoot() == nil && sc.RunAsUser() == nil && s.psp.Spec.RunAsUser.Rule == extensions.RunAsUserStrategyMustRunAsNonRoot {
if sc.RunAsNonRoot() == nil && sc.RunAsUser() == nil && s.psp.Spec.RunAsUser.Rule == policy.RunAsUserStrategyMustRunAsNonRoot {
nonRoot := true
sc.SetRunAsNonRoot(&nonRoot)
}
@ -226,15 +226,38 @@ func (s *simpleProvider) ValidatePod(pod *api.Pod, fldPath *field.Path) field.Er
continue
}
if fsType == extensions.HostPath {
if !psputil.AllowsHostVolumePath(s.psp, v.HostPath.Path) {
if fsType == policy.HostPath {
allows, mustBeReadOnly := psputil.AllowsHostVolumePath(s.psp, v.HostPath.Path)
if !allows {
allErrs = append(allErrs, field.Invalid(
field.NewPath("spec", "volumes").Index(i).Child("hostPath", "pathPrefix"), v.HostPath.Path,
fmt.Sprintf("is not allowed to be used")))
} else if mustBeReadOnly {
// Ensure all the VolumeMounts that use this volume are read-only
for i, c := range pod.Spec.InitContainers {
for j, cv := range c.VolumeMounts {
if cv.Name == v.Name && !cv.ReadOnly {
allErrs = append(allErrs, field.Invalid(
field.NewPath("spec", "initContainers").Index(i).Child("volumeMounts").Index(j).Child("readOnly"),
cv.ReadOnly, "must be read-only"),
)
}
}
}
for i, c := range pod.Spec.Containers {
for j, cv := range c.VolumeMounts {
if cv.Name == v.Name && !cv.ReadOnly {
allErrs = append(allErrs, field.Invalid(
field.NewPath("spec", "containers").Index(i).Child("volumeMounts").Index(j).Child("readOnly"),
cv.ReadOnly, "must be read-only"),
)
}
}
}
}
}
if fsType == extensions.FlexVolume && len(s.psp.Spec.AllowedFlexVolumes) > 0 {
if fsType == policy.FlexVolume && len(s.psp.Spec.AllowedFlexVolumes) > 0 {
found := false
driver := v.FlexVolume.Driver
for _, allowedFlexVolume := range s.psp.Spec.AllowedFlexVolumes {
@ -273,10 +296,6 @@ func (s *simpleProvider) ValidateContainerSecurityContext(pod *api.Pod, containe
allErrs = append(allErrs, s.strategies.CapabilitiesStrategy.Validate(pod, container, sc.Capabilities())...)
if !s.psp.Spec.HostNetwork && podSC.HostNetwork() {
allErrs = append(allErrs, field.Invalid(fldPath.Child("hostNetwork"), podSC.HostNetwork(), "Host network is not allowed to be used"))
}
containersPath := fldPath.Child("containers")
for idx, c := range pod.Spec.Containers {
idxPath := containersPath.Index(idx)
@ -289,14 +308,6 @@ func (s *simpleProvider) ValidateContainerSecurityContext(pod *api.Pod, containe
allErrs = append(allErrs, s.hasInvalidHostPort(&c, idxPath)...)
}
if !s.psp.Spec.HostPID && podSC.HostPID() {
allErrs = append(allErrs, field.Invalid(fldPath.Child("hostPID"), podSC.HostPID(), "Host PID is not allowed to be used"))
}
if !s.psp.Spec.HostIPC && podSC.HostIPC() {
allErrs = append(allErrs, field.Invalid(fldPath.Child("hostIPC"), podSC.HostIPC(), "Host IPC is not allowed to be used"))
}
if s.psp.Spec.ReadOnlyRootFilesystem {
readOnly := sc.ReadOnlyRootFilesystem()
if readOnly == nil {
@ -345,7 +356,7 @@ func (s *simpleProvider) GetPSPName() string {
return s.psp.Name
}
func hostPortRangesToString(ranges []extensions.HostPortRange) string {
func hostPortRangesToString(ranges []policy.HostPortRange) string {
formattedString := ""
if ranges != nil {
strRanges := []string{}

View File

@ -30,7 +30,7 @@ import (
"k8s.io/apimachinery/pkg/util/validation/field"
api "k8s.io/kubernetes/pkg/apis/core"
k8s_api_v1 "k8s.io/kubernetes/pkg/apis/core/v1"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/apis/policy"
"k8s.io/kubernetes/pkg/security/apparmor"
"k8s.io/kubernetes/pkg/security/podsecuritypolicy/seccomp"
psputil "k8s.io/kubernetes/pkg/security/podsecuritypolicy/util"
@ -49,27 +49,27 @@ func TestDefaultPodSecurityContextNonmutating(t *testing.T) {
}
// Create a PSP with strategies that will populate a blank psc
createPSP := func() *extensions.PodSecurityPolicy {
return &extensions.PodSecurityPolicy{
createPSP := func() *policy.PodSecurityPolicy {
return &policy.PodSecurityPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "psp-sa",
Annotations: map[string]string{
seccomp.AllowedProfilesAnnotationKey: "*",
},
},
Spec: extensions.PodSecurityPolicySpec{
Spec: policy.PodSecurityPolicySpec{
AllowPrivilegeEscalation: true,
RunAsUser: extensions.RunAsUserStrategyOptions{
Rule: extensions.RunAsUserStrategyRunAsAny,
RunAsUser: policy.RunAsUserStrategyOptions{
Rule: policy.RunAsUserStrategyRunAsAny,
},
SELinux: extensions.SELinuxStrategyOptions{
Rule: extensions.SELinuxStrategyRunAsAny,
SELinux: policy.SELinuxStrategyOptions{
Rule: policy.SELinuxStrategyRunAsAny,
},
FSGroup: extensions.FSGroupStrategyOptions{
Rule: extensions.FSGroupStrategyRunAsAny,
FSGroup: policy.FSGroupStrategyOptions{
Rule: policy.FSGroupStrategyRunAsAny,
},
SupplementalGroups: extensions.SupplementalGroupsStrategyOptions{
Rule: extensions.SupplementalGroupsStrategyRunAsAny,
SupplementalGroups: policy.SupplementalGroupsStrategyOptions{
Rule: policy.SupplementalGroupsStrategyRunAsAny,
},
},
}
@ -120,8 +120,8 @@ func TestDefaultContainerSecurityContextNonmutating(t *testing.T) {
}
// Create a PSP with strategies that will populate a blank security context
createPSP := func() *extensions.PodSecurityPolicy {
return &extensions.PodSecurityPolicy{
createPSP := func() *policy.PodSecurityPolicy {
return &policy.PodSecurityPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "psp-sa",
Annotations: map[string]string{
@ -129,19 +129,19 @@ func TestDefaultContainerSecurityContextNonmutating(t *testing.T) {
seccomp.DefaultProfileAnnotationKey: "foo",
},
},
Spec: extensions.PodSecurityPolicySpec{
Spec: policy.PodSecurityPolicySpec{
AllowPrivilegeEscalation: true,
RunAsUser: extensions.RunAsUserStrategyOptions{
Rule: extensions.RunAsUserStrategyRunAsAny,
RunAsUser: policy.RunAsUserStrategyOptions{
Rule: policy.RunAsUserStrategyRunAsAny,
},
SELinux: extensions.SELinuxStrategyOptions{
Rule: extensions.SELinuxStrategyRunAsAny,
SELinux: policy.SELinuxStrategyOptions{
Rule: policy.SELinuxStrategyRunAsAny,
},
FSGroup: extensions.FSGroupStrategyOptions{
Rule: extensions.FSGroupStrategyRunAsAny,
FSGroup: policy.FSGroupStrategyOptions{
Rule: policy.FSGroupStrategyRunAsAny,
},
SupplementalGroups: extensions.SupplementalGroupsStrategyOptions{
Rule: extensions.SupplementalGroupsStrategyRunAsAny,
SupplementalGroups: policy.SupplementalGroupsStrategyOptions{
Rule: policy.SupplementalGroupsStrategyRunAsAny,
},
},
}
@ -184,9 +184,9 @@ func TestValidatePodSecurityContextFailures(t *testing.T) {
failSupplementalGroupPod := defaultPod()
failSupplementalGroupPod.Spec.SecurityContext.SupplementalGroups = []int64{999}
failSupplementalGroupPSP := defaultPSP()
failSupplementalGroupPSP.Spec.SupplementalGroups = extensions.SupplementalGroupsStrategyOptions{
Rule: extensions.SupplementalGroupsStrategyMustRunAs,
Ranges: []extensions.GroupIDRange{
failSupplementalGroupPSP.Spec.SupplementalGroups = policy.SupplementalGroupsStrategyOptions{
Rule: policy.SupplementalGroupsStrategyMustRunAs,
Ranges: []policy.IDRange{
{Min: 1, Max: 1},
},
}
@ -195,16 +195,16 @@ func TestValidatePodSecurityContextFailures(t *testing.T) {
fsGroup := int64(999)
failFSGroupPod.Spec.SecurityContext.FSGroup = &fsGroup
failFSGroupPSP := defaultPSP()
failFSGroupPSP.Spec.FSGroup = extensions.FSGroupStrategyOptions{
Rule: extensions.FSGroupStrategyMustRunAs,
Ranges: []extensions.GroupIDRange{
failFSGroupPSP.Spec.FSGroup = policy.FSGroupStrategyOptions{
Rule: policy.FSGroupStrategyMustRunAs,
Ranges: []policy.IDRange{
{Min: 1, Max: 1},
},
}
failNilSELinuxPod := defaultPod()
failSELinuxPSP := defaultPSP()
failSELinuxPSP.Spec.SELinux.Rule = extensions.SELinuxStrategyMustRunAs
failSELinuxPSP.Spec.SELinux.Rule = policy.SELinuxStrategyMustRunAs
failSELinuxPSP.Spec.SELinux.SELinuxOptions = &api.SELinuxOptions{
Level: "foo",
}
@ -236,22 +236,65 @@ func TestValidatePodSecurityContextFailures(t *testing.T) {
},
}
failHostPathDirPSP := defaultPSP()
failHostPathDirPSP.Spec.Volumes = []extensions.FSType{extensions.HostPath}
failHostPathDirPSP.Spec.AllowedHostPaths = []extensions.AllowedHostPath{
failHostPathDirPSP.Spec.Volumes = []policy.FSType{policy.HostPath}
failHostPathDirPSP.Spec.AllowedHostPaths = []policy.AllowedHostPath{
{PathPrefix: "/foo/bar"},
}
failOtherSysctlsAllowedPSP := defaultPSP()
failOtherSysctlsAllowedPSP.Annotations[extensions.SysctlsPodSecurityPolicyAnnotationKey] = "bar,abc"
failHostPathReadOnlyPod := defaultPod()
failHostPathReadOnlyPod.Spec.Containers[0].VolumeMounts = []api.VolumeMount{
{
Name: "bad volume",
ReadOnly: false,
},
}
failHostPathReadOnlyPod.Spec.Volumes = []api.Volume{
{
Name: "bad volume",
VolumeSource: api.VolumeSource{
HostPath: &api.HostPathVolumeSource{
Path: "/foo",
},
},
},
}
failHostPathReadOnlyPSP := defaultPSP()
failHostPathReadOnlyPSP.Spec.Volumes = []policy.FSType{policy.HostPath}
failHostPathReadOnlyPSP.Spec.AllowedHostPaths = []policy.AllowedHostPath{
{
PathPrefix: "/foo",
ReadOnly: true,
},
}
failNoSysctlAllowedPSP := defaultPSP()
failNoSysctlAllowedPSP.Annotations[extensions.SysctlsPodSecurityPolicyAnnotationKey] = ""
failSysctlDisallowedPSP := defaultPSP()
failSysctlDisallowedPSP.Spec.ForbiddenSysctls = []string{"kernel.shm_rmid_forced"}
failSafeSysctlFooPod := defaultPod()
failSafeSysctlFooPod.Annotations[api.SysctlsPodAnnotationKey] = "foo=1"
failNoSafeSysctlAllowedPSP := defaultPSP()
failNoSafeSysctlAllowedPSP.Spec.ForbiddenSysctls = []string{"*"}
failUnsafeSysctlFooPod := defaultPod()
failUnsafeSysctlFooPod.Annotations[api.UnsafeSysctlsPodAnnotationKey] = "foo=1"
failAllUnsafeSysctlsPSP := defaultPSP()
failAllUnsafeSysctlsPSP.Spec.AllowedUnsafeSysctls = []string{}
failSafeSysctlKernelPod := defaultPod()
failSafeSysctlKernelPod.Spec.SecurityContext = &api.PodSecurityContext{
Sysctls: []api.Sysctl{
{
Name: "kernel.shm_rmid_forced",
Value: "1",
},
},
}
failUnsafeSysctlPod := defaultPod()
failUnsafeSysctlPod.Spec.SecurityContext = &api.PodSecurityContext{
Sysctls: []api.Sysctl{
{
Name: "kernel.sem",
Value: "32000",
},
},
}
failSeccompProfilePod := defaultPod()
failSeccompProfilePod.Annotations = map[string]string{api.SeccompPodAnnotationKey: "foo"}
@ -270,7 +313,7 @@ func TestValidatePodSecurityContextFailures(t *testing.T) {
errorCases := map[string]struct {
pod *api.Pod
psp *extensions.PodSecurityPolicy
psp *policy.PodSecurityPolicy
expectedError string
}{
"failHostNetwork": {
@ -291,7 +334,7 @@ func TestValidatePodSecurityContextFailures(t *testing.T) {
"failSupplementalGroupOutOfRange": {
pod: failSupplementalGroupPod,
psp: failSupplementalGroupPSP,
expectedError: "999 is not an allowed group",
expectedError: "group 999 must be in the ranges: [{1 1}]",
},
"failSupplementalGroupEmpty": {
pod: defaultPod(),
@ -301,7 +344,7 @@ func TestValidatePodSecurityContextFailures(t *testing.T) {
"failFSGroupOutOfRange": {
pod: failFSGroupPod,
psp: failFSGroupPSP,
expectedError: "999 is not an allowed group",
expectedError: "group 999 must be in the ranges: [{1 1}]",
},
"failFSGroupEmpty": {
pod: defaultPod(),
@ -328,25 +371,25 @@ func TestValidatePodSecurityContextFailures(t *testing.T) {
psp: failHostPathDirPSP,
expectedError: "is not allowed to be used",
},
"failSafeSysctlFooPod with failNoSysctlAllowedSCC": {
pod: failSafeSysctlFooPod,
psp: failNoSysctlAllowedPSP,
expectedError: "sysctls are not allowed",
"failHostPathReadOnlyPSP": {
pod: failHostPathReadOnlyPod,
psp: failHostPathReadOnlyPSP,
expectedError: "must be read-only",
},
"failUnsafeSysctlFooPod with failNoSysctlAllowedSCC": {
pod: failUnsafeSysctlFooPod,
psp: failNoSysctlAllowedPSP,
expectedError: "sysctls are not allowed",
"failSafeSysctlKernelPod with failNoSafeSysctlAllowedPSP": {
pod: failSafeSysctlKernelPod,
psp: failNoSafeSysctlAllowedPSP,
expectedError: "sysctl \"kernel.shm_rmid_forced\" is not allowed",
},
"failSafeSysctlFooPod with failOtherSysctlsAllowedSCC": {
pod: failSafeSysctlFooPod,
psp: failOtherSysctlsAllowedPSP,
expectedError: "sysctl \"foo\" is not allowed",
"failSafeSysctlKernelPod with failSysctlDisallowedPSP": {
pod: failSafeSysctlKernelPod,
psp: failSysctlDisallowedPSP,
expectedError: "sysctl \"kernel.shm_rmid_forced\" is not allowed",
},
"failUnsafeSysctlFooPod with failOtherSysctlsAllowedSCC": {
pod: failUnsafeSysctlFooPod,
psp: failOtherSysctlsAllowedPSP,
expectedError: "sysctl \"foo\" is not allowed",
"failUnsafeSysctlPod with failAllUnsafeSysctlsPSP": {
pod: failUnsafeSysctlPod,
psp: failAllUnsafeSysctlsPSP,
expectedError: "unsafe sysctl \"kernel.sem\" is not allowed",
},
"failInvalidSeccomp": {
pod: failSeccompProfilePod,
@ -380,24 +423,24 @@ func TestValidatePodSecurityContextFailures(t *testing.T) {
}
}
func allowFlexVolumesPSP(allowAllFlexVolumes, allowAllVolumes bool) *extensions.PodSecurityPolicy {
func allowFlexVolumesPSP(allowAllFlexVolumes, allowAllVolumes bool) *policy.PodSecurityPolicy {
psp := defaultPSP()
allowedVolumes := []extensions.AllowedFlexVolume{
allowedVolumes := []policy.AllowedFlexVolume{
{Driver: "example/foo"},
{Driver: "example/bar"},
}
if allowAllFlexVolumes {
allowedVolumes = []extensions.AllowedFlexVolume{}
allowedVolumes = []policy.AllowedFlexVolume{}
}
allowedVolumeType := extensions.FlexVolume
allowedVolumeType := policy.FlexVolume
if allowAllVolumes {
allowedVolumeType = extensions.All
allowedVolumeType = policy.All
}
psp.Spec.AllowedFlexVolumes = allowedVolumes
psp.Spec.Volumes = []extensions.FSType{allowedVolumeType}
psp.Spec.Volumes = []policy.FSType{allowedVolumeType}
return psp
}
@ -407,17 +450,17 @@ func TestValidateContainerSecurityContextFailures(t *testing.T) {
failUserPSP := defaultPSP()
uid := int64(999)
badUID := int64(1)
failUserPSP.Spec.RunAsUser = extensions.RunAsUserStrategyOptions{
Rule: extensions.RunAsUserStrategyMustRunAs,
Ranges: []extensions.UserIDRange{{Min: uid, Max: uid}},
failUserPSP.Spec.RunAsUser = policy.RunAsUserStrategyOptions{
Rule: policy.RunAsUserStrategyMustRunAs,
Ranges: []policy.IDRange{{Min: uid, Max: uid}},
}
failUserPod := defaultPod()
failUserPod.Spec.Containers[0].SecurityContext.RunAsUser = &badUID
// fail selinux strategy
failSELinuxPSP := defaultPSP()
failSELinuxPSP.Spec.SELinux = extensions.SELinuxStrategyOptions{
Rule: extensions.SELinuxStrategyMustRunAs,
failSELinuxPSP.Spec.SELinux = policy.SELinuxStrategyOptions{
Rule: policy.SELinuxStrategyMustRunAs,
SELinuxOptions: &api.SELinuxOptions{
Level: "foo",
},
@ -469,7 +512,7 @@ func TestValidateContainerSecurityContextFailures(t *testing.T) {
errorCases := map[string]struct {
pod *api.Pod
psp *extensions.PodSecurityPolicy
psp *policy.PodSecurityPolicy
expectedError string
}{
"failUserPSP": {
@ -562,9 +605,9 @@ func TestValidatePodSecurityContextSuccess(t *testing.T) {
hostIPCPod.Spec.SecurityContext.HostIPC = true
supGroupPSP := defaultPSP()
supGroupPSP.Spec.SupplementalGroups = extensions.SupplementalGroupsStrategyOptions{
Rule: extensions.SupplementalGroupsStrategyMustRunAs,
Ranges: []extensions.GroupIDRange{
supGroupPSP.Spec.SupplementalGroups = policy.SupplementalGroupsStrategyOptions{
Rule: policy.SupplementalGroupsStrategyMustRunAs,
Ranges: []policy.IDRange{
{Min: 1, Max: 5},
},
}
@ -572,9 +615,9 @@ func TestValidatePodSecurityContextSuccess(t *testing.T) {
supGroupPod.Spec.SecurityContext.SupplementalGroups = []int64{3}
fsGroupPSP := defaultPSP()
fsGroupPSP.Spec.FSGroup = extensions.FSGroupStrategyOptions{
Rule: extensions.FSGroupStrategyMustRunAs,
Ranges: []extensions.GroupIDRange{
fsGroupPSP.Spec.FSGroup = policy.FSGroupStrategyOptions{
Rule: policy.FSGroupStrategyMustRunAs,
Ranges: []policy.IDRange{
{Min: 1, Max: 5},
},
}
@ -590,7 +633,7 @@ func TestValidatePodSecurityContextSuccess(t *testing.T) {
Level: "level",
}
seLinuxPSP := defaultPSP()
seLinuxPSP.Spec.SELinux.Rule = extensions.SELinuxStrategyMustRunAs
seLinuxPSP.Spec.SELinux.Rule = policy.SELinuxStrategyMustRunAs
seLinuxPSP.Spec.SELinux.SELinuxOptions = &api.SELinuxOptions{
User: "user",
Role: "role",
@ -598,38 +641,107 @@ func TestValidatePodSecurityContextSuccess(t *testing.T) {
Level: "level",
}
hostPathDirPodVolumeMounts := []api.VolumeMount{
{
Name: "writeable /foo/bar",
ReadOnly: false,
},
{
Name: "read only /foo/bar/baz",
ReadOnly: true,
},
{
Name: "parent read only volume",
ReadOnly: true,
},
{
Name: "read only child volume",
ReadOnly: true,
},
}
hostPathDirPod := defaultPod()
hostPathDirPod.Spec.InitContainers = []api.Container{
{
Name: defaultContainerName,
VolumeMounts: hostPathDirPodVolumeMounts,
},
}
hostPathDirPod.Spec.Containers[0].VolumeMounts = hostPathDirPodVolumeMounts
hostPathDirPod.Spec.Volumes = []api.Volume{
{
Name: "good volume",
Name: "writeable /foo/bar",
VolumeSource: api.VolumeSource{
HostPath: &api.HostPathVolumeSource{
Path: "/foo/bar",
},
},
},
{
Name: "read only /foo/bar/baz",
VolumeSource: api.VolumeSource{
HostPath: &api.HostPathVolumeSource{
Path: "/foo/bar/baz",
},
},
},
{
Name: "parent read only volume",
VolumeSource: api.VolumeSource{
HostPath: &api.HostPathVolumeSource{
Path: "/foo/",
},
},
},
{
Name: "read only child volume",
VolumeSource: api.VolumeSource{
HostPath: &api.HostPathVolumeSource{
Path: "/foo/readonly/child",
},
},
},
}
hostPathDirPSP := defaultPSP()
hostPathDirPSP.Spec.Volumes = []extensions.FSType{extensions.HostPath}
hostPathDirPSP.Spec.AllowedHostPaths = []extensions.AllowedHostPath{
{PathPrefix: "/foo/bar"},
hostPathDirPSP.Spec.Volumes = []policy.FSType{policy.HostPath}
hostPathDirPSP.Spec.AllowedHostPaths = []policy.AllowedHostPath{
// overlapping test case where child is different than parent directory.
{PathPrefix: "/foo/bar/baz", ReadOnly: true},
{PathPrefix: "/foo", ReadOnly: true},
{PathPrefix: "/foo/bar", ReadOnly: false},
}
hostPathDirAsterisksPSP := defaultPSP()
hostPathDirAsterisksPSP.Spec.Volumes = []extensions.FSType{extensions.All}
hostPathDirAsterisksPSP.Spec.AllowedHostPaths = []extensions.AllowedHostPath{
{PathPrefix: "/foo/bar"},
hostPathDirAsterisksPSP.Spec.Volumes = []policy.FSType{policy.All}
hostPathDirAsterisksPSP.Spec.AllowedHostPaths = []policy.AllowedHostPath{
{PathPrefix: "/foo"},
}
sysctlAllowFooPSP := defaultPSP()
sysctlAllowFooPSP.Annotations[extensions.SysctlsPodSecurityPolicyAnnotationKey] = "foo"
sysctlAllowAllPSP := defaultPSP()
sysctlAllowAllPSP.Spec.ForbiddenSysctls = []string{}
sysctlAllowAllPSP.Spec.AllowedUnsafeSysctls = []string{"*"}
safeSysctlFooPod := defaultPod()
safeSysctlFooPod.Annotations[api.SysctlsPodAnnotationKey] = "foo=1"
safeSysctlKernelPod := defaultPod()
safeSysctlKernelPod.Spec.SecurityContext = &api.PodSecurityContext{
Sysctls: []api.Sysctl{
{
Name: "kernel.shm_rmid_forced",
Value: "1",
},
},
}
unsafeSysctlFooPod := defaultPod()
unsafeSysctlFooPod.Annotations[api.UnsafeSysctlsPodAnnotationKey] = "foo=1"
unsafeSysctlKernelPod := defaultPod()
unsafeSysctlKernelPod.Spec.SecurityContext = &api.PodSecurityContext{
Sysctls: []api.Sysctl{
{
Name: "kernel.sem",
Value: "32000",
},
},
}
seccompPSP := defaultPSP()
seccompPSP.Annotations = map[string]string{
@ -655,7 +767,7 @@ func TestValidatePodSecurityContextSuccess(t *testing.T) {
successCases := map[string]struct {
pod *api.Pod
psp *extensions.PodSecurityPolicy
psp *policy.PodSecurityPolicy
}{
"pass hostNetwork validating PSP": {
pod: hostNetworkPod,
@ -681,21 +793,13 @@ func TestValidatePodSecurityContextSuccess(t *testing.T) {
pod: seLinuxPod,
psp: seLinuxPSP,
},
"pass sysctl specific profile with safe sysctl": {
pod: safeSysctlFooPod,
psp: sysctlAllowFooPSP,
"pass sysctl specific profile with safe kernel sysctl": {
pod: safeSysctlKernelPod,
psp: sysctlAllowAllPSP,
},
"pass sysctl specific profile with unsafe sysctl": {
pod: unsafeSysctlFooPod,
psp: sysctlAllowFooPSP,
},
"pass empty profile with safe sysctl": {
pod: safeSysctlFooPod,
psp: defaultPSP(),
},
"pass empty profile with unsafe sysctl": {
pod: unsafeSysctlFooPod,
psp: defaultPSP(),
"pass sysctl specific profile with unsafe kernel sysctl": {
pod: unsafeSysctlKernelPod,
psp: sysctlAllowAllPSP,
},
"pass hostDir allowed directory validating PSP": {
pod: hostPathDirPod,
@ -744,17 +848,17 @@ func TestValidateContainerSecurityContextSuccess(t *testing.T) {
// success user strategy
userPSP := defaultPSP()
uid := int64(999)
userPSP.Spec.RunAsUser = extensions.RunAsUserStrategyOptions{
Rule: extensions.RunAsUserStrategyMustRunAs,
Ranges: []extensions.UserIDRange{{Min: uid, Max: uid}},
userPSP.Spec.RunAsUser = policy.RunAsUserStrategyOptions{
Rule: policy.RunAsUserStrategyMustRunAs,
Ranges: []policy.IDRange{{Min: uid, Max: uid}},
}
userPod := defaultPod()
userPod.Spec.Containers[0].SecurityContext.RunAsUser = &uid
// success selinux strategy
seLinuxPSP := defaultPSP()
seLinuxPSP.Spec.SELinux = extensions.SELinuxStrategyOptions{
Rule: extensions.SELinuxStrategyMustRunAs,
seLinuxPSP.Spec.SELinux = policy.SELinuxStrategyOptions{
Rule: policy.SELinuxStrategyMustRunAs,
SELinuxOptions: &api.SELinuxOptions{
Level: "foo",
},
@ -795,7 +899,7 @@ func TestValidateContainerSecurityContextSuccess(t *testing.T) {
}
hostDirPSP := defaultPSP()
hostDirPSP.Spec.Volumes = []extensions.FSType{extensions.HostPath}
hostDirPSP.Spec.Volumes = []policy.FSType{policy.HostPath}
hostDirPod := defaultPod()
hostDirPod.Spec.Volumes = []api.Volume{
{
@ -807,7 +911,7 @@ func TestValidateContainerSecurityContextSuccess(t *testing.T) {
}
hostPortPSP := defaultPSP()
hostPortPSP.Spec.HostPorts = []extensions.HostPortRange{{Min: 1, Max: 1}}
hostPortPSP.Spec.HostPorts = []policy.HostPortRange{{Min: 1, Max: 1}}
hostPortPod := defaultPod()
hostPortPod.Spec.Containers[0].Ports = []api.ContainerPort{{HostPort: 1}}
@ -836,7 +940,7 @@ func TestValidateContainerSecurityContextSuccess(t *testing.T) {
successCases := map[string]struct {
pod *api.Pod
psp *extensions.PodSecurityPolicy
psp *policy.PodSecurityPolicy
}{
"pass user must run as PSP": {
pod: userPod,
@ -922,7 +1026,7 @@ func TestGenerateContainerSecurityContextReadOnlyRootFS(t *testing.T) {
tests := map[string]struct {
pod *api.Pod
psp *extensions.PodSecurityPolicy
psp *policy.PodSecurityPolicy
expected *bool
}{
"false psp, nil sc": {
@ -985,24 +1089,24 @@ func TestGenerateContainerSecurityContextReadOnlyRootFS(t *testing.T) {
}
}
func defaultPSP() *extensions.PodSecurityPolicy {
return &extensions.PodSecurityPolicy{
func defaultPSP() *policy.PodSecurityPolicy {
return &policy.PodSecurityPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "psp-sa",
Annotations: map[string]string{},
},
Spec: extensions.PodSecurityPolicySpec{
RunAsUser: extensions.RunAsUserStrategyOptions{
Rule: extensions.RunAsUserStrategyRunAsAny,
Spec: policy.PodSecurityPolicySpec{
RunAsUser: policy.RunAsUserStrategyOptions{
Rule: policy.RunAsUserStrategyRunAsAny,
},
SELinux: extensions.SELinuxStrategyOptions{
Rule: extensions.SELinuxStrategyRunAsAny,
SELinux: policy.SELinuxStrategyOptions{
Rule: policy.SELinuxStrategyRunAsAny,
},
FSGroup: extensions.FSGroupStrategyOptions{
Rule: extensions.FSGroupStrategyRunAsAny,
FSGroup: policy.FSGroupStrategyOptions{
Rule: policy.FSGroupStrategyRunAsAny,
},
SupplementalGroups: extensions.SupplementalGroupsStrategyOptions{
Rule: extensions.SupplementalGroupsStrategyRunAsAny,
SupplementalGroups: policy.SupplementalGroupsStrategyOptions{
Rule: policy.SupplementalGroupsStrategyRunAsAny,
},
AllowPrivilegeEscalation: true,
},
@ -1017,7 +1121,7 @@ func defaultPod() *api.Pod {
},
Spec: api.PodSpec{
SecurityContext: &api.PodSecurityContext{
// fill in for test cases
// fill in for test cases
},
Containers: []api.Container{
{
@ -1041,7 +1145,7 @@ func defaultV1Pod() *v1.Pod {
},
Spec: v1.PodSpec{
SecurityContext: &v1.PodSecurityContext{
// fill in for test cases
// fill in for test cases
},
Containers: []v1.Container{
{
@ -1104,14 +1208,14 @@ func TestValidateAllowedVolumes(t *testing.T) {
}
// now add the fstype directly to the psp and it should validate
psp.Spec.Volumes = []extensions.FSType{fsType}
psp.Spec.Volumes = []policy.FSType{fsType}
errs = provider.ValidatePod(pod, field.NewPath(""))
if len(errs) != 0 {
t.Errorf("directly allowing volume expected no errors for %s but got %v", fieldVal.Name, errs)
}
// now change the psp to allow any volumes and the pod should still validate
psp.Spec.Volumes = []extensions.FSType{extensions.All}
psp.Spec.Volumes = []policy.FSType{policy.All}
errs = provider.ValidatePod(pod, field.NewPath(""))
if len(errs) != 0 {
t.Errorf("wildcard volume expected no errors for %s but got %v", fieldVal.Name, errs)

View File

@ -17,7 +17,7 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/security/podsecuritypolicy/selinux",
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/apis/policy:go_default_library",
"//pkg/security/podsecuritypolicy/util:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
],
@ -32,7 +32,7 @@ go_test(
embed = [":go_default_library"],
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/apis/policy:go_default_library",
],
)

View File

@ -23,17 +23,17 @@ import (
"k8s.io/apimachinery/pkg/util/validation/field"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/apis/policy"
"k8s.io/kubernetes/pkg/security/podsecuritypolicy/util"
)
type mustRunAs struct {
opts *extensions.SELinuxStrategyOptions
opts *policy.SELinuxStrategyOptions
}
var _ SELinuxStrategy = &mustRunAs{}
func NewMustRunAs(options *extensions.SELinuxStrategyOptions) (SELinuxStrategy, error) {
func NewMustRunAs(options *policy.SELinuxStrategyOptions) (SELinuxStrategy, error) {
if options == nil {
return nil, fmt.Errorf("MustRunAs requires SELinuxContextStrategyOptions")
}

View File

@ -18,7 +18,7 @@ package selinux
import (
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/apis/policy"
"reflect"
"strings"
"testing"
@ -26,15 +26,19 @@ import (
func TestMustRunAsOptions(t *testing.T) {
tests := map[string]struct {
opts *extensions.SELinuxStrategyOptions
opts *policy.SELinuxStrategyOptions
pass bool
}{
"nil opts": {
opts: nil,
pass: false,
},
"invalid opts": {
opts: &extensions.SELinuxStrategyOptions{},
opts: &policy.SELinuxStrategyOptions{},
pass: false,
},
"valid opts": {
opts: &extensions.SELinuxStrategyOptions{SELinuxOptions: &api.SELinuxOptions{}},
opts: &policy.SELinuxStrategyOptions{SELinuxOptions: &api.SELinuxOptions{}},
pass: true,
},
}
@ -50,7 +54,7 @@ func TestMustRunAsOptions(t *testing.T) {
}
func TestMustRunAsGenerate(t *testing.T) {
opts := &extensions.SELinuxStrategyOptions{
opts := &policy.SELinuxStrategyOptions{
SELinuxOptions: &api.SELinuxOptions{
User: "user",
Role: "role",
@ -141,7 +145,7 @@ func TestMustRunAsValidate(t *testing.T) {
}
for name, tc := range tests {
opts := &extensions.SELinuxStrategyOptions{
opts := &policy.SELinuxStrategyOptions{
SELinuxOptions: tc.pspSeLinux,
}
mustRunAs, err := NewMustRunAs(opts)

View File

@ -19,7 +19,7 @@ package selinux
import (
"k8s.io/apimachinery/pkg/util/validation/field"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/apis/policy"
)
// runAsAny implements the SELinuxStrategy interface.
@ -28,7 +28,7 @@ type runAsAny struct{}
var _ SELinuxStrategy = &runAsAny{}
// NewRunAsAny provides a strategy that will return the configured se linux context or nil.
func NewRunAsAny(options *extensions.SELinuxStrategyOptions) (SELinuxStrategy, error) {
func NewRunAsAny(options *policy.SELinuxStrategyOptions) (SELinuxStrategy, error) {
return &runAsAny{}, nil
}

View File

@ -18,7 +18,7 @@ package selinux
import (
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/apis/policy"
"testing"
)
@ -27,14 +27,14 @@ func TestRunAsAnyOptions(t *testing.T) {
if err != nil {
t.Fatalf("unexpected error initializing NewRunAsAny %v", err)
}
_, err = NewRunAsAny(&extensions.SELinuxStrategyOptions{})
_, err = NewRunAsAny(&policy.SELinuxStrategyOptions{})
if err != nil {
t.Errorf("unexpected error initializing NewRunAsAny %v", err)
}
}
func TestRunAsAnyGenerate(t *testing.T) {
s, err := NewRunAsAny(&extensions.SELinuxStrategyOptions{})
s, err := NewRunAsAny(&policy.SELinuxStrategyOptions{})
if err != nil {
t.Fatalf("unexpected error initializing NewRunAsAny %v", err)
}
@ -48,7 +48,7 @@ func TestRunAsAnyGenerate(t *testing.T) {
}
func TestRunAsAnyValidate(t *testing.T) {
s, err := NewRunAsAny(&extensions.SELinuxStrategyOptions{
s, err := NewRunAsAny(&policy.SELinuxStrategyOptions{
SELinuxOptions: &api.SELinuxOptions{
Level: "foo",
},
@ -61,7 +61,7 @@ func TestRunAsAnyValidate(t *testing.T) {
if len(errs) != 0 {
t.Errorf("unexpected errors validating with ")
}
s, err = NewRunAsAny(&extensions.SELinuxStrategyOptions{})
s, err = NewRunAsAny(&policy.SELinuxStrategyOptions{})
if err != nil {
t.Fatalf("unexpected error initializing NewRunAsAny %v", err)
}

View File

@ -15,7 +15,6 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/security/podsecuritypolicy/sysctl",
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/apis/core/helper:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
],
)
@ -24,10 +23,7 @@ go_test(
name = "go_default_test",
srcs = ["mustmatchpatterns_test.go"],
embed = [":go_default_library"],
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/apis/core/helper:go_default_library",
],
deps = ["//pkg/apis/core:go_default_library"],
)
filegroup(

View File

@ -22,12 +22,26 @@ import (
"k8s.io/apimachinery/pkg/util/validation/field"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/core/helper"
)
// SafeSysctlWhitelist returns the whitelist of safe sysctls and safe sysctl patterns (ending in *).
//
// A sysctl is called safe iff
// - it is namespaced in the container or the pod
// - it is isolated, i.e. has no influence on any other pod on the same node.
func SafeSysctlWhitelist() []string {
return []string{
"kernel.shm_rmid_forced",
"net.ipv4.ip_local_port_range",
"net.ipv4.tcp_syncookies",
}
}
// mustMatchPatterns implements the SysctlsStrategy interface
type mustMatchPatterns struct {
patterns []string
safeWhitelist []string
allowedUnsafeSysctls []string
forbiddenSysctls []string
}
var (
@ -38,56 +52,75 @@ var (
// NewMustMatchPatterns creates a new mustMatchPatterns strategy that will provide validation.
// Passing nil means the default pattern, passing an empty list means to disallow all sysctls.
func NewMustMatchPatterns(patterns []string) SysctlsStrategy {
if patterns == nil {
patterns = defaultSysctlsPatterns
}
func NewMustMatchPatterns(safeWhitelist, allowedUnsafeSysctls, forbiddenSysctls []string) SysctlsStrategy {
return &mustMatchPatterns{
patterns: patterns,
safeWhitelist: safeWhitelist,
allowedUnsafeSysctls: allowedUnsafeSysctls,
forbiddenSysctls: forbiddenSysctls,
}
}
func (s *mustMatchPatterns) isForbidden(sysctlName string) bool {
// Is the sysctl forbidden?
for _, s := range s.forbiddenSysctls {
if strings.HasSuffix(s, "*") {
prefix := strings.TrimSuffix(s, "*")
if strings.HasPrefix(sysctlName, prefix) {
return true
}
} else if sysctlName == s {
return true
}
}
return false
}
func (s *mustMatchPatterns) isSafe(sysctlName string) bool {
for _, ws := range s.safeWhitelist {
if sysctlName == ws {
return true
}
}
return false
}
func (s *mustMatchPatterns) isAllowedUnsafe(sysctlName string) bool {
for _, s := range s.allowedUnsafeSysctls {
if strings.HasSuffix(s, "*") {
prefix := strings.TrimSuffix(s, "*")
if strings.HasPrefix(sysctlName, prefix) {
return true
}
} else if sysctlName == s {
return true
}
}
return false
}
// Validate ensures that the specified values fall within the range of the strategy.
func (s *mustMatchPatterns) Validate(pod *api.Pod) field.ErrorList {
allErrs := field.ErrorList{}
allErrs = append(allErrs, s.validateAnnotation(pod, api.SysctlsPodAnnotationKey)...)
allErrs = append(allErrs, s.validateAnnotation(pod, api.UnsafeSysctlsPodAnnotationKey)...)
return allErrs
}
func (s *mustMatchPatterns) validateAnnotation(pod *api.Pod, key string) field.ErrorList {
allErrs := field.ErrorList{}
fieldPath := field.NewPath("pod", "metadata", "annotations").Key(key)
sysctls, err := helper.SysctlsFromPodAnnotation(pod.Annotations[key])
if err != nil {
allErrs = append(allErrs, field.Invalid(fieldPath, pod.Annotations[key], err.Error()))
var sysctls []api.Sysctl
if pod.Spec.SecurityContext != nil {
sysctls = pod.Spec.SecurityContext.Sysctls
}
if len(sysctls) > 0 {
if len(s.patterns) == 0 {
allErrs = append(allErrs, field.Invalid(fieldPath, pod.Annotations[key], "sysctls are not allowed"))
} else {
for i, sysctl := range sysctls {
allErrs = append(allErrs, s.ValidateSysctl(sysctl.Name, fieldPath.Index(i))...)
}
fieldPath := field.NewPath("pod", "spec", "securityContext").Child("sysctls")
for i, sysctl := range sysctls {
switch {
case s.isForbidden(sysctl.Name):
allErrs = append(allErrs, field.ErrorList{field.Forbidden(fieldPath.Index(i), fmt.Sprintf("sysctl %q is not allowed", sysctl.Name))}...)
case s.isSafe(sysctl.Name):
continue
case s.isAllowedUnsafe(sysctl.Name):
continue
default:
allErrs = append(allErrs, field.ErrorList{field.Forbidden(fieldPath.Index(i), fmt.Sprintf("unsafe sysctl %q is not allowed", sysctl.Name))}...)
}
}
return allErrs
}
func (s *mustMatchPatterns) ValidateSysctl(sysctlName string, fldPath *field.Path) field.ErrorList {
for _, s := range s.patterns {
if s[len(s)-1] == '*' {
prefix := s[:len(s)-1]
if strings.HasPrefix(sysctlName, string(prefix)) {
return nil
}
} else if sysctlName == s {
return nil
}
}
return field.ErrorList{field.Forbidden(fldPath, fmt.Sprintf("sysctl %q is not allowed", sysctlName))}
}

View File

@ -17,48 +17,47 @@ limitations under the License.
package sysctl
import (
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/core/helper"
"testing"
api "k8s.io/kubernetes/pkg/apis/core"
)
func TestValidate(t *testing.T) {
tests := map[string]struct {
patterns []string
allowed []string
disallowed []string
whitelist []string
forbiddenSafe []string
allowedUnsafe []string
allowed []string
disallowed []string
}{
// no container requests
"nil": {
patterns: nil,
allowed: []string{"foo"},
"with allow all": {
whitelist: []string{"foo"},
allowed: []string{"foo"},
},
"empty": {
patterns: []string{},
disallowed: []string{"foo"},
whitelist: []string{"foo"},
forbiddenSafe: []string{"*"},
disallowed: []string{"foo"},
},
"without wildcard": {
patterns: []string{"a", "a.b"},
whitelist: []string{"a", "a.b"},
allowed: []string{"a", "a.b"},
disallowed: []string{"b"},
},
"with catch-all wildcard": {
patterns: []string{"*"},
allowed: []string{"a", "a.b"},
},
"with catch-all wildcard and non-wildcard": {
patterns: []string{"a.b.c", "*"},
allowed: []string{"a", "a.b", "a.b.c", "b"},
allowedUnsafe: []string{"a.b.c", "*"},
allowed: []string{"a", "a.b", "a.b.c", "b"},
},
"without catch-all wildcard": {
patterns: []string{"a.*", "b.*", "c.d.e", "d.e.f.*"},
allowed: []string{"a.b", "b.c", "c.d.e", "d.e.f.g.h"},
disallowed: []string{"a", "b", "c", "c.d", "d.e", "d.e.f"},
allowedUnsafe: []string{"a.*", "b.*", "c.d.e", "d.e.f.*"},
allowed: []string{"a.b", "b.c", "c.d.e", "d.e.f.g.h"},
disallowed: []string{"a", "b", "c", "c.d", "d.e", "d.e.f"},
},
}
for k, v := range tests {
strategy := NewMustMatchPatterns(v.patterns)
strategy := NewMustMatchPatterns(v.whitelist, v.allowedUnsafe, v.forbiddenSafe)
pod := &api.Pod{}
errs := strategy.Validate(pod)
@ -66,37 +65,40 @@ func TestValidate(t *testing.T) {
t.Errorf("%s: unexpected validaton errors for empty sysctls: %v", k, errs)
}
sysctls := []api.Sysctl{}
for _, s := range v.allowed {
sysctls = append(sysctls, api.Sysctl{
Name: s,
Value: "dummy",
})
}
testAllowed := func(key string, category string) {
pod.Annotations = map[string]string{
key: helper.PodAnnotationsFromSysctls(sysctls),
testAllowed := func() {
sysctls := []api.Sysctl{}
for _, s := range v.allowed {
sysctls = append(sysctls, api.Sysctl{
Name: s,
Value: "dummy",
})
}
pod.Spec.SecurityContext = &api.PodSecurityContext{
Sysctls: sysctls,
}
errs = strategy.Validate(pod)
if len(errs) != 0 {
t.Errorf("%s: unexpected validaton errors for %s sysctls: %v", k, category, errs)
t.Errorf("%s: unexpected validaton errors for sysctls: %v", k, errs)
}
}
testDisallowed := func(key string, category string) {
testDisallowed := func() {
for _, s := range v.disallowed {
pod.Annotations = map[string]string{
key: helper.PodAnnotationsFromSysctls([]api.Sysctl{{Name: s, Value: "dummy"}}),
pod.Spec.SecurityContext = &api.PodSecurityContext{
Sysctls: []api.Sysctl{
{
Name: s,
Value: "dummy",
},
},
}
errs = strategy.Validate(pod)
if len(errs) == 0 {
t.Errorf("%s: expected error for %s sysctl %q", k, category, s)
t.Errorf("%s: expected error for sysctl %q", k, s)
}
}
}
testAllowed(api.SysctlsPodAnnotationKey, "safe")
testAllowed(api.UnsafeSysctlsPodAnnotationKey, "unsafe")
testDisallowed(api.SysctlsPodAnnotationKey, "safe")
testDisallowed(api.UnsafeSysctlsPodAnnotationKey, "unsafe")
testAllowed()
testDisallowed()
}
}

View File

@ -19,7 +19,7 @@ package podsecuritypolicy
import (
"k8s.io/apimachinery/pkg/util/validation/field"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/apis/policy"
"k8s.io/kubernetes/pkg/security/podsecuritypolicy/apparmor"
"k8s.io/kubernetes/pkg/security/podsecuritypolicy/capabilities"
"k8s.io/kubernetes/pkg/security/podsecuritypolicy/group"
@ -54,7 +54,7 @@ type Provider interface {
type StrategyFactory interface {
// CreateStrategies creates the strategies that a provider will use. The namespace argument
// should be the namespace of the object being checked (the pod's namespace).
CreateStrategies(psp *extensions.PodSecurityPolicy, namespace string) (*ProviderStrategies, error)
CreateStrategies(psp *policy.PodSecurityPolicy, namespace string) (*ProviderStrategies, error)
}
// ProviderStrategies is a holder for all strategies that the provider requires to be populated.

View File

@ -18,7 +18,7 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/security/podsecuritypolicy/user",
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/apis/policy:go_default_library",
"//pkg/security/podsecuritypolicy/util:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
],
@ -34,7 +34,7 @@ go_test(
embed = [":go_default_library"],
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/apis/policy:go_default_library",
],
)

View File

@ -21,22 +21,22 @@ import (
"k8s.io/apimachinery/pkg/util/validation/field"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/apis/policy"
psputil "k8s.io/kubernetes/pkg/security/podsecuritypolicy/util"
)
// mustRunAs implements the RunAsUserStrategy interface
type mustRunAs struct {
opts *extensions.RunAsUserStrategyOptions
opts *policy.RunAsUserStrategyOptions
}
// NewMustRunAs provides a strategy that requires the container to run as a specific UID in a range.
func NewMustRunAs(options *extensions.RunAsUserStrategyOptions) (RunAsUserStrategy, error) {
func NewMustRunAs(options *policy.RunAsUserStrategyOptions) (RunAsUserStrategy, error) {
if options == nil {
return nil, fmt.Errorf("MustRunAsRange requires run as user options")
return nil, fmt.Errorf("MustRunAs requires run as user options")
}
if len(options.Ranges) == 0 {
return nil, fmt.Errorf("MustRunAsRange requires at least one range")
return nil, fmt.Errorf("MustRunAs requires at least one range")
}
return &mustRunAs{
opts: options,

View File

@ -18,14 +18,14 @@ package user
import (
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/apis/policy"
"strings"
"testing"
)
func TestNewMustRunAs(t *testing.T) {
tests := map[string]struct {
opts *extensions.RunAsUserStrategyOptions
opts *policy.RunAsUserStrategyOptions
pass bool
}{
"nil opts": {
@ -33,12 +33,12 @@ func TestNewMustRunAs(t *testing.T) {
pass: false,
},
"invalid opts": {
opts: &extensions.RunAsUserStrategyOptions{},
opts: &policy.RunAsUserStrategyOptions{},
pass: false,
},
"valid opts": {
opts: &extensions.RunAsUserStrategyOptions{
Ranges: []extensions.UserIDRange{
opts: &policy.RunAsUserStrategyOptions{
Ranges: []policy.IDRange{
{Min: 1, Max: 1},
},
},
@ -57,8 +57,8 @@ func TestNewMustRunAs(t *testing.T) {
}
func TestGenerate(t *testing.T) {
opts := &extensions.RunAsUserStrategyOptions{
Ranges: []extensions.UserIDRange{
opts := &policy.RunAsUserStrategyOptions{
Ranges: []policy.IDRange{
{Min: 1, Max: 1},
},
}
@ -76,8 +76,8 @@ func TestGenerate(t *testing.T) {
}
func TestValidate(t *testing.T) {
opts := &extensions.RunAsUserStrategyOptions{
Ranges: []extensions.UserIDRange{
opts := &policy.RunAsUserStrategyOptions{
Ranges: []policy.IDRange{
{Min: 1, Max: 1},
{Min: 10, Max: 20},
},

View File

@ -19,14 +19,14 @@ package user
import (
"k8s.io/apimachinery/pkg/util/validation/field"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/apis/policy"
)
type nonRoot struct{}
var _ RunAsUserStrategy = &nonRoot{}
func NewRunAsNonRoot(options *extensions.RunAsUserStrategyOptions) (RunAsUserStrategy, error) {
func NewRunAsNonRoot(options *policy.RunAsUserStrategyOptions) (RunAsUserStrategy, error) {
return &nonRoot{}, nil
}

View File

@ -18,7 +18,7 @@ package user
import (
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/apis/policy"
"testing"
)
@ -27,14 +27,14 @@ func TestNonRootOptions(t *testing.T) {
if err != nil {
t.Fatalf("unexpected error initializing NewRunAsNonRoot %v", err)
}
_, err = NewRunAsNonRoot(&extensions.RunAsUserStrategyOptions{})
_, err = NewRunAsNonRoot(&policy.RunAsUserStrategyOptions{})
if err != nil {
t.Errorf("unexpected error initializing NewRunAsNonRoot %v", err)
}
}
func TestNonRootGenerate(t *testing.T) {
s, err := NewRunAsNonRoot(&extensions.RunAsUserStrategyOptions{})
s, err := NewRunAsNonRoot(&policy.RunAsUserStrategyOptions{})
if err != nil {
t.Fatalf("unexpected error initializing NewRunAsNonRoot %v", err)
}
@ -52,7 +52,7 @@ func TestNonRootValidate(t *testing.T) {
badUID := int64(0)
untrue := false
unfalse := true
s, err := NewRunAsNonRoot(&extensions.RunAsUserStrategyOptions{})
s, err := NewRunAsNonRoot(&policy.RunAsUserStrategyOptions{})
if err != nil {
t.Fatalf("unexpected error initializing NewMustRunAs %v", err)
}

View File

@ -19,7 +19,7 @@ package user
import (
"k8s.io/apimachinery/pkg/util/validation/field"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/apis/policy"
)
// runAsAny implements the interface RunAsUserStrategy.
@ -28,7 +28,7 @@ type runAsAny struct{}
var _ RunAsUserStrategy = &runAsAny{}
// NewRunAsAny provides a strategy that will return nil.
func NewRunAsAny(options *extensions.RunAsUserStrategyOptions) (RunAsUserStrategy, error) {
func NewRunAsAny(options *policy.RunAsUserStrategyOptions) (RunAsUserStrategy, error) {
return &runAsAny{}, nil
}

View File

@ -19,7 +19,7 @@ package user
import (
"testing"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/apis/policy"
)
func TestRunAsAnyOptions(t *testing.T) {
@ -27,14 +27,14 @@ func TestRunAsAnyOptions(t *testing.T) {
if err != nil {
t.Fatalf("unexpected error initializing NewRunAsAny %v", err)
}
_, err = NewRunAsAny(&extensions.RunAsUserStrategyOptions{})
_, err = NewRunAsAny(&policy.RunAsUserStrategyOptions{})
if err != nil {
t.Errorf("unexpected error initializing NewRunAsAny %v", err)
}
}
func TestRunAsAnyGenerate(t *testing.T) {
s, err := NewRunAsAny(&extensions.RunAsUserStrategyOptions{})
s, err := NewRunAsAny(&policy.RunAsUserStrategyOptions{})
if err != nil {
t.Fatalf("unexpected error initializing NewRunAsAny %v", err)
}
@ -48,7 +48,7 @@ func TestRunAsAnyGenerate(t *testing.T) {
}
func TestRunAsAnyValidate(t *testing.T) {
s, err := NewRunAsAny(&extensions.RunAsUserStrategyOptions{})
s, err := NewRunAsAny(&policy.RunAsUserStrategyOptions{})
if err != nil {
t.Fatalf("unexpected error initializing NewRunAsAny %v", err)
}

View File

@ -15,7 +15,7 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/security/podsecuritypolicy/util",
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/apis/policy:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
],
)
@ -26,7 +26,7 @@ go_test(
embed = [":go_default_library"],
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/apis/policy:go_default_library",
],
)

View File

@ -22,7 +22,7 @@ import (
"k8s.io/apimachinery/pkg/util/sets"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/apis/policy"
)
const (
@ -40,102 +40,102 @@ func GetAllFSTypesExcept(exceptions ...string) sets.String {
func GetAllFSTypesAsSet() sets.String {
fstypes := sets.NewString()
fstypes.Insert(
string(extensions.HostPath),
string(extensions.AzureFile),
string(extensions.Flocker),
string(extensions.FlexVolume),
string(extensions.EmptyDir),
string(extensions.GCEPersistentDisk),
string(extensions.AWSElasticBlockStore),
string(extensions.GitRepo),
string(extensions.Secret),
string(extensions.NFS),
string(extensions.ISCSI),
string(extensions.Glusterfs),
string(extensions.PersistentVolumeClaim),
string(extensions.RBD),
string(extensions.Cinder),
string(extensions.CephFS),
string(extensions.DownwardAPI),
string(extensions.FC),
string(extensions.ConfigMap),
string(extensions.VsphereVolume),
string(extensions.Quobyte),
string(extensions.AzureDisk),
string(extensions.PhotonPersistentDisk),
string(extensions.StorageOS),
string(extensions.Projected),
string(extensions.PortworxVolume),
string(extensions.ScaleIO),
string(extensions.CSI),
string(policy.HostPath),
string(policy.AzureFile),
string(policy.Flocker),
string(policy.FlexVolume),
string(policy.EmptyDir),
string(policy.GCEPersistentDisk),
string(policy.AWSElasticBlockStore),
string(policy.GitRepo),
string(policy.Secret),
string(policy.NFS),
string(policy.ISCSI),
string(policy.Glusterfs),
string(policy.PersistentVolumeClaim),
string(policy.RBD),
string(policy.Cinder),
string(policy.CephFS),
string(policy.DownwardAPI),
string(policy.FC),
string(policy.ConfigMap),
string(policy.VsphereVolume),
string(policy.Quobyte),
string(policy.AzureDisk),
string(policy.PhotonPersistentDisk),
string(policy.StorageOS),
string(policy.Projected),
string(policy.PortworxVolume),
string(policy.ScaleIO),
string(policy.CSI),
)
return fstypes
}
// getVolumeFSType gets the FSType for a volume.
func GetVolumeFSType(v api.Volume) (extensions.FSType, error) {
func GetVolumeFSType(v api.Volume) (policy.FSType, error) {
switch {
case v.HostPath != nil:
return extensions.HostPath, nil
return policy.HostPath, nil
case v.EmptyDir != nil:
return extensions.EmptyDir, nil
return policy.EmptyDir, nil
case v.GCEPersistentDisk != nil:
return extensions.GCEPersistentDisk, nil
return policy.GCEPersistentDisk, nil
case v.AWSElasticBlockStore != nil:
return extensions.AWSElasticBlockStore, nil
return policy.AWSElasticBlockStore, nil
case v.GitRepo != nil:
return extensions.GitRepo, nil
return policy.GitRepo, nil
case v.Secret != nil:
return extensions.Secret, nil
return policy.Secret, nil
case v.NFS != nil:
return extensions.NFS, nil
return policy.NFS, nil
case v.ISCSI != nil:
return extensions.ISCSI, nil
return policy.ISCSI, nil
case v.Glusterfs != nil:
return extensions.Glusterfs, nil
return policy.Glusterfs, nil
case v.PersistentVolumeClaim != nil:
return extensions.PersistentVolumeClaim, nil
return policy.PersistentVolumeClaim, nil
case v.RBD != nil:
return extensions.RBD, nil
return policy.RBD, nil
case v.FlexVolume != nil:
return extensions.FlexVolume, nil
return policy.FlexVolume, nil
case v.Cinder != nil:
return extensions.Cinder, nil
return policy.Cinder, nil
case v.CephFS != nil:
return extensions.CephFS, nil
return policy.CephFS, nil
case v.Flocker != nil:
return extensions.Flocker, nil
return policy.Flocker, nil
case v.DownwardAPI != nil:
return extensions.DownwardAPI, nil
return policy.DownwardAPI, nil
case v.FC != nil:
return extensions.FC, nil
return policy.FC, nil
case v.AzureFile != nil:
return extensions.AzureFile, nil
return policy.AzureFile, nil
case v.ConfigMap != nil:
return extensions.ConfigMap, nil
return policy.ConfigMap, nil
case v.VsphereVolume != nil:
return extensions.VsphereVolume, nil
return policy.VsphereVolume, nil
case v.Quobyte != nil:
return extensions.Quobyte, nil
return policy.Quobyte, nil
case v.AzureDisk != nil:
return extensions.AzureDisk, nil
return policy.AzureDisk, nil
case v.PhotonPersistentDisk != nil:
return extensions.PhotonPersistentDisk, nil
return policy.PhotonPersistentDisk, nil
case v.StorageOS != nil:
return extensions.StorageOS, nil
return policy.StorageOS, nil
case v.Projected != nil:
return extensions.Projected, nil
return policy.Projected, nil
case v.PortworxVolume != nil:
return extensions.PortworxVolume, nil
return policy.PortworxVolume, nil
case v.ScaleIO != nil:
return extensions.ScaleIO, nil
return policy.ScaleIO, nil
}
return "", fmt.Errorf("unknown volume type for volume: %#v", v)
}
// FSTypeToStringSet converts an FSType slice to a string set.
func FSTypeToStringSet(fsTypes []extensions.FSType) sets.String {
func FSTypeToStringSet(fsTypes []policy.FSType) sets.String {
set := sets.NewString()
for _, v := range fsTypes {
set.Insert(string(v))
@ -144,19 +144,19 @@ func FSTypeToStringSet(fsTypes []extensions.FSType) sets.String {
}
// PSPAllowsAllVolumes checks for FSTypeAll in the psp's allowed volumes.
func PSPAllowsAllVolumes(psp *extensions.PodSecurityPolicy) bool {
return PSPAllowsFSType(psp, extensions.All)
func PSPAllowsAllVolumes(psp *policy.PodSecurityPolicy) bool {
return PSPAllowsFSType(psp, policy.All)
}
// PSPAllowsFSType is a utility for checking if a PSP allows a particular FSType.
// If all volumes are allowed then this will return true for any FSType passed.
func PSPAllowsFSType(psp *extensions.PodSecurityPolicy, fsType extensions.FSType) bool {
func PSPAllowsFSType(psp *policy.PodSecurityPolicy, fsType policy.FSType) bool {
if psp == nil {
return false
}
for _, v := range psp.Spec.Volumes {
if v == fsType || v == extensions.All {
if v == fsType || v == policy.All {
return true
}
}
@ -164,34 +164,38 @@ func PSPAllowsFSType(psp *extensions.PodSecurityPolicy, fsType extensions.FSType
}
// UserFallsInRange is a utility to determine it the id falls in the valid range.
func UserFallsInRange(id int64, rng extensions.UserIDRange) bool {
func UserFallsInRange(id int64, rng policy.IDRange) bool {
return id >= rng.Min && id <= rng.Max
}
// GroupFallsInRange is a utility to determine it the id falls in the valid range.
func GroupFallsInRange(id int64, rng extensions.GroupIDRange) bool {
func GroupFallsInRange(id int64, rng policy.IDRange) bool {
return id >= rng.Min && id <= rng.Max
}
// AllowsHostVolumePath 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 AllowsHostVolumePath(psp *extensions.PodSecurityPolicy, hostPath string) bool {
func AllowsHostVolumePath(psp *policy.PodSecurityPolicy, hostPath string) (pathIsAllowed, mustBeReadOnly bool) {
if psp == nil {
return false
return false, false
}
// If no allowed paths are specified then allow any path
if len(psp.Spec.AllowedHostPaths) == 0 {
return true
return true, false
}
for _, allowedPath := range psp.Spec.AllowedHostPaths {
if hasPathPrefix(hostPath, allowedPath.PathPrefix) {
return true
if !allowedPath.ReadOnly {
return true, allowedPath.ReadOnly
}
pathIsAllowed = true
mustBeReadOnly = true
}
}
return false
return pathIsAllowed, mustBeReadOnly
}
// hasPathPrefix returns true if the string matches pathPrefix exactly, or if is prefixed with pathPrefix at a path segment boundary

View File

@ -17,10 +17,11 @@ limitations under the License.
package util
import (
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/extensions"
"reflect"
"testing"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/policy"
)
// TestVolumeSourceFSTypeDrift ensures that for every known type of volume source (by the fields on
@ -52,45 +53,45 @@ func TestVolumeSourceFSTypeDrift(t *testing.T) {
func TestPSPAllowsFSType(t *testing.T) {
tests := map[string]struct {
psp *extensions.PodSecurityPolicy
fsType extensions.FSType
psp *policy.PodSecurityPolicy
fsType policy.FSType
allows bool
}{
"nil psp": {
psp: nil,
fsType: extensions.HostPath,
fsType: policy.HostPath,
allows: false,
},
"empty volumes": {
psp: &extensions.PodSecurityPolicy{},
fsType: extensions.HostPath,
psp: &policy.PodSecurityPolicy{},
fsType: policy.HostPath,
allows: false,
},
"non-matching": {
psp: &extensions.PodSecurityPolicy{
Spec: extensions.PodSecurityPolicySpec{
Volumes: []extensions.FSType{extensions.AWSElasticBlockStore},
psp: &policy.PodSecurityPolicy{
Spec: policy.PodSecurityPolicySpec{
Volumes: []policy.FSType{policy.AWSElasticBlockStore},
},
},
fsType: extensions.HostPath,
fsType: policy.HostPath,
allows: false,
},
"match on FSTypeAll": {
psp: &extensions.PodSecurityPolicy{
Spec: extensions.PodSecurityPolicySpec{
Volumes: []extensions.FSType{extensions.All},
psp: &policy.PodSecurityPolicy{
Spec: policy.PodSecurityPolicySpec{
Volumes: []policy.FSType{policy.All},
},
},
fsType: extensions.HostPath,
fsType: policy.HostPath,
allows: true,
},
"match on direct match": {
psp: &extensions.PodSecurityPolicy{
Spec: extensions.PodSecurityPolicySpec{
Volumes: []extensions.FSType{extensions.HostPath},
psp: &policy.PodSecurityPolicy{
Spec: policy.PodSecurityPolicySpec{
Volumes: []policy.FSType{policy.HostPath},
},
},
fsType: extensions.HostPath,
fsType: policy.HostPath,
allows: true,
},
}
@ -105,92 +106,113 @@ func TestPSPAllowsFSType(t *testing.T) {
func TestAllowsHostVolumePath(t *testing.T) {
tests := map[string]struct {
psp *extensions.PodSecurityPolicy
path string
allows bool
psp *policy.PodSecurityPolicy
path string
allows bool
mustBeReadOnly bool
}{
"nil psp": {
psp: nil,
path: "/test",
allows: false,
psp: nil,
path: "/test",
allows: false,
mustBeReadOnly: false,
},
"empty allowed paths": {
psp: &extensions.PodSecurityPolicy{},
path: "/test",
allows: true,
psp: &policy.PodSecurityPolicy{},
path: "/test",
allows: true,
mustBeReadOnly: false,
},
"non-matching": {
psp: &extensions.PodSecurityPolicy{
Spec: extensions.PodSecurityPolicySpec{
AllowedHostPaths: []extensions.AllowedHostPath{
{PathPrefix: "/foo"},
psp: &policy.PodSecurityPolicy{
Spec: policy.PodSecurityPolicySpec{
AllowedHostPaths: []policy.AllowedHostPath{
{
PathPrefix: "/foo",
ReadOnly: true,
},
},
},
},
path: "/foobar",
allows: false,
path: "/foobar",
allows: false,
mustBeReadOnly: false,
},
"match on direct match": {
psp: &extensions.PodSecurityPolicy{
Spec: extensions.PodSecurityPolicySpec{
AllowedHostPaths: []extensions.AllowedHostPath{
{PathPrefix: "/foo"},
psp: &policy.PodSecurityPolicy{
Spec: policy.PodSecurityPolicySpec{
AllowedHostPaths: []policy.AllowedHostPath{
{
PathPrefix: "/foo",
ReadOnly: true,
},
},
},
},
path: "/foo",
allows: true,
path: "/foo",
allows: true,
mustBeReadOnly: true,
},
"match with trailing slash on host path": {
psp: &extensions.PodSecurityPolicy{
Spec: extensions.PodSecurityPolicySpec{
AllowedHostPaths: []extensions.AllowedHostPath{
psp: &policy.PodSecurityPolicy{
Spec: policy.PodSecurityPolicySpec{
AllowedHostPaths: []policy.AllowedHostPath{
{PathPrefix: "/foo"},
},
},
},
path: "/foo/",
allows: true,
path: "/foo/",
allows: true,
mustBeReadOnly: false,
},
"match with trailing slash on allowed path": {
psp: &extensions.PodSecurityPolicy{
Spec: extensions.PodSecurityPolicySpec{
AllowedHostPaths: []extensions.AllowedHostPath{
psp: &policy.PodSecurityPolicy{
Spec: policy.PodSecurityPolicySpec{
AllowedHostPaths: []policy.AllowedHostPath{
{PathPrefix: "/foo/"},
},
},
},
path: "/foo",
allows: true,
path: "/foo",
allows: true,
mustBeReadOnly: false,
},
"match child directory": {
psp: &extensions.PodSecurityPolicy{
Spec: extensions.PodSecurityPolicySpec{
AllowedHostPaths: []extensions.AllowedHostPath{
{PathPrefix: "/foo/"},
psp: &policy.PodSecurityPolicy{
Spec: policy.PodSecurityPolicySpec{
AllowedHostPaths: []policy.AllowedHostPath{
{
PathPrefix: "/foo/",
ReadOnly: true,
},
},
},
},
path: "/foo/bar",
allows: true,
path: "/foo/bar",
allows: true,
mustBeReadOnly: true,
},
"non-matching parent directory": {
psp: &extensions.PodSecurityPolicy{
Spec: extensions.PodSecurityPolicySpec{
AllowedHostPaths: []extensions.AllowedHostPath{
psp: &policy.PodSecurityPolicy{
Spec: policy.PodSecurityPolicySpec{
AllowedHostPaths: []policy.AllowedHostPath{
{PathPrefix: "/foo/bar"},
},
},
},
path: "/foo",
allows: false,
path: "/foo",
allows: false,
mustBeReadOnly: false,
},
}
for k, v := range tests {
allows := AllowsHostVolumePath(v.psp, v.path)
allows, mustBeReadOnly := AllowsHostVolumePath(v.psp, v.path)
if v.allows != allows {
t.Errorf("%s expected %t but got %t", k, v.allows, allows)
t.Errorf("allows: %s expected %t but got %t", k, v.allows, allows)
}
if v.mustBeReadOnly != mustBeReadOnly {
t.Errorf("mustBeReadOnly: %s expected %t but got %t", k, v.mustBeReadOnly, mustBeReadOnly)
}
}
}