mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-13 22:05:59 +00:00
AppArmor API changes
This commit is contained in:
parent
b0ee334374
commit
94927afb50
@ -20,7 +20,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
v1 "k8s.io/api/core/v1"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
metavalidation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
|
metavalidation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
@ -540,12 +539,21 @@ func dropDisabledFields(
|
|||||||
podSpec = &api.PodSpec{}
|
podSpec = &api.PodSpec{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !utilfeature.DefaultFeatureGate.Enabled(features.AppArmor) && !appArmorInUse(oldPodAnnotations) {
|
if !utilfeature.DefaultFeatureGate.Enabled(features.AppArmor) && !appArmorInUse(oldPodAnnotations, oldPodSpec) {
|
||||||
for k := range podAnnotations {
|
for k := range podAnnotations {
|
||||||
if strings.HasPrefix(k, v1.AppArmorBetaContainerAnnotationKeyPrefix) {
|
if strings.HasPrefix(k, api.AppArmorContainerAnnotationKeyPrefix) {
|
||||||
delete(podAnnotations, k)
|
delete(podAnnotations, k)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if podSpec.SecurityContext != nil {
|
||||||
|
podSpec.SecurityContext.AppArmorProfile = nil
|
||||||
|
}
|
||||||
|
VisitContainers(podSpec, AllContainers, func(c *api.Container, _ ContainerType) bool {
|
||||||
|
if c.SecurityContext != nil {
|
||||||
|
c.SecurityContext.AppArmorProfile = nil
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the feature is disabled and not in use, drop the hostUsers field.
|
// If the feature is disabled and not in use, drop the hostUsers field.
|
||||||
@ -940,13 +948,28 @@ func procMountInUse(podSpec *api.PodSpec) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// appArmorInUse returns true if the pod has apparmor related information
|
// appArmorInUse returns true if the pod has apparmor related information
|
||||||
func appArmorInUse(podAnnotations map[string]string) bool {
|
func appArmorInUse(podAnnotations map[string]string, podSpec *api.PodSpec) bool {
|
||||||
|
if podSpec == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
for k := range podAnnotations {
|
for k := range podAnnotations {
|
||||||
if strings.HasPrefix(k, v1.AppArmorBetaContainerAnnotationKeyPrefix) {
|
if strings.HasPrefix(k, api.AppArmorContainerAnnotationKeyPrefix) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
if podSpec.SecurityContext != nil && podSpec.SecurityContext.AppArmorProfile != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
hasAppArmorContainer := false
|
||||||
|
VisitContainers(podSpec, AllContainers, func(c *api.Container, _ ContainerType) bool {
|
||||||
|
if c.SecurityContext != nil && c.SecurityContext.AppArmorProfile != nil {
|
||||||
|
hasAppArmorContainer = true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
return hasAppArmorContainer
|
||||||
}
|
}
|
||||||
|
|
||||||
// restartableInitContainersInUse returns true if the pod spec is non-nil and
|
// restartableInitContainersInUse returns true if the pod spec is non-nil and
|
||||||
|
@ -23,6 +23,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
@ -704,83 +706,84 @@ func TestDropProcMount(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDropAppArmor(t *testing.T) {
|
func TestDropAppArmor(t *testing.T) {
|
||||||
podWithAppArmor := func() *api.Pod {
|
tests := []struct {
|
||||||
return &api.Pod{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{"a": "1", v1.AppArmorBetaContainerAnnotationKeyPrefix + "foo": "default"}},
|
|
||||||
Spec: api.PodSpec{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
podWithoutAppArmor := func() *api.Pod {
|
|
||||||
return &api.Pod{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{"a": "1"}},
|
|
||||||
Spec: api.PodSpec{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
podInfo := []struct {
|
|
||||||
description string
|
description string
|
||||||
hasAppArmor bool
|
hasAppArmor bool
|
||||||
pod func() *api.Pod
|
pod api.Pod
|
||||||
}{
|
}{{
|
||||||
{
|
description: "with AppArmor Annotations",
|
||||||
description: "has AppArmor",
|
hasAppArmor: true,
|
||||||
hasAppArmor: true,
|
pod: api.Pod{
|
||||||
pod: podWithAppArmor,
|
ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{"a": "1", v1.AppArmorBetaContainerAnnotationKeyPrefix + "foo": "default"}},
|
||||||
|
Spec: api.PodSpec{},
|
||||||
},
|
},
|
||||||
{
|
}, {
|
||||||
description: "does not have AppArmor",
|
description: "with pod AppArmor profile",
|
||||||
hasAppArmor: false,
|
hasAppArmor: true,
|
||||||
pod: podWithoutAppArmor,
|
pod: api.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{"a": "1"}},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
SecurityContext: &api.PodSecurityContext{
|
||||||
|
AppArmorProfile: &api.AppArmorProfile{
|
||||||
|
Type: api.AppArmorProfileTypeRuntimeDefault,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
}, {
|
||||||
description: "is nil",
|
description: "with container AppArmor profile",
|
||||||
hasAppArmor: false,
|
hasAppArmor: true,
|
||||||
pod: func() *api.Pod { return nil },
|
pod: api.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{"a": "1"}},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
Containers: []api.Container{{
|
||||||
|
SecurityContext: &api.SecurityContext{
|
||||||
|
AppArmorProfile: &api.AppArmorProfile{
|
||||||
|
Type: api.AppArmorProfileTypeRuntimeDefault,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}, {
|
||||||
|
description: "without AppArmor",
|
||||||
|
hasAppArmor: false,
|
||||||
|
pod: api.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{"a": "1"}},
|
||||||
|
Spec: api.PodSpec{},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
|
||||||
for _, enabled := range []bool{true, false} {
|
for _, test := range tests {
|
||||||
for _, oldPodInfo := range podInfo {
|
for _, enabled := range []bool{true, false} {
|
||||||
for _, newPodInfo := range podInfo {
|
t.Run(fmt.Sprintf("%v/enabled=%v", test.description, enabled), func(t *testing.T) {
|
||||||
oldPodHasAppArmor, oldPod := oldPodInfo.hasAppArmor, oldPodInfo.pod()
|
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.AppArmor, enabled)()
|
||||||
newPodHasAppArmor, newPod := newPodInfo.hasAppArmor, newPodInfo.pod()
|
|
||||||
if newPod == nil {
|
newPod := test.pod.DeepCopy()
|
||||||
continue
|
|
||||||
|
if actual := appArmorInUse(newPod.Annotations, &newPod.Spec); actual != test.hasAppArmor {
|
||||||
|
t.Errorf("appArmorInUse does not match expectation: %t != %t", actual, test.hasAppArmor)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run(fmt.Sprintf("feature enabled=%v, old pod %v, new pod %v", enabled, oldPodInfo.description, newPodInfo.description), func(t *testing.T) {
|
DropDisabledPodFields(newPod, newPod)
|
||||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.AppArmor, enabled)()
|
require.Equal(t, &test.pod, newPod, "unchanged pod should never be mutated")
|
||||||
|
|
||||||
DropDisabledPodFields(newPod, oldPod)
|
DropDisabledPodFields(newPod, nil)
|
||||||
|
|
||||||
// old pod should never be changed
|
if enabled {
|
||||||
if !reflect.DeepEqual(oldPod, oldPodInfo.pod()) {
|
assert.Equal(t, &test.pod, newPod, "pod should not be mutated when AppArmor is enabled")
|
||||||
t.Errorf("old pod changed: %v", cmp.Diff(oldPod, oldPodInfo.pod()))
|
} else {
|
||||||
|
if appArmorInUse(newPod.Annotations, &newPod.Spec) {
|
||||||
|
t.Errorf("newPod should not be using appArmor after dropping disabled fields")
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
if test.hasAppArmor {
|
||||||
case enabled || oldPodHasAppArmor:
|
assert.NotEqual(t, &test.pod, newPod, "pod should be mutated to drop AppArmor")
|
||||||
// new pod should not be changed if the feature is enabled, or if the old pod had AppArmor
|
} else {
|
||||||
if !reflect.DeepEqual(newPod, newPodInfo.pod()) {
|
assert.Equal(t, &test.pod, newPod, "pod without AppArmor should not be mutated")
|
||||||
t.Errorf("new pod changed: %v", cmp.Diff(newPod, newPodInfo.pod()))
|
|
||||||
}
|
|
||||||
case newPodHasAppArmor:
|
|
||||||
// new pod should be changed
|
|
||||||
if reflect.DeepEqual(newPod, newPodInfo.pod()) {
|
|
||||||
t.Errorf("new pod was not changed")
|
|
||||||
}
|
|
||||||
// new pod should not have AppArmor
|
|
||||||
if !reflect.DeepEqual(newPod, podWithoutAppArmor()) {
|
|
||||||
t.Errorf("new pod had EmptyDir SizeLimit: %v", cmp.Diff(newPod, podWithoutAppArmor()))
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
// new pod should not need to be changed
|
|
||||||
if !reflect.DeepEqual(newPod, newPodInfo.pod()) {
|
|
||||||
t.Errorf("new pod changed: %v", cmp.Diff(newPod, newPodInfo.pod()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,19 @@ const (
|
|||||||
// Deprecated: set a pod or container security context `seccompProfile` of type "RuntimeDefault" instead.
|
// Deprecated: set a pod or container security context `seccompProfile` of type "RuntimeDefault" instead.
|
||||||
DeprecatedSeccompProfileDockerDefault string = "docker/default"
|
DeprecatedSeccompProfileDockerDefault string = "docker/default"
|
||||||
|
|
||||||
|
// AppArmorContainerAnnotationKeyPrefix is the prefix to an annotation key specifying a container's apparmor profile.
|
||||||
|
// Deprecated: use a pod or container security context `appArmorProfile` field instead.
|
||||||
|
AppArmorContainerAnnotationKeyPrefix = "container.apparmor.security.beta.kubernetes.io/"
|
||||||
|
|
||||||
|
// AppArmorProfileRuntimeDefault is the profile specifying the runtime default.
|
||||||
|
AppArmorProfileRuntimeDefault = "runtime/default"
|
||||||
|
|
||||||
|
// AppArmorProfileLocalhostPrefix is the prefix for specifying profiles loaded on the node.
|
||||||
|
AppArmorProfileLocalhostPrefix = "localhost/"
|
||||||
|
|
||||||
|
// AppArmorProfileNameUnconfined is the Unconfined AppArmor profile
|
||||||
|
AppArmorProfileNameUnconfined = "unconfined"
|
||||||
|
|
||||||
// PreferAvoidPodsAnnotationKey represents the key of preferAvoidPods data (json serialized)
|
// PreferAvoidPodsAnnotationKey represents the key of preferAvoidPods data (json serialized)
|
||||||
// in the Annotations of a Node.
|
// in the Annotations of a Node.
|
||||||
PreferAvoidPodsAnnotationKey string = "scheduler.alpha.kubernetes.io/preferAvoidPods"
|
PreferAvoidPodsAnnotationKey string = "scheduler.alpha.kubernetes.io/preferAvoidPods"
|
||||||
|
@ -3325,6 +3325,7 @@ type PodSpec struct {
|
|||||||
// - spec.hostPID
|
// - spec.hostPID
|
||||||
// - spec.hostIPC
|
// - spec.hostIPC
|
||||||
// - spec.hostUsers
|
// - spec.hostUsers
|
||||||
|
// - spec.securityContext.appArmorProfile
|
||||||
// - spec.securityContext.seLinuxOptions
|
// - spec.securityContext.seLinuxOptions
|
||||||
// - spec.securityContext.seccompProfile
|
// - spec.securityContext.seccompProfile
|
||||||
// - spec.securityContext.fsGroup
|
// - spec.securityContext.fsGroup
|
||||||
@ -3334,6 +3335,7 @@ type PodSpec struct {
|
|||||||
// - spec.securityContext.runAsUser
|
// - spec.securityContext.runAsUser
|
||||||
// - spec.securityContext.runAsGroup
|
// - spec.securityContext.runAsGroup
|
||||||
// - spec.securityContext.supplementalGroups
|
// - spec.securityContext.supplementalGroups
|
||||||
|
// - spec.containers[*].securityContext.appArmorProfile
|
||||||
// - spec.containers[*].securityContext.seLinuxOptions
|
// - spec.containers[*].securityContext.seLinuxOptions
|
||||||
// - spec.containers[*].securityContext.seccompProfile
|
// - spec.containers[*].securityContext.seccompProfile
|
||||||
// - spec.containers[*].securityContext.capabilities
|
// - spec.containers[*].securityContext.capabilities
|
||||||
@ -3598,6 +3600,10 @@ type PodSecurityContext struct {
|
|||||||
// Note that this field cannot be set when spec.os.name is windows.
|
// Note that this field cannot be set when spec.os.name is windows.
|
||||||
// +optional
|
// +optional
|
||||||
SeccompProfile *SeccompProfile
|
SeccompProfile *SeccompProfile
|
||||||
|
// appArmorProfile is the AppArmor options to use by the containers in this pod.
|
||||||
|
// Note that this field cannot be set when spec.os.name is windows.
|
||||||
|
// +optional
|
||||||
|
AppArmorProfile *AppArmorProfile
|
||||||
}
|
}
|
||||||
|
|
||||||
// SeccompProfile defines a pod/container's seccomp profile settings.
|
// SeccompProfile defines a pod/container's seccomp profile settings.
|
||||||
@ -3625,6 +3631,37 @@ const (
|
|||||||
SeccompProfileTypeLocalhost SeccompProfileType = "Localhost"
|
SeccompProfileTypeLocalhost SeccompProfileType = "Localhost"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// AppArmorProfile defines a pod or container's AppArmor settings.
|
||||||
|
// +union
|
||||||
|
type AppArmorProfile struct {
|
||||||
|
// type indicates which kind of AppArmor profile will be applied.
|
||||||
|
// Valid options are:
|
||||||
|
// Localhost - a profile pre-loaded on the node.
|
||||||
|
// RuntimeDefault - the container runtime's default profile.
|
||||||
|
// Unconfined - no AppArmor enforcement.
|
||||||
|
// +unionDescriminator
|
||||||
|
Type AppArmorProfileType
|
||||||
|
|
||||||
|
// localhostProfile indicates a profile loaded on the node that should be used.
|
||||||
|
// The profile must be preconfigured on the node to work.
|
||||||
|
// Must match the loaded name of the profile.
|
||||||
|
// Must be set if and only if type is "Localhost".
|
||||||
|
// +optional
|
||||||
|
LocalhostProfile *string
|
||||||
|
}
|
||||||
|
|
||||||
|
type AppArmorProfileType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// AppArmorProfileTypeUnconfined indicates that no AppArmor profile should be enforced.
|
||||||
|
AppArmorProfileTypeUnconfined AppArmorProfileType = "Unconfined"
|
||||||
|
// AppArmorProfileTypeRuntimeDefault indicates that the container runtime's default AppArmor
|
||||||
|
// profile should be used.
|
||||||
|
AppArmorProfileTypeRuntimeDefault AppArmorProfileType = "RuntimeDefault"
|
||||||
|
// AppArmorProfileTypeLocalhost indicates that a profile pre-loaded on the node should be used.
|
||||||
|
AppArmorProfileTypeLocalhost AppArmorProfileType = "Localhost"
|
||||||
|
)
|
||||||
|
|
||||||
// PodQOSClass defines the supported qos classes of Pods.
|
// PodQOSClass defines the supported qos classes of Pods.
|
||||||
type PodQOSClass string
|
type PodQOSClass string
|
||||||
|
|
||||||
@ -6028,6 +6065,11 @@ type SecurityContext struct {
|
|||||||
// Note that this field cannot be set when spec.os.name is windows.
|
// Note that this field cannot be set when spec.os.name is windows.
|
||||||
// +optional
|
// +optional
|
||||||
SeccompProfile *SeccompProfile
|
SeccompProfile *SeccompProfile
|
||||||
|
// appArmorProfile is the AppArmor options to use by this container. If set, this profile
|
||||||
|
// overrides the pod's appArmorProfile.
|
||||||
|
// Note that this field cannot be set when spec.os.name is windows.
|
||||||
|
// +optional
|
||||||
|
AppArmorProfile *AppArmorProfile
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcMountType defines the type of proc mount
|
// ProcMountType defines the type of proc mount
|
||||||
|
@ -4234,6 +4234,9 @@ func validateWindows(spec *core.PodSpec, fldPath *field.Path) field.ErrorList {
|
|||||||
securityContext := spec.SecurityContext
|
securityContext := spec.SecurityContext
|
||||||
// validate Pod SecurityContext
|
// validate Pod SecurityContext
|
||||||
if securityContext != nil {
|
if securityContext != nil {
|
||||||
|
if securityContext.AppArmorProfile != nil {
|
||||||
|
allErrs = append(allErrs, field.Forbidden(fldPath.Child("securityContext").Child("appArmorProfile"), "cannot be set for a windows pod"))
|
||||||
|
}
|
||||||
if securityContext.SELinuxOptions != nil {
|
if securityContext.SELinuxOptions != nil {
|
||||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("securityContext").Child("seLinuxOptions"), "cannot be set for a windows pod"))
|
allErrs = append(allErrs, field.Forbidden(fldPath.Child("securityContext").Child("seLinuxOptions"), "cannot be set for a windows pod"))
|
||||||
}
|
}
|
||||||
@ -4280,6 +4283,9 @@ func validateWindows(spec *core.PodSpec, fldPath *field.Path) field.ErrorList {
|
|||||||
// TODO: Think if we need to relax this restriction or some of the restrictions
|
// TODO: Think if we need to relax this restriction or some of the restrictions
|
||||||
if sc != nil {
|
if sc != nil {
|
||||||
fldPath := cFldPath.Child("securityContext")
|
fldPath := cFldPath.Child("securityContext")
|
||||||
|
if sc.AppArmorProfile != nil {
|
||||||
|
allErrs = append(allErrs, field.Forbidden(fldPath.Child("appArmorProfile"), "cannot be set for a windows pod"))
|
||||||
|
}
|
||||||
if sc.SELinuxOptions != nil {
|
if sc.SELinuxOptions != nil {
|
||||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("seLinuxOptions"), "cannot be set for a windows pod"))
|
allErrs = append(allErrs, field.Forbidden(fldPath.Child("seLinuxOptions"), "cannot be set for a windows pod"))
|
||||||
}
|
}
|
||||||
@ -4657,6 +4663,43 @@ func validateSeccompProfileType(fldPath *field.Path, seccompProfileType core.Sec
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateAppArmorProfileField(profile *core.AppArmorProfile, fldPath *field.Path) field.ErrorList {
|
||||||
|
if profile == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
allErrs := field.ErrorList{}
|
||||||
|
|
||||||
|
switch profile.Type {
|
||||||
|
case core.AppArmorProfileTypeLocalhost:
|
||||||
|
if profile.LocalhostProfile == nil {
|
||||||
|
allErrs = append(allErrs, field.Required(fldPath.Child("localhostProfile"), "must be set when AppArmor type is Localhost"))
|
||||||
|
} else {
|
||||||
|
localhostProfile := strings.TrimSpace(*profile.LocalhostProfile)
|
||||||
|
if localhostProfile != *profile.LocalhostProfile {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fldPath.Child("localhostProfile"), *profile.LocalhostProfile, "must not be padded with whitespace"))
|
||||||
|
} else if localhostProfile == "" {
|
||||||
|
allErrs = append(allErrs, field.Required(fldPath.Child("localhostProfile"), "must be set when AppArmor type is Localhost"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case core.AppArmorProfileTypeRuntimeDefault, core.AppArmorProfileTypeUnconfined:
|
||||||
|
if profile.LocalhostProfile != nil {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fldPath.Child("localhostProfile"), profile.LocalhostProfile, "can only be set when AppArmor type is Localhost"))
|
||||||
|
}
|
||||||
|
|
||||||
|
case "":
|
||||||
|
allErrs = append(allErrs, field.Required(fldPath.Child("type"), "type is required when appArmorProfile is set"))
|
||||||
|
|
||||||
|
default:
|
||||||
|
allErrs = append(allErrs, field.NotSupported(fldPath.Child("type"), profile.Type,
|
||||||
|
[]core.AppArmorProfileType{core.AppArmorProfileTypeLocalhost, core.AppArmorProfileTypeRuntimeDefault, core.AppArmorProfileTypeUnconfined}))
|
||||||
|
}
|
||||||
|
|
||||||
|
return allErrs
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func ValidateAppArmorPodAnnotations(annotations map[string]string, spec *core.PodSpec, fldPath *field.Path) field.ErrorList {
|
func ValidateAppArmorPodAnnotations(annotations map[string]string, spec *core.PodSpec, fldPath *field.Path) field.ErrorList {
|
||||||
allErrs := field.ErrorList{}
|
allErrs := field.ErrorList{}
|
||||||
for k, p := range annotations {
|
for k, p := range annotations {
|
||||||
@ -4799,6 +4842,7 @@ func validatePodSpecSecurityContext(securityContext *core.PodSecurityContext, sp
|
|||||||
|
|
||||||
allErrs = append(allErrs, validateSeccompProfileField(securityContext.SeccompProfile, fldPath.Child("seccompProfile"))...)
|
allErrs = append(allErrs, validateSeccompProfileField(securityContext.SeccompProfile, fldPath.Child("seccompProfile"))...)
|
||||||
allErrs = append(allErrs, validateWindowsSecurityContextOptions(securityContext.WindowsOptions, fldPath.Child("windowsOptions"))...)
|
allErrs = append(allErrs, validateWindowsSecurityContextOptions(securityContext.WindowsOptions, fldPath.Child("windowsOptions"))...)
|
||||||
|
allErrs = append(allErrs, validateAppArmorProfileField(securityContext.AppArmorProfile, fldPath.Child("appArmorProfile"))...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return allErrs
|
return allErrs
|
||||||
@ -7084,6 +7128,7 @@ func ValidateSecurityContext(sc *core.SecurityContext, fldPath *field.Path) fiel
|
|||||||
}
|
}
|
||||||
|
|
||||||
allErrs = append(allErrs, validateWindowsSecurityContextOptions(sc.WindowsOptions, fldPath.Child("windowsOptions"))...)
|
allErrs = append(allErrs, validateWindowsSecurityContextOptions(sc.WindowsOptions, fldPath.Child("windowsOptions"))...)
|
||||||
|
allErrs = append(allErrs, validateAppArmorProfileField(sc.AppArmorProfile, fldPath.Child("appArmorProfile"))...)
|
||||||
|
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
@ -10289,7 +10289,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
DNSPolicy: core.DNSDefault,
|
DNSPolicy: core.DNSDefault,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"default AppArmor profile for a container": {
|
"default AppArmor annotation for a container": {
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "123",
|
Name: "123",
|
||||||
Namespace: "ns",
|
Namespace: "ns",
|
||||||
@ -10299,7 +10299,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Spec: validPodSpec(nil),
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
"default AppArmor profile for an init container": {
|
"default AppArmor annotation for an init container": {
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "123",
|
Name: "123",
|
||||||
Namespace: "ns",
|
Namespace: "ns",
|
||||||
@ -10314,7 +10314,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
DNSPolicy: core.DNSClusterFirst,
|
DNSPolicy: core.DNSClusterFirst,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"localhost AppArmor profile for a container": {
|
"localhost AppArmor annotation for a container": {
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "123",
|
Name: "123",
|
||||||
Namespace: "ns",
|
Namespace: "ns",
|
||||||
@ -10324,6 +10324,107 @@ func TestValidatePod(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Spec: validPodSpec(nil),
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
|
"runtime default AppArmor profile for a pod": {
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "123",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
Spec: core.PodSpec{
|
||||||
|
Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||||
|
RestartPolicy: core.RestartPolicyAlways,
|
||||||
|
DNSPolicy: core.DNSDefault,
|
||||||
|
SecurityContext: &core.PodSecurityContext{
|
||||||
|
AppArmorProfile: &core.AppArmorProfile{
|
||||||
|
Type: core.AppArmorProfileTypeRuntimeDefault,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"runtime default AppArmor profile for a container": {
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "123",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
Spec: core.PodSpec{
|
||||||
|
Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File",
|
||||||
|
SecurityContext: &core.SecurityContext{
|
||||||
|
AppArmorProfile: &core.AppArmorProfile{
|
||||||
|
Type: core.AppArmorProfileTypeRuntimeDefault,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
RestartPolicy: core.RestartPolicyAlways,
|
||||||
|
DNSPolicy: core.DNSDefault,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"unconfined AppArmor profile for a pod": {
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "123",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
Spec: core.PodSpec{
|
||||||
|
Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||||
|
RestartPolicy: core.RestartPolicyAlways,
|
||||||
|
DNSPolicy: core.DNSDefault,
|
||||||
|
SecurityContext: &core.PodSecurityContext{
|
||||||
|
AppArmorProfile: &core.AppArmorProfile{
|
||||||
|
Type: core.AppArmorProfileTypeUnconfined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"unconfined AppArmor profile for a container": {
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "123",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
Spec: core.PodSpec{
|
||||||
|
Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File",
|
||||||
|
SecurityContext: &core.SecurityContext{
|
||||||
|
AppArmorProfile: &core.AppArmorProfile{
|
||||||
|
Type: core.AppArmorProfileTypeUnconfined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
RestartPolicy: core.RestartPolicyAlways,
|
||||||
|
DNSPolicy: core.DNSDefault,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"localhost AppArmor profile for a pod": {
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "123",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
Spec: core.PodSpec{
|
||||||
|
Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||||
|
RestartPolicy: core.RestartPolicyAlways,
|
||||||
|
DNSPolicy: core.DNSDefault,
|
||||||
|
SecurityContext: &core.PodSecurityContext{
|
||||||
|
AppArmorProfile: &core.AppArmorProfile{
|
||||||
|
Type: core.AppArmorProfileTypeLocalhost,
|
||||||
|
LocalhostProfile: ptr.To("example-org/application-foo"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"localhost AppArmor profile for a container field": {
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "123",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
Spec: core.PodSpec{
|
||||||
|
Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File",
|
||||||
|
SecurityContext: &core.SecurityContext{
|
||||||
|
AppArmorProfile: &core.AppArmorProfile{
|
||||||
|
Type: core.AppArmorProfileTypeLocalhost,
|
||||||
|
LocalhostProfile: ptr.To("example-org/application-foo"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
RestartPolicy: core.RestartPolicyAlways,
|
||||||
|
DNSPolicy: core.DNSDefault,
|
||||||
|
},
|
||||||
|
},
|
||||||
"syntactically valid sysctls": {
|
"syntactically valid sysctls": {
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "123",
|
Name: "123",
|
||||||
@ -11880,6 +11981,143 @@ func TestValidatePod(t *testing.T) {
|
|||||||
Spec: validPodSpec(nil),
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"unsupported pod AppArmor profile type": {
|
||||||
|
expectedError: `Unsupported value: "test"`,
|
||||||
|
spec: core.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "123",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
Spec: core.PodSpec{
|
||||||
|
Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||||
|
RestartPolicy: core.RestartPolicyAlways,
|
||||||
|
DNSPolicy: core.DNSDefault,
|
||||||
|
SecurityContext: &core.PodSecurityContext{
|
||||||
|
AppArmorProfile: &core.AppArmorProfile{
|
||||||
|
Type: "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"unsupported container AppArmor profile type": {
|
||||||
|
expectedError: `Unsupported value: "test"`,
|
||||||
|
spec: core.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "123",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
Spec: core.PodSpec{
|
||||||
|
Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File",
|
||||||
|
SecurityContext: &core.SecurityContext{
|
||||||
|
AppArmorProfile: &core.AppArmorProfile{
|
||||||
|
Type: "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
RestartPolicy: core.RestartPolicyAlways,
|
||||||
|
DNSPolicy: core.DNSDefault,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"missing pod AppArmor profile type": {
|
||||||
|
expectedError: "Required value: type is required when appArmorProfile is set",
|
||||||
|
spec: core.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "123",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
Spec: core.PodSpec{
|
||||||
|
Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||||
|
RestartPolicy: core.RestartPolicyAlways,
|
||||||
|
DNSPolicy: core.DNSDefault,
|
||||||
|
SecurityContext: &core.PodSecurityContext{
|
||||||
|
AppArmorProfile: &core.AppArmorProfile{
|
||||||
|
Type: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"missing AppArmor localhost profile": {
|
||||||
|
expectedError: "Required value: must be set when AppArmor type is Localhost",
|
||||||
|
spec: core.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "123",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
Spec: core.PodSpec{
|
||||||
|
Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||||
|
RestartPolicy: core.RestartPolicyAlways,
|
||||||
|
DNSPolicy: core.DNSDefault,
|
||||||
|
SecurityContext: &core.PodSecurityContext{
|
||||||
|
AppArmorProfile: &core.AppArmorProfile{
|
||||||
|
Type: core.AppArmorProfileTypeLocalhost,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"empty AppArmor localhost profile": {
|
||||||
|
expectedError: "Required value: must be set when AppArmor type is Localhost",
|
||||||
|
spec: core.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "123",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
Spec: core.PodSpec{
|
||||||
|
Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||||
|
RestartPolicy: core.RestartPolicyAlways,
|
||||||
|
DNSPolicy: core.DNSDefault,
|
||||||
|
SecurityContext: &core.PodSecurityContext{
|
||||||
|
AppArmorProfile: &core.AppArmorProfile{
|
||||||
|
Type: core.AppArmorProfileTypeLocalhost,
|
||||||
|
LocalhostProfile: ptr.To(""),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"invalid AppArmor localhost profile type": {
|
||||||
|
expectedError: `Invalid value: "foo-bar"`,
|
||||||
|
spec: core.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "123",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
Spec: core.PodSpec{
|
||||||
|
Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||||
|
RestartPolicy: core.RestartPolicyAlways,
|
||||||
|
DNSPolicy: core.DNSDefault,
|
||||||
|
SecurityContext: &core.PodSecurityContext{
|
||||||
|
AppArmorProfile: &core.AppArmorProfile{
|
||||||
|
Type: core.AppArmorProfileTypeRuntimeDefault,
|
||||||
|
LocalhostProfile: ptr.To("foo-bar"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"invalid AppArmor localhost profile": {
|
||||||
|
expectedError: `Invalid value: "foo-bar "`,
|
||||||
|
spec: core.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "123",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
Spec: core.PodSpec{
|
||||||
|
Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||||
|
RestartPolicy: core.RestartPolicyAlways,
|
||||||
|
DNSPolicy: core.DNSDefault,
|
||||||
|
SecurityContext: &core.PodSecurityContext{
|
||||||
|
AppArmorProfile: &core.AppArmorProfile{
|
||||||
|
Type: core.AppArmorProfileTypeLocalhost,
|
||||||
|
LocalhostProfile: ptr.To("foo-bar "),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
"invalid extended resource name in container request": {
|
"invalid extended resource name in container request": {
|
||||||
expectedError: "must be a standard resource for containers",
|
expectedError: "must be a standard resource for containers",
|
||||||
spec: core.Pod{
|
spec: core.Pod{
|
||||||
@ -21579,6 +21817,12 @@ func TestValidateWindowsSecurityContext(t *testing.T) {
|
|||||||
expectError: true,
|
expectError: true,
|
||||||
errorMsg: "cannot be set for a windows pod",
|
errorMsg: "cannot be set for a windows pod",
|
||||||
errorType: "FieldValueForbidden",
|
errorType: "FieldValueForbidden",
|
||||||
|
}, {
|
||||||
|
name: "pod with AppArmorProfile",
|
||||||
|
sc: &core.PodSpec{Containers: []core.Container{{SecurityContext: &core.SecurityContext{AppArmorProfile: &core.AppArmorProfile{Type: core.AppArmorProfileTypeRuntimeDefault}}}}},
|
||||||
|
expectError: true,
|
||||||
|
errorMsg: "cannot be set for a windows pod",
|
||||||
|
errorType: "FieldValueForbidden",
|
||||||
}, {
|
}, {
|
||||||
name: "pod with WindowsOptions, no error",
|
name: "pod with WindowsOptions, no error",
|
||||||
sc: &core.PodSpec{Containers: []core.Container{{SecurityContext: &core.SecurityContext{WindowsOptions: &core.WindowsSecurityContextOptions{RunAsUserName: utilpointer.String("dummy")}}}}},
|
sc: &core.PodSpec{Containers: []core.Container{{SecurityContext: &core.SecurityContext{WindowsOptions: &core.WindowsSecurityContextOptions{RunAsUserName: utilpointer.String("dummy")}}}}},
|
||||||
@ -21613,6 +21857,7 @@ func TestValidateOSFields(t *testing.T) {
|
|||||||
// - Add documentation to the os field in the api
|
// - Add documentation to the os field in the api
|
||||||
// - Add validation logic validateLinux, validateWindows functions to make sure the field is only set for eligible OSes
|
// - Add validation logic validateLinux, validateWindows functions to make sure the field is only set for eligible OSes
|
||||||
osSpecificFields := sets.NewString(
|
osSpecificFields := sets.NewString(
|
||||||
|
"Containers[*].SecurityContext.AppArmorProfile",
|
||||||
"Containers[*].SecurityContext.AllowPrivilegeEscalation",
|
"Containers[*].SecurityContext.AllowPrivilegeEscalation",
|
||||||
"Containers[*].SecurityContext.Capabilities",
|
"Containers[*].SecurityContext.Capabilities",
|
||||||
"Containers[*].SecurityContext.Privileged",
|
"Containers[*].SecurityContext.Privileged",
|
||||||
@ -21623,6 +21868,7 @@ func TestValidateOSFields(t *testing.T) {
|
|||||||
"Containers[*].SecurityContext.SELinuxOptions",
|
"Containers[*].SecurityContext.SELinuxOptions",
|
||||||
"Containers[*].SecurityContext.SeccompProfile",
|
"Containers[*].SecurityContext.SeccompProfile",
|
||||||
"Containers[*].SecurityContext.WindowsOptions",
|
"Containers[*].SecurityContext.WindowsOptions",
|
||||||
|
"InitContainers[*].SecurityContext.AppArmorProfile",
|
||||||
"InitContainers[*].SecurityContext.AllowPrivilegeEscalation",
|
"InitContainers[*].SecurityContext.AllowPrivilegeEscalation",
|
||||||
"InitContainers[*].SecurityContext.Capabilities",
|
"InitContainers[*].SecurityContext.Capabilities",
|
||||||
"InitContainers[*].SecurityContext.Privileged",
|
"InitContainers[*].SecurityContext.Privileged",
|
||||||
@ -21633,6 +21879,7 @@ func TestValidateOSFields(t *testing.T) {
|
|||||||
"InitContainers[*].SecurityContext.SELinuxOptions",
|
"InitContainers[*].SecurityContext.SELinuxOptions",
|
||||||
"InitContainers[*].SecurityContext.SeccompProfile",
|
"InitContainers[*].SecurityContext.SeccompProfile",
|
||||||
"InitContainers[*].SecurityContext.WindowsOptions",
|
"InitContainers[*].SecurityContext.WindowsOptions",
|
||||||
|
"EphemeralContainers[*].EphemeralContainerCommon.SecurityContext.AppArmorProfile",
|
||||||
"EphemeralContainers[*].EphemeralContainerCommon.SecurityContext.AllowPrivilegeEscalation",
|
"EphemeralContainers[*].EphemeralContainerCommon.SecurityContext.AllowPrivilegeEscalation",
|
||||||
"EphemeralContainers[*].EphemeralContainerCommon.SecurityContext.Capabilities",
|
"EphemeralContainers[*].EphemeralContainerCommon.SecurityContext.Capabilities",
|
||||||
"EphemeralContainers[*].EphemeralContainerCommon.SecurityContext.Privileged",
|
"EphemeralContainers[*].EphemeralContainerCommon.SecurityContext.Privileged",
|
||||||
@ -21644,6 +21891,7 @@ func TestValidateOSFields(t *testing.T) {
|
|||||||
"EphemeralContainers[*].EphemeralContainerCommon.SecurityContext.SeccompProfile",
|
"EphemeralContainers[*].EphemeralContainerCommon.SecurityContext.SeccompProfile",
|
||||||
"EphemeralContainers[*].EphemeralContainerCommon.SecurityContext.WindowsOptions",
|
"EphemeralContainers[*].EphemeralContainerCommon.SecurityContext.WindowsOptions",
|
||||||
"OS",
|
"OS",
|
||||||
|
"SecurityContext.AppArmorProfile",
|
||||||
"SecurityContext.FSGroup",
|
"SecurityContext.FSGroup",
|
||||||
"SecurityContext.FSGroupChangePolicy",
|
"SecurityContext.FSGroupChangePolicy",
|
||||||
"SecurityContext.HostIPC",
|
"SecurityContext.HostIPC",
|
||||||
|
@ -55,11 +55,8 @@ const (
|
|||||||
SeccompLocalhostProfileNamePrefix = "localhost/"
|
SeccompLocalhostProfileNamePrefix = "localhost/"
|
||||||
|
|
||||||
// AppArmorBetaContainerAnnotationKeyPrefix is the prefix to an annotation key specifying a container's apparmor profile.
|
// AppArmorBetaContainerAnnotationKeyPrefix is the prefix to an annotation key specifying a container's apparmor profile.
|
||||||
|
// Deprecated: use a pod or container security context `appArmorProfile` field instead.
|
||||||
AppArmorBetaContainerAnnotationKeyPrefix = "container.apparmor.security.beta.kubernetes.io/"
|
AppArmorBetaContainerAnnotationKeyPrefix = "container.apparmor.security.beta.kubernetes.io/"
|
||||||
// AppArmorBetaDefaultProfileAnnotationKey is the annotation key specifying the default AppArmor profile.
|
|
||||||
AppArmorBetaDefaultProfileAnnotationKey = "apparmor.security.beta.kubernetes.io/defaultProfileName"
|
|
||||||
// AppArmorBetaAllowedProfilesAnnotationKey is the annotation key specifying the allowed AppArmor profiles.
|
|
||||||
AppArmorBetaAllowedProfilesAnnotationKey = "apparmor.security.beta.kubernetes.io/allowedProfileNames"
|
|
||||||
|
|
||||||
// AppArmorBetaProfileRuntimeDefault is the profile specifying the runtime default.
|
// AppArmorBetaProfileRuntimeDefault is the profile specifying the runtime default.
|
||||||
AppArmorBetaProfileRuntimeDefault = "runtime/default"
|
AppArmorBetaProfileRuntimeDefault = "runtime/default"
|
||||||
|
@ -3757,6 +3757,7 @@ type PodSpec struct {
|
|||||||
// - spec.hostPID
|
// - spec.hostPID
|
||||||
// - spec.hostIPC
|
// - spec.hostIPC
|
||||||
// - spec.hostUsers
|
// - spec.hostUsers
|
||||||
|
// - spec.securityContext.appArmorProfile
|
||||||
// - spec.securityContext.seLinuxOptions
|
// - spec.securityContext.seLinuxOptions
|
||||||
// - spec.securityContext.seccompProfile
|
// - spec.securityContext.seccompProfile
|
||||||
// - spec.securityContext.fsGroup
|
// - spec.securityContext.fsGroup
|
||||||
@ -3766,6 +3767,7 @@ type PodSpec struct {
|
|||||||
// - spec.securityContext.runAsUser
|
// - spec.securityContext.runAsUser
|
||||||
// - spec.securityContext.runAsGroup
|
// - spec.securityContext.runAsGroup
|
||||||
// - spec.securityContext.supplementalGroups
|
// - spec.securityContext.supplementalGroups
|
||||||
|
// - spec.containers[*].securityContext.appArmorProfile
|
||||||
// - spec.containers[*].securityContext.seLinuxOptions
|
// - spec.containers[*].securityContext.seLinuxOptions
|
||||||
// - spec.containers[*].securityContext.seccompProfile
|
// - spec.containers[*].securityContext.seccompProfile
|
||||||
// - spec.containers[*].securityContext.capabilities
|
// - spec.containers[*].securityContext.capabilities
|
||||||
@ -4158,6 +4160,10 @@ type PodSecurityContext struct {
|
|||||||
// Note that this field cannot be set when spec.os.name is windows.
|
// Note that this field cannot be set when spec.os.name is windows.
|
||||||
// +optional
|
// +optional
|
||||||
SeccompProfile *SeccompProfile `json:"seccompProfile,omitempty" protobuf:"bytes,10,opt,name=seccompProfile"`
|
SeccompProfile *SeccompProfile `json:"seccompProfile,omitempty" protobuf:"bytes,10,opt,name=seccompProfile"`
|
||||||
|
// appArmorProfile is the AppArmor options to use by the containers in this pod.
|
||||||
|
// Note that this field cannot be set when spec.os.name is windows.
|
||||||
|
// +optional
|
||||||
|
AppArmorProfile *AppArmorProfile `json:"appArmorProfile,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SeccompProfile defines a pod/container's seccomp profile settings.
|
// SeccompProfile defines a pod/container's seccomp profile settings.
|
||||||
@ -4194,6 +4200,38 @@ const (
|
|||||||
SeccompProfileTypeLocalhost SeccompProfileType = "Localhost"
|
SeccompProfileTypeLocalhost SeccompProfileType = "Localhost"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// AppArmorProfile defines a pod or container's AppArmor settings.
|
||||||
|
// +union
|
||||||
|
type AppArmorProfile struct {
|
||||||
|
// type indicates which kind of AppArmor profile will be applied.
|
||||||
|
// Valid options are:
|
||||||
|
// Localhost - a profile pre-loaded on the node.
|
||||||
|
// RuntimeDefault - the container runtime's default profile.
|
||||||
|
// Unconfined - no AppArmor enforcement.
|
||||||
|
// +unionDiscriminator
|
||||||
|
Type AppArmorProfileType `json:"type"`
|
||||||
|
|
||||||
|
// localhostProfile indicates a profile loaded on the node that should be used.
|
||||||
|
// The profile must be preconfigured on the node to work.
|
||||||
|
// Must match the loaded name of the profile.
|
||||||
|
// Must be set if and only if type is "Localhost".
|
||||||
|
// +optional
|
||||||
|
LocalhostProfile *string `json:"localhostProfile,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +enum
|
||||||
|
type AppArmorProfileType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// AppArmorProfileTypeUnconfined indicates that no AppArmor profile should be enforced.
|
||||||
|
AppArmorProfileTypeUnconfined AppArmorProfileType = "Unconfined"
|
||||||
|
// AppArmorProfileTypeRuntimeDefault indicates that the container runtime's default AppArmor
|
||||||
|
// profile should be used.
|
||||||
|
AppArmorProfileTypeRuntimeDefault AppArmorProfileType = "RuntimeDefault"
|
||||||
|
// AppArmorProfileTypeLocalhost indicates that a profile pre-loaded on the node should be used.
|
||||||
|
AppArmorProfileTypeLocalhost AppArmorProfileType = "Localhost"
|
||||||
|
)
|
||||||
|
|
||||||
// PodQOSClass defines the supported qos classes of Pods.
|
// PodQOSClass defines the supported qos classes of Pods.
|
||||||
// +enum
|
// +enum
|
||||||
type PodQOSClass string
|
type PodQOSClass string
|
||||||
@ -7213,6 +7251,11 @@ type SecurityContext struct {
|
|||||||
// Note that this field cannot be set when spec.os.name is windows.
|
// Note that this field cannot be set when spec.os.name is windows.
|
||||||
// +optional
|
// +optional
|
||||||
SeccompProfile *SeccompProfile `json:"seccompProfile,omitempty" protobuf:"bytes,11,opt,name=seccompProfile"`
|
SeccompProfile *SeccompProfile `json:"seccompProfile,omitempty" protobuf:"bytes,11,opt,name=seccompProfile"`
|
||||||
|
// appArmorProfile is the AppArmor options to use by this container. If set, this profile
|
||||||
|
// overrides the pod's appArmorProfile.
|
||||||
|
// Note that this field cannot be set when spec.os.name is windows.
|
||||||
|
// +optional
|
||||||
|
AppArmorProfile *AppArmorProfile `json:"appArmorProfile,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// +enum
|
// +enum
|
||||||
|
Loading…
Reference in New Issue
Block a user