diff --git a/pkg/api/validation/validation.go b/pkg/api/validation/validation.go index 42a8e5f6b78..614d56c4118 100644 --- a/pkg/api/validation/validation.go +++ b/pkg/api/validation/validation.go @@ -38,6 +38,7 @@ import ( "k8s.io/kubernetes/pkg/capabilities" "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/security/apparmor" + utilconfig "k8s.io/kubernetes/pkg/util/config" "k8s.io/kubernetes/pkg/util/intstr" "k8s.io/kubernetes/pkg/util/sets" "k8s.io/kubernetes/pkg/util/validation" @@ -2119,13 +2120,17 @@ func ValidateAppArmorPodAnnotations(annotations map[string]string, spec *api.Pod if !strings.HasPrefix(k, apparmor.ContainerAnnotationKeyPrefix) { continue } + if !utilconfig.DefaultFeatureGate.AppArmor() { + allErrs = append(allErrs, field.Forbidden(fldPath.Key(k), "AppArmor is disabled by feature-gate")) + continue + } containerName := strings.TrimPrefix(k, apparmor.ContainerAnnotationKeyPrefix) if !podSpecHasContainer(spec, containerName) { - allErrs = append(allErrs, field.Invalid(fldPath.Child(k), containerName, "container not found")) + allErrs = append(allErrs, field.Invalid(fldPath.Key(k), containerName, "container not found")) } if err := apparmor.ValidateProfileFormat(p); err != nil { - allErrs = append(allErrs, field.Invalid(fldPath.Child(k), p, err.Error())) + allErrs = append(allErrs, field.Invalid(fldPath.Key(k), p, err.Error())) } } diff --git a/pkg/security/apparmor/validate.go b/pkg/security/apparmor/validate.go index a34636caea2..e7fe2d31e43 100644 --- a/pkg/security/apparmor/validate.go +++ b/pkg/security/apparmor/validate.go @@ -27,6 +27,7 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/util" + utilconfig "k8s.io/kubernetes/pkg/util/config" ) // Whether AppArmor should be disabled by default. @@ -88,9 +89,14 @@ func (v *validator) Validate(pod *api.Pod) error { // Verify that the host and runtime is capable of enforcing AppArmor profiles. func validateHost(runtime string) error { + // Check feature-gates + if !utilconfig.DefaultFeatureGate.AppArmor() { + return errors.New("AppArmor disabled by feature-gate") + } + // Check build support. if isDisabledBuild { - return errors.New("Binary not compiled for linux.") + return errors.New("Binary not compiled for linux") } // Check kernel support. diff --git a/pkg/util/config/feature_gate.go b/pkg/util/config/feature_gate.go index 71e5e330fe0..3daf48ced19 100644 --- a/pkg/util/config/feature_gate.go +++ b/pkg/util/config/feature_gate.go @@ -39,9 +39,9 @@ const ( // AllAlpha=true,NewFeature=false will result in newFeature=false allAlphaGate = "AllAlpha" externalTrafficLocalOnly = "AllowExtTrafficLocalEndpoints" + appArmor = "AppArmor" dynamicKubeletConfig = "DynamicKubeletConfig" dynamicVolumeProvisioning = "DynamicVolumeProvisioning" - // TODO: Define gate/accessor for AppArmor ) var ( @@ -50,6 +50,7 @@ var ( knownFeatures = map[string]featureSpec{ allAlphaGate: {false, alpha}, externalTrafficLocalOnly: {false, alpha}, + appArmor: {true, alpha}, dynamicKubeletConfig: {false, alpha}, dynamicVolumeProvisioning: {true, alpha}, } @@ -91,6 +92,10 @@ type FeatureGate interface { // // alpha: v1.4 // MyFeature() bool + // owner: @timstclair + // alpha: v1.4 + AppArmor() bool + // owner: @girishkalele // alpha: v1.4 ExternalTrafficLocalOnly() bool @@ -175,6 +180,11 @@ func (f *featureGate) ExternalTrafficLocalOnly() bool { return f.lookup(externalTrafficLocalOnly) } +// AppArmor returns the value for the AppArmor feature gate. +func (f *featureGate) AppArmor() bool { + return f.lookup(appArmor) +} + // DynamicKubeletConfig returns value for dynamicKubeletConfig func (f *featureGate) DynamicKubeletConfig() bool { return f.lookup(dynamicKubeletConfig)