mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-27 21:47:07 +00:00
support flexvlome in psp
This commit is contained in:
parent
84b3dcca08
commit
98faf6b39c
@ -860,6 +860,11 @@ type PodSecurityPolicySpec struct {
|
|||||||
// AllowedHostPaths is a white list of allowed host paths. Empty indicates that all host paths may be used.
|
// AllowedHostPaths is a white list of allowed host paths. Empty indicates that all host paths may be used.
|
||||||
// +optional
|
// +optional
|
||||||
AllowedHostPaths []AllowedHostPath
|
AllowedHostPaths []AllowedHostPath
|
||||||
|
// AllowedFlexVolumes is a whitelist of allowed Flexvolumes. Empty or nil indicates that all
|
||||||
|
// Flexvolumes may be used. This parameter is effective only when the usage of the Flexvolumes
|
||||||
|
// is allowed in the "Volumes" field.
|
||||||
|
// +optional
|
||||||
|
AllowedFlexVolumes []AllowedFlexVolume
|
||||||
}
|
}
|
||||||
|
|
||||||
// AllowedHostPath defines the host volume conditions that will be enabled by a policy
|
// AllowedHostPath defines the host volume conditions that will be enabled by a policy
|
||||||
@ -923,6 +928,12 @@ var (
|
|||||||
All FSType = "*"
|
All FSType = "*"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// AllowedFlexVolume represents a single Flexvolume that is allowed to be used.
|
||||||
|
type AllowedFlexVolume struct {
|
||||||
|
// Driver is the name of the Flexvolume driver.
|
||||||
|
Driver string
|
||||||
|
}
|
||||||
|
|
||||||
// SELinuxStrategyOptions defines the strategy type and any options used to create the strategy.
|
// SELinuxStrategyOptions defines the strategy type and any options used to create the strategy.
|
||||||
type SELinuxStrategyOptions struct {
|
type SELinuxStrategyOptions struct {
|
||||||
// Rule is the strategy that will dictate the allowable labels that may be set.
|
// Rule is the strategy that will dictate the allowable labels that may be set.
|
||||||
|
@ -655,6 +655,7 @@ func ValidatePodSecurityPolicySpec(spec *extensions.PodSecurityPolicySpec, fldPa
|
|||||||
allErrs = append(allErrs, validatePSPCapsAgainstDrops(spec.RequiredDropCapabilities, spec.AllowedCapabilities, field.NewPath("allowedCapabilities"))...)
|
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, validatePSPDefaultAllowPrivilegeEscalation(fldPath.Child("defaultAllowPrivilegeEscalation"), spec.DefaultAllowPrivilegeEscalation, spec.AllowPrivilegeEscalation)...)
|
||||||
allErrs = append(allErrs, validatePSPAllowedHostPaths(fldPath.Child("allowedHostPaths"), spec.AllowedHostPaths)...)
|
allErrs = append(allErrs, validatePSPAllowedHostPaths(fldPath.Child("allowedHostPaths"), spec.AllowedHostPaths)...)
|
||||||
|
allErrs = append(allErrs, validatePSPAllowedFlexVolumes(fldPath.Child("allowedFlexVolumes"), spec.AllowedFlexVolumes)...)
|
||||||
|
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
@ -721,6 +722,20 @@ func validatePSPAllowedHostPaths(fldPath *field.Path, allowedHostPaths []extensi
|
|||||||
return allErrs
|
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.
|
// validatePSPSELinux validates the SELinux fields of PodSecurityPolicy.
|
||||||
func validatePSPSELinux(fldPath *field.Path, seLinux *extensions.SELinuxStrategyOptions) field.ErrorList {
|
func validatePSPSELinux(fldPath *field.Path, seLinux *extensions.SELinuxStrategyOptions) field.ErrorList {
|
||||||
allErrs := field.ErrorList{}
|
allErrs := field.ErrorList{}
|
||||||
@ -802,7 +817,6 @@ func validatePodSecurityPolicyVolumes(fldPath *field.Path, volumes []extensions.
|
|||||||
allErrs = append(allErrs, field.NotSupported(fldPath.Child("volumes"), v, allowed.List()))
|
allErrs = append(allErrs, field.NotSupported(fldPath.Child("volumes"), v, allowed.List()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2450,6 +2450,13 @@ func TestValidatePodSecurityPolicy(t *testing.T) {
|
|||||||
pe := true
|
pe := true
|
||||||
invalidDefaultAllowPrivilegeEscalation.Spec.DefaultAllowPrivilegeEscalation = &pe
|
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 {
|
type testCase struct {
|
||||||
psp *extensions.PodSecurityPolicy
|
psp *extensions.PodSecurityPolicy
|
||||||
errorType field.ErrorType
|
errorType field.ErrorType
|
||||||
@ -2581,6 +2588,11 @@ func TestValidatePodSecurityPolicy(t *testing.T) {
|
|||||||
errorType: field.ErrorTypeInvalid,
|
errorType: field.ErrorTypeInvalid,
|
||||||
errorDetail: "must not contain '..'",
|
errorDetail: "must not contain '..'",
|
||||||
},
|
},
|
||||||
|
"empty flex volume driver": {
|
||||||
|
psp: emptyFlexDriver,
|
||||||
|
errorType: field.ErrorTypeRequired,
|
||||||
|
errorDetail: "must specify a driver",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range errorCases {
|
for k, v := range errorCases {
|
||||||
@ -2660,6 +2672,17 @@ func TestValidatePodSecurityPolicy(t *testing.T) {
|
|||||||
validDefaultAllowPrivilegeEscalation.Spec.DefaultAllowPrivilegeEscalation = &pe
|
validDefaultAllowPrivilegeEscalation.Spec.DefaultAllowPrivilegeEscalation = &pe
|
||||||
validDefaultAllowPrivilegeEscalation.Spec.AllowPrivilegeEscalation = true
|
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 {
|
successCases := map[string]struct {
|
||||||
psp *extensions.PodSecurityPolicy
|
psp *extensions.PodSecurityPolicy
|
||||||
}{
|
}{
|
||||||
@ -2690,6 +2713,12 @@ func TestValidatePodSecurityPolicy(t *testing.T) {
|
|||||||
"valid defaultAllowPrivilegeEscalation as true": {
|
"valid defaultAllowPrivilegeEscalation as true": {
|
||||||
psp: validDefaultAllowPrivilegeEscalation,
|
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 {
|
for k, v := range successCases {
|
||||||
|
@ -3386,6 +3386,9 @@ func describePodSecurityPolicy(psp *extensions.PodSecurityPolicy) (string, error
|
|||||||
w.Write(LEVEL_1, "Allowed Capabilities:\t%s\n", capsToString(psp.Spec.AllowedCapabilities))
|
w.Write(LEVEL_1, "Allowed Capabilities:\t%s\n", capsToString(psp.Spec.AllowedCapabilities))
|
||||||
w.Write(LEVEL_1, "Allowed Volume Types:\t%s\n", fsTypeToString(psp.Spec.Volumes))
|
w.Write(LEVEL_1, "Allowed Volume Types:\t%s\n", fsTypeToString(psp.Spec.Volumes))
|
||||||
|
|
||||||
|
if len(psp.Spec.AllowedFlexVolumes) > 0 {
|
||||||
|
w.Write(LEVEL_1, "Allowed FlexVolume Types:\t%s\n", flexVolumesToString(psp.Spec.AllowedFlexVolumes))
|
||||||
|
}
|
||||||
w.Write(LEVEL_1, "Allow Host Network:\t%t\n", psp.Spec.HostNetwork)
|
w.Write(LEVEL_1, "Allow Host Network:\t%t\n", psp.Spec.HostNetwork)
|
||||||
w.Write(LEVEL_1, "Allow Host Ports:\t%s\n", hostPortRangeToString(psp.Spec.HostPorts))
|
w.Write(LEVEL_1, "Allow Host Ports:\t%s\n", hostPortRangeToString(psp.Spec.HostPorts))
|
||||||
w.Write(LEVEL_1, "Allow Host PID:\t%t\n", psp.Spec.HostPID)
|
w.Write(LEVEL_1, "Allow Host PID:\t%t\n", psp.Spec.HostPID)
|
||||||
@ -3419,10 +3422,14 @@ func describePodSecurityPolicy(psp *extensions.PodSecurityPolicy) (string, error
|
|||||||
}
|
}
|
||||||
|
|
||||||
func stringOrNone(s string) string {
|
func stringOrNone(s string) string {
|
||||||
|
return stringOrDefaultValue(s, "<none>")
|
||||||
|
}
|
||||||
|
|
||||||
|
func stringOrDefaultValue(s, defaultValue string) string {
|
||||||
if len(s) > 0 {
|
if len(s) > 0 {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
return "<none>"
|
return defaultValue
|
||||||
}
|
}
|
||||||
|
|
||||||
func fsTypeToString(volumes []extensions.FSType) string {
|
func fsTypeToString(volumes []extensions.FSType) string {
|
||||||
@ -3433,6 +3440,14 @@ func fsTypeToString(volumes []extensions.FSType) string {
|
|||||||
return stringOrNone(strings.Join(strVolumes, ","))
|
return stringOrNone(strings.Join(strVolumes, ","))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func flexVolumesToString(flexVolumes []extensions.AllowedFlexVolume) string {
|
||||||
|
volumes := []string{}
|
||||||
|
for _, flexVolume := range flexVolumes {
|
||||||
|
volumes = append(volumes, "driver="+flexVolume.Driver)
|
||||||
|
}
|
||||||
|
return stringOrDefaultValue(strings.Join(volumes, ","), "<all>")
|
||||||
|
}
|
||||||
|
|
||||||
func hostPortRangeToString(ranges []extensions.HostPortRange) string {
|
func hostPortRangeToString(ranges []extensions.HostPortRange) string {
|
||||||
formattedString := ""
|
formattedString := ""
|
||||||
if ranges != nil {
|
if ranges != nil {
|
||||||
|
@ -233,9 +233,24 @@ func (s *simpleProvider) ValidatePodSecurityContext(pod *api.Pod, fldPath *field
|
|||||||
fmt.Sprintf("is not allowed to be used")))
|
fmt.Sprintf("is not allowed to be used")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if fsType == extensions.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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
allErrs = append(allErrs,
|
||||||
|
field.Invalid(fldPath.Child("volumes").Index(i).Child("driver"), driver,
|
||||||
|
"Flexvolume driver is not allowed to be used"))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,6 +256,18 @@ func TestValidatePodSecurityContextFailures(t *testing.T) {
|
|||||||
failSeccompProfilePod := defaultPod()
|
failSeccompProfilePod := defaultPod()
|
||||||
failSeccompProfilePod.Annotations = map[string]string{api.SeccompPodAnnotationKey: "foo"}
|
failSeccompProfilePod.Annotations = map[string]string{api.SeccompPodAnnotationKey: "foo"}
|
||||||
|
|
||||||
|
podWithInvalidFlexVolumeDriver := defaultPod()
|
||||||
|
podWithInvalidFlexVolumeDriver.Spec.Volumes = []api.Volume{
|
||||||
|
{
|
||||||
|
Name: "flex-volume",
|
||||||
|
VolumeSource: api.VolumeSource{
|
||||||
|
FlexVolume: &api.FlexVolumeSource{
|
||||||
|
Driver: "example/unknown",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
errorCases := map[string]struct {
|
errorCases := map[string]struct {
|
||||||
pod *api.Pod
|
pod *api.Pod
|
||||||
psp *extensions.PodSecurityPolicy
|
psp *extensions.PodSecurityPolicy
|
||||||
@ -341,6 +353,16 @@ func TestValidatePodSecurityContextFailures(t *testing.T) {
|
|||||||
psp: defaultPSP(),
|
psp: defaultPSP(),
|
||||||
expectedError: "Forbidden: seccomp may not be set",
|
expectedError: "Forbidden: seccomp may not be set",
|
||||||
},
|
},
|
||||||
|
"fail pod with disallowed flexVolume when flex volumes are allowed": {
|
||||||
|
pod: podWithInvalidFlexVolumeDriver,
|
||||||
|
psp: allowFlexVolumesPSP(false, false),
|
||||||
|
expectedError: "Flexvolume driver is not allowed to be used",
|
||||||
|
},
|
||||||
|
"fail pod with disallowed flexVolume when all volumes are allowed": {
|
||||||
|
pod: podWithInvalidFlexVolumeDriver,
|
||||||
|
psp: allowFlexVolumesPSP(false, true),
|
||||||
|
expectedError: "Flexvolume driver is not allowed to be used",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for k, v := range errorCases {
|
for k, v := range errorCases {
|
||||||
provider, err := NewSimpleProvider(v.psp, "namespace", NewSimpleStrategyFactory())
|
provider, err := NewSimpleProvider(v.psp, "namespace", NewSimpleStrategyFactory())
|
||||||
@ -358,6 +380,28 @@ func TestValidatePodSecurityContextFailures(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func allowFlexVolumesPSP(allowAllFlexVolumes, allowAllVolumes bool) *extensions.PodSecurityPolicy {
|
||||||
|
psp := defaultPSP()
|
||||||
|
|
||||||
|
allowedVolumes := []extensions.AllowedFlexVolume{
|
||||||
|
{Driver: "example/foo"},
|
||||||
|
{Driver: "example/bar"},
|
||||||
|
}
|
||||||
|
if allowAllFlexVolumes {
|
||||||
|
allowedVolumes = []extensions.AllowedFlexVolume{}
|
||||||
|
}
|
||||||
|
|
||||||
|
allowedVolumeType := extensions.FlexVolume
|
||||||
|
if allowAllVolumes {
|
||||||
|
allowedVolumeType = extensions.All
|
||||||
|
}
|
||||||
|
|
||||||
|
psp.Spec.AllowedFlexVolumes = allowedVolumes
|
||||||
|
psp.Spec.Volumes = []extensions.FSType{allowedVolumeType}
|
||||||
|
|
||||||
|
return psp
|
||||||
|
}
|
||||||
|
|
||||||
func TestValidateContainerSecurityContextFailures(t *testing.T) {
|
func TestValidateContainerSecurityContextFailures(t *testing.T) {
|
||||||
// fail user strat
|
// fail user strat
|
||||||
failUserPSP := defaultPSP()
|
failUserPSP := defaultPSP()
|
||||||
@ -597,6 +641,18 @@ func TestValidatePodSecurityContextSuccess(t *testing.T) {
|
|||||||
api.SeccompPodAnnotationKey: "foo",
|
api.SeccompPodAnnotationKey: "foo",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flexVolumePod := defaultPod()
|
||||||
|
flexVolumePod.Spec.Volumes = []api.Volume{
|
||||||
|
{
|
||||||
|
Name: "flex-volume",
|
||||||
|
VolumeSource: api.VolumeSource{
|
||||||
|
FlexVolume: &api.FlexVolumeSource{
|
||||||
|
Driver: "example/bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
successCases := map[string]struct {
|
successCases := map[string]struct {
|
||||||
pod *api.Pod
|
pod *api.Pod
|
||||||
psp *extensions.PodSecurityPolicy
|
psp *extensions.PodSecurityPolicy
|
||||||
@ -653,6 +709,22 @@ func TestValidatePodSecurityContextSuccess(t *testing.T) {
|
|||||||
pod: seccompPod,
|
pod: seccompPod,
|
||||||
psp: seccompPSP,
|
psp: seccompPSP,
|
||||||
},
|
},
|
||||||
|
"flex volume driver in a whitelist (all volumes are allowed)": {
|
||||||
|
pod: flexVolumePod,
|
||||||
|
psp: allowFlexVolumesPSP(false, true),
|
||||||
|
},
|
||||||
|
"flex volume driver with empty whitelist (all volumes are allowed)": {
|
||||||
|
pod: flexVolumePod,
|
||||||
|
psp: allowFlexVolumesPSP(true, true),
|
||||||
|
},
|
||||||
|
"flex volume driver in a whitelist (only flex volumes are allowed)": {
|
||||||
|
pod: flexVolumePod,
|
||||||
|
psp: allowFlexVolumesPSP(false, false),
|
||||||
|
},
|
||||||
|
"flex volume driver with empty whitelist (only flex volumes volumes are allowed)": {
|
||||||
|
pod: flexVolumePod,
|
||||||
|
psp: allowFlexVolumesPSP(true, false),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range successCases {
|
for k, v := range successCases {
|
||||||
|
@ -938,6 +938,11 @@ type PodSecurityPolicySpec struct {
|
|||||||
// is a white list of allowed host paths. Empty indicates that all host paths may be used.
|
// is a white list of allowed host paths. Empty indicates that all host paths may be used.
|
||||||
// +optional
|
// +optional
|
||||||
AllowedHostPaths []AllowedHostPath `json:"allowedHostPaths,omitempty" protobuf:"bytes,17,rep,name=allowedHostPaths"`
|
AllowedHostPaths []AllowedHostPath `json:"allowedHostPaths,omitempty" protobuf:"bytes,17,rep,name=allowedHostPaths"`
|
||||||
|
// AllowedFlexVolumes is a whitelist of allowed Flexvolumes. Empty or nil indicates that all
|
||||||
|
// Flexvolumes may be used. This parameter is effective only when the usage of the Flexvolumes
|
||||||
|
// is allowed in the "Volumes" field.
|
||||||
|
// +optional
|
||||||
|
AllowedFlexVolumes []AllowedFlexVolume `json:"allowedFlexVolumes,omitempty" protobuf:"bytes,18,rep,name=allowedFlexVolumes"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// defines the host volume conditions that will be enabled by a policy
|
// defines the host volume conditions that will be enabled by a policy
|
||||||
@ -981,6 +986,12 @@ var (
|
|||||||
All FSType = "*"
|
All FSType = "*"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// AllowedFlexVolume represents a single Flexvolume that is allowed to be used.
|
||||||
|
type AllowedFlexVolume struct {
|
||||||
|
// Driver is the name of the Flexvolume driver.
|
||||||
|
Driver string `json:"driver" protobuf:"bytes,1,opt,name=driver"`
|
||||||
|
}
|
||||||
|
|
||||||
// Host Port Range defines a range of host ports that will be enabled by a policy
|
// Host Port Range defines a range of host ports that will be enabled by a policy
|
||||||
// for pods to use. It requires both the start and end to be defined.
|
// for pods to use. It requires both the start and end to be defined.
|
||||||
type HostPortRange struct {
|
type HostPortRange struct {
|
||||||
|
Loading…
Reference in New Issue
Block a user