PodSecurityPolicy.allowedCapabilities: add support for using * to allow to request any capabilities.

Also modify "privileged" PSP to use it and allow privileged users to use
any capabilities.
pull/6/head
Slava Semushin 2017-08-25 16:30:27 +02:00
parent bef5cf386e
commit 9015a82692
7 changed files with 47 additions and 2 deletions

View File

@ -14,6 +14,8 @@ spec:
rule: RunAsAny
volumes:
- '*'
allowedCapabilities:
- '*'
---
apiVersion: extensions/v1beta1
kind: PodSecurityPolicy

View File

@ -898,6 +898,7 @@ type PodSecurityPolicySpec struct {
// AllowedCapabilities is a list of capabilities that can be requested to add to the container.
// Capabilities in this field may be added at the pod author's discretion.
// You must not list a capability in both AllowedCapabilities and RequiredDropCapabilities.
// To allow all capabilities you may use '*'.
// +optional
AllowedCapabilities []api.Capability
// Volumes is a white list of allowed volume plugins. Empty indicates that all plugins
@ -966,6 +967,10 @@ type HostPortRange struct {
Max int
}
// AllowAllCapabilities can be used as a value for the PodSecurityPolicy.AllowAllCapabilities
// field and means that any capabilities are allowed to be requested.
var AllowAllCapabilities api.Capability = "*"
// FSType gives strong typing to different file systems that are used by volumes.
type FSType string

View File

@ -660,6 +660,10 @@ func ValidatePodSecurityPolicySpec(spec *extensions.PodSecurityPolicySpec, fldPa
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)...)

View File

@ -2472,6 +2472,10 @@ func TestValidatePodSecurityPolicy(t *testing.T) {
{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"}
@ -2586,6 +2590,11 @@ func TestValidatePodSecurityPolicy(t *testing.T) {
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,

View File

@ -22,6 +22,7 @@ import (
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/extensions"
)
// defaultCapabilities implements the Strategy interface
@ -101,9 +102,15 @@ func (s *defaultCapabilities) Validate(pod *api.Pod, container *api.Container) f
return allErrs
}
allowedAdd := makeCapSet(s.allowedCaps)
allowAllCaps := allowedAdd.Has(string(extensions.AllowAllCapabilities))
if allowAllCaps {
// skip validation against allowed/defaultAdd/requiredDrop because all capabilities are allowed by a wildcard
return allErrs
}
// validate that anything being added is in the default or allowed sets
defaultAdd := makeCapSet(s.defaultAddCapabilities)
allowedAdd := makeCapSet(s.allowedCaps)
for _, cap := range container.SecurityContext.Capabilities.Add {
sCap := string(cap)

View File

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

View File

@ -272,6 +272,10 @@ func TestAdmitCaps(t *testing.T) {
requiresFooToBeDropped.Name = "requireDrop"
requiresFooToBeDropped.Spec.RequiredDropCapabilities = []kapi.Capability{"foo"}
allowAllInAllowed := restrictivePSP()
allowAllInAllowed.Name = "allowAllCapsInAllowed"
allowAllInAllowed.Spec.AllowedCapabilities = []kapi.Capability{extensions.AllowAllCapabilities}
tc := map[string]struct {
pod *kapi.Pod
psps []*extensions.PodSecurityPolicy
@ -337,6 +341,13 @@ func TestAdmitCaps(t *testing.T) {
},
expectedPSP: requiresFooToBeDropped.Name,
},
// UC 8: using '*' in allowed caps
"should accept cap add when all caps are allowed": {
pod: createPodWithCaps(&kapi.Capabilities{Add: []kapi.Capability{"foo"}}),
psps: []*extensions.PodSecurityPolicy{restricted, allowAllInAllowed},
shouldPass: true,
expectedPSP: allowAllInAllowed.Name,
},
}
for k, v := range tc {
@ -1360,7 +1371,7 @@ func testPSPAdmit(testCaseName string, psps []*extensions.PodSecurityPolicy, pod
if shouldPass && err == nil {
if pod.Annotations[psputil.ValidatedPSPAnnotation] != expectedPSP {
t.Errorf("%s: expected to validate under %s but found %s", testCaseName, expectedPSP, pod.Annotations[psputil.ValidatedPSPAnnotation])
t.Errorf("%s: expected to validate under %q PSP but found %q", testCaseName, expectedPSP, pod.Annotations[psputil.ValidatedPSPAnnotation])
}
}