Skip to content

Commit

Permalink
Merge pull request #76915 from vladimirvivien/csi-inline-podsec-policy
Browse files Browse the repository at this point in the history
CSI ephemeral - Enforcing pod security policy AllowedCSIDriver
  • Loading branch information
k8s-ci-robot committed May 30, 2019
2 parents 8d5052e + d15ff34 commit 3aecf43
Show file tree
Hide file tree
Showing 15 changed files with 228 additions and 38 deletions.
4 changes: 2 additions & 2 deletions api/openapi-spec/swagger.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion pkg/apis/policy/types.go
Expand Up @@ -209,7 +209,8 @@ type PodSecurityPolicySpec struct {
// +optional
AllowedFlexVolumes []AllowedFlexVolume
// AllowedCSIDrivers is a whitelist of inline CSI drivers that must be explicitly set to be embedded within a pod spec.
// An empty value means no CSI drivers can run inline within a pod spec.
// An empty value indicates that any CSI driver can be used for inline ephemeral volumes.
// This is an alpha field, and is only honored if the API server enables the CSIInlineVolume feature gate.
// +optional
AllowedCSIDrivers []AllowedCSIDriver
// AllowedUnsafeSysctls is a list of explicitly allowed unsafe sysctls, defaults to none.
Expand Down
22 changes: 22 additions & 0 deletions pkg/apis/policy/validation/validation_test.go
Expand Up @@ -281,6 +281,10 @@ func TestValidatePodSecurityPolicy(t *testing.T) {
invalidProcMount := validPSP()
invalidProcMount.Spec.AllowedProcMountTypes = []api.ProcMountType{api.ProcMountType("bogus")}

allowedCSIDriverPSP := validPSP()
allowedCSIDriverPSP.Spec.Volumes = []policy.FSType{policy.CSI}
allowedCSIDriverPSP.Spec.AllowedCSIDrivers = []policy.AllowedCSIDriver{{}}

type testCase struct {
psp *policy.PodSecurityPolicy
errorType field.ErrorType
Expand Down Expand Up @@ -447,6 +451,10 @@ func TestValidatePodSecurityPolicy(t *testing.T) {
errorType: field.ErrorTypeRequired,
errorDetail: "must specify a driver",
},
"CSI policy with empty allowed driver list": {
psp: allowedCSIDriverPSP,
errorType: field.ErrorTypeRequired,
},
"invalid allowedProcMountTypes": {
psp: invalidProcMount,
errorType: field.ErrorTypeNotSupported,
Expand Down Expand Up @@ -549,6 +557,14 @@ func TestValidatePodSecurityPolicy(t *testing.T) {
validProcMount := validPSP()
validProcMount.Spec.AllowedProcMountTypes = []api.ProcMountType{api.DefaultProcMount, api.UnmaskedProcMount}

allowedCSIDriversWithCSIFsType := validPSP()
allowedCSIDriversWithCSIFsType.Spec.Volumes = []policy.FSType{policy.CSI}
allowedCSIDriversWithCSIFsType.Spec.AllowedCSIDrivers = []policy.AllowedCSIDriver{{Name: "foo"}}

allowedCSIDriversWithAllFsTypes := validPSP()
allowedCSIDriversWithAllFsTypes.Spec.Volumes = []policy.FSType{policy.All}
allowedCSIDriversWithAllFsTypes.Spec.AllowedCSIDrivers = []policy.AllowedCSIDriver{{Name: "bar"}}

successCases := map[string]struct {
psp *policy.PodSecurityPolicy
}{
Expand Down Expand Up @@ -591,6 +607,12 @@ func TestValidatePodSecurityPolicy(t *testing.T) {
"valid allowedProcMountTypes": {
psp: validProcMount,
},
"allowed CSI drivers when FSType policy is set to CSI": {
psp: allowedCSIDriversWithCSIFsType,
},
"allowed CSI drivers when FSType policy is set to All": {
psp: allowedCSIDriversWithAllFsTypes,
},
}

for k, v := range successCases {
Expand Down
13 changes: 13 additions & 0 deletions pkg/kubectl/describe/versioned/describe.go
Expand Up @@ -3856,6 +3856,11 @@ func describePodSecurityPolicy(psp *policyv1beta1.PodSecurityPolicy) (string, er
if len(psp.Spec.AllowedFlexVolumes) > 0 {
w.Write(LEVEL_1, "Allowed FlexVolume Types:\t%s\n", flexVolumesToString(psp.Spec.AllowedFlexVolumes))
}

if len(psp.Spec.AllowedCSIDrivers) > 0 {
w.Write(LEVEL_1, "Allowed CSI Drivers:\t%s\n", csiDriversToString(psp.Spec.AllowedCSIDrivers))
}

if len(psp.Spec.AllowedUnsafeSysctls) > 0 {
w.Write(LEVEL_1, "Allowed Unsafe Sysctls:\t%s\n", sysctlsToString(psp.Spec.AllowedUnsafeSysctls))
}
Expand Down Expand Up @@ -3921,6 +3926,14 @@ func flexVolumesToString(flexVolumes []policyv1beta1.AllowedFlexVolume) string {
return stringOrDefaultValue(strings.Join(volumes, ","), "<all>")
}

func csiDriversToString(csiDrivers []policyv1beta1.AllowedCSIDriver) string {
drivers := []string{}
for _, csiDriver := range csiDrivers {
drivers = append(drivers, "driver="+csiDriver.Name)
}
return stringOrDefaultValue(strings.Join(drivers, ","), "<all>")
}

func sysctlsToString(sysctls []string) string {
return stringOrNone(strings.Join(sysctls, ","))
}
Expand Down
3 changes: 3 additions & 0 deletions pkg/security/podsecuritypolicy/BUILD
Expand Up @@ -42,13 +42,16 @@ go_test(
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/apis/core/v1:go_default_library",
"//pkg/features:go_default_library",
"//pkg/security/apparmor:go_default_library",
"//pkg/security/podsecuritypolicy/seccomp:go_default_library",
"//pkg/security/podsecuritypolicy/util:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/api/policy/v1beta1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//staging/src/k8s.io/component-base/featuregate/testing:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library",
"//vendor/github.com/stretchr/testify/require:go_default_library",
"//vendor/k8s.io/utils/pointer:go_default_library",
Expand Down
83 changes: 56 additions & 27 deletions pkg/security/podsecuritypolicy/provider.go
Expand Up @@ -233,6 +233,28 @@ func (s *simpleProvider) ValidatePod(pod *api.Pod) field.ErrorList {

allErrs = append(allErrs, s.strategies.SysctlsStrategy.Validate(pod)...)

allErrs = append(allErrs, s.validatePodVolumes(pod)...)

if s.psp.Spec.RuntimeClass != nil {
allErrs = append(allErrs, validateRuntimeClassName(pod.Spec.RuntimeClassName, s.psp.Spec.RuntimeClass.AllowedRuntimeClassNames)...)
}

fldPath := field.NewPath("spec", "initContainers")
for i := range pod.Spec.InitContainers {
allErrs = append(allErrs, s.validateContainer(pod, &pod.Spec.InitContainers[i], fldPath.Index(i))...)
}

fldPath = field.NewPath("spec", "containers")
for i := range pod.Spec.Containers {
allErrs = append(allErrs, s.validateContainer(pod, &pod.Spec.Containers[i], fldPath.Index(i))...)
}

return allErrs
}

func (s *simpleProvider) validatePodVolumes(pod *api.Pod) field.ErrorList {
allErrs := field.ErrorList{}

if len(pod.Spec.Volumes) > 0 {
allowsAllVolumeTypes := psputil.PSPAllowsAllVolumes(s.psp)
allowedVolumes := psputil.FSTypeToStringSet(s.psp.Spec.Volumes)
Expand All @@ -250,7 +272,8 @@ func (s *simpleProvider) ValidatePod(pod *api.Pod) field.ErrorList {
continue
}

if fsType == policy.HostPath {
switch fsType {
case policy.HostPath:
allows, mustBeReadOnly := psputil.AllowsHostVolumePath(s.psp, v.HostPath.Path)
if !allows {
allErrs = append(allErrs, field.Invalid(
Expand Down Expand Up @@ -279,40 +302,46 @@ func (s *simpleProvider) ValidatePod(pod *api.Pod) field.ErrorList {
}
}
}
}

if fsType == policy.FlexVolume && len(s.psp.Spec.AllowedFlexVolumes) > 0 {
found := false
driver := v.FlexVolume.Driver
for _, allowedFlexVolume := range s.psp.Spec.AllowedFlexVolumes {
if driver == allowedFlexVolume.Driver {
found = true
break
case policy.FlexVolume:
if len(s.psp.Spec.AllowedFlexVolumes) > 0 {
found := false
driver := v.FlexVolume.Driver
for _, allowedFlexVolume := range s.psp.Spec.AllowedFlexVolumes {
if driver == allowedFlexVolume.Driver {
found = true
break
}
}
if !found {
allErrs = append(allErrs,
field.Invalid(field.NewPath("spec", "volumes").Index(i).Child("driver"), driver,
"Flexvolume driver is not allowed to be used"))
}
}
if !found {
allErrs = append(allErrs,
field.Invalid(field.NewPath("spec", "volumes").Index(i).Child("driver"), driver,
"Flexvolume driver is not allowed to be used"))

case policy.CSI:
if utilfeature.DefaultFeatureGate.Enabled(features.CSIInlineVolume) {
if len(s.psp.Spec.AllowedCSIDrivers) > 0 {
found := false
driver := v.CSI.Driver
for _, allowedCSIDriver := range s.psp.Spec.AllowedCSIDrivers {
if driver == allowedCSIDriver.Name {
found = true
break
}
}
if !found {
allErrs = append(allErrs,
field.Invalid(field.NewPath("spec", "volumes").Index(i).Child("csi", "driver"), driver,
"Inline CSI driver is not allowed to be used"))
}
}
}
}
}
}

if s.psp.Spec.RuntimeClass != nil {
allErrs = append(allErrs, validateRuntimeClassName(pod.Spec.RuntimeClassName, s.psp.Spec.RuntimeClass.AllowedRuntimeClassNames)...)
}

fldPath := field.NewPath("spec", "initContainers")
for i := range pod.Spec.InitContainers {
allErrs = append(allErrs, s.validateContainer(pod, &pod.Spec.InitContainers[i], fldPath.Index(i))...)
}

fldPath = field.NewPath("spec", "containers")
for i := range pod.Spec.Containers {
allErrs = append(allErrs, s.validateContainer(pod, &pod.Spec.Containers[i], fldPath.Index(i))...)
}

return allErrs
}

Expand Down

0 comments on commit 3aecf43

Please sign in to comment.