mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-14 18:53:35 +00:00
vendor update for CSI 0.3.0
This commit is contained in:
7
vendor/k8s.io/kubernetes/pkg/apis/extensions/validation/BUILD
generated
vendored
7
vendor/k8s.io/kubernetes/pkg/apis/extensions/validation/BUILD
generated
vendored
@ -14,15 +14,11 @@ go_library(
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/apis/core/validation:go_default_library",
|
||||
"//pkg/apis/extensions:go_default_library",
|
||||
"//pkg/security/apparmor:go_default_library",
|
||||
"//pkg/security/podsecuritypolicy/seccomp:go_default_library",
|
||||
"//pkg/security/podsecuritypolicy/util:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/validation:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||
],
|
||||
@ -35,9 +31,6 @@ go_test(
|
||||
deps = [
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/apis/extensions:go_default_library",
|
||||
"//pkg/security/apparmor:go_default_library",
|
||||
"//pkg/security/podsecuritypolicy/seccomp:go_default_library",
|
||||
"//pkg/security/podsecuritypolicy/util:go_default_library",
|
||||
"//vendor/github.com/davecgh/go-spew/spew:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
|
||||
|
303
vendor/k8s.io/kubernetes/pkg/apis/extensions/validation/validation.go
generated
vendored
303
vendor/k8s.io/kubernetes/pkg/apis/extensions/validation/validation.go
generated
vendored
@ -17,10 +17,7 @@ limitations under the License.
|
||||
package validation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -30,15 +27,11 @@ import (
|
||||
unversionedvalidation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
apivalidation "k8s.io/kubernetes/pkg/apis/core/validation"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/security/apparmor"
|
||||
"k8s.io/kubernetes/pkg/security/podsecuritypolicy/seccomp"
|
||||
psputil "k8s.io/kubernetes/pkg/security/podsecuritypolicy/util"
|
||||
)
|
||||
|
||||
// ValidateDaemonSet tests if required fields in the DaemonSet are set.
|
||||
@ -613,299 +606,3 @@ func ValidatePodTemplateSpecForReplicaSet(template *api.PodTemplateSpec, selecto
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidatePodSecurityPolicyName can be used to check whether the given
|
||||
// pod security policy name is valid.
|
||||
// Prefix indicates this name will be used as part of generation, in which case
|
||||
// trailing dashes are allowed.
|
||||
var ValidatePodSecurityPolicyName = apivalidation.NameIsDNSSubdomain
|
||||
|
||||
func ValidatePodSecurityPolicy(psp *extensions.PodSecurityPolicy) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&psp.ObjectMeta, false, ValidatePodSecurityPolicyName, field.NewPath("metadata"))...)
|
||||
allErrs = append(allErrs, ValidatePodSecurityPolicySpecificAnnotations(psp.Annotations, field.NewPath("metadata").Child("annotations"))...)
|
||||
allErrs = append(allErrs, ValidatePodSecurityPolicySpec(&psp.Spec, field.NewPath("spec"))...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func ValidatePodSecurityPolicySpec(spec *extensions.PodSecurityPolicySpec, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
allErrs = append(allErrs, validatePSPRunAsUser(fldPath.Child("runAsUser"), &spec.RunAsUser)...)
|
||||
allErrs = append(allErrs, validatePSPSELinux(fldPath.Child("seLinux"), &spec.SELinux)...)
|
||||
allErrs = append(allErrs, validatePSPSupplementalGroup(fldPath.Child("supplementalGroups"), &spec.SupplementalGroups)...)
|
||||
allErrs = append(allErrs, validatePSPFSGroup(fldPath.Child("fsGroup"), &spec.FSGroup)...)
|
||||
allErrs = append(allErrs, validatePodSecurityPolicyVolumes(fldPath, spec.Volumes)...)
|
||||
if len(spec.RequiredDropCapabilities) > 0 && hasCap(extensions.AllowAllCapabilities, spec.AllowedCapabilities) {
|
||||
allErrs = append(allErrs, field.Invalid(field.NewPath("requiredDropCapabilities"), spec.RequiredDropCapabilities,
|
||||
"must be empty when all capabilities are allowed by a wildcard"))
|
||||
}
|
||||
allErrs = append(allErrs, validatePSPCapsAgainstDrops(spec.RequiredDropCapabilities, spec.DefaultAddCapabilities, field.NewPath("defaultAddCapabilities"))...)
|
||||
allErrs = append(allErrs, validatePSPCapsAgainstDrops(spec.RequiredDropCapabilities, spec.AllowedCapabilities, field.NewPath("allowedCapabilities"))...)
|
||||
allErrs = append(allErrs, validatePSPDefaultAllowPrivilegeEscalation(fldPath.Child("defaultAllowPrivilegeEscalation"), spec.DefaultAllowPrivilegeEscalation, spec.AllowPrivilegeEscalation)...)
|
||||
allErrs = append(allErrs, validatePSPAllowedHostPaths(fldPath.Child("allowedHostPaths"), spec.AllowedHostPaths)...)
|
||||
allErrs = append(allErrs, validatePSPAllowedFlexVolumes(fldPath.Child("allowedFlexVolumes"), spec.AllowedFlexVolumes)...)
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func ValidatePodSecurityPolicySpecificAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
if p := annotations[apparmor.DefaultProfileAnnotationKey]; p != "" {
|
||||
if err := apparmor.ValidateProfileFormat(p); err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Key(apparmor.DefaultProfileAnnotationKey), p, err.Error()))
|
||||
}
|
||||
}
|
||||
if allowed := annotations[apparmor.AllowedProfilesAnnotationKey]; allowed != "" {
|
||||
for _, p := range strings.Split(allowed, ",") {
|
||||
if err := apparmor.ValidateProfileFormat(p); err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Key(apparmor.AllowedProfilesAnnotationKey), allowed, err.Error()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sysctlAnnotation := annotations[extensions.SysctlsPodSecurityPolicyAnnotationKey]
|
||||
sysctlFldPath := fldPath.Key(extensions.SysctlsPodSecurityPolicyAnnotationKey)
|
||||
sysctls, err := extensions.SysctlsFromPodSecurityPolicyAnnotation(sysctlAnnotation)
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(sysctlFldPath, sysctlAnnotation, err.Error()))
|
||||
} else {
|
||||
allErrs = append(allErrs, validatePodSecurityPolicySysctls(sysctlFldPath, sysctls)...)
|
||||
}
|
||||
|
||||
if p := annotations[seccomp.DefaultProfileAnnotationKey]; p != "" {
|
||||
allErrs = append(allErrs, apivalidation.ValidateSeccompProfile(p, fldPath.Key(seccomp.DefaultProfileAnnotationKey))...)
|
||||
}
|
||||
if allowed := annotations[seccomp.AllowedProfilesAnnotationKey]; allowed != "" {
|
||||
for _, p := range strings.Split(allowed, ",") {
|
||||
if p == seccomp.AllowAny {
|
||||
continue
|
||||
}
|
||||
allErrs = append(allErrs, apivalidation.ValidateSeccompProfile(p, fldPath.Key(seccomp.AllowedProfilesAnnotationKey))...)
|
||||
}
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// validatePSPAllowedHostPaths makes sure all allowed host paths follow:
|
||||
// 1. path prefix is required
|
||||
// 2. path prefix does not have any element which is ".."
|
||||
func validatePSPAllowedHostPaths(fldPath *field.Path, allowedHostPaths []extensions.AllowedHostPath) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
for i, target := range allowedHostPaths {
|
||||
if target.PathPrefix == "" {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Index(i), "is required"))
|
||||
break
|
||||
}
|
||||
parts := strings.Split(filepath.ToSlash(target.PathPrefix), "/")
|
||||
for _, item := range parts {
|
||||
if item == ".." {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Index(i), target.PathPrefix, "must not contain '..'"))
|
||||
break // even for `../../..`, one error is sufficient to make the point
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// validatePSPAllowedFlexVolumes
|
||||
func validatePSPAllowedFlexVolumes(fldPath *field.Path, flexVolumes []extensions.AllowedFlexVolume) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if len(flexVolumes) > 0 {
|
||||
for idx, fv := range flexVolumes {
|
||||
if len(fv.Driver) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("allowedFlexVolumes").Index(idx).Child("driver"),
|
||||
"must specify a driver"))
|
||||
}
|
||||
}
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// validatePSPSELinux validates the SELinux fields of PodSecurityPolicy.
|
||||
func validatePSPSELinux(fldPath *field.Path, seLinux *extensions.SELinuxStrategyOptions) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
// ensure the selinux strategy has a valid rule
|
||||
supportedSELinuxRules := sets.NewString(string(extensions.SELinuxStrategyMustRunAs),
|
||||
string(extensions.SELinuxStrategyRunAsAny))
|
||||
if !supportedSELinuxRules.Has(string(seLinux.Rule)) {
|
||||
allErrs = append(allErrs, field.NotSupported(fldPath.Child("rule"), seLinux.Rule, supportedSELinuxRules.List()))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// validatePSPRunAsUser validates the RunAsUser fields of PodSecurityPolicy.
|
||||
func validatePSPRunAsUser(fldPath *field.Path, runAsUser *extensions.RunAsUserStrategyOptions) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
// ensure the user strategy has a valid rule
|
||||
supportedRunAsUserRules := sets.NewString(string(extensions.RunAsUserStrategyMustRunAs),
|
||||
string(extensions.RunAsUserStrategyMustRunAsNonRoot),
|
||||
string(extensions.RunAsUserStrategyRunAsAny))
|
||||
if !supportedRunAsUserRules.Has(string(runAsUser.Rule)) {
|
||||
allErrs = append(allErrs, field.NotSupported(fldPath.Child("rule"), runAsUser.Rule, supportedRunAsUserRules.List()))
|
||||
}
|
||||
|
||||
// validate range settings
|
||||
for idx, rng := range runAsUser.Ranges {
|
||||
allErrs = append(allErrs, validateUserIDRange(fldPath.Child("ranges").Index(idx), rng)...)
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// validatePSPFSGroup validates the FSGroupStrategyOptions fields of the PodSecurityPolicy.
|
||||
func validatePSPFSGroup(fldPath *field.Path, groupOptions *extensions.FSGroupStrategyOptions) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
supportedRules := sets.NewString(
|
||||
string(extensions.FSGroupStrategyMustRunAs),
|
||||
string(extensions.FSGroupStrategyRunAsAny),
|
||||
)
|
||||
if !supportedRules.Has(string(groupOptions.Rule)) {
|
||||
allErrs = append(allErrs, field.NotSupported(fldPath.Child("rule"), groupOptions.Rule, supportedRules.List()))
|
||||
}
|
||||
|
||||
for idx, rng := range groupOptions.Ranges {
|
||||
allErrs = append(allErrs, validateGroupIDRange(fldPath.Child("ranges").Index(idx), rng)...)
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// validatePSPSupplementalGroup validates the SupplementalGroupsStrategyOptions fields of the PodSecurityPolicy.
|
||||
func validatePSPSupplementalGroup(fldPath *field.Path, groupOptions *extensions.SupplementalGroupsStrategyOptions) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
supportedRules := sets.NewString(
|
||||
string(extensions.SupplementalGroupsStrategyRunAsAny),
|
||||
string(extensions.SupplementalGroupsStrategyMustRunAs),
|
||||
)
|
||||
if !supportedRules.Has(string(groupOptions.Rule)) {
|
||||
allErrs = append(allErrs, field.NotSupported(fldPath.Child("rule"), groupOptions.Rule, supportedRules.List()))
|
||||
}
|
||||
|
||||
for idx, rng := range groupOptions.Ranges {
|
||||
allErrs = append(allErrs, validateGroupIDRange(fldPath.Child("ranges").Index(idx), rng)...)
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// validatePodSecurityPolicyVolumes validates the volume fields of PodSecurityPolicy.
|
||||
func validatePodSecurityPolicyVolumes(fldPath *field.Path, volumes []extensions.FSType) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
allowed := psputil.GetAllFSTypesAsSet()
|
||||
// add in the * value since that is a pseudo type that is not included by default
|
||||
allowed.Insert(string(extensions.All))
|
||||
for _, v := range volumes {
|
||||
if !allowed.Has(string(v)) {
|
||||
allErrs = append(allErrs, field.NotSupported(fldPath.Child("volumes"), v, allowed.List()))
|
||||
}
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// validatePSPDefaultAllowPrivilegeEscalation validates the DefaultAllowPrivilegeEscalation field against the AllowPrivilegeEscalation field of a PodSecurityPolicy.
|
||||
func validatePSPDefaultAllowPrivilegeEscalation(fldPath *field.Path, defaultAllowPrivilegeEscalation *bool, allowPrivilegeEscalation bool) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if defaultAllowPrivilegeEscalation != nil && *defaultAllowPrivilegeEscalation && !allowPrivilegeEscalation {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, defaultAllowPrivilegeEscalation, "Cannot set DefaultAllowPrivilegeEscalation to true without also setting AllowPrivilegeEscalation to true"))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
const sysctlPatternSegmentFmt string = "([a-z0-9][-_a-z0-9]*)?[a-z0-9*]"
|
||||
const SysctlPatternFmt string = "(" + apivalidation.SysctlSegmentFmt + "\\.)*" + sysctlPatternSegmentFmt
|
||||
|
||||
var sysctlPatternRegexp = regexp.MustCompile("^" + SysctlPatternFmt + "$")
|
||||
|
||||
func IsValidSysctlPattern(name string) bool {
|
||||
if len(name) > apivalidation.SysctlMaxLength {
|
||||
return false
|
||||
}
|
||||
return sysctlPatternRegexp.MatchString(name)
|
||||
}
|
||||
|
||||
// validatePodSecurityPolicySysctls validates the sysctls fields of PodSecurityPolicy.
|
||||
func validatePodSecurityPolicySysctls(fldPath *field.Path, sysctls []string) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
for i, s := range sysctls {
|
||||
if !IsValidSysctlPattern(string(s)) {
|
||||
allErrs = append(
|
||||
allErrs,
|
||||
field.Invalid(fldPath.Index(i), sysctls[i], fmt.Sprintf("must have at most %d characters and match regex %s",
|
||||
apivalidation.SysctlMaxLength,
|
||||
SysctlPatternFmt,
|
||||
)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateUserIDRange(fldPath *field.Path, rng extensions.UserIDRange) field.ErrorList {
|
||||
return validateIDRanges(fldPath, int64(rng.Min), int64(rng.Max))
|
||||
}
|
||||
|
||||
func validateGroupIDRange(fldPath *field.Path, rng extensions.GroupIDRange) field.ErrorList {
|
||||
return validateIDRanges(fldPath, int64(rng.Min), int64(rng.Max))
|
||||
}
|
||||
|
||||
// validateIDRanges ensures the range is valid.
|
||||
func validateIDRanges(fldPath *field.Path, min, max int64) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
// if 0 <= Min <= Max then we do not need to validate max. It is always greater than or
|
||||
// equal to 0 and Min.
|
||||
if min < 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("min"), min, "min cannot be negative"))
|
||||
}
|
||||
if max < 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("max"), max, "max cannot be negative"))
|
||||
}
|
||||
if min > max {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("min"), min, "min cannot be greater than max"))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// validatePSPCapsAgainstDrops ensures an allowed cap is not listed in the required drops.
|
||||
func validatePSPCapsAgainstDrops(requiredDrops []api.Capability, capsToCheck []api.Capability, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if requiredDrops == nil {
|
||||
return allErrs
|
||||
}
|
||||
for _, cap := range capsToCheck {
|
||||
if hasCap(cap, requiredDrops) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, cap,
|
||||
fmt.Sprintf("capability is listed in %s and requiredDropCapabilities", fldPath.String())))
|
||||
}
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// hasCap checks for needle in haystack.
|
||||
func hasCap(needle api.Capability, haystack []api.Capability) bool {
|
||||
for _, c := range haystack {
|
||||
if needle == c {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ValidatePodSecurityPolicyUpdate validates a PSP for updates.
|
||||
func ValidatePodSecurityPolicyUpdate(old *extensions.PodSecurityPolicy, new *extensions.PodSecurityPolicy) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&new.ObjectMeta, &old.ObjectMeta, field.NewPath("metadata"))...)
|
||||
allErrs = append(allErrs, ValidatePodSecurityPolicySpecificAnnotations(new.Annotations, field.NewPath("metadata").Child("annotations"))...)
|
||||
allErrs = append(allErrs, ValidatePodSecurityPolicySpec(&new.Spec, field.NewPath("spec"))...)
|
||||
return allErrs
|
||||
}
|
||||
|
499
vendor/k8s.io/kubernetes/pkg/apis/extensions/validation/validation_test.go
generated
vendored
499
vendor/k8s.io/kubernetes/pkg/apis/extensions/validation/validation_test.go
generated
vendored
@ -28,9 +28,6 @@ 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/security/apparmor"
|
||||
"k8s.io/kubernetes/pkg/security/podsecuritypolicy/seccomp"
|
||||
psputil "k8s.io/kubernetes/pkg/security/podsecuritypolicy/util"
|
||||
)
|
||||
|
||||
func TestValidateDaemonSetStatusUpdate(t *testing.T) {
|
||||
@ -2317,499 +2314,3 @@ func TestValidateReplicaSet(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatePodSecurityPolicy(t *testing.T) {
|
||||
validPSP := func() *extensions.PodSecurityPolicy {
|
||||
return &extensions.PodSecurityPolicy{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Annotations: map[string]string{},
|
||||
},
|
||||
Spec: extensions.PodSecurityPolicySpec{
|
||||
SELinux: extensions.SELinuxStrategyOptions{
|
||||
Rule: extensions.SELinuxStrategyRunAsAny,
|
||||
},
|
||||
RunAsUser: extensions.RunAsUserStrategyOptions{
|
||||
Rule: extensions.RunAsUserStrategyRunAsAny,
|
||||
},
|
||||
FSGroup: extensions.FSGroupStrategyOptions{
|
||||
Rule: extensions.FSGroupStrategyRunAsAny,
|
||||
},
|
||||
SupplementalGroups: extensions.SupplementalGroupsStrategyOptions{
|
||||
Rule: extensions.SupplementalGroupsStrategyRunAsAny,
|
||||
},
|
||||
AllowedHostPaths: []extensions.AllowedHostPath{
|
||||
{PathPrefix: "/foo/bar"},
|
||||
{PathPrefix: "/baz/"},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
noUserOptions := validPSP()
|
||||
noUserOptions.Spec.RunAsUser.Rule = ""
|
||||
|
||||
noSELinuxOptions := validPSP()
|
||||
noSELinuxOptions.Spec.SELinux.Rule = ""
|
||||
|
||||
invalidUserStratType := validPSP()
|
||||
invalidUserStratType.Spec.RunAsUser.Rule = "invalid"
|
||||
|
||||
invalidSELinuxStratType := validPSP()
|
||||
invalidSELinuxStratType.Spec.SELinux.Rule = "invalid"
|
||||
|
||||
invalidUIDPSP := validPSP()
|
||||
invalidUIDPSP.Spec.RunAsUser.Rule = extensions.RunAsUserStrategyMustRunAs
|
||||
invalidUIDPSP.Spec.RunAsUser.Ranges = []extensions.UserIDRange{{Min: -1, Max: 1}}
|
||||
|
||||
missingObjectMetaName := validPSP()
|
||||
missingObjectMetaName.ObjectMeta.Name = ""
|
||||
|
||||
noFSGroupOptions := validPSP()
|
||||
noFSGroupOptions.Spec.FSGroup.Rule = ""
|
||||
|
||||
invalidFSGroupStratType := validPSP()
|
||||
invalidFSGroupStratType.Spec.FSGroup.Rule = "invalid"
|
||||
|
||||
noSupplementalGroupsOptions := validPSP()
|
||||
noSupplementalGroupsOptions.Spec.SupplementalGroups.Rule = ""
|
||||
|
||||
invalidSupGroupStratType := validPSP()
|
||||
invalidSupGroupStratType.Spec.SupplementalGroups.Rule = "invalid"
|
||||
|
||||
invalidRangeMinGreaterThanMax := validPSP()
|
||||
invalidRangeMinGreaterThanMax.Spec.FSGroup.Ranges = []extensions.GroupIDRange{
|
||||
{Min: 2, Max: 1},
|
||||
}
|
||||
|
||||
invalidRangeNegativeMin := validPSP()
|
||||
invalidRangeNegativeMin.Spec.FSGroup.Ranges = []extensions.GroupIDRange{
|
||||
{Min: -1, Max: 10},
|
||||
}
|
||||
|
||||
invalidRangeNegativeMax := validPSP()
|
||||
invalidRangeNegativeMax.Spec.FSGroup.Ranges = []extensions.GroupIDRange{
|
||||
{Min: 1, Max: -10},
|
||||
}
|
||||
|
||||
wildcardAllowedCapAndRequiredDrop := validPSP()
|
||||
wildcardAllowedCapAndRequiredDrop.Spec.RequiredDropCapabilities = []api.Capability{"foo"}
|
||||
wildcardAllowedCapAndRequiredDrop.Spec.AllowedCapabilities = []api.Capability{extensions.AllowAllCapabilities}
|
||||
|
||||
requiredCapAddAndDrop := validPSP()
|
||||
requiredCapAddAndDrop.Spec.DefaultAddCapabilities = []api.Capability{"foo"}
|
||||
requiredCapAddAndDrop.Spec.RequiredDropCapabilities = []api.Capability{"foo"}
|
||||
|
||||
allowedCapListedInRequiredDrop := validPSP()
|
||||
allowedCapListedInRequiredDrop.Spec.RequiredDropCapabilities = []api.Capability{"foo"}
|
||||
allowedCapListedInRequiredDrop.Spec.AllowedCapabilities = []api.Capability{"foo"}
|
||||
|
||||
invalidAppArmorDefault := validPSP()
|
||||
invalidAppArmorDefault.Annotations = map[string]string{
|
||||
apparmor.DefaultProfileAnnotationKey: "not-good",
|
||||
}
|
||||
invalidAppArmorAllowed := validPSP()
|
||||
invalidAppArmorAllowed.Annotations = map[string]string{
|
||||
apparmor.AllowedProfilesAnnotationKey: apparmor.ProfileRuntimeDefault + ",not-good",
|
||||
}
|
||||
|
||||
invalidSysctlPattern := validPSP()
|
||||
invalidSysctlPattern.Annotations[extensions.SysctlsPodSecurityPolicyAnnotationKey] = "a.*.b"
|
||||
|
||||
invalidSeccompDefault := validPSP()
|
||||
invalidSeccompDefault.Annotations = map[string]string{
|
||||
seccomp.DefaultProfileAnnotationKey: "not-good",
|
||||
}
|
||||
invalidSeccompAllowAnyDefault := validPSP()
|
||||
invalidSeccompAllowAnyDefault.Annotations = map[string]string{
|
||||
seccomp.DefaultProfileAnnotationKey: "*",
|
||||
}
|
||||
invalidSeccompAllowed := validPSP()
|
||||
invalidSeccompAllowed.Annotations = map[string]string{
|
||||
seccomp.AllowedProfilesAnnotationKey: "docker/default,not-good",
|
||||
}
|
||||
|
||||
invalidAllowedHostPathMissingPath := validPSP()
|
||||
invalidAllowedHostPathMissingPath.Spec.AllowedHostPaths = []extensions.AllowedHostPath{
|
||||
{PathPrefix: ""},
|
||||
}
|
||||
|
||||
invalidAllowedHostPathBacksteps := validPSP()
|
||||
invalidAllowedHostPathBacksteps.Spec.AllowedHostPaths = []extensions.AllowedHostPath{
|
||||
{PathPrefix: "/dont/allow/backsteps/.."},
|
||||
}
|
||||
|
||||
invalidDefaultAllowPrivilegeEscalation := validPSP()
|
||||
pe := true
|
||||
invalidDefaultAllowPrivilegeEscalation.Spec.DefaultAllowPrivilegeEscalation = &pe
|
||||
|
||||
emptyFlexDriver := validPSP()
|
||||
emptyFlexDriver.Spec.Volumes = []extensions.FSType{extensions.FlexVolume}
|
||||
emptyFlexDriver.Spec.AllowedFlexVolumes = []extensions.AllowedFlexVolume{{}}
|
||||
|
||||
nonEmptyFlexVolumes := validPSP()
|
||||
nonEmptyFlexVolumes.Spec.AllowedFlexVolumes = []extensions.AllowedFlexVolume{{Driver: "example/driver"}}
|
||||
|
||||
type testCase struct {
|
||||
psp *extensions.PodSecurityPolicy
|
||||
errorType field.ErrorType
|
||||
errorDetail string
|
||||
}
|
||||
errorCases := map[string]testCase{
|
||||
"no user options": {
|
||||
psp: noUserOptions,
|
||||
errorType: field.ErrorTypeNotSupported,
|
||||
errorDetail: `supported values: "MustRunAs", "MustRunAsNonRoot", "RunAsAny"`,
|
||||
},
|
||||
"no selinux options": {
|
||||
psp: noSELinuxOptions,
|
||||
errorType: field.ErrorTypeNotSupported,
|
||||
errorDetail: `supported values: "MustRunAs", "RunAsAny"`,
|
||||
},
|
||||
"no fsgroup options": {
|
||||
psp: noFSGroupOptions,
|
||||
errorType: field.ErrorTypeNotSupported,
|
||||
errorDetail: `supported values: "MustRunAs", "RunAsAny"`,
|
||||
},
|
||||
"no sup group options": {
|
||||
psp: noSupplementalGroupsOptions,
|
||||
errorType: field.ErrorTypeNotSupported,
|
||||
errorDetail: `supported values: "MustRunAs", "RunAsAny"`,
|
||||
},
|
||||
"invalid user strategy type": {
|
||||
psp: invalidUserStratType,
|
||||
errorType: field.ErrorTypeNotSupported,
|
||||
errorDetail: `supported values: "MustRunAs", "MustRunAsNonRoot", "RunAsAny"`,
|
||||
},
|
||||
"invalid selinux strategy type": {
|
||||
psp: invalidSELinuxStratType,
|
||||
errorType: field.ErrorTypeNotSupported,
|
||||
errorDetail: `supported values: "MustRunAs", "RunAsAny"`,
|
||||
},
|
||||
"invalid sup group strategy type": {
|
||||
psp: invalidSupGroupStratType,
|
||||
errorType: field.ErrorTypeNotSupported,
|
||||
errorDetail: `supported values: "MustRunAs", "RunAsAny"`,
|
||||
},
|
||||
"invalid fs group strategy type": {
|
||||
psp: invalidFSGroupStratType,
|
||||
errorType: field.ErrorTypeNotSupported,
|
||||
errorDetail: `supported values: "MustRunAs", "RunAsAny"`,
|
||||
},
|
||||
"invalid uid": {
|
||||
psp: invalidUIDPSP,
|
||||
errorType: field.ErrorTypeInvalid,
|
||||
errorDetail: "min cannot be negative",
|
||||
},
|
||||
"missing object meta name": {
|
||||
psp: missingObjectMetaName,
|
||||
errorType: field.ErrorTypeRequired,
|
||||
errorDetail: "name or generateName is required",
|
||||
},
|
||||
"invalid range min greater than max": {
|
||||
psp: invalidRangeMinGreaterThanMax,
|
||||
errorType: field.ErrorTypeInvalid,
|
||||
errorDetail: "min cannot be greater than max",
|
||||
},
|
||||
"invalid range negative min": {
|
||||
psp: invalidRangeNegativeMin,
|
||||
errorType: field.ErrorTypeInvalid,
|
||||
errorDetail: "min cannot be negative",
|
||||
},
|
||||
"invalid range negative max": {
|
||||
psp: invalidRangeNegativeMax,
|
||||
errorType: field.ErrorTypeInvalid,
|
||||
errorDetail: "max cannot be negative",
|
||||
},
|
||||
"non-empty required drops and all caps are allowed by a wildcard": {
|
||||
psp: wildcardAllowedCapAndRequiredDrop,
|
||||
errorType: field.ErrorTypeInvalid,
|
||||
errorDetail: "must be empty when all capabilities are allowed by a wildcard",
|
||||
},
|
||||
"invalid required caps": {
|
||||
psp: requiredCapAddAndDrop,
|
||||
errorType: field.ErrorTypeInvalid,
|
||||
errorDetail: "capability is listed in defaultAddCapabilities and requiredDropCapabilities",
|
||||
},
|
||||
"allowed cap listed in required drops": {
|
||||
psp: allowedCapListedInRequiredDrop,
|
||||
errorType: field.ErrorTypeInvalid,
|
||||
errorDetail: "capability is listed in allowedCapabilities and requiredDropCapabilities",
|
||||
},
|
||||
"invalid AppArmor default profile": {
|
||||
psp: invalidAppArmorDefault,
|
||||
errorType: field.ErrorTypeInvalid,
|
||||
errorDetail: "invalid AppArmor profile name: \"not-good\"",
|
||||
},
|
||||
"invalid AppArmor allowed profile": {
|
||||
psp: invalidAppArmorAllowed,
|
||||
errorType: field.ErrorTypeInvalid,
|
||||
errorDetail: "invalid AppArmor profile name: \"not-good\"",
|
||||
},
|
||||
"invalid sysctl pattern": {
|
||||
psp: invalidSysctlPattern,
|
||||
errorType: field.ErrorTypeInvalid,
|
||||
errorDetail: fmt.Sprintf("must have at most 253 characters and match regex %s", SysctlPatternFmt),
|
||||
},
|
||||
"invalid seccomp default profile": {
|
||||
psp: invalidSeccompDefault,
|
||||
errorType: field.ErrorTypeInvalid,
|
||||
errorDetail: "must be a valid seccomp profile",
|
||||
},
|
||||
"invalid seccomp allow any default profile": {
|
||||
psp: invalidSeccompAllowAnyDefault,
|
||||
errorType: field.ErrorTypeInvalid,
|
||||
errorDetail: "must be a valid seccomp profile",
|
||||
},
|
||||
"invalid seccomp allowed profile": {
|
||||
psp: invalidSeccompAllowed,
|
||||
errorType: field.ErrorTypeInvalid,
|
||||
errorDetail: "must be a valid seccomp profile",
|
||||
},
|
||||
"invalid defaultAllowPrivilegeEscalation": {
|
||||
psp: invalidDefaultAllowPrivilegeEscalation,
|
||||
errorType: field.ErrorTypeInvalid,
|
||||
errorDetail: "Cannot set DefaultAllowPrivilegeEscalation to true without also setting AllowPrivilegeEscalation to true",
|
||||
},
|
||||
"invalid allowed host path empty path": {
|
||||
psp: invalidAllowedHostPathMissingPath,
|
||||
errorType: field.ErrorTypeRequired,
|
||||
errorDetail: "is required",
|
||||
},
|
||||
"invalid allowed host path with backsteps": {
|
||||
psp: invalidAllowedHostPathBacksteps,
|
||||
errorType: field.ErrorTypeInvalid,
|
||||
errorDetail: "must not contain '..'",
|
||||
},
|
||||
"empty flex volume driver": {
|
||||
psp: emptyFlexDriver,
|
||||
errorType: field.ErrorTypeRequired,
|
||||
errorDetail: "must specify a driver",
|
||||
},
|
||||
}
|
||||
|
||||
for k, v := range errorCases {
|
||||
errs := ValidatePodSecurityPolicy(v.psp)
|
||||
if len(errs) == 0 {
|
||||
t.Errorf("%s expected errors but got none", k)
|
||||
continue
|
||||
}
|
||||
if errs[0].Type != v.errorType {
|
||||
t.Errorf("[%s] received an unexpected error type. Expected: '%s' got: '%s'", k, v.errorType, errs[0].Type)
|
||||
}
|
||||
if errs[0].Detail != v.errorDetail {
|
||||
t.Errorf("[%s] received an unexpected error detail. Expected '%s' got: '%s'", k, v.errorDetail, errs[0].Detail)
|
||||
}
|
||||
}
|
||||
|
||||
// Update error is different for 'missing object meta name'.
|
||||
errorCases["missing object meta name"] = testCase{
|
||||
psp: errorCases["missing object meta name"].psp,
|
||||
errorType: field.ErrorTypeInvalid,
|
||||
errorDetail: "field is immutable",
|
||||
}
|
||||
|
||||
// Should not be able to update to an invalid policy.
|
||||
for k, v := range errorCases {
|
||||
v.psp.ResourceVersion = "444" // Required for updates.
|
||||
errs := ValidatePodSecurityPolicyUpdate(validPSP(), v.psp)
|
||||
if len(errs) == 0 {
|
||||
t.Errorf("[%s] expected update errors but got none", k)
|
||||
continue
|
||||
}
|
||||
if errs[0].Type != v.errorType {
|
||||
t.Errorf("[%s] received an unexpected error type. Expected: '%s' got: '%s'", k, v.errorType, errs[0].Type)
|
||||
}
|
||||
if errs[0].Detail != v.errorDetail {
|
||||
t.Errorf("[%s] received an unexpected error detail. Expected '%s' got: '%s'", k, v.errorDetail, errs[0].Detail)
|
||||
}
|
||||
}
|
||||
|
||||
mustRunAs := validPSP()
|
||||
mustRunAs.Spec.FSGroup.Rule = extensions.FSGroupStrategyMustRunAs
|
||||
mustRunAs.Spec.SupplementalGroups.Rule = extensions.SupplementalGroupsStrategyMustRunAs
|
||||
mustRunAs.Spec.RunAsUser.Rule = extensions.RunAsUserStrategyMustRunAs
|
||||
mustRunAs.Spec.RunAsUser.Ranges = []extensions.UserIDRange{
|
||||
{Min: 1, Max: 1},
|
||||
}
|
||||
mustRunAs.Spec.SELinux.Rule = extensions.SELinuxStrategyMustRunAs
|
||||
|
||||
runAsNonRoot := validPSP()
|
||||
runAsNonRoot.Spec.RunAsUser.Rule = extensions.RunAsUserStrategyMustRunAsNonRoot
|
||||
|
||||
caseInsensitiveAddDrop := validPSP()
|
||||
caseInsensitiveAddDrop.Spec.DefaultAddCapabilities = []api.Capability{"foo"}
|
||||
caseInsensitiveAddDrop.Spec.RequiredDropCapabilities = []api.Capability{"FOO"}
|
||||
|
||||
caseInsensitiveAllowedDrop := validPSP()
|
||||
caseInsensitiveAllowedDrop.Spec.RequiredDropCapabilities = []api.Capability{"FOO"}
|
||||
caseInsensitiveAllowedDrop.Spec.AllowedCapabilities = []api.Capability{"foo"}
|
||||
|
||||
validAppArmor := validPSP()
|
||||
validAppArmor.Annotations = map[string]string{
|
||||
apparmor.DefaultProfileAnnotationKey: apparmor.ProfileRuntimeDefault,
|
||||
apparmor.AllowedProfilesAnnotationKey: apparmor.ProfileRuntimeDefault + "," + apparmor.ProfileNamePrefix + "foo",
|
||||
}
|
||||
|
||||
withSysctl := validPSP()
|
||||
withSysctl.Annotations[extensions.SysctlsPodSecurityPolicyAnnotationKey] = "net.*"
|
||||
|
||||
validSeccomp := validPSP()
|
||||
validSeccomp.Annotations = map[string]string{
|
||||
seccomp.DefaultProfileAnnotationKey: "docker/default",
|
||||
seccomp.AllowedProfilesAnnotationKey: "docker/default,unconfined,localhost/foo,*",
|
||||
}
|
||||
|
||||
validDefaultAllowPrivilegeEscalation := validPSP()
|
||||
pe = true
|
||||
validDefaultAllowPrivilegeEscalation.Spec.DefaultAllowPrivilegeEscalation = &pe
|
||||
validDefaultAllowPrivilegeEscalation.Spec.AllowPrivilegeEscalation = true
|
||||
|
||||
flexvolumeWhenFlexVolumesAllowed := validPSP()
|
||||
flexvolumeWhenFlexVolumesAllowed.Spec.Volumes = []extensions.FSType{extensions.FlexVolume}
|
||||
flexvolumeWhenFlexVolumesAllowed.Spec.AllowedFlexVolumes = []extensions.AllowedFlexVolume{
|
||||
{Driver: "example/driver1"},
|
||||
}
|
||||
|
||||
flexvolumeWhenAllVolumesAllowed := validPSP()
|
||||
flexvolumeWhenAllVolumesAllowed.Spec.Volumes = []extensions.FSType{extensions.All}
|
||||
flexvolumeWhenAllVolumesAllowed.Spec.AllowedFlexVolumes = []extensions.AllowedFlexVolume{
|
||||
{Driver: "example/driver2"},
|
||||
}
|
||||
successCases := map[string]struct {
|
||||
psp *extensions.PodSecurityPolicy
|
||||
}{
|
||||
"must run as": {
|
||||
psp: mustRunAs,
|
||||
},
|
||||
"run as any": {
|
||||
psp: validPSP(),
|
||||
},
|
||||
"run as non-root (user only)": {
|
||||
psp: runAsNonRoot,
|
||||
},
|
||||
"comparison for add -> drop is case sensitive": {
|
||||
psp: caseInsensitiveAddDrop,
|
||||
},
|
||||
"comparison for allowed -> drop is case sensitive": {
|
||||
psp: caseInsensitiveAllowedDrop,
|
||||
},
|
||||
"valid AppArmor annotations": {
|
||||
psp: validAppArmor,
|
||||
},
|
||||
"with network sysctls": {
|
||||
psp: withSysctl,
|
||||
},
|
||||
"valid seccomp annotations": {
|
||||
psp: validSeccomp,
|
||||
},
|
||||
"valid defaultAllowPrivilegeEscalation as true": {
|
||||
psp: validDefaultAllowPrivilegeEscalation,
|
||||
},
|
||||
"allow white-listed flexVolume when flex volumes are allowed": {
|
||||
psp: flexvolumeWhenFlexVolumesAllowed,
|
||||
},
|
||||
"allow white-listed flexVolume when all volumes are allowed": {
|
||||
psp: flexvolumeWhenAllVolumesAllowed,
|
||||
},
|
||||
}
|
||||
|
||||
for k, v := range successCases {
|
||||
if errs := ValidatePodSecurityPolicy(v.psp); len(errs) != 0 {
|
||||
t.Errorf("Expected success for %s, got %v", k, errs)
|
||||
}
|
||||
|
||||
// Should be able to update to a valid PSP.
|
||||
v.psp.ResourceVersion = "444" // Required for updates.
|
||||
if errs := ValidatePodSecurityPolicyUpdate(validPSP(), v.psp); len(errs) != 0 {
|
||||
t.Errorf("Expected success for %s update, got %v", k, errs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatePSPVolumes(t *testing.T) {
|
||||
validPSP := func() *extensions.PodSecurityPolicy {
|
||||
return &extensions.PodSecurityPolicy{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
|
||||
Spec: extensions.PodSecurityPolicySpec{
|
||||
SELinux: extensions.SELinuxStrategyOptions{
|
||||
Rule: extensions.SELinuxStrategyRunAsAny,
|
||||
},
|
||||
RunAsUser: extensions.RunAsUserStrategyOptions{
|
||||
Rule: extensions.RunAsUserStrategyRunAsAny,
|
||||
},
|
||||
FSGroup: extensions.FSGroupStrategyOptions{
|
||||
Rule: extensions.FSGroupStrategyRunAsAny,
|
||||
},
|
||||
SupplementalGroups: extensions.SupplementalGroupsStrategyOptions{
|
||||
Rule: extensions.SupplementalGroupsStrategyRunAsAny,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
volumes := psputil.GetAllFSTypesAsSet()
|
||||
// add in the * value since that is a pseudo type that is not included by default
|
||||
volumes.Insert(string(extensions.All))
|
||||
|
||||
for _, strVolume := range volumes.List() {
|
||||
psp := validPSP()
|
||||
psp.Spec.Volumes = []extensions.FSType{extensions.FSType(strVolume)}
|
||||
errs := ValidatePodSecurityPolicy(psp)
|
||||
if len(errs) != 0 {
|
||||
t.Errorf("%s validation expected no errors but received %v", strVolume, errs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsValidSysctlPattern(t *testing.T) {
|
||||
valid := []string{
|
||||
"a.b.c.d",
|
||||
"a",
|
||||
"a_b",
|
||||
"a-b",
|
||||
"abc",
|
||||
"abc.def",
|
||||
"*",
|
||||
"a.*",
|
||||
"*",
|
||||
"abc*",
|
||||
"a.abc*",
|
||||
"a.b.*",
|
||||
}
|
||||
invalid := []string{
|
||||
"",
|
||||
"ä",
|
||||
"a_",
|
||||
"_",
|
||||
"_a",
|
||||
"_a._b",
|
||||
"__",
|
||||
"-",
|
||||
".",
|
||||
"a.",
|
||||
".a",
|
||||
"a.b.",
|
||||
"a*.b",
|
||||
"a*b",
|
||||
"*a",
|
||||
"Abc",
|
||||
func(n int) string {
|
||||
x := make([]byte, n)
|
||||
for i := range x {
|
||||
x[i] = byte('a')
|
||||
}
|
||||
return string(x)
|
||||
}(256),
|
||||
}
|
||||
for _, s := range valid {
|
||||
if !IsValidSysctlPattern(s) {
|
||||
t.Errorf("%q expected to be a valid sysctl pattern", s)
|
||||
}
|
||||
}
|
||||
for _, s := range invalid {
|
||||
if IsValidSysctlPattern(s) {
|
||||
t.Errorf("%q expected to be an invalid sysctl pattern", s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user