mirror of
https://github.com/kubernetes/kubernetes.git
synced 2026-06-09 00:34:10 -04:00
Merge pull request #123435 from tallclair/apparmor-ga
AppArmor fields API
This commit is contained in:
commit
bd25605619
103 changed files with 4465 additions and 1427 deletions
35
api/openapi-spec/swagger.json
generated
35
api/openapi-spec/swagger.json
generated
|
|
@ -5389,6 +5389,31 @@
|
|||
},
|
||||
"type": "object"
|
||||
},
|
||||
"io.k8s.api.core.v1.AppArmorProfile": {
|
||||
"description": "AppArmorProfile defines a pod or container's AppArmor settings.",
|
||||
"properties": {
|
||||
"localhostProfile": {
|
||||
"description": "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\".",
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"description": "type indicates which kind of AppArmor profile will be applied. Valid options are:\n Localhost - a profile pre-loaded on the node.\n RuntimeDefault - the container runtime's default profile.\n Unconfined - no AppArmor enforcement.",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"type": "object",
|
||||
"x-kubernetes-unions": [
|
||||
{
|
||||
"discriminator": "type",
|
||||
"fields-to-discriminateBy": {
|
||||
"localhostProfile": "LocalhostProfile"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"io.k8s.api.core.v1.AttachedVolume": {
|
||||
"description": "AttachedVolume describes a volume attached to a node",
|
||||
"properties": {
|
||||
|
|
@ -9268,6 +9293,10 @@
|
|||
"io.k8s.api.core.v1.PodSecurityContext": {
|
||||
"description": "PodSecurityContext holds pod-level security attributes and common container settings. Some fields are also present in container.securityContext. Field values of container.securityContext take precedence over field values of PodSecurityContext.",
|
||||
"properties": {
|
||||
"appArmorProfile": {
|
||||
"$ref": "#/definitions/io.k8s.api.core.v1.AppArmorProfile",
|
||||
"description": "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."
|
||||
},
|
||||
"fsGroup": {
|
||||
"description": "A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod:\n\n1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw----\n\nIf unset, the Kubelet will not modify the ownership and permissions of any volume. Note that this field cannot be set when spec.os.name is windows.",
|
||||
"format": "int64",
|
||||
|
|
@ -9450,7 +9479,7 @@
|
|||
},
|
||||
"os": {
|
||||
"$ref": "#/definitions/io.k8s.api.core.v1.PodOS",
|
||||
"description": "Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup"
|
||||
"description": "Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.appArmorProfile - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.containers[*].securityContext.appArmorProfile - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup"
|
||||
},
|
||||
"overhead": {
|
||||
"additionalProperties": {
|
||||
|
|
@ -10772,6 +10801,10 @@
|
|||
"description": "AllowPrivilegeEscalation controls whether a process can gain more privileges than its parent process. This bool directly controls if the no_new_privs flag will be set on the container process. AllowPrivilegeEscalation is true always when the container is: 1) run as Privileged 2) has CAP_SYS_ADMIN Note that this field cannot be set when spec.os.name is windows.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"$ref": "#/definitions/io.k8s.api.core.v1.AppArmorProfile",
|
||||
"description": "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."
|
||||
},
|
||||
"capabilities": {
|
||||
"$ref": "#/definitions/io.k8s.api.core.v1.Capabilities",
|
||||
"description": "The capabilities to add/drop when running containers. Defaults to the default set of capabilities granted by the container runtime. Note that this field cannot be set when spec.os.name is windows."
|
||||
|
|
|
|||
|
|
@ -263,6 +263,32 @@
|
|||
},
|
||||
"type": "object"
|
||||
},
|
||||
"io.k8s.api.core.v1.AppArmorProfile": {
|
||||
"description": "AppArmorProfile defines a pod or container's AppArmor settings.",
|
||||
"properties": {
|
||||
"localhostProfile": {
|
||||
"description": "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\".",
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"default": "",
|
||||
"description": "type indicates which kind of AppArmor profile will be applied. Valid options are:\n Localhost - a profile pre-loaded on the node.\n RuntimeDefault - the container runtime's default profile.\n Unconfined - no AppArmor enforcement.",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"type": "object",
|
||||
"x-kubernetes-unions": [
|
||||
{
|
||||
"discriminator": "type",
|
||||
"fields-to-discriminateBy": {
|
||||
"localhostProfile": "LocalhostProfile"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"io.k8s.api.core.v1.AttachedVolume": {
|
||||
"description": "AttachedVolume describes a volume attached to a node",
|
||||
"properties": {
|
||||
|
|
@ -5161,6 +5187,14 @@
|
|||
"io.k8s.api.core.v1.PodSecurityContext": {
|
||||
"description": "PodSecurityContext holds pod-level security attributes and common container settings. Some fields are also present in container.securityContext. Field values of container.securityContext take precedence over field values of PodSecurityContext.",
|
||||
"properties": {
|
||||
"appArmorProfile": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/io.k8s.api.core.v1.AppArmorProfile"
|
||||
}
|
||||
],
|
||||
"description": "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."
|
||||
},
|
||||
"fsGroup": {
|
||||
"description": "A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod:\n\n1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw----\n\nIf unset, the Kubelet will not modify the ownership and permissions of any volume. Note that this field cannot be set when spec.os.name is windows.",
|
||||
"format": "int64",
|
||||
|
|
@ -5399,7 +5433,7 @@
|
|||
"$ref": "#/components/schemas/io.k8s.api.core.v1.PodOS"
|
||||
}
|
||||
],
|
||||
"description": "Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup"
|
||||
"description": "Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.appArmorProfile - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.containers[*].securityContext.appArmorProfile - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup"
|
||||
},
|
||||
"overhead": {
|
||||
"additionalProperties": {
|
||||
|
|
@ -6999,6 +7033,14 @@
|
|||
"description": "AllowPrivilegeEscalation controls whether a process can gain more privileges than its parent process. This bool directly controls if the no_new_privs flag will be set on the container process. AllowPrivilegeEscalation is true always when the container is: 1) run as Privileged 2) has CAP_SYS_ADMIN Note that this field cannot be set when spec.os.name is windows.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/io.k8s.api.core.v1.AppArmorProfile"
|
||||
}
|
||||
],
|
||||
"description": "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."
|
||||
},
|
||||
"capabilities": {
|
||||
"allOf": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1391,6 +1391,32 @@
|
|||
},
|
||||
"type": "object"
|
||||
},
|
||||
"io.k8s.api.core.v1.AppArmorProfile": {
|
||||
"description": "AppArmorProfile defines a pod or container's AppArmor settings.",
|
||||
"properties": {
|
||||
"localhostProfile": {
|
||||
"description": "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\".",
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"default": "",
|
||||
"description": "type indicates which kind of AppArmor profile will be applied. Valid options are:\n Localhost - a profile pre-loaded on the node.\n RuntimeDefault - the container runtime's default profile.\n Unconfined - no AppArmor enforcement.",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"type": "object",
|
||||
"x-kubernetes-unions": [
|
||||
{
|
||||
"discriminator": "type",
|
||||
"fields-to-discriminateBy": {
|
||||
"localhostProfile": "LocalhostProfile"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"io.k8s.api.core.v1.AzureDiskVolumeSource": {
|
||||
"description": "AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.",
|
||||
"properties": {
|
||||
|
|
@ -3578,6 +3604,14 @@
|
|||
"io.k8s.api.core.v1.PodSecurityContext": {
|
||||
"description": "PodSecurityContext holds pod-level security attributes and common container settings. Some fields are also present in container.securityContext. Field values of container.securityContext take precedence over field values of PodSecurityContext.",
|
||||
"properties": {
|
||||
"appArmorProfile": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/io.k8s.api.core.v1.AppArmorProfile"
|
||||
}
|
||||
],
|
||||
"description": "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."
|
||||
},
|
||||
"fsGroup": {
|
||||
"description": "A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod:\n\n1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw----\n\nIf unset, the Kubelet will not modify the ownership and permissions of any volume. Note that this field cannot be set when spec.os.name is windows.",
|
||||
"format": "int64",
|
||||
|
|
@ -3816,7 +3850,7 @@
|
|||
"$ref": "#/components/schemas/io.k8s.api.core.v1.PodOS"
|
||||
}
|
||||
],
|
||||
"description": "Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup"
|
||||
"description": "Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.appArmorProfile - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.containers[*].securityContext.appArmorProfile - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup"
|
||||
},
|
||||
"overhead": {
|
||||
"additionalProperties": {
|
||||
|
|
@ -4524,6 +4558,14 @@
|
|||
"description": "AllowPrivilegeEscalation controls whether a process can gain more privileges than its parent process. This bool directly controls if the no_new_privs flag will be set on the container process. AllowPrivilegeEscalation is true always when the container is: 1) run as Privileged 2) has CAP_SYS_ADMIN Note that this field cannot be set when spec.os.name is windows.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/io.k8s.api.core.v1.AppArmorProfile"
|
||||
}
|
||||
],
|
||||
"description": "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."
|
||||
},
|
||||
"capabilities": {
|
||||
"allOf": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -695,6 +695,32 @@
|
|||
},
|
||||
"type": "object"
|
||||
},
|
||||
"io.k8s.api.core.v1.AppArmorProfile": {
|
||||
"description": "AppArmorProfile defines a pod or container's AppArmor settings.",
|
||||
"properties": {
|
||||
"localhostProfile": {
|
||||
"description": "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\".",
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"default": "",
|
||||
"description": "type indicates which kind of AppArmor profile will be applied. Valid options are:\n Localhost - a profile pre-loaded on the node.\n RuntimeDefault - the container runtime's default profile.\n Unconfined - no AppArmor enforcement.",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"type": "object",
|
||||
"x-kubernetes-unions": [
|
||||
{
|
||||
"discriminator": "type",
|
||||
"fields-to-discriminateBy": {
|
||||
"localhostProfile": "LocalhostProfile"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"io.k8s.api.core.v1.AzureDiskVolumeSource": {
|
||||
"description": "AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.",
|
||||
"properties": {
|
||||
|
|
@ -2737,6 +2763,14 @@
|
|||
"io.k8s.api.core.v1.PodSecurityContext": {
|
||||
"description": "PodSecurityContext holds pod-level security attributes and common container settings. Some fields are also present in container.securityContext. Field values of container.securityContext take precedence over field values of PodSecurityContext.",
|
||||
"properties": {
|
||||
"appArmorProfile": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/io.k8s.api.core.v1.AppArmorProfile"
|
||||
}
|
||||
],
|
||||
"description": "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."
|
||||
},
|
||||
"fsGroup": {
|
||||
"description": "A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod:\n\n1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw----\n\nIf unset, the Kubelet will not modify the ownership and permissions of any volume. Note that this field cannot be set when spec.os.name is windows.",
|
||||
"format": "int64",
|
||||
|
|
@ -2975,7 +3009,7 @@
|
|||
"$ref": "#/components/schemas/io.k8s.api.core.v1.PodOS"
|
||||
}
|
||||
],
|
||||
"description": "Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup"
|
||||
"description": "Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.appArmorProfile - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.containers[*].securityContext.appArmorProfile - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup"
|
||||
},
|
||||
"overhead": {
|
||||
"additionalProperties": {
|
||||
|
|
@ -3683,6 +3717,14 @@
|
|||
"description": "AllowPrivilegeEscalation controls whether a process can gain more privileges than its parent process. This bool directly controls if the no_new_privs flag will be set on the container process. AllowPrivilegeEscalation is true always when the container is: 1) run as Privileged 2) has CAP_SYS_ADMIN Note that this field cannot be set when spec.os.name is windows.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/io.k8s.api.core.v1.AppArmorProfile"
|
||||
}
|
||||
],
|
||||
"description": "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."
|
||||
},
|
||||
"capabilities": {
|
||||
"allOf": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
metavalidation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
|
|
@ -624,13 +623,24 @@ func dropDisabledFields(
|
|||
podSpec = &api.PodSpec{}
|
||||
}
|
||||
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.AppArmor) && !appArmorInUse(oldPodAnnotations) {
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.AppArmor) && !appArmorAnnotationsInUse(oldPodAnnotations) {
|
||||
for k := range podAnnotations {
|
||||
if strings.HasPrefix(k, v1.AppArmorBetaContainerAnnotationKeyPrefix) {
|
||||
if strings.HasPrefix(k, api.DeprecatedAppArmorAnnotationKeyPrefix) {
|
||||
delete(podAnnotations, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!utilfeature.DefaultFeatureGate.Enabled(features.AppArmor) || !utilfeature.DefaultFeatureGate.Enabled(features.AppArmorFields)) && !appArmorFieldsInUse(oldPodSpec) {
|
||||
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 !utilfeature.DefaultFeatureGate.Enabled(features.UserNamespacesSupport) && !hostUsersInUse(oldPodSpec) {
|
||||
|
|
@ -1023,16 +1033,35 @@ func procMountInUse(podSpec *api.PodSpec) bool {
|
|||
return inUse
|
||||
}
|
||||
|
||||
// appArmorInUse returns true if the pod has apparmor related information
|
||||
func appArmorInUse(podAnnotations map[string]string) bool {
|
||||
// appArmorAnnotationsInUse returns true if the pod has apparmor annotations
|
||||
func appArmorAnnotationsInUse(podAnnotations map[string]string) bool {
|
||||
for k := range podAnnotations {
|
||||
if strings.HasPrefix(k, v1.AppArmorBetaContainerAnnotationKeyPrefix) {
|
||||
if strings.HasPrefix(k, api.DeprecatedAppArmorAnnotationKeyPrefix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// appArmorFieldsInUse returns true if the pod has apparmor fields set
|
||||
func appArmorFieldsInUse(podSpec *api.PodSpec) bool {
|
||||
if podSpec == nil {
|
||||
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
|
||||
// it has any init container with ContainerRestartPolicyAlways.
|
||||
func restartableInitContainersInUse(podSpec *api.PodSpec) bool {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
|
|
@ -704,80 +706,104 @@ func TestDropProcMount(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDropAppArmor(t *testing.T) {
|
||||
podWithAppArmor := func() *api.Pod {
|
||||
return &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{"a": "1", v1.AppArmorBetaContainerAnnotationKeyPrefix + "foo": "default"}},
|
||||
tests := []struct {
|
||||
description string
|
||||
hasAnnotations bool
|
||||
hasFields bool
|
||||
pod api.Pod
|
||||
}{{
|
||||
description: "with AppArmor Annotations",
|
||||
hasAnnotations: true,
|
||||
pod: api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{"a": "1", v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "foo": "default"}},
|
||||
Spec: api.PodSpec{},
|
||||
}
|
||||
}
|
||||
podWithoutAppArmor := func() *api.Pod {
|
||||
return &api.Pod{
|
||||
},
|
||||
}, {
|
||||
description: "with AppArmor Annotations & fields",
|
||||
hasAnnotations: true,
|
||||
hasFields: true,
|
||||
pod: api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{"a": "1", v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "foo": "default"}},
|
||||
Spec: api.PodSpec{
|
||||
SecurityContext: &api.PodSecurityContext{
|
||||
AppArmorProfile: &api.AppArmorProfile{
|
||||
Type: api.AppArmorProfileTypeRuntimeDefault,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
description: "with pod AppArmor profile",
|
||||
hasFields: true,
|
||||
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: "with container AppArmor profile",
|
||||
hasFields: true,
|
||||
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",
|
||||
pod: api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{"a": "1"}},
|
||||
Spec: api.PodSpec{},
|
||||
}
|
||||
}
|
||||
|
||||
podInfo := []struct {
|
||||
description string
|
||||
hasAppArmor bool
|
||||
pod func() *api.Pod
|
||||
}{
|
||||
{
|
||||
description: "has AppArmor",
|
||||
hasAppArmor: true,
|
||||
pod: podWithAppArmor,
|
||||
},
|
||||
{
|
||||
description: "does not have AppArmor",
|
||||
hasAppArmor: false,
|
||||
pod: podWithoutAppArmor,
|
||||
},
|
||||
{
|
||||
description: "is nil",
|
||||
hasAppArmor: false,
|
||||
pod: func() *api.Pod { return nil },
|
||||
},
|
||||
}
|
||||
}}
|
||||
|
||||
for _, enabled := range []bool{true, false} {
|
||||
for _, oldPodInfo := range podInfo {
|
||||
for _, newPodInfo := range podInfo {
|
||||
oldPodHasAppArmor, oldPod := oldPodInfo.hasAppArmor, oldPodInfo.pod()
|
||||
newPodHasAppArmor, newPod := newPodInfo.hasAppArmor, newPodInfo.pod()
|
||||
if newPod == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
t.Run(fmt.Sprintf("feature enabled=%v, old pod %v, new pod %v", enabled, oldPodInfo.description, newPodInfo.description), func(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
for _, enabled := range []bool{true, false} {
|
||||
for _, fieldsEnabled := range []bool{true, false} {
|
||||
t.Run(fmt.Sprintf("%v/enabled=%v/fields=%v", test.description, enabled, fieldsEnabled), func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.AppArmor, enabled)()
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.AppArmorFields, fieldsEnabled)()
|
||||
|
||||
DropDisabledPodFields(newPod, oldPod)
|
||||
newPod := test.pod.DeepCopy()
|
||||
|
||||
// old pod should never be changed
|
||||
if !reflect.DeepEqual(oldPod, oldPodInfo.pod()) {
|
||||
t.Errorf("old pod changed: %v", cmp.Diff(oldPod, oldPodInfo.pod()))
|
||||
if hasAnnotations := appArmorAnnotationsInUse(newPod.Annotations); hasAnnotations != test.hasAnnotations {
|
||||
t.Errorf("appArmorAnnotationsInUse does not match expectation: %t != %t", hasAnnotations, test.hasAnnotations)
|
||||
}
|
||||
if hasFields := appArmorFieldsInUse(&newPod.Spec); hasFields != test.hasFields {
|
||||
t.Errorf("appArmorFieldsInUse does not match expectation: %t != %t", hasFields, test.hasFields)
|
||||
}
|
||||
|
||||
switch {
|
||||
case enabled || oldPodHasAppArmor:
|
||||
// new pod should not be changed if the feature is enabled, or if the old pod had AppArmor
|
||||
if !reflect.DeepEqual(newPod, newPodInfo.pod()) {
|
||||
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()))
|
||||
}
|
||||
DropDisabledPodFields(newPod, newPod)
|
||||
require.Equal(t, &test.pod, newPod, "unchanged pod should never be mutated")
|
||||
|
||||
DropDisabledPodFields(newPod, nil)
|
||||
|
||||
if enabled && fieldsEnabled {
|
||||
assert.Equal(t, &test.pod, newPod, "pod should not be mutated when both feature gates are enabled")
|
||||
return
|
||||
}
|
||||
|
||||
expectAnnotations := test.hasAnnotations && enabled
|
||||
assert.Equal(t, expectAnnotations, appArmorAnnotationsInUse(newPod.Annotations), "AppArmor annotations expectation")
|
||||
if expectAnnotations == test.hasAnnotations {
|
||||
assert.Equal(t, test.pod.Annotations, newPod.Annotations, "annotations should not be mutated")
|
||||
}
|
||||
|
||||
expectFields := test.hasFields && enabled && fieldsEnabled
|
||||
assert.Equal(t, expectFields, appArmorFieldsInUse(&newPod.Spec), "AppArmor fields expectation")
|
||||
if expectFields == test.hasFields {
|
||||
assert.Equal(t, &test.pod.Spec, &newPod.Spec, "PodSpec should not be mutated")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,19 @@ const (
|
|||
// Deprecated: set a pod or container security context `seccompProfile` of type "RuntimeDefault" instead.
|
||||
DeprecatedSeccompProfileDockerDefault string = "docker/default"
|
||||
|
||||
// DeprecatedAppArmorAnnotationKeyPrefix is the prefix to an annotation key specifying a container's apparmor profile.
|
||||
// Deprecated: use a pod or container security context `appArmorProfile` field instead.
|
||||
DeprecatedAppArmorAnnotationKeyPrefix = "container.apparmor.security.beta.kubernetes.io/"
|
||||
|
||||
// DeprecatedAppArmorAnnotationValueRuntimeDefault is the profile specifying the runtime default.
|
||||
DeprecatedAppArmorAnnotationValueRuntimeDefault = "runtime/default"
|
||||
|
||||
// DeprecatedAppArmorAnnotationValueLocalhostPrefix is the prefix for specifying profiles loaded on the node.
|
||||
DeprecatedAppArmorAnnotationValueLocalhostPrefix = "localhost/"
|
||||
|
||||
// DeprecatedAppArmorAnnotationValueUnconfined is the Unconfined AppArmor profile
|
||||
DeprecatedAppArmorAnnotationValueUnconfined = "unconfined"
|
||||
|
||||
// PreferAvoidPodsAnnotationKey represents the key of preferAvoidPods data (json serialized)
|
||||
// in the Annotations of a Node.
|
||||
PreferAvoidPodsAnnotationKey string = "scheduler.alpha.kubernetes.io/preferAvoidPods"
|
||||
|
|
|
|||
|
|
@ -3329,6 +3329,7 @@ type PodSpec struct {
|
|||
// - spec.hostPID
|
||||
// - spec.hostIPC
|
||||
// - spec.hostUsers
|
||||
// - spec.securityContext.appArmorProfile
|
||||
// - spec.securityContext.seLinuxOptions
|
||||
// - spec.securityContext.seccompProfile
|
||||
// - spec.securityContext.fsGroup
|
||||
|
|
@ -3338,6 +3339,7 @@ type PodSpec struct {
|
|||
// - spec.securityContext.runAsUser
|
||||
// - spec.securityContext.runAsGroup
|
||||
// - spec.securityContext.supplementalGroups
|
||||
// - spec.containers[*].securityContext.appArmorProfile
|
||||
// - spec.containers[*].securityContext.seLinuxOptions
|
||||
// - spec.containers[*].securityContext.seccompProfile
|
||||
// - spec.containers[*].securityContext.capabilities
|
||||
|
|
@ -3602,6 +3604,10 @@ type PodSecurityContext struct {
|
|||
// Note that this field cannot be set when spec.os.name is windows.
|
||||
// +optional
|
||||
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.
|
||||
|
|
@ -3629,6 +3635,38 @@ const (
|
|||
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
|
||||
}
|
||||
|
||||
// +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.
|
||||
type PodQOSClass string
|
||||
|
||||
|
|
@ -6032,6 +6070,11 @@ type SecurityContext struct {
|
|||
// Note that this field cannot be set when spec.os.name is windows.
|
||||
// +optional
|
||||
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
|
||||
|
|
|
|||
36
pkg/apis/core/v1/zz_generated.conversion.go
generated
36
pkg/apis/core/v1/zz_generated.conversion.go
generated
|
|
@ -62,6 +62,16 @@ func RegisterConversions(s *runtime.Scheme) error {
|
|||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v1.AppArmorProfile)(nil), (*core.AppArmorProfile)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1_AppArmorProfile_To_core_AppArmorProfile(a.(*v1.AppArmorProfile), b.(*core.AppArmorProfile), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*core.AppArmorProfile)(nil), (*v1.AppArmorProfile)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_core_AppArmorProfile_To_v1_AppArmorProfile(a.(*core.AppArmorProfile), b.(*v1.AppArmorProfile), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v1.AttachedVolume)(nil), (*core.AttachedVolume)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1_AttachedVolume_To_core_AttachedVolume(a.(*v1.AttachedVolume), b.(*core.AttachedVolume), scope)
|
||||
}); err != nil {
|
||||
|
|
@ -2375,6 +2385,28 @@ func Convert_core_Affinity_To_v1_Affinity(in *core.Affinity, out *v1.Affinity, s
|
|||
return autoConvert_core_Affinity_To_v1_Affinity(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_AppArmorProfile_To_core_AppArmorProfile(in *v1.AppArmorProfile, out *core.AppArmorProfile, s conversion.Scope) error {
|
||||
out.Type = core.AppArmorProfileType(in.Type)
|
||||
out.LocalhostProfile = (*string)(unsafe.Pointer(in.LocalhostProfile))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1_AppArmorProfile_To_core_AppArmorProfile is an autogenerated conversion function.
|
||||
func Convert_v1_AppArmorProfile_To_core_AppArmorProfile(in *v1.AppArmorProfile, out *core.AppArmorProfile, s conversion.Scope) error {
|
||||
return autoConvert_v1_AppArmorProfile_To_core_AppArmorProfile(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_core_AppArmorProfile_To_v1_AppArmorProfile(in *core.AppArmorProfile, out *v1.AppArmorProfile, s conversion.Scope) error {
|
||||
out.Type = v1.AppArmorProfileType(in.Type)
|
||||
out.LocalhostProfile = (*string)(unsafe.Pointer(in.LocalhostProfile))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_core_AppArmorProfile_To_v1_AppArmorProfile is an autogenerated conversion function.
|
||||
func Convert_core_AppArmorProfile_To_v1_AppArmorProfile(in *core.AppArmorProfile, out *v1.AppArmorProfile, s conversion.Scope) error {
|
||||
return autoConvert_core_AppArmorProfile_To_v1_AppArmorProfile(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_AttachedVolume_To_core_AttachedVolume(in *v1.AttachedVolume, out *core.AttachedVolume, s conversion.Scope) error {
|
||||
out.Name = core.UniqueVolumeName(in.Name)
|
||||
out.DevicePath = in.DevicePath
|
||||
|
|
@ -6382,6 +6414,7 @@ func autoConvert_v1_PodSecurityContext_To_core_PodSecurityContext(in *v1.PodSecu
|
|||
out.Sysctls = *(*[]core.Sysctl)(unsafe.Pointer(&in.Sysctls))
|
||||
out.FSGroupChangePolicy = (*core.PodFSGroupChangePolicy)(unsafe.Pointer(in.FSGroupChangePolicy))
|
||||
out.SeccompProfile = (*core.SeccompProfile)(unsafe.Pointer(in.SeccompProfile))
|
||||
out.AppArmorProfile = (*core.AppArmorProfile)(unsafe.Pointer(in.AppArmorProfile))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -6406,6 +6439,7 @@ func autoConvert_core_PodSecurityContext_To_v1_PodSecurityContext(in *core.PodSe
|
|||
out.FSGroupChangePolicy = (*v1.PodFSGroupChangePolicy)(unsafe.Pointer(in.FSGroupChangePolicy))
|
||||
out.Sysctls = *(*[]v1.Sysctl)(unsafe.Pointer(&in.Sysctls))
|
||||
out.SeccompProfile = (*v1.SeccompProfile)(unsafe.Pointer(in.SeccompProfile))
|
||||
out.AppArmorProfile = (*v1.AppArmorProfile)(unsafe.Pointer(in.AppArmorProfile))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -7759,6 +7793,7 @@ func autoConvert_v1_SecurityContext_To_core_SecurityContext(in *v1.SecurityConte
|
|||
out.AllowPrivilegeEscalation = (*bool)(unsafe.Pointer(in.AllowPrivilegeEscalation))
|
||||
out.ProcMount = (*core.ProcMountType)(unsafe.Pointer(in.ProcMount))
|
||||
out.SeccompProfile = (*core.SeccompProfile)(unsafe.Pointer(in.SeccompProfile))
|
||||
out.AppArmorProfile = (*core.AppArmorProfile)(unsafe.Pointer(in.AppArmorProfile))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -7779,6 +7814,7 @@ func autoConvert_core_SecurityContext_To_v1_SecurityContext(in *core.SecurityCon
|
|||
out.AllowPrivilegeEscalation = (*bool)(unsafe.Pointer(in.AllowPrivilegeEscalation))
|
||||
out.ProcMount = (*v1.ProcMountType)(unsafe.Pointer(in.ProcMount))
|
||||
out.SeccompProfile = (*v1.SeccompProfile)(unsafe.Pointer(in.SeccompProfile))
|
||||
out.AppArmorProfile = (*v1.AppArmorProfile)(unsafe.Pointer(in.AppArmorProfile))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ func ValidatePodSpecificAnnotationUpdates(newPod, oldPod *core.Pod, fldPath *fie
|
|||
if newVal, exists := newAnnotations[k]; exists && newVal == oldVal {
|
||||
continue // No change.
|
||||
}
|
||||
if strings.HasPrefix(k, v1.AppArmorBetaContainerAnnotationKeyPrefix) {
|
||||
if strings.HasPrefix(k, v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix) {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Key(k), "may not remove or update AppArmor annotations"))
|
||||
}
|
||||
if k == core.MirrorPodAnnotationKey {
|
||||
|
|
@ -216,7 +216,7 @@ func ValidatePodSpecificAnnotationUpdates(newPod, oldPod *core.Pod, fldPath *fie
|
|||
if _, ok := oldAnnotations[k]; ok {
|
||||
continue // No change.
|
||||
}
|
||||
if strings.HasPrefix(k, v1.AppArmorBetaContainerAnnotationKeyPrefix) {
|
||||
if strings.HasPrefix(k, v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix) {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Key(k), "may not add AppArmor annotations"))
|
||||
}
|
||||
if k == core.MirrorPodAnnotationKey {
|
||||
|
|
@ -4248,6 +4248,9 @@ func validateWindows(spec *core.PodSpec, fldPath *field.Path) field.ErrorList {
|
|||
securityContext := spec.SecurityContext
|
||||
// validate Pod SecurityContext
|
||||
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 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("securityContext").Child("seLinuxOptions"), "cannot be set for a windows pod"))
|
||||
}
|
||||
|
|
@ -4294,6 +4297,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
|
||||
if sc != nil {
|
||||
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 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("seLinuxOptions"), "cannot be set for a windows pod"))
|
||||
}
|
||||
|
|
@ -4671,13 +4677,55 @@ 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"))
|
||||
}
|
||||
|
||||
const maxLocalhostProfileLength = 4095 // PATH_MAX - 1
|
||||
if len(*profile.LocalhostProfile) > maxLocalhostProfileLength {
|
||||
allErrs = append(allErrs, field.TooLongMaxLength(fldPath.Child("localhostProfile"), *profile.LocalhostProfile, maxLocalhostProfileLength))
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
allErrs := field.ErrorList{}
|
||||
for k, p := range annotations {
|
||||
if !strings.HasPrefix(k, v1.AppArmorBetaContainerAnnotationKeyPrefix) {
|
||||
if !strings.HasPrefix(k, v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix) {
|
||||
continue
|
||||
}
|
||||
containerName := strings.TrimPrefix(k, v1.AppArmorBetaContainerAnnotationKeyPrefix)
|
||||
containerName := strings.TrimPrefix(k, v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix)
|
||||
if !podSpecHasContainer(spec, containerName) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Key(k), containerName, "container not found"))
|
||||
}
|
||||
|
|
@ -4691,15 +4739,70 @@ func ValidateAppArmorPodAnnotations(annotations map[string]string, spec *core.Po
|
|||
}
|
||||
|
||||
func ValidateAppArmorProfileFormat(profile string) error {
|
||||
if profile == "" || profile == v1.AppArmorBetaProfileRuntimeDefault || profile == v1.AppArmorBetaProfileNameUnconfined {
|
||||
if profile == "" || profile == v1.DeprecatedAppArmorBetaProfileRuntimeDefault || profile == v1.DeprecatedAppArmorBetaProfileNameUnconfined {
|
||||
return nil
|
||||
}
|
||||
if !strings.HasPrefix(profile, v1.AppArmorBetaProfileNamePrefix) {
|
||||
if !strings.HasPrefix(profile, v1.DeprecatedAppArmorBetaProfileNamePrefix) {
|
||||
return fmt.Errorf("invalid AppArmor profile name: %q", profile)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateAppArmorAnnotationsAndFieldsMatchOnCreate validates that AppArmor fields and annotations are consistent.
|
||||
func validateAppArmorAnnotationsAndFieldsMatchOnCreate(objectMeta metav1.ObjectMeta, podSpec *core.PodSpec, specPath *field.Path) field.ErrorList {
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.AppArmorFields) {
|
||||
return nil
|
||||
}
|
||||
if podSpec.OS != nil && podSpec.OS.Name == core.Windows {
|
||||
// Skip consistency check for windows pods.
|
||||
return nil
|
||||
}
|
||||
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
var podProfile *core.AppArmorProfile
|
||||
if podSpec.SecurityContext != nil {
|
||||
podProfile = podSpec.SecurityContext.AppArmorProfile
|
||||
}
|
||||
podshelper.VisitContainersWithPath(podSpec, specPath, func(c *core.Container, cFldPath *field.Path) bool {
|
||||
containerProfile := podProfile
|
||||
if c.SecurityContext != nil && c.SecurityContext.AppArmorProfile != nil {
|
||||
containerProfile = c.SecurityContext.AppArmorProfile
|
||||
}
|
||||
|
||||
if containerProfile == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
key := core.DeprecatedAppArmorAnnotationKeyPrefix + c.Name
|
||||
if annotation, found := objectMeta.Annotations[key]; found {
|
||||
apparmorPath := cFldPath.Child("securityContext").Child("appArmorProfile")
|
||||
|
||||
switch containerProfile.Type {
|
||||
case core.AppArmorProfileTypeUnconfined:
|
||||
if annotation != core.DeprecatedAppArmorAnnotationValueUnconfined {
|
||||
allErrs = append(allErrs, field.Forbidden(apparmorPath.Child("type"), "apparmor type in annotation and field must match"))
|
||||
}
|
||||
|
||||
case core.AppArmorProfileTypeRuntimeDefault:
|
||||
if annotation != core.DeprecatedAppArmorAnnotationValueRuntimeDefault {
|
||||
allErrs = append(allErrs, field.Forbidden(apparmorPath.Child("type"), "apparmor type in annotation and field must match"))
|
||||
}
|
||||
|
||||
case core.AppArmorProfileTypeLocalhost:
|
||||
if !strings.HasPrefix(annotation, core.DeprecatedAppArmorAnnotationValueLocalhostPrefix) {
|
||||
allErrs = append(allErrs, field.Forbidden(apparmorPath.Child("type"), "apparmor type in annotation and field must match"))
|
||||
} else if containerProfile.LocalhostProfile == nil || strings.TrimPrefix(annotation, core.DeprecatedAppArmorAnnotationValueLocalhostPrefix) != *containerProfile.LocalhostProfile {
|
||||
allErrs = append(allErrs, field.Forbidden(apparmorPath.Child("localhostProfile"), "apparmor profile in annotation and field must match"))
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func podSpecHasContainer(spec *core.PodSpec, containerName string) bool {
|
||||
var hasContainer bool
|
||||
podshelper.VisitContainersWithPath(spec, field.NewPath("spec"), func(c *core.Container, _ *field.Path) bool {
|
||||
|
|
@ -4813,6 +4916,7 @@ func validatePodSpecSecurityContext(securityContext *core.PodSecurityContext, sp
|
|||
|
||||
allErrs = append(allErrs, validateSeccompProfileField(securityContext.SeccompProfile, fldPath.Child("seccompProfile"))...)
|
||||
allErrs = append(allErrs, validateWindowsSecurityContextOptions(securityContext.WindowsOptions, fldPath.Child("windowsOptions"))...)
|
||||
allErrs = append(allErrs, ValidateAppArmorProfileField(securityContext.AppArmorProfile, fldPath.Child("appArmorProfile"))...)
|
||||
}
|
||||
|
||||
return allErrs
|
||||
|
|
@ -4853,6 +4957,7 @@ func ValidatePodCreate(pod *core.Pod, opts PodValidationOptions) field.ErrorList
|
|||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("nodeName"), "cannot be set until all schedulingGates have been cleared"))
|
||||
}
|
||||
allErrs = append(allErrs, validateSeccompAnnotationsAndFields(pod.ObjectMeta, &pod.Spec, fldPath)...)
|
||||
allErrs = append(allErrs, validateAppArmorAnnotationsAndFieldsMatchOnCreate(pod.ObjectMeta, &pod.Spec, fldPath)...)
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
|
@ -5830,6 +5935,7 @@ func ValidatePodTemplateSpec(spec *core.PodTemplateSpec, fldPath *field.Path, op
|
|||
allErrs = append(allErrs, ValidatePodSpecificAnnotations(spec.Annotations, &spec.Spec, fldPath.Child("annotations"), opts)...)
|
||||
allErrs = append(allErrs, ValidatePodSpec(&spec.Spec, nil, fldPath.Child("spec"), opts)...)
|
||||
allErrs = append(allErrs, validateSeccompAnnotationsAndFields(spec.ObjectMeta, &spec.Spec, fldPath.Child("spec"))...)
|
||||
allErrs = append(allErrs, validateAppArmorAnnotationsAndFieldsMatchOnCreate(spec.ObjectMeta, &spec.Spec, fldPath.Child("spec"))...)
|
||||
|
||||
if len(spec.Spec.EphemeralContainers) > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("spec", "ephemeralContainers"), "ephemeral containers not allowed in pod template"))
|
||||
|
|
@ -7098,6 +7204,7 @@ func ValidateSecurityContext(sc *core.SecurityContext, fldPath *field.Path) fiel
|
|||
}
|
||||
|
||||
allErrs = append(allErrs, validateWindowsSecurityContextOptions(sc.WindowsOptions, fldPath.Child("windowsOptions"))...)
|
||||
allErrs = append(allErrs, ValidateAppArmorProfileField(sc.AppArmorProfile, fldPath.Child("appArmorProfile"))...)
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10892,22 +10892,22 @@ func TestValidatePod(t *testing.T) {
|
|||
DNSPolicy: core.DNSDefault,
|
||||
},
|
||||
},
|
||||
"default AppArmor profile for a container": {
|
||||
"default AppArmor annotation for a container": {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
Annotations: map[string]string{
|
||||
v1.AppArmorBetaContainerAnnotationKeyPrefix + "ctr": v1.AppArmorBetaProfileRuntimeDefault,
|
||||
v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "ctr": v1.DeprecatedAppArmorBetaProfileRuntimeDefault,
|
||||
},
|
||||
},
|
||||
Spec: validPodSpec(nil),
|
||||
},
|
||||
"default AppArmor profile for an init container": {
|
||||
"default AppArmor annotation for an init container": {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
Annotations: map[string]string{
|
||||
v1.AppArmorBetaContainerAnnotationKeyPrefix + "init-ctr": v1.AppArmorBetaProfileRuntimeDefault,
|
||||
v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "init-ctr": v1.DeprecatedAppArmorBetaProfileRuntimeDefault,
|
||||
},
|
||||
},
|
||||
Spec: core.PodSpec{
|
||||
|
|
@ -10917,16 +10917,158 @@ func TestValidatePod(t *testing.T) {
|
|||
DNSPolicy: core.DNSClusterFirst,
|
||||
},
|
||||
},
|
||||
"localhost AppArmor profile for a container": {
|
||||
"localhost AppArmor annotation for a container": {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
Annotations: map[string]string{
|
||||
v1.AppArmorBetaContainerAnnotationKeyPrefix + "ctr": v1.AppArmorBetaProfileNamePrefix + "foo",
|
||||
v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "ctr": v1.DeprecatedAppArmorBetaProfileNamePrefix + "foo",
|
||||
},
|
||||
},
|
||||
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,
|
||||
},
|
||||
},
|
||||
"matching AppArmor fields and annotations": {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
Annotations: map[string]string{
|
||||
core.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": core.DeprecatedAppArmorAnnotationValueLocalhostPrefix + "foo",
|
||||
},
|
||||
},
|
||||
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("foo"),
|
||||
},
|
||||
},
|
||||
}},
|
||||
RestartPolicy: core.RestartPolicyAlways,
|
||||
DNSPolicy: core.DNSDefault,
|
||||
},
|
||||
},
|
||||
"matching AppArmor pod field and annotations": {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
Annotations: map[string]string{
|
||||
core.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": core.DeprecatedAppArmorAnnotationValueLocalhostPrefix + "foo",
|
||||
},
|
||||
},
|
||||
Spec: core.PodSpec{
|
||||
SecurityContext: &core.PodSecurityContext{
|
||||
AppArmorProfile: &core.AppArmorProfile{
|
||||
Type: core.AppArmorProfileTypeLocalhost,
|
||||
LocalhostProfile: ptr.To("foo"),
|
||||
},
|
||||
},
|
||||
Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
RestartPolicy: core.RestartPolicyAlways,
|
||||
DNSPolicy: core.DNSDefault,
|
||||
},
|
||||
},
|
||||
"syntactically valid sysctls": {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "123",
|
||||
|
|
@ -12444,9 +12586,9 @@ func TestValidatePod(t *testing.T) {
|
|||
Name: "123",
|
||||
Namespace: "ns",
|
||||
Annotations: map[string]string{
|
||||
v1.AppArmorBetaContainerAnnotationKeyPrefix + "ctr": v1.AppArmorBetaProfileRuntimeDefault,
|
||||
v1.AppArmorBetaContainerAnnotationKeyPrefix + "init-ctr": v1.AppArmorBetaProfileRuntimeDefault,
|
||||
v1.AppArmorBetaContainerAnnotationKeyPrefix + "fake-ctr": v1.AppArmorBetaProfileRuntimeDefault,
|
||||
v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "ctr": v1.DeprecatedAppArmorBetaProfileRuntimeDefault,
|
||||
v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "init-ctr": v1.DeprecatedAppArmorBetaProfileRuntimeDefault,
|
||||
v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "fake-ctr": v1.DeprecatedAppArmorBetaProfileRuntimeDefault,
|
||||
},
|
||||
},
|
||||
Spec: core.PodSpec{
|
||||
|
|
@ -12464,7 +12606,7 @@ func TestValidatePod(t *testing.T) {
|
|||
Name: "123",
|
||||
Namespace: "ns",
|
||||
Annotations: map[string]string{
|
||||
v1.AppArmorBetaContainerAnnotationKeyPrefix + "ctr": "bad-name",
|
||||
v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "ctr": "bad-name",
|
||||
},
|
||||
},
|
||||
Spec: validPodSpec(nil),
|
||||
|
|
@ -12477,12 +12619,238 @@ func TestValidatePod(t *testing.T) {
|
|||
Name: "123",
|
||||
Namespace: "ns",
|
||||
Annotations: map[string]string{
|
||||
v1.AppArmorBetaContainerAnnotationKeyPrefix + "ctr": "runtime/foo",
|
||||
v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "ctr": "runtime/foo",
|
||||
},
|
||||
},
|
||||
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 "),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"too long AppArmor localhost profile": {
|
||||
expectedError: "Too long: may not be longer than 4095",
|
||||
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(strings.Repeat("a", 4096)),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"mismatched AppArmor field and annotation types": {
|
||||
expectedError: "Forbidden: apparmor type in annotation and field must match",
|
||||
spec: core.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
Annotations: map[string]string{
|
||||
core.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": core.DeprecatedAppArmorAnnotationValueRuntimeDefault,
|
||||
},
|
||||
},
|
||||
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,
|
||||
},
|
||||
},
|
||||
},
|
||||
"mismatched AppArmor pod field and annotation types": {
|
||||
expectedError: "Forbidden: apparmor type in annotation and field must match",
|
||||
spec: core.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
Annotations: map[string]string{
|
||||
core.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": core.DeprecatedAppArmorAnnotationValueRuntimeDefault,
|
||||
},
|
||||
},
|
||||
Spec: core.PodSpec{
|
||||
SecurityContext: &core.PodSecurityContext{
|
||||
AppArmorProfile: &core.AppArmorProfile{
|
||||
Type: core.AppArmorProfileTypeUnconfined,
|
||||
},
|
||||
},
|
||||
Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
RestartPolicy: core.RestartPolicyAlways,
|
||||
DNSPolicy: core.DNSDefault,
|
||||
},
|
||||
},
|
||||
},
|
||||
"mismatched AppArmor localhost profiles": {
|
||||
expectedError: "Forbidden: apparmor profile in annotation and field must match",
|
||||
spec: core.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
Annotations: map[string]string{
|
||||
core.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": core.DeprecatedAppArmorAnnotationValueLocalhostPrefix + "foo",
|
||||
},
|
||||
},
|
||||
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("bar"),
|
||||
},
|
||||
},
|
||||
}},
|
||||
RestartPolicy: core.RestartPolicyAlways,
|
||||
DNSPolicy: core.DNSDefault,
|
||||
},
|
||||
},
|
||||
},
|
||||
"invalid extended resource name in container request": {
|
||||
expectedError: "must be a standard resource for containers",
|
||||
spec: core.Pod{
|
||||
|
|
@ -22182,6 +22550,12 @@ func TestValidateWindowsSecurityContext(t *testing.T) {
|
|||
expectError: true,
|
||||
errorMsg: "cannot be set for a windows pod",
|
||||
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",
|
||||
sc: &core.PodSpec{Containers: []core.Container{{SecurityContext: &core.SecurityContext{WindowsOptions: &core.WindowsSecurityContextOptions{RunAsUserName: utilpointer.String("dummy")}}}}},
|
||||
|
|
@ -22216,6 +22590,7 @@ func TestValidateOSFields(t *testing.T) {
|
|||
// - 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
|
||||
osSpecificFields := sets.NewString(
|
||||
"Containers[*].SecurityContext.AppArmorProfile",
|
||||
"Containers[*].SecurityContext.AllowPrivilegeEscalation",
|
||||
"Containers[*].SecurityContext.Capabilities",
|
||||
"Containers[*].SecurityContext.Privileged",
|
||||
|
|
@ -22226,6 +22601,7 @@ func TestValidateOSFields(t *testing.T) {
|
|||
"Containers[*].SecurityContext.SELinuxOptions",
|
||||
"Containers[*].SecurityContext.SeccompProfile",
|
||||
"Containers[*].SecurityContext.WindowsOptions",
|
||||
"InitContainers[*].SecurityContext.AppArmorProfile",
|
||||
"InitContainers[*].SecurityContext.AllowPrivilegeEscalation",
|
||||
"InitContainers[*].SecurityContext.Capabilities",
|
||||
"InitContainers[*].SecurityContext.Privileged",
|
||||
|
|
@ -22236,6 +22612,7 @@ func TestValidateOSFields(t *testing.T) {
|
|||
"InitContainers[*].SecurityContext.SELinuxOptions",
|
||||
"InitContainers[*].SecurityContext.SeccompProfile",
|
||||
"InitContainers[*].SecurityContext.WindowsOptions",
|
||||
"EphemeralContainers[*].EphemeralContainerCommon.SecurityContext.AppArmorProfile",
|
||||
"EphemeralContainers[*].EphemeralContainerCommon.SecurityContext.AllowPrivilegeEscalation",
|
||||
"EphemeralContainers[*].EphemeralContainerCommon.SecurityContext.Capabilities",
|
||||
"EphemeralContainers[*].EphemeralContainerCommon.SecurityContext.Privileged",
|
||||
|
|
@ -22247,6 +22624,7 @@ func TestValidateOSFields(t *testing.T) {
|
|||
"EphemeralContainers[*].EphemeralContainerCommon.SecurityContext.SeccompProfile",
|
||||
"EphemeralContainers[*].EphemeralContainerCommon.SecurityContext.WindowsOptions",
|
||||
"OS",
|
||||
"SecurityContext.AppArmorProfile",
|
||||
"SecurityContext.FSGroup",
|
||||
"SecurityContext.FSGroupChangePolicy",
|
||||
"SecurityContext.HostIPC",
|
||||
|
|
@ -25431,11 +25809,11 @@ func TestValidateAppArmorProfileFormat(t *testing.T) {
|
|||
expectValid bool
|
||||
}{
|
||||
{"", true},
|
||||
{v1.AppArmorBetaProfileRuntimeDefault, true},
|
||||
{v1.AppArmorBetaProfileNameUnconfined, true},
|
||||
{v1.DeprecatedAppArmorBetaProfileRuntimeDefault, true},
|
||||
{v1.DeprecatedAppArmorBetaProfileNameUnconfined, true},
|
||||
{"baz", false}, // Missing local prefix.
|
||||
{v1.AppArmorBetaProfileNamePrefix + "/usr/sbin/ntpd", true},
|
||||
{v1.AppArmorBetaProfileNamePrefix + "foo-bar", true},
|
||||
{v1.DeprecatedAppArmorBetaProfileNamePrefix + "/usr/sbin/ntpd", true},
|
||||
{v1.DeprecatedAppArmorBetaProfileNamePrefix + "foo-bar", true},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
|
|
|||
31
pkg/apis/core/zz_generated.deepcopy.go
generated
31
pkg/apis/core/zz_generated.deepcopy.go
generated
|
|
@ -74,6 +74,27 @@ func (in *Affinity) DeepCopy() *Affinity {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AppArmorProfile) DeepCopyInto(out *AppArmorProfile) {
|
||||
*out = *in
|
||||
if in.LocalhostProfile != nil {
|
||||
in, out := &in.LocalhostProfile, &out.LocalhostProfile
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AppArmorProfile.
|
||||
func (in *AppArmorProfile) DeepCopy() *AppArmorProfile {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AppArmorProfile)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AttachedVolume) DeepCopyInto(out *AttachedVolume) {
|
||||
*out = *in
|
||||
|
|
@ -4010,6 +4031,11 @@ func (in *PodSecurityContext) DeepCopyInto(out *PodSecurityContext) {
|
|||
*out = new(SeccompProfile)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.AppArmorProfile != nil {
|
||||
in, out := &in.AppArmorProfile, &out.AppArmorProfile
|
||||
*out = new(AppArmorProfile)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -5378,6 +5404,11 @@ func (in *SecurityContext) DeepCopyInto(out *SecurityContext) {
|
|||
*out = new(SeccompProfile)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.AppArmorProfile != nil {
|
||||
in, out := &in.AppArmorProfile, &out.AppArmorProfile
|
||||
*out = new(AppArmorProfile)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -63,6 +63,10 @@ const (
|
|||
// beta: v1.4
|
||||
AppArmor featuregate.Feature = "AppArmor"
|
||||
|
||||
// owner: @tallclair
|
||||
// beta: v1.30
|
||||
AppArmorFields featuregate.Feature = "AppArmorFields"
|
||||
|
||||
// owner: @danwinship
|
||||
// alpha: v1.27
|
||||
// beta: v1.29
|
||||
|
|
@ -984,6 +988,8 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
|
|||
|
||||
AppArmor: {Default: true, PreRelease: featuregate.Beta},
|
||||
|
||||
AppArmorFields: {Default: true, PreRelease: featuregate.Beta},
|
||||
|
||||
CloudDualStackNodeIPs: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.32
|
||||
|
||||
ClusterTrustBundle: {Default: false, PreRelease: featuregate.Alpha},
|
||||
|
|
|
|||
61
pkg/generated/openapi/zz_generated.openapi.go
generated
61
pkg/generated/openapi/zz_generated.openapi.go
generated
|
|
@ -376,6 +376,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
|
|||
"k8s.io/api/coordination/v1beta1.LeaseSpec": schema_k8sio_api_coordination_v1beta1_LeaseSpec(ref),
|
||||
"k8s.io/api/core/v1.AWSElasticBlockStoreVolumeSource": schema_k8sio_api_core_v1_AWSElasticBlockStoreVolumeSource(ref),
|
||||
"k8s.io/api/core/v1.Affinity": schema_k8sio_api_core_v1_Affinity(ref),
|
||||
"k8s.io/api/core/v1.AppArmorProfile": schema_k8sio_api_core_v1_AppArmorProfile(ref),
|
||||
"k8s.io/api/core/v1.AttachedVolume": schema_k8sio_api_core_v1_AttachedVolume(ref),
|
||||
"k8s.io/api/core/v1.AvoidPods": schema_k8sio_api_core_v1_AvoidPods(ref),
|
||||
"k8s.io/api/core/v1.AzureDiskVolumeSource": schema_k8sio_api_core_v1_AzureDiskVolumeSource(ref),
|
||||
|
|
@ -18870,6 +18871,48 @@ func schema_k8sio_api_core_v1_Affinity(ref common.ReferenceCallback) common.Open
|
|||
}
|
||||
}
|
||||
|
||||
func schema_k8sio_api_core_v1_AppArmorProfile(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "AppArmorProfile defines a pod or container's AppArmor settings.",
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"type": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "type indicates which kind of AppArmor profile will be applied. Valid options are:\n Localhost - a profile pre-loaded on the node.\n RuntimeDefault - the container runtime's default profile.\n Unconfined - no AppArmor enforcement.\n\nPossible enum values:\n - `\"Localhost\"` indicates that a profile pre-loaded on the node should be used.\n - `\"RuntimeDefault\"` indicates that the container runtime's default AppArmor profile should be used.\n - `\"Unconfined\"` indicates that no AppArmor profile should be enforced.",
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
Enum: []interface{}{"Localhost", "RuntimeDefault", "Unconfined"},
|
||||
},
|
||||
},
|
||||
"localhostProfile": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "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\".",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"type"},
|
||||
},
|
||||
VendorExtensible: spec.VendorExtensible{
|
||||
Extensions: spec.Extensions{
|
||||
"x-kubernetes-unions": []interface{}{
|
||||
map[string]interface{}{
|
||||
"discriminator": "type",
|
||||
"fields-to-discriminateBy": map[string]interface{}{
|
||||
"localhostProfile": "LocalhostProfile",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_k8sio_api_core_v1_AttachedVolume(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
|
|
@ -26891,11 +26934,17 @@ func schema_k8sio_api_core_v1_PodSecurityContext(ref common.ReferenceCallback) c
|
|||
Ref: ref("k8s.io/api/core/v1.SeccompProfile"),
|
||||
},
|
||||
},
|
||||
"appArmorProfile": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "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.",
|
||||
Ref: ref("k8s.io/api/core/v1.AppArmorProfile"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"k8s.io/api/core/v1.SELinuxOptions", "k8s.io/api/core/v1.SeccompProfile", "k8s.io/api/core/v1.Sysctl", "k8s.io/api/core/v1.WindowsSecurityContextOptions"},
|
||||
"k8s.io/api/core/v1.AppArmorProfile", "k8s.io/api/core/v1.SELinuxOptions", "k8s.io/api/core/v1.SeccompProfile", "k8s.io/api/core/v1.Sysctl", "k8s.io/api/core/v1.WindowsSecurityContextOptions"},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -27339,7 +27388,7 @@ func schema_k8sio_api_core_v1_PodSpec(ref common.ReferenceCallback) common.OpenA
|
|||
},
|
||||
"os": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup",
|
||||
Description: "Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.appArmorProfile - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.containers[*].securityContext.appArmorProfile - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup",
|
||||
Ref: ref("k8s.io/api/core/v1.PodOS"),
|
||||
},
|
||||
},
|
||||
|
|
@ -29768,11 +29817,17 @@ func schema_k8sio_api_core_v1_SecurityContext(ref common.ReferenceCallback) comm
|
|||
Ref: ref("k8s.io/api/core/v1.SeccompProfile"),
|
||||
},
|
||||
},
|
||||
"appArmorProfile": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "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.",
|
||||
Ref: ref("k8s.io/api/core/v1.AppArmorProfile"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"k8s.io/api/core/v1.Capabilities", "k8s.io/api/core/v1.SELinuxOptions", "k8s.io/api/core/v1.SeccompProfile", "k8s.io/api/core/v1.WindowsSecurityContextOptions"},
|
||||
"k8s.io/api/core/v1.AppArmorProfile", "k8s.io/api/core/v1.Capabilities", "k8s.io/api/core/v1.SELinuxOptions", "k8s.io/api/core/v1.SeccompProfile", "k8s.io/api/core/v1.WindowsSecurityContextOptions"},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -732,10 +732,6 @@ func (kl *Kubelet) defaultNodeStatusFuncs() []func(context.Context, *v1.Node) er
|
|||
if kl.cloud != nil {
|
||||
nodeAddressesFunc = kl.cloudResourceSyncManager.NodeAddresses
|
||||
}
|
||||
var validateHostFunc func() error
|
||||
if kl.appArmorValidator != nil {
|
||||
validateHostFunc = kl.appArmorValidator.ValidateHost
|
||||
}
|
||||
var setters []func(ctx context.Context, n *v1.Node) error
|
||||
setters = append(setters,
|
||||
nodestatus.NodeAddress(kl.nodeIPs, kl.nodeIPValidator, kl.hostname, kl.hostnameOverridden, kl.externalCloudProvider, kl.cloud, nodeAddressesFunc),
|
||||
|
|
@ -754,7 +750,7 @@ func (kl *Kubelet) defaultNodeStatusFuncs() []func(context.Context, *v1.Node) er
|
|||
nodestatus.DiskPressureCondition(kl.clock.Now, kl.evictionManager.IsUnderDiskPressure, kl.recordNodeStatusEvent),
|
||||
nodestatus.PIDPressureCondition(kl.clock.Now, kl.evictionManager.IsUnderPIDPressure, kl.recordNodeStatusEvent),
|
||||
nodestatus.ReadyCondition(kl.clock.Now, kl.runtimeState.runtimeErrors, kl.runtimeState.networkErrors, kl.runtimeState.storageErrors,
|
||||
validateHostFunc, kl.containerManager.Status, kl.shutdownManager.ShutdownStatus, kl.recordNodeStatusEvent, kl.supportLocalStorageCapacityIsolation()),
|
||||
kl.containerManager.Status, kl.shutdownManager.ShutdownStatus, kl.recordNodeStatusEvent, kl.supportLocalStorageCapacityIsolation()),
|
||||
nodestatus.VolumesInUse(kl.volumeManager.ReconcilerStatesHasBeenSynced, kl.volumeManager.GetVolumesInUse),
|
||||
// TODO(mtaufen): I decided not to move this setter for now, since all it does is send an event
|
||||
// and record state back to the Kubelet runtime object. In the future, I'd like to isolate
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package kuberuntime
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
|
@ -28,6 +29,7 @@ import (
|
|||
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
|
||||
"k8s.io/klog/v2"
|
||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||
"k8s.io/kubernetes/pkg/security/apparmor"
|
||||
)
|
||||
|
||||
type podsByID []*kubecontainer.Pod
|
||||
|
|
@ -285,3 +287,35 @@ func (m *kubeGenericRuntimeManager) getSeccompProfile(annotations map[string]str
|
|||
ProfileType: runtimeapi.SecurityProfile_Unconfined,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getAppArmorProfile(pod *v1.Pod, container *v1.Container) (*runtimeapi.SecurityProfile, error) {
|
||||
profile := apparmor.GetProfile(pod, container)
|
||||
if profile == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
switch profile.Type {
|
||||
case v1.AppArmorProfileTypeRuntimeDefault:
|
||||
return &runtimeapi.SecurityProfile{
|
||||
ProfileType: runtimeapi.SecurityProfile_RuntimeDefault,
|
||||
}, nil
|
||||
|
||||
case v1.AppArmorProfileTypeUnconfined:
|
||||
return &runtimeapi.SecurityProfile{
|
||||
ProfileType: runtimeapi.SecurityProfile_Unconfined,
|
||||
}, nil
|
||||
|
||||
case v1.AppArmorProfileTypeLocalhost:
|
||||
if profile.LocalhostProfile == nil {
|
||||
return nil, errors.New("missing localhost apparmor profile name")
|
||||
}
|
||||
return &runtimeapi.SecurityProfile{
|
||||
ProfileType: runtimeapi.SecurityProfile_Localhost,
|
||||
LocalhostRef: *profile.LocalhostProfile,
|
||||
}, nil
|
||||
|
||||
default:
|
||||
// Shouldn't happen.
|
||||
return nil, fmt.Errorf("unknown apparmor profile type: %q", profile.Type)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import (
|
|||
runtimetesting "k8s.io/cri-api/pkg/apis/testing"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||
"k8s.io/utils/ptr"
|
||||
)
|
||||
|
||||
type podStatusProviderFunc func(uid types.UID, name, namespace string) (*kubecontainer.PodStatus, error)
|
||||
|
|
@ -363,3 +364,75 @@ func TestToKubeContainerState(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAppArmorProfile(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
podProfile *v1.AppArmorProfile
|
||||
expectedProfile *runtimeapi.SecurityProfile
|
||||
expectError bool
|
||||
}{{
|
||||
name: "no appArmor",
|
||||
expectedProfile: nil,
|
||||
}, {
|
||||
name: "runtime default",
|
||||
podProfile: &v1.AppArmorProfile{Type: v1.AppArmorProfileTypeRuntimeDefault},
|
||||
expectedProfile: &runtimeapi.SecurityProfile{
|
||||
ProfileType: runtimeapi.SecurityProfile_RuntimeDefault,
|
||||
},
|
||||
}, {
|
||||
name: "unconfined",
|
||||
podProfile: &v1.AppArmorProfile{Type: v1.AppArmorProfileTypeUnconfined},
|
||||
expectedProfile: &runtimeapi.SecurityProfile{
|
||||
ProfileType: runtimeapi.SecurityProfile_Unconfined,
|
||||
},
|
||||
}, {
|
||||
name: "localhost",
|
||||
podProfile: &v1.AppArmorProfile{
|
||||
Type: v1.AppArmorProfileTypeLocalhost,
|
||||
LocalhostProfile: ptr.To("test"),
|
||||
},
|
||||
expectedProfile: &runtimeapi.SecurityProfile{
|
||||
ProfileType: runtimeapi.SecurityProfile_Localhost,
|
||||
LocalhostRef: "test",
|
||||
},
|
||||
}, {
|
||||
name: "invalid localhost",
|
||||
podProfile: &v1.AppArmorProfile{
|
||||
Type: v1.AppArmorProfileTypeLocalhost,
|
||||
},
|
||||
expectError: true,
|
||||
}, {
|
||||
name: "invalid type",
|
||||
podProfile: &v1.AppArmorProfile{
|
||||
Type: "foo",
|
||||
},
|
||||
expectError: true,
|
||||
}}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
pod := v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "bar",
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
SecurityContext: &v1.PodSecurityContext{
|
||||
AppArmorProfile: test.podProfile,
|
||||
},
|
||||
Containers: []v1.Container{{Name: "foo"}},
|
||||
},
|
||||
}
|
||||
|
||||
actual, err := getAppArmorProfile(&pod, &pod.Spec.Containers[0])
|
||||
|
||||
if test.expectError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
assert.Equal(t, test.expectedProfile, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import (
|
|||
v1 "k8s.io/api/core/v1"
|
||||
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
|
||||
runtimeutil "k8s.io/kubernetes/pkg/kubelet/kuberuntime/util"
|
||||
"k8s.io/kubernetes/pkg/security/apparmor"
|
||||
"k8s.io/kubernetes/pkg/securitycontext"
|
||||
)
|
||||
|
||||
|
|
@ -42,7 +41,10 @@ func (m *kubeGenericRuntimeManager) determineEffectiveSecurityContext(pod *v1.Po
|
|||
}
|
||||
|
||||
// set ApparmorProfile.
|
||||
synthesized.ApparmorProfile = apparmor.GetProfileNameFromPodAnnotations(pod.Annotations, container.Name)
|
||||
synthesized.Apparmor, err = getAppArmorProfile(pod, container)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// set RunAsUser.
|
||||
if synthesized.RunAsUser == nil {
|
||||
|
|
|
|||
|
|
@ -486,7 +486,6 @@ func ReadyCondition(
|
|||
runtimeErrorsFunc func() error, // typically Kubelet.runtimeState.runtimeErrors
|
||||
networkErrorsFunc func() error, // typically Kubelet.runtimeState.networkErrors
|
||||
storageErrorsFunc func() error, // typically Kubelet.runtimeState.storageErrors
|
||||
appArmorValidateHostFunc func() error, // typically Kubelet.appArmorValidator.ValidateHost, might be nil depending on whether there was an appArmorValidator
|
||||
cmStatusFunc func() cm.Status, // typically Kubelet.containerManager.Status
|
||||
nodeShutdownManagerErrorsFunc func() error, // typically kubelet.shutdownManager.errors.
|
||||
recordEventFunc func(eventType, event string), // typically Kubelet.recordNodeStatusEvent
|
||||
|
|
@ -527,13 +526,6 @@ func ReadyCondition(
|
|||
LastHeartbeatTime: currentTime,
|
||||
}
|
||||
}
|
||||
// Append AppArmor status if it's enabled.
|
||||
// TODO(tallclair): This is a temporary message until node feature reporting is added.
|
||||
if appArmorValidateHostFunc != nil && newNodeReadyCondition.Status == v1.ConditionTrue {
|
||||
if err := appArmorValidateHostFunc(); err == nil {
|
||||
newNodeReadyCondition.Message = fmt.Sprintf("%s. AppArmor enabled", newNodeReadyCondition.Message)
|
||||
}
|
||||
}
|
||||
|
||||
// Record any soft requirements that were not met in the container manager.
|
||||
status := cmStatusFunc()
|
||||
|
|
|
|||
|
|
@ -1509,7 +1509,6 @@ func TestReadyCondition(t *testing.T) {
|
|||
runtimeErrors error
|
||||
networkErrors error
|
||||
storageErrors error
|
||||
appArmorValidateHostFunc func() error
|
||||
cmStatus cm.Status
|
||||
nodeShutdownManagerErrors error
|
||||
expectConditions []v1.NodeCondition
|
||||
|
|
@ -1524,19 +1523,6 @@ func TestReadyCondition(t *testing.T) {
|
|||
// the reason for this is unclear, so we may want to actually send an event, and change these test cases
|
||||
// to ensure an event is sent.
|
||||
},
|
||||
{
|
||||
desc: "new, ready: apparmor validator passed",
|
||||
node: withCapacity.DeepCopy(),
|
||||
appArmorValidateHostFunc: func() error { return nil },
|
||||
expectConditions: []v1.NodeCondition{*makeReadyCondition(true, "kubelet is posting ready status. AppArmor enabled", now, now)},
|
||||
},
|
||||
{
|
||||
desc: "new, ready: apparmor validator failed",
|
||||
node: withCapacity.DeepCopy(),
|
||||
appArmorValidateHostFunc: func() error { return fmt.Errorf("foo") },
|
||||
// absence of an additional message is understood to mean that AppArmor is disabled
|
||||
expectConditions: []v1.NodeCondition{*makeReadyCondition(true, "kubelet is posting ready status", now, now)},
|
||||
},
|
||||
{
|
||||
desc: "new, ready: soft requirement warning",
|
||||
node: withCapacity.DeepCopy(),
|
||||
|
|
@ -1655,7 +1641,7 @@ func TestReadyCondition(t *testing.T) {
|
|||
})
|
||||
}
|
||||
// construct setter
|
||||
setter := ReadyCondition(nowFunc, runtimeErrorsFunc, networkErrorsFunc, storageErrorsFunc, tc.appArmorValidateHostFunc, cmStatusFunc, nodeShutdownErrorsFunc, recordEventFunc, !tc.disableLocalStorageCapacityIsolation)
|
||||
setter := ReadyCondition(nowFunc, runtimeErrorsFunc, networkErrorsFunc, storageErrorsFunc, cmStatusFunc, nodeShutdownErrorsFunc, recordEventFunc, !tc.disableLocalStorageCapacityIsolation)
|
||||
// call setter on node
|
||||
if err := setter(ctx, tc.node); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import (
|
|||
"time"
|
||||
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
|
|
@ -91,6 +92,7 @@ func (podStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
|||
|
||||
applySchedulingGatedCondition(pod)
|
||||
mutatePodAffinity(pod)
|
||||
applyAppArmorVersionSkew(pod)
|
||||
}
|
||||
|
||||
// PrepareForUpdate clears fields that are not allowed to be set by end users on update.
|
||||
|
|
@ -758,3 +760,117 @@ func applySchedulingGatedCondition(pod *api.Pod) {
|
|||
Message: "Scheduling is blocked due to non-empty scheduling gates",
|
||||
})
|
||||
}
|
||||
|
||||
// applyAppArmorVersionSkew implements the version skew behavior described in:
|
||||
// https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/24-apparmor#version-skew-strategy
|
||||
func applyAppArmorVersionSkew(pod *api.Pod) {
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.AppArmorFields) {
|
||||
return
|
||||
}
|
||||
|
||||
if pod.Spec.OS != nil && pod.Spec.OS.Name == api.Windows {
|
||||
return
|
||||
}
|
||||
|
||||
var podProfile *api.AppArmorProfile
|
||||
if pod.Spec.SecurityContext != nil {
|
||||
podProfile = pod.Spec.SecurityContext.AppArmorProfile
|
||||
}
|
||||
|
||||
// Handle the containers of the pod
|
||||
podutil.VisitContainers(&pod.Spec, podutil.AllFeatureEnabledContainers(),
|
||||
func(ctr *api.Container, _ podutil.ContainerType) bool {
|
||||
// get possible annotation and field
|
||||
key := api.DeprecatedAppArmorAnnotationKeyPrefix + ctr.Name
|
||||
annotation, hasAnnotation := pod.Annotations[key]
|
||||
|
||||
var containerProfile *api.AppArmorProfile
|
||||
if ctr.SecurityContext != nil {
|
||||
containerProfile = ctr.SecurityContext.AppArmorProfile
|
||||
}
|
||||
|
||||
// sync field and annotation
|
||||
if !hasAnnotation {
|
||||
newAnnotation := ""
|
||||
if containerProfile != nil {
|
||||
newAnnotation = appArmorAnnotationForField(containerProfile)
|
||||
} else if podProfile != nil {
|
||||
newAnnotation = appArmorAnnotationForField(podProfile)
|
||||
}
|
||||
|
||||
if newAnnotation != "" {
|
||||
if pod.Annotations == nil {
|
||||
pod.Annotations = map[string]string{}
|
||||
}
|
||||
pod.Annotations[key] = newAnnotation
|
||||
}
|
||||
} else if containerProfile == nil {
|
||||
newField := apparmorFieldForAnnotation(annotation)
|
||||
if errs := corevalidation.ValidateAppArmorProfileField(newField, &field.Path{}); len(errs) > 0 {
|
||||
// Skip copying invalid value.
|
||||
newField = nil
|
||||
}
|
||||
|
||||
// Only copy the annotation to the field if it is different from the pod-level profile.
|
||||
if newField != nil && !apiequality.Semantic.DeepEqual(newField, podProfile) {
|
||||
if ctr.SecurityContext == nil {
|
||||
ctr.SecurityContext = &api.SecurityContext{}
|
||||
}
|
||||
ctr.SecurityContext.AppArmorProfile = newField
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// appArmorFieldForAnnotation takes a pod apparmor profile field and returns the
|
||||
// converted annotation value
|
||||
func appArmorAnnotationForField(field *api.AppArmorProfile) string {
|
||||
// If only apparmor fields are specified, add the corresponding annotations.
|
||||
// This ensures that the fields are enforced even if the node version
|
||||
// trails the API version
|
||||
switch field.Type {
|
||||
case api.AppArmorProfileTypeUnconfined:
|
||||
return api.DeprecatedAppArmorAnnotationValueUnconfined
|
||||
|
||||
case api.AppArmorProfileTypeRuntimeDefault:
|
||||
return api.DeprecatedAppArmorAnnotationValueRuntimeDefault
|
||||
|
||||
case api.AppArmorProfileTypeLocalhost:
|
||||
if field.LocalhostProfile != nil {
|
||||
return api.DeprecatedAppArmorAnnotationValueLocalhostPrefix + *field.LocalhostProfile
|
||||
}
|
||||
}
|
||||
|
||||
// we can only reach this code path if the LocalhostProfile is nil but the
|
||||
// provided field type is AppArmorProfileTypeLocalhost or if an unrecognized
|
||||
// type is specified
|
||||
return ""
|
||||
}
|
||||
|
||||
// apparmorFieldForAnnotation takes a pod annotation and returns the converted
|
||||
// apparmor profile field.
|
||||
func apparmorFieldForAnnotation(annotation string) *api.AppArmorProfile {
|
||||
if annotation == api.DeprecatedAppArmorAnnotationValueUnconfined {
|
||||
return &api.AppArmorProfile{Type: api.AppArmorProfileTypeUnconfined}
|
||||
}
|
||||
|
||||
if annotation == api.DeprecatedAppArmorAnnotationValueRuntimeDefault {
|
||||
return &api.AppArmorProfile{Type: api.AppArmorProfileTypeRuntimeDefault}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(annotation, api.DeprecatedAppArmorAnnotationValueLocalhostPrefix) {
|
||||
localhostProfile := strings.TrimPrefix(annotation, api.DeprecatedAppArmorAnnotationValueLocalhostPrefix)
|
||||
if localhostProfile != "" {
|
||||
return &api.AppArmorProfile{
|
||||
Type: api.AppArmorProfileTypeLocalhost,
|
||||
LocalhostProfile: &localhostProfile,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we can only reach this code path if the localhostProfile name has a zero
|
||||
// length or if the annotation has an unrecognized value
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,10 +22,12 @@ import (
|
|||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/stretchr/testify/assert"
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
|
|
@ -2106,3 +2108,540 @@ func TestPodLifecycleSleepActionEnablement(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyAppArmorVersionSkew(t *testing.T) {
|
||||
testProfile := "test"
|
||||
|
||||
tests := []struct {
|
||||
description string
|
||||
pod *api.Pod
|
||||
validation func(*testing.T, *api.Pod)
|
||||
}{{
|
||||
description: "Security context nil",
|
||||
pod: &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
InitContainers: []api.Container{{Name: "init"}},
|
||||
Containers: []api.Container{{Name: "ctr"}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
assert.Empty(t, pod.Annotations)
|
||||
assert.Nil(t, pod.Spec.SecurityContext)
|
||||
},
|
||||
}, {
|
||||
description: "Security context not nil",
|
||||
pod: &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
SecurityContext: &api.PodSecurityContext{},
|
||||
InitContainers: []api.Container{{Name: "init"}},
|
||||
Containers: []api.Container{{Name: "ctr"}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
assert.Empty(t, pod.Annotations)
|
||||
assert.Nil(t, pod.Spec.SecurityContext.AppArmorProfile)
|
||||
},
|
||||
}, {
|
||||
description: "Pod field unconfined and no annotation present",
|
||||
pod: &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
SecurityContext: &api.PodSecurityContext{
|
||||
AppArmorProfile: &api.AppArmorProfile{
|
||||
Type: api.AppArmorProfileTypeUnconfined,
|
||||
},
|
||||
},
|
||||
InitContainers: []api.Container{{Name: "init"}},
|
||||
Containers: []api.Container{{Name: "ctr"}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
assert.Equal(t, map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "init": api.DeprecatedAppArmorAnnotationValueUnconfined,
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": api.DeprecatedAppArmorAnnotationValueUnconfined,
|
||||
}, pod.Annotations)
|
||||
},
|
||||
}, {
|
||||
description: "Pod field default and no annotation present",
|
||||
pod: &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
SecurityContext: &api.PodSecurityContext{
|
||||
AppArmorProfile: &api.AppArmorProfile{
|
||||
Type: api.AppArmorProfileTypeRuntimeDefault,
|
||||
},
|
||||
},
|
||||
InitContainers: []api.Container{{Name: "init"}},
|
||||
Containers: []api.Container{{Name: "ctr"}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
assert.Equal(t, map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "init": api.DeprecatedAppArmorAnnotationValueRuntimeDefault,
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": api.DeprecatedAppArmorAnnotationValueRuntimeDefault,
|
||||
}, pod.Annotations)
|
||||
},
|
||||
}, {
|
||||
description: "Pod field localhost and no annotation present",
|
||||
pod: &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
SecurityContext: &api.PodSecurityContext{
|
||||
AppArmorProfile: &api.AppArmorProfile{
|
||||
Type: api.AppArmorProfileTypeLocalhost,
|
||||
LocalhostProfile: &testProfile,
|
||||
},
|
||||
},
|
||||
InitContainers: []api.Container{{Name: "init"}},
|
||||
Containers: []api.Container{{Name: "ctr"}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
assert.Equal(t, map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "init": api.DeprecatedAppArmorAnnotationValueLocalhostPrefix + testProfile,
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": api.DeprecatedAppArmorAnnotationValueLocalhostPrefix + testProfile,
|
||||
}, pod.Annotations)
|
||||
},
|
||||
}, {
|
||||
description: "Pod field localhost but profile is nil",
|
||||
pod: &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
SecurityContext: &api.PodSecurityContext{
|
||||
AppArmorProfile: &api.AppArmorProfile{
|
||||
Type: api.AppArmorProfileTypeLocalhost,
|
||||
},
|
||||
},
|
||||
InitContainers: []api.Container{{Name: "init"}},
|
||||
Containers: []api.Container{{Name: "ctr"}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
assert.Len(t, pod.Annotations, 0)
|
||||
},
|
||||
}, {
|
||||
description: "Container security context not nil",
|
||||
pod: &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{{
|
||||
Name: "ctr",
|
||||
SecurityContext: &api.SecurityContext{},
|
||||
}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
assert.Len(t, pod.Annotations, 0)
|
||||
},
|
||||
}, {
|
||||
description: "Container field RuntimeDefault and no annotation present",
|
||||
pod: &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{{
|
||||
Name: "ctr",
|
||||
SecurityContext: &api.SecurityContext{
|
||||
AppArmorProfile: &api.AppArmorProfile{
|
||||
Type: api.AppArmorProfileTypeRuntimeDefault,
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
assert.Equal(t, map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": api.DeprecatedAppArmorAnnotationValueRuntimeDefault,
|
||||
}, pod.Annotations)
|
||||
assert.Nil(t, pod.Spec.SecurityContext)
|
||||
assert.Equal(t, api.AppArmorProfileTypeRuntimeDefault, pod.Spec.Containers[0].SecurityContext.AppArmorProfile.Type)
|
||||
},
|
||||
}, {
|
||||
description: "Container field localhost and no annotation present",
|
||||
pod: &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{{
|
||||
Name: "ctr",
|
||||
SecurityContext: &api.SecurityContext{
|
||||
AppArmorProfile: &api.AppArmorProfile{
|
||||
Type: api.AppArmorProfileTypeLocalhost,
|
||||
LocalhostProfile: &testProfile,
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
assert.Equal(t, map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": api.DeprecatedAppArmorAnnotationValueLocalhostPrefix + testProfile,
|
||||
}, pod.Annotations)
|
||||
assert.Nil(t, pod.Spec.SecurityContext)
|
||||
assert.Equal(t, api.AppArmorProfileTypeLocalhost, pod.Spec.Containers[0].SecurityContext.AppArmorProfile.Type)
|
||||
},
|
||||
}, {
|
||||
description: "Container overrides pod profile",
|
||||
pod: &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
SecurityContext: &api.PodSecurityContext{
|
||||
AppArmorProfile: &api.AppArmorProfile{
|
||||
Type: api.AppArmorProfileTypeRuntimeDefault,
|
||||
},
|
||||
},
|
||||
Containers: []api.Container{{
|
||||
Name: "ctr",
|
||||
SecurityContext: &api.SecurityContext{
|
||||
AppArmorProfile: &api.AppArmorProfile{
|
||||
Type: api.AppArmorProfileTypeUnconfined,
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
assert.Equal(t, map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": api.DeprecatedAppArmorAnnotationValueUnconfined,
|
||||
}, pod.Annotations)
|
||||
assert.Equal(t, api.AppArmorProfileTypeRuntimeDefault, pod.Spec.SecurityContext.AppArmorProfile.Type)
|
||||
assert.Equal(t, api.AppArmorProfileTypeUnconfined, pod.Spec.Containers[0].SecurityContext.AppArmorProfile.Type)
|
||||
},
|
||||
}, {
|
||||
description: "Multiple containers with fields (container)",
|
||||
pod: &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
InitContainers: []api.Container{{
|
||||
Name: "init",
|
||||
SecurityContext: &api.SecurityContext{
|
||||
AppArmorProfile: &api.AppArmorProfile{
|
||||
Type: api.AppArmorProfileTypeLocalhost,
|
||||
LocalhostProfile: &testProfile,
|
||||
},
|
||||
},
|
||||
}},
|
||||
Containers: []api.Container{{
|
||||
Name: "a",
|
||||
SecurityContext: &api.SecurityContext{
|
||||
AppArmorProfile: &api.AppArmorProfile{
|
||||
Type: api.AppArmorProfileTypeUnconfined,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
Name: "b",
|
||||
}, {
|
||||
Name: "c",
|
||||
SecurityContext: &api.SecurityContext{
|
||||
AppArmorProfile: &api.AppArmorProfile{
|
||||
Type: api.AppArmorProfileTypeRuntimeDefault,
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
assert.Equal(t, map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "init": api.DeprecatedAppArmorAnnotationValueLocalhostPrefix + testProfile,
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "a": api.DeprecatedAppArmorAnnotationValueUnconfined,
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "c": api.DeprecatedAppArmorAnnotationValueRuntimeDefault,
|
||||
}, pod.Annotations)
|
||||
assert.Nil(t, pod.Spec.SecurityContext)
|
||||
assert.Equal(t, api.AppArmorProfileTypeLocalhost, pod.Spec.InitContainers[0].SecurityContext.AppArmorProfile.Type)
|
||||
assert.Equal(t, api.AppArmorProfileTypeUnconfined, pod.Spec.Containers[0].SecurityContext.AppArmorProfile.Type)
|
||||
assert.Nil(t, pod.Spec.Containers[1].SecurityContext)
|
||||
assert.Equal(t, api.AppArmorProfileTypeRuntimeDefault, pod.Spec.Containers[2].SecurityContext.AppArmorProfile.Type)
|
||||
},
|
||||
}, {
|
||||
description: "Annotation 'unconfined' and no fields present",
|
||||
pod: &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": api.DeprecatedAppArmorAnnotationValueUnconfined,
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{{Name: "ctr"}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
assert.Equal(t, map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": api.DeprecatedAppArmorAnnotationValueUnconfined,
|
||||
}, pod.Annotations)
|
||||
assert.Equal(t, api.AppArmorProfileTypeUnconfined, pod.Spec.Containers[0].SecurityContext.AppArmorProfile.Type)
|
||||
assert.Nil(t, pod.Spec.Containers[0].SecurityContext.AppArmorProfile.LocalhostProfile)
|
||||
assert.Nil(t, pod.Spec.SecurityContext)
|
||||
},
|
||||
}, {
|
||||
description: "Annotation for non-existent container",
|
||||
pod: &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "foo-bar": api.DeprecatedAppArmorAnnotationValueUnconfined,
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{{Name: "ctr"}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
assert.Equal(t, map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "foo-bar": api.DeprecatedAppArmorAnnotationValueUnconfined,
|
||||
}, pod.Annotations)
|
||||
assert.Nil(t, pod.Spec.Containers[0].SecurityContext)
|
||||
assert.Nil(t, pod.Spec.SecurityContext)
|
||||
},
|
||||
}, {
|
||||
description: "Annotation 'runtime/default' and no fields present",
|
||||
pod: &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": api.DeprecatedAppArmorAnnotationValueRuntimeDefault,
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
SecurityContext: &api.PodSecurityContext{
|
||||
AppArmorProfile: &api.AppArmorProfile{
|
||||
Type: api.AppArmorProfileTypeUnconfined,
|
||||
},
|
||||
},
|
||||
Containers: []api.Container{{
|
||||
Name: "ctr",
|
||||
SecurityContext: &api.SecurityContext{},
|
||||
}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
assert.Equal(t, map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": api.DeprecatedAppArmorAnnotationValueRuntimeDefault,
|
||||
}, pod.Annotations)
|
||||
assert.Equal(t, api.AppArmorProfileTypeRuntimeDefault, pod.Spec.Containers[0].SecurityContext.AppArmorProfile.Type)
|
||||
assert.Nil(t, pod.Spec.Containers[0].SecurityContext.AppArmorProfile.LocalhostProfile)
|
||||
assert.Equal(t, api.AppArmorProfileTypeUnconfined, pod.Spec.SecurityContext.AppArmorProfile.Type)
|
||||
},
|
||||
}, {
|
||||
description: "Multiple containers by annotations",
|
||||
pod: &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "init": api.DeprecatedAppArmorAnnotationValueUnconfined,
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "a": api.DeprecatedAppArmorAnnotationValueLocalhostPrefix + testProfile,
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "c": api.DeprecatedAppArmorAnnotationValueRuntimeDefault,
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
SecurityContext: &api.PodSecurityContext{
|
||||
AppArmorProfile: &api.AppArmorProfile{
|
||||
Type: api.AppArmorProfileTypeRuntimeDefault,
|
||||
},
|
||||
},
|
||||
InitContainers: []api.Container{{Name: "init"}},
|
||||
Containers: []api.Container{
|
||||
{Name: "a"},
|
||||
{Name: "b"},
|
||||
{Name: "c"},
|
||||
},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
assert.Equal(t, map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "init": api.DeprecatedAppArmorAnnotationValueUnconfined,
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "a": api.DeprecatedAppArmorAnnotationValueLocalhostPrefix + testProfile,
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "b": api.DeprecatedAppArmorAnnotationValueRuntimeDefault,
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "c": api.DeprecatedAppArmorAnnotationValueRuntimeDefault,
|
||||
}, pod.Annotations)
|
||||
assert.Equal(t, api.AppArmorProfileTypeUnconfined, pod.Spec.InitContainers[0].SecurityContext.AppArmorProfile.Type)
|
||||
assert.Equal(t, api.AppArmorProfileTypeLocalhost, pod.Spec.Containers[0].SecurityContext.AppArmorProfile.Type)
|
||||
assert.Equal(t, testProfile, *pod.Spec.Containers[0].SecurityContext.AppArmorProfile.LocalhostProfile)
|
||||
assert.Nil(t, pod.Spec.Containers[1].SecurityContext)
|
||||
assert.Nil(t, pod.Spec.Containers[2].SecurityContext)
|
||||
assert.Equal(t, api.AppArmorProfileTypeRuntimeDefault, pod.Spec.SecurityContext.AppArmorProfile.Type)
|
||||
},
|
||||
}, {
|
||||
description: "Conflicting field and annotations",
|
||||
pod: &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": api.DeprecatedAppArmorAnnotationValueLocalhostPrefix + testProfile,
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{{
|
||||
Name: "ctr",
|
||||
SecurityContext: &api.SecurityContext{
|
||||
AppArmorProfile: &api.AppArmorProfile{
|
||||
Type: api.AppArmorProfileTypeRuntimeDefault,
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
assert.Equal(t, map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": api.DeprecatedAppArmorAnnotationValueLocalhostPrefix + testProfile,
|
||||
}, pod.Annotations)
|
||||
assert.Equal(t, api.AppArmorProfileTypeRuntimeDefault, pod.Spec.Containers[0].SecurityContext.AppArmorProfile.Type)
|
||||
assert.Nil(t, pod.Spec.Containers[0].SecurityContext.AppArmorProfile.LocalhostProfile)
|
||||
assert.Nil(t, pod.Spec.SecurityContext)
|
||||
},
|
||||
}, {
|
||||
description: "Pod field and matching annotations",
|
||||
pod: &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": api.DeprecatedAppArmorAnnotationValueRuntimeDefault,
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
SecurityContext: &api.PodSecurityContext{
|
||||
AppArmorProfile: &api.AppArmorProfile{
|
||||
Type: api.AppArmorProfileTypeRuntimeDefault,
|
||||
},
|
||||
},
|
||||
Containers: []api.Container{{
|
||||
Name: "ctr",
|
||||
}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
assert.Equal(t, map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": api.DeprecatedAppArmorAnnotationValueRuntimeDefault,
|
||||
}, pod.Annotations)
|
||||
assert.Equal(t, api.AppArmorProfileTypeRuntimeDefault, pod.Spec.SecurityContext.AppArmorProfile.Type)
|
||||
// Annotation shouldn't be synced to container security context
|
||||
assert.Nil(t, pod.Spec.Containers[0].SecurityContext)
|
||||
},
|
||||
}, {
|
||||
description: "Annotation overrides pod field",
|
||||
pod: &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": api.DeprecatedAppArmorAnnotationValueUnconfined,
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
SecurityContext: &api.PodSecurityContext{
|
||||
AppArmorProfile: &api.AppArmorProfile{
|
||||
Type: api.AppArmorProfileTypeRuntimeDefault,
|
||||
},
|
||||
},
|
||||
Containers: []api.Container{{
|
||||
Name: "ctr",
|
||||
}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
assert.Equal(t, map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": api.DeprecatedAppArmorAnnotationValueUnconfined,
|
||||
}, pod.Annotations)
|
||||
assert.Equal(t, api.AppArmorProfileTypeRuntimeDefault, pod.Spec.SecurityContext.AppArmorProfile.Type)
|
||||
assert.Equal(t, api.AppArmorProfileTypeUnconfined, pod.Spec.Containers[0].SecurityContext.AppArmorProfile.Type)
|
||||
},
|
||||
}, {
|
||||
description: "Mixed annotations and fields",
|
||||
pod: &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "unconf-annot": api.DeprecatedAppArmorAnnotationValueUnconfined,
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
SecurityContext: &api.PodSecurityContext{
|
||||
AppArmorProfile: &api.AppArmorProfile{
|
||||
Type: api.AppArmorProfileTypeRuntimeDefault,
|
||||
},
|
||||
},
|
||||
Containers: []api.Container{{
|
||||
Name: "unconf-annot",
|
||||
}, {
|
||||
Name: "unconf-field",
|
||||
SecurityContext: &api.SecurityContext{
|
||||
AppArmorProfile: &api.AppArmorProfile{
|
||||
Type: api.AppArmorProfileTypeUnconfined,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
Name: "default-pod",
|
||||
}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
assert.Equal(t, map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "unconf-annot": api.DeprecatedAppArmorAnnotationValueUnconfined,
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "unconf-field": api.DeprecatedAppArmorAnnotationValueUnconfined,
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "default-pod": api.DeprecatedAppArmorAnnotationValueRuntimeDefault,
|
||||
}, pod.Annotations)
|
||||
assert.Equal(t, api.AppArmorProfileTypeRuntimeDefault, pod.Spec.SecurityContext.AppArmorProfile.Type)
|
||||
assert.Equal(t, api.AppArmorProfileTypeUnconfined, pod.Spec.Containers[0].SecurityContext.AppArmorProfile.Type)
|
||||
assert.Equal(t, api.AppArmorProfileTypeUnconfined, pod.Spec.Containers[1].SecurityContext.AppArmorProfile.Type)
|
||||
assert.Nil(t, pod.Spec.Containers[2].SecurityContext)
|
||||
},
|
||||
}, {
|
||||
description: "Invalid annotation value",
|
||||
pod: &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": "not-a-real-type",
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{{Name: "ctr"}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
assert.Equal(t, map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": "not-a-real-type",
|
||||
}, pod.Annotations)
|
||||
assert.Nil(t, pod.Spec.Containers[0].SecurityContext)
|
||||
assert.Nil(t, pod.Spec.SecurityContext)
|
||||
},
|
||||
}, {
|
||||
description: "Invalid localhost annotation",
|
||||
pod: &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": api.DeprecatedAppArmorAnnotationValueLocalhostPrefix + strings.Repeat("a", 4096),
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{{Name: "ctr"}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
assert.Contains(t, pod.Annotations, api.DeprecatedAppArmorAnnotationKeyPrefix+"ctr")
|
||||
assert.Nil(t, pod.Spec.Containers[0].SecurityContext)
|
||||
assert.Nil(t, pod.Spec.SecurityContext)
|
||||
},
|
||||
}, {
|
||||
description: "Invalid field type",
|
||||
pod: &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
SecurityContext: &api.PodSecurityContext{
|
||||
AppArmorProfile: &api.AppArmorProfile{
|
||||
Type: "invalid-type",
|
||||
},
|
||||
},
|
||||
Containers: []api.Container{{Name: "ctr"}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
assert.Empty(t, pod.Annotations)
|
||||
assert.Nil(t, pod.Spec.Containers[0].SecurityContext)
|
||||
},
|
||||
}, {
|
||||
description: "Ignore annotations on windows",
|
||||
pod: &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": api.DeprecatedAppArmorAnnotationValueRuntimeDefault,
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
OS: &api.PodOS{Name: api.Windows},
|
||||
Containers: []api.Container{{Name: "ctr"}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
assert.Equal(t, map[string]string{
|
||||
api.DeprecatedAppArmorAnnotationKeyPrefix + "ctr": api.DeprecatedAppArmorAnnotationValueRuntimeDefault,
|
||||
}, pod.Annotations)
|
||||
assert.Nil(t, pod.Spec.Containers[0].SecurityContext)
|
||||
},
|
||||
}}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.description, func(t *testing.T) {
|
||||
applyAppArmorVersionSkew(test.pod)
|
||||
test.validation(t, test.pod)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,26 +19,87 @@ package apparmor
|
|||
import (
|
||||
"strings"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
)
|
||||
|
||||
// Checks whether app armor is required for pod to be run.
|
||||
// Checks whether app armor is required for the pod to run. AppArmor is considered required if any
|
||||
// non-unconfined profiles are specified.
|
||||
func isRequired(pod *v1.Pod) bool {
|
||||
if pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.AppArmorProfile != nil &&
|
||||
pod.Spec.SecurityContext.AppArmorProfile.Type != v1.AppArmorProfileTypeUnconfined {
|
||||
return true
|
||||
}
|
||||
|
||||
inUse := !podutil.VisitContainers(&pod.Spec, podutil.AllContainers, func(c *v1.Container, _ podutil.ContainerType) bool {
|
||||
if c.SecurityContext != nil && c.SecurityContext.AppArmorProfile != nil &&
|
||||
c.SecurityContext.AppArmorProfile.Type != v1.AppArmorProfileTypeUnconfined {
|
||||
return false // is in use; short-circuit
|
||||
}
|
||||
return true
|
||||
})
|
||||
if inUse {
|
||||
return true
|
||||
}
|
||||
|
||||
for key, value := range pod.Annotations {
|
||||
if strings.HasPrefix(key, v1.AppArmorBetaContainerAnnotationKeyPrefix) {
|
||||
return value != v1.AppArmorBetaProfileNameUnconfined
|
||||
if strings.HasPrefix(key, v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix) {
|
||||
return value != v1.DeprecatedAppArmorBetaProfileNameUnconfined
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetProfileName returns the name of the profile to use with the container.
|
||||
func GetProfileName(pod *v1.Pod, containerName string) string {
|
||||
return GetProfileNameFromPodAnnotations(pod.Annotations, containerName)
|
||||
func GetProfile(pod *v1.Pod, container *v1.Container) *v1.AppArmorProfile {
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.AppArmorFields) {
|
||||
return getProfileFromPodAnnotations(pod.Annotations, container.Name)
|
||||
}
|
||||
|
||||
if container.SecurityContext != nil && container.SecurityContext.AppArmorProfile != nil {
|
||||
return container.SecurityContext.AppArmorProfile
|
||||
}
|
||||
|
||||
// Static pods may not have had annotations synced to fields, so fallback to annotations before
|
||||
// the pod profile.
|
||||
if profile := getProfileFromPodAnnotations(pod.Annotations, container.Name); profile != nil {
|
||||
return profile
|
||||
}
|
||||
|
||||
if pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.AppArmorProfile != nil {
|
||||
return pod.Spec.SecurityContext.AppArmorProfile
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetProfileNameFromPodAnnotations gets the name of the profile to use with container from
|
||||
// pod annotations
|
||||
func GetProfileNameFromPodAnnotations(annotations map[string]string, containerName string) string {
|
||||
return annotations[v1.AppArmorBetaContainerAnnotationKeyPrefix+containerName]
|
||||
// getProfileFromPodAnnotations gets the AppArmor profile to use with container from
|
||||
// (deprecated) pod annotations.
|
||||
func getProfileFromPodAnnotations(annotations map[string]string, containerName string) *v1.AppArmorProfile {
|
||||
val, ok := annotations[v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix+containerName]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch {
|
||||
case val == v1.DeprecatedAppArmorBetaProfileRuntimeDefault:
|
||||
return &v1.AppArmorProfile{Type: v1.AppArmorProfileTypeRuntimeDefault}
|
||||
|
||||
case val == v1.DeprecatedAppArmorBetaProfileNameUnconfined:
|
||||
return &v1.AppArmorProfile{Type: v1.AppArmorProfileTypeUnconfined}
|
||||
|
||||
case strings.HasPrefix(val, v1.DeprecatedAppArmorBetaProfileNamePrefix):
|
||||
// Note: an invalid empty localhost profile will be rejected by kubelet admission.
|
||||
profileName := strings.TrimPrefix(val, v1.DeprecatedAppArmorBetaProfileNamePrefix)
|
||||
return &v1.AppArmorProfile{
|
||||
Type: v1.AppArmorProfileTypeLocalhost,
|
||||
LocalhostProfile: &profileName,
|
||||
}
|
||||
|
||||
default:
|
||||
// Invalid annotation.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
|||
124
pkg/security/apparmor/helpers_test.go
Normal file
124
pkg/security/apparmor/helpers_test.go
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
Copyright 2024 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package apparmor
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/utils/ptr"
|
||||
)
|
||||
|
||||
func TestGetProfile(t *testing.T) {
|
||||
runtimeDefault := &v1.AppArmorProfile{Type: v1.AppArmorProfileTypeRuntimeDefault}
|
||||
unconfined := &v1.AppArmorProfile{Type: v1.AppArmorProfileTypeUnconfined}
|
||||
localhost := &v1.AppArmorProfile{
|
||||
Type: v1.AppArmorProfileTypeLocalhost,
|
||||
LocalhostProfile: ptr.To("test"),
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
annotationProfile string
|
||||
containerProfile *v1.AppArmorProfile
|
||||
podProfile *v1.AppArmorProfile
|
||||
expectedProfile *v1.AppArmorProfile
|
||||
}{{
|
||||
name: "no appArmor",
|
||||
expectedProfile: nil,
|
||||
}, {
|
||||
name: "pod profile",
|
||||
podProfile: runtimeDefault,
|
||||
expectedProfile: runtimeDefault,
|
||||
}, {
|
||||
name: "container profile",
|
||||
containerProfile: unconfined,
|
||||
expectedProfile: unconfined,
|
||||
}, {
|
||||
name: "annotation profile",
|
||||
annotationProfile: v1.DeprecatedAppArmorBetaProfileNamePrefix + "test",
|
||||
expectedProfile: localhost,
|
||||
}, {
|
||||
name: "invalid annotation",
|
||||
annotationProfile: "invalid",
|
||||
expectedProfile: nil,
|
||||
}, {
|
||||
name: "invalid annotation with pod field",
|
||||
annotationProfile: "invalid",
|
||||
podProfile: runtimeDefault,
|
||||
expectedProfile: runtimeDefault,
|
||||
}, {
|
||||
name: "container field before annotation",
|
||||
annotationProfile: v1.DeprecatedAppArmorBetaProfileNameUnconfined,
|
||||
containerProfile: runtimeDefault,
|
||||
expectedProfile: runtimeDefault,
|
||||
}, {
|
||||
name: "container field before pod field",
|
||||
containerProfile: runtimeDefault,
|
||||
podProfile: unconfined,
|
||||
expectedProfile: runtimeDefault,
|
||||
}, {
|
||||
name: "annotation before pod field",
|
||||
annotationProfile: v1.DeprecatedAppArmorBetaProfileNameUnconfined,
|
||||
podProfile: runtimeDefault,
|
||||
expectedProfile: unconfined,
|
||||
}, {
|
||||
name: "all profiles",
|
||||
annotationProfile: v1.DeprecatedAppArmorBetaProfileRuntimeDefault,
|
||||
containerProfile: localhost,
|
||||
podProfile: unconfined,
|
||||
expectedProfile: localhost,
|
||||
}}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
container := v1.Container{
|
||||
Name: "foo",
|
||||
}
|
||||
if test.containerProfile != nil {
|
||||
container.SecurityContext = &v1.SecurityContext{
|
||||
AppArmorProfile: test.containerProfile.DeepCopy(),
|
||||
}
|
||||
}
|
||||
pod := v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "bar",
|
||||
Annotations: map[string]string{
|
||||
"unrelated": "baz",
|
||||
v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "other": v1.DeprecatedAppArmorBetaProfileRuntimeDefault,
|
||||
},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{container},
|
||||
},
|
||||
}
|
||||
if test.annotationProfile != "" {
|
||||
pod.Annotations[v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix+container.Name] = test.annotationProfile
|
||||
}
|
||||
if test.podProfile != nil {
|
||||
pod.Spec.SecurityContext = &v1.PodSecurityContext{
|
||||
AppArmorProfile: test.podProfile.DeepCopy(),
|
||||
}
|
||||
}
|
||||
|
||||
actual := GetProfile(&pod, &container)
|
||||
assert.Equal(t, test.expectedProfile, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -25,7 +25,6 @@ import (
|
|||
v1 "k8s.io/api/core/v1"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
|
||||
"k8s.io/kubernetes/pkg/apis/core/validation"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
)
|
||||
|
||||
|
|
@ -62,15 +61,15 @@ func (v *validator) Validate(pod *v1.Pod) error {
|
|||
|
||||
var retErr error
|
||||
podutil.VisitContainers(&pod.Spec, podutil.AllContainers, func(container *v1.Container, containerType podutil.ContainerType) bool {
|
||||
profile := GetProfileName(pod, container.Name)
|
||||
retErr = validation.ValidateAppArmorProfileFormat(profile)
|
||||
if retErr != nil {
|
||||
return false
|
||||
profile := GetProfile(pod, container)
|
||||
if profile == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
// TODO(#64841): This would ideally be part of validation.ValidateAppArmorProfileFormat, but
|
||||
// that is called for API validation, and this is tightening validation.
|
||||
if strings.HasPrefix(profile, v1.AppArmorBetaProfileNamePrefix) {
|
||||
if strings.TrimSpace(strings.TrimPrefix(profile, v1.AppArmorBetaProfileNamePrefix)) == "" {
|
||||
if profile.Type == v1.AppArmorProfileTypeLocalhost {
|
||||
if profile.LocalhostProfile == nil || strings.TrimSpace(*profile.LocalhostProfile) == "" {
|
||||
retErr = fmt.Errorf("invalid empty AppArmor profile name: %q", profile)
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ func TestValidateBadHost(t *testing.T) {
|
|||
expectValid bool
|
||||
}{
|
||||
{"", true},
|
||||
{v1.AppArmorBetaProfileRuntimeDefault, false},
|
||||
{v1.AppArmorBetaProfileNamePrefix + "docker-default", false},
|
||||
{v1.DeprecatedAppArmorBetaProfileRuntimeDefault, false},
|
||||
{v1.DeprecatedAppArmorBetaProfileNamePrefix + "docker-default", false},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
|
@ -60,13 +60,12 @@ func TestValidateValidHost(t *testing.T) {
|
|||
expectValid bool
|
||||
}{
|
||||
{"", true},
|
||||
{v1.AppArmorBetaProfileRuntimeDefault, true},
|
||||
{v1.AppArmorBetaProfileNamePrefix + "docker-default", true},
|
||||
{v1.AppArmorBetaProfileNamePrefix + "foo-container", true},
|
||||
{v1.AppArmorBetaProfileNamePrefix + "/usr/sbin/ntpd", true},
|
||||
{"docker-default", false},
|
||||
{v1.AppArmorBetaProfileNamePrefix + "", false}, // Empty profile explicitly forbidden.
|
||||
{v1.AppArmorBetaProfileNamePrefix + " ", false},
|
||||
{v1.DeprecatedAppArmorBetaProfileRuntimeDefault, true},
|
||||
{v1.DeprecatedAppArmorBetaProfileNamePrefix + "docker-default", true},
|
||||
{v1.DeprecatedAppArmorBetaProfileNamePrefix + "foo-container", true},
|
||||
{v1.DeprecatedAppArmorBetaProfileNamePrefix + "/usr/sbin/ntpd", true},
|
||||
{v1.DeprecatedAppArmorBetaProfileNamePrefix + "", false}, // Empty profile explicitly forbidden.
|
||||
{v1.DeprecatedAppArmorBetaProfileNamePrefix + " ", false},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
|
@ -82,9 +81,9 @@ func TestValidateValidHost(t *testing.T) {
|
|||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
v1.AppArmorBetaContainerAnnotationKeyPrefix + "init": v1.AppArmorBetaProfileNamePrefix + "foo-container",
|
||||
v1.AppArmorBetaContainerAnnotationKeyPrefix + "test1": v1.AppArmorBetaProfileRuntimeDefault,
|
||||
v1.AppArmorBetaContainerAnnotationKeyPrefix + "test2": v1.AppArmorBetaProfileNamePrefix + "docker-default",
|
||||
v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "init": v1.DeprecatedAppArmorBetaProfileNamePrefix + "foo-container",
|
||||
v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "test1": v1.DeprecatedAppArmorBetaProfileRuntimeDefault,
|
||||
v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "test2": v1.DeprecatedAppArmorBetaProfileNamePrefix + "docker-default",
|
||||
},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
|
|
@ -103,7 +102,7 @@ func TestValidateValidHost(t *testing.T) {
|
|||
|
||||
func getPodWithProfile(profile string) *v1.Pod {
|
||||
annotations := map[string]string{
|
||||
v1.AppArmorBetaContainerAnnotationKeyPrefix + "test": profile,
|
||||
v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "test": profile,
|
||||
}
|
||||
if profile == "" {
|
||||
annotations = map[string]string{
|
||||
|
|
|
|||
|
|
@ -54,21 +54,18 @@ const (
|
|||
// SeccompLocalhostProfileNamePrefix is the prefix for specifying profiles loaded from the node's disk.
|
||||
SeccompLocalhostProfileNamePrefix = "localhost/"
|
||||
|
||||
// AppArmorBetaContainerAnnotationKeyPrefix is the prefix to an annotation key specifying a container's apparmor profile.
|
||||
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"
|
||||
// DeprecatedAppArmorBetaContainerAnnotationKeyPrefix is the prefix to an annotation key specifying a container's apparmor profile.
|
||||
// Deprecated: use a pod or container security context `appArmorProfile` field instead.
|
||||
DeprecatedAppArmorBetaContainerAnnotationKeyPrefix = "container.apparmor.security.beta.kubernetes.io/"
|
||||
|
||||
// AppArmorBetaProfileRuntimeDefault is the profile specifying the runtime default.
|
||||
AppArmorBetaProfileRuntimeDefault = "runtime/default"
|
||||
// DeprecatedAppArmorBetaProfileRuntimeDefault is the profile specifying the runtime default.
|
||||
DeprecatedAppArmorBetaProfileRuntimeDefault = "runtime/default"
|
||||
|
||||
// AppArmorBetaProfileNamePrefix is the prefix for specifying profiles loaded on the node.
|
||||
AppArmorBetaProfileNamePrefix = "localhost/"
|
||||
// DeprecatedAppArmorBetaProfileNamePrefix is the prefix for specifying profiles loaded on the node.
|
||||
DeprecatedAppArmorBetaProfileNamePrefix = "localhost/"
|
||||
|
||||
// AppArmorBetaProfileNameUnconfined is the Unconfined AppArmor profile
|
||||
AppArmorBetaProfileNameUnconfined = "unconfined"
|
||||
// DeprecatedAppArmorBetaProfileNameUnconfined is the Unconfined AppArmor profile
|
||||
DeprecatedAppArmorBetaProfileNameUnconfined = "unconfined"
|
||||
|
||||
// DeprecatedSeccompProfileDockerDefault represents the default seccomp profile used by docker.
|
||||
// Deprecated: set a pod or container security context `seccompProfile` of type "RuntimeDefault" instead.
|
||||
|
|
|
|||
2688
staging/src/k8s.io/api/core/v1/generated.pb.go
generated
2688
staging/src/k8s.io/api/core/v1/generated.pb.go
generated
File diff suppressed because it is too large
Load diff
|
|
@ -77,6 +77,25 @@ message Affinity {
|
|||
optional PodAntiAffinity podAntiAffinity = 3;
|
||||
}
|
||||
|
||||
// AppArmorProfile defines a pod or container's AppArmor settings.
|
||||
// +union
|
||||
message AppArmorProfile {
|
||||
// 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
|
||||
optional string type = 1;
|
||||
|
||||
// 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
|
||||
optional string localhostProfile = 2;
|
||||
}
|
||||
|
||||
// AttachedVolume describes a volume attached to a node
|
||||
message AttachedVolume {
|
||||
// Name of the attached volume
|
||||
|
|
@ -3866,6 +3885,11 @@ message PodSecurityContext {
|
|||
// Note that this field cannot be set when spec.os.name is windows.
|
||||
// +optional
|
||||
optional SeccompProfile seccompProfile = 10;
|
||||
|
||||
// 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
|
||||
optional AppArmorProfile appArmorProfile = 11;
|
||||
}
|
||||
|
||||
// Describes the class of pods that should avoid this node.
|
||||
|
|
@ -4154,6 +4178,7 @@ message PodSpec {
|
|||
// - spec.hostPID
|
||||
// - spec.hostIPC
|
||||
// - spec.hostUsers
|
||||
// - spec.securityContext.appArmorProfile
|
||||
// - spec.securityContext.seLinuxOptions
|
||||
// - spec.securityContext.seccompProfile
|
||||
// - spec.securityContext.fsGroup
|
||||
|
|
@ -4163,6 +4188,7 @@ message PodSpec {
|
|||
// - spec.securityContext.runAsUser
|
||||
// - spec.securityContext.runAsGroup
|
||||
// - spec.securityContext.supplementalGroups
|
||||
// - spec.containers[*].securityContext.appArmorProfile
|
||||
// - spec.containers[*].securityContext.seLinuxOptions
|
||||
// - spec.containers[*].securityContext.seccompProfile
|
||||
// - spec.containers[*].securityContext.capabilities
|
||||
|
|
@ -5343,6 +5369,12 @@ message SecurityContext {
|
|||
// Note that this field cannot be set when spec.os.name is windows.
|
||||
// +optional
|
||||
optional SeccompProfile seccompProfile = 11;
|
||||
|
||||
// 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
|
||||
optional AppArmorProfile appArmorProfile = 12;
|
||||
}
|
||||
|
||||
// SerializedReference is a reference to serialized object.
|
||||
|
|
|
|||
|
|
@ -3757,6 +3757,7 @@ type PodSpec struct {
|
|||
// - spec.hostPID
|
||||
// - spec.hostIPC
|
||||
// - spec.hostUsers
|
||||
// - spec.securityContext.appArmorProfile
|
||||
// - spec.securityContext.seLinuxOptions
|
||||
// - spec.securityContext.seccompProfile
|
||||
// - spec.securityContext.fsGroup
|
||||
|
|
@ -3766,6 +3767,7 @@ type PodSpec struct {
|
|||
// - spec.securityContext.runAsUser
|
||||
// - spec.securityContext.runAsGroup
|
||||
// - spec.securityContext.supplementalGroups
|
||||
// - spec.containers[*].securityContext.appArmorProfile
|
||||
// - spec.containers[*].securityContext.seLinuxOptions
|
||||
// - spec.containers[*].securityContext.seccompProfile
|
||||
// - spec.containers[*].securityContext.capabilities
|
||||
|
|
@ -4158,6 +4160,10 @@ type PodSecurityContext struct {
|
|||
// Note that this field cannot be set when spec.os.name is windows.
|
||||
// +optional
|
||||
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" protobuf:"bytes,11,opt,name=appArmorProfile"`
|
||||
}
|
||||
|
||||
// SeccompProfile defines a pod/container's seccomp profile settings.
|
||||
|
|
@ -4194,6 +4200,38 @@ const (
|
|||
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" protobuf:"bytes,1,opt,name=type,casttype=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 `json:"localhostProfile,omitempty" protobuf:"bytes,2,opt,name=localhostProfile"`
|
||||
}
|
||||
|
||||
// +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.
|
||||
// +enum
|
||||
type PodQOSClass string
|
||||
|
|
@ -7213,6 +7251,11 @@ type SecurityContext struct {
|
|||
// Note that this field cannot be set when spec.os.name is windows.
|
||||
// +optional
|
||||
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" protobuf:"bytes,12,opt,name=appArmorProfile"`
|
||||
}
|
||||
|
||||
// +enum
|
||||
|
|
|
|||
|
|
@ -50,6 +50,16 @@ func (Affinity) SwaggerDoc() map[string]string {
|
|||
return map_Affinity
|
||||
}
|
||||
|
||||
var map_AppArmorProfile = map[string]string{
|
||||
"": "AppArmorProfile defines a pod or container's AppArmor settings.",
|
||||
"type": "type indicates which kind of AppArmor profile will be applied. Valid options are:\n Localhost - a profile pre-loaded on the node.\n RuntimeDefault - the container runtime's default profile.\n Unconfined - no AppArmor enforcement.",
|
||||
"localhostProfile": "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\".",
|
||||
}
|
||||
|
||||
func (AppArmorProfile) SwaggerDoc() map[string]string {
|
||||
return map_AppArmorProfile
|
||||
}
|
||||
|
||||
var map_AttachedVolume = map[string]string{
|
||||
"": "AttachedVolume describes a volume attached to a node",
|
||||
"name": "Name of the attached volume",
|
||||
|
|
@ -1705,6 +1715,7 @@ var map_PodSecurityContext = map[string]string{
|
|||
"sysctls": "Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported sysctls (by the container runtime) might fail to launch. Note that this field cannot be set when spec.os.name is windows.",
|
||||
"fsGroupChangePolicy": "fsGroupChangePolicy defines behavior of changing ownership and permission of the volume before being exposed inside Pod. This field will only apply to volume types which support fsGroup based ownership(and permissions). It will have no effect on ephemeral volume types such as: secret, configmaps and emptydir. Valid values are \"OnRootMismatch\" and \"Always\". If not specified, \"Always\" is used. Note that this field cannot be set when spec.os.name is windows.",
|
||||
"seccompProfile": "The seccomp options to use by the containers in this pod. Note that this field cannot be set when spec.os.name is windows.",
|
||||
"appArmorProfile": "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.",
|
||||
}
|
||||
|
||||
func (PodSecurityContext) SwaggerDoc() map[string]string {
|
||||
|
|
@ -1757,7 +1768,7 @@ var map_PodSpec = map[string]string{
|
|||
"overhead": "Overhead represents the resource overhead associated with running a pod for a given RuntimeClass. This field will be autopopulated at admission time by the RuntimeClass admission controller. If the RuntimeClass admission controller is enabled, overhead must not be set in Pod create requests. The RuntimeClass admission controller will reject Pod create requests which have the overhead already set. If RuntimeClass is configured and selected in the PodSpec, Overhead will be set to the value defined in the corresponding RuntimeClass, otherwise it will remain unset and treated as zero. More info: https://git.k8s.io/enhancements/keps/sig-node/688-pod-overhead/README.md",
|
||||
"topologySpreadConstraints": "TopologySpreadConstraints describes how a group of pods ought to spread across topology domains. Scheduler will schedule pods in a way which abides by the constraints. All topologySpreadConstraints are ANDed.",
|
||||
"setHostnameAsFQDN": "If true the pod's hostname will be configured as the pod's FQDN, rather than the leaf name (the default). In Linux containers, this means setting the FQDN in the hostname field of the kernel (the nodename field of struct utsname). In Windows containers, this means setting the registry value of hostname for the registry key HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters to FQDN. If a pod does not have FQDN, this has no effect. Default to false.",
|
||||
"os": "Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup",
|
||||
"os": "Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.appArmorProfile - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.containers[*].securityContext.appArmorProfile - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup",
|
||||
"hostUsers": "Use the host's user namespace. Optional: Default to true. If set to true or not present, the pod will be run in the host user namespace, useful for when the pod needs a feature only available to the host user namespace, such as loading a kernel module with CAP_SYS_MODULE. When set to false, a new userns is created for the pod. Setting false is useful for mitigating container breakout vulnerabilities even allowing users to run their containers as root without actually having root privileges on the host. This field is alpha-level and is only honored by servers that enable the UserNamespacesSupport feature.",
|
||||
"schedulingGates": "SchedulingGates is an opaque list of values that if specified will block scheduling the pod. If schedulingGates is not empty, the pod will stay in the SchedulingGated state and the scheduler will not attempt to schedule the pod.\n\nSchedulingGates can only be set at pod creation time, and be removed only afterwards.",
|
||||
"resourceClaims": "ResourceClaims defines which ResourceClaims must be allocated and reserved before the Pod is allowed to start. The resources will be made available to those containers which consume them by name.\n\nThis is an alpha field and requires enabling the DynamicResourceAllocation feature gate.\n\nThis field is immutable.",
|
||||
|
|
@ -2274,6 +2285,7 @@ var map_SecurityContext = map[string]string{
|
|||
"allowPrivilegeEscalation": "AllowPrivilegeEscalation controls whether a process can gain more privileges than its parent process. This bool directly controls if the no_new_privs flag will be set on the container process. AllowPrivilegeEscalation is true always when the container is: 1) run as Privileged 2) has CAP_SYS_ADMIN Note that this field cannot be set when spec.os.name is windows.",
|
||||
"procMount": "procMount denotes the type of proc mount to use for the containers. The default is DefaultProcMount which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows.",
|
||||
"seccompProfile": "The seccomp options to use by this container. If seccomp options are provided at both the pod & container level, the container options override the pod options. Note that this field cannot be set when spec.os.name is windows.",
|
||||
"appArmorProfile": "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.",
|
||||
}
|
||||
|
||||
func (SecurityContext) SwaggerDoc() map[string]string {
|
||||
|
|
|
|||
|
|
@ -74,6 +74,27 @@ func (in *Affinity) DeepCopy() *Affinity {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AppArmorProfile) DeepCopyInto(out *AppArmorProfile) {
|
||||
*out = *in
|
||||
if in.LocalhostProfile != nil {
|
||||
in, out := &in.LocalhostProfile, &out.LocalhostProfile
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AppArmorProfile.
|
||||
func (in *AppArmorProfile) DeepCopy() *AppArmorProfile {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AppArmorProfile)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AttachedVolume) DeepCopyInto(out *AttachedVolume) {
|
||||
*out = *in
|
||||
|
|
@ -3998,6 +4019,11 @@ func (in *PodSecurityContext) DeepCopyInto(out *PodSecurityContext) {
|
|||
*out = new(SeccompProfile)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.AppArmorProfile != nil {
|
||||
in, out := &in.AppArmorProfile, &out.AppArmorProfile
|
||||
*out = new(AppArmorProfile)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -5388,6 +5414,11 @@ func (in *SecurityContext) DeepCopyInto(out *SecurityContext) {
|
|||
*out = new(SeccompProfile)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.AppArmorProfile != nil {
|
||||
in, out := &in.AppArmorProfile, &out.AppArmorProfile
|
||||
*out = new(AppArmorProfile)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -777,6 +777,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1067,6 +1071,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1357,6 +1365,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1410,6 +1422,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"imagePullSecrets": [
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -345,6 +345,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -556,6 +559,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -769,6 +775,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -856,6 +865,9 @@ spec:
|
|||
schedulingGates:
|
||||
- name: nameValue
|
||||
securityContext:
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
fsGroup: 5
|
||||
fsGroupChangePolicy: fsGroupChangePolicyValue
|
||||
runAsGroup: 6
|
||||
|
|
|
|||
|
|
@ -778,6 +778,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1068,6 +1072,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1358,6 +1366,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1411,6 +1423,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"imagePullSecrets": [
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -353,6 +353,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -564,6 +567,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -777,6 +783,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -864,6 +873,9 @@ spec:
|
|||
schedulingGates:
|
||||
- name: nameValue
|
||||
securityContext:
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
fsGroup: 5
|
||||
fsGroupChangePolicy: fsGroupChangePolicyValue
|
||||
runAsGroup: 6
|
||||
|
|
|
|||
|
|
@ -779,6 +779,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1069,6 +1073,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1359,6 +1367,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1412,6 +1424,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"imagePullSecrets": [
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -345,6 +345,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -556,6 +559,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -769,6 +775,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -856,6 +865,9 @@ spec:
|
|||
schedulingGates:
|
||||
- name: nameValue
|
||||
securityContext:
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
fsGroup: 5
|
||||
fsGroupChangePolicy: fsGroupChangePolicyValue
|
||||
runAsGroup: 6
|
||||
|
|
|
|||
|
|
@ -778,6 +778,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1068,6 +1072,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1358,6 +1366,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1411,6 +1423,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"imagePullSecrets": [
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -353,6 +353,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -564,6 +567,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -777,6 +783,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -864,6 +873,9 @@ spec:
|
|||
schedulingGates:
|
||||
- name: nameValue
|
||||
securityContext:
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
fsGroup: 5
|
||||
fsGroupChangePolicy: fsGroupChangePolicyValue
|
||||
runAsGroup: 6
|
||||
|
|
|
|||
|
|
@ -778,6 +778,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1068,6 +1072,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1358,6 +1366,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1411,6 +1423,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"imagePullSecrets": [
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -355,6 +355,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -566,6 +569,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -779,6 +785,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -866,6 +875,9 @@ spec:
|
|||
schedulingGates:
|
||||
- name: nameValue
|
||||
securityContext:
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
fsGroup: 5
|
||||
fsGroupChangePolicy: fsGroupChangePolicyValue
|
||||
runAsGroup: 6
|
||||
|
|
|
|||
|
|
@ -778,6 +778,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1068,6 +1072,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1358,6 +1366,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1411,6 +1423,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"imagePullSecrets": [
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -353,6 +353,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -564,6 +567,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -777,6 +783,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -864,6 +873,9 @@ spec:
|
|||
schedulingGates:
|
||||
- name: nameValue
|
||||
securityContext:
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
fsGroup: 5
|
||||
fsGroupChangePolicy: fsGroupChangePolicyValue
|
||||
runAsGroup: 6
|
||||
|
|
|
|||
|
|
@ -777,6 +777,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1067,6 +1071,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1357,6 +1365,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1410,6 +1422,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"imagePullSecrets": [
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -345,6 +345,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -556,6 +559,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -769,6 +775,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -856,6 +865,9 @@ spec:
|
|||
schedulingGates:
|
||||
- name: nameValue
|
||||
securityContext:
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
fsGroup: 5
|
||||
fsGroupChangePolicy: fsGroupChangePolicyValue
|
||||
runAsGroup: 6
|
||||
|
|
|
|||
|
|
@ -778,6 +778,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1068,6 +1072,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1358,6 +1366,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1411,6 +1423,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"imagePullSecrets": [
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -353,6 +353,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -564,6 +567,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -777,6 +783,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -864,6 +873,9 @@ spec:
|
|||
schedulingGates:
|
||||
- name: nameValue
|
||||
securityContext:
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
fsGroup: 5
|
||||
fsGroupChangePolicy: fsGroupChangePolicyValue
|
||||
runAsGroup: 6
|
||||
|
|
|
|||
|
|
@ -779,6 +779,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1069,6 +1073,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1359,6 +1367,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1412,6 +1424,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"imagePullSecrets": [
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -345,6 +345,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -556,6 +559,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -769,6 +775,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -856,6 +865,9 @@ spec:
|
|||
schedulingGates:
|
||||
- name: nameValue
|
||||
securityContext:
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
fsGroup: 5
|
||||
fsGroupChangePolicy: fsGroupChangePolicyValue
|
||||
runAsGroup: 6
|
||||
|
|
|
|||
|
|
@ -778,6 +778,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1068,6 +1072,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1358,6 +1366,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1411,6 +1423,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"imagePullSecrets": [
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -353,6 +353,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -564,6 +567,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -777,6 +783,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -864,6 +873,9 @@ spec:
|
|||
schedulingGates:
|
||||
- name: nameValue
|
||||
securityContext:
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
fsGroup: 5
|
||||
fsGroupChangePolicy: fsGroupChangePolicyValue
|
||||
runAsGroup: 6
|
||||
|
|
|
|||
|
|
@ -853,6 +853,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1143,6 +1147,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1433,6 +1441,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1486,6 +1498,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"imagePullSecrets": [
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -401,6 +401,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -612,6 +615,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -825,6 +831,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -912,6 +921,9 @@ spec:
|
|||
schedulingGates:
|
||||
- name: nameValue
|
||||
securityContext:
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
fsGroup: 5
|
||||
fsGroupChangePolicy: fsGroupChangePolicyValue
|
||||
runAsGroup: 6
|
||||
|
|
|
|||
|
|
@ -804,6 +804,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1094,6 +1098,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1384,6 +1392,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1437,6 +1449,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"imagePullSecrets": [
|
||||
|
|
|
|||
BIN
staging/src/k8s.io/api/testdata/HEAD/batch.v1.Job.pb
vendored
BIN
staging/src/k8s.io/api/testdata/HEAD/batch.v1.Job.pb
vendored
Binary file not shown.
|
|
@ -365,6 +365,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -576,6 +579,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -789,6 +795,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -876,6 +885,9 @@ spec:
|
|||
schedulingGates:
|
||||
- name: nameValue
|
||||
securityContext:
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
fsGroup: 5
|
||||
fsGroupChangePolicy: fsGroupChangePolicyValue
|
||||
runAsGroup: 6
|
||||
|
|
|
|||
|
|
@ -853,6 +853,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1143,6 +1147,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1433,6 +1441,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1486,6 +1498,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"imagePullSecrets": [
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -401,6 +401,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -612,6 +615,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -825,6 +831,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -912,6 +921,9 @@ spec:
|
|||
schedulingGates:
|
||||
- name: nameValue
|
||||
securityContext:
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
fsGroup: 5
|
||||
fsGroupChangePolicy: fsGroupChangePolicyValue
|
||||
runAsGroup: 6
|
||||
|
|
|
|||
|
|
@ -719,6 +719,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1009,6 +1013,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1299,6 +1307,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1352,6 +1364,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"imagePullSecrets": [
|
||||
|
|
|
|||
BIN
staging/src/k8s.io/api/testdata/HEAD/core.v1.Pod.pb
vendored
BIN
staging/src/k8s.io/api/testdata/HEAD/core.v1.Pod.pb
vendored
Binary file not shown.
|
|
@ -301,6 +301,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -512,6 +515,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -725,6 +731,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -812,6 +821,9 @@ spec:
|
|||
schedulingGates:
|
||||
- name: nameValue
|
||||
securityContext:
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
fsGroup: 5
|
||||
fsGroupChangePolicy: fsGroupChangePolicyValue
|
||||
runAsGroup: 6
|
||||
|
|
|
|||
|
|
@ -762,6 +762,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1052,6 +1056,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1342,6 +1350,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1395,6 +1407,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"imagePullSecrets": [
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -334,6 +334,9 @@ template:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -545,6 +548,9 @@ template:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -758,6 +764,9 @@ template:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -845,6 +854,9 @@ template:
|
|||
schedulingGates:
|
||||
- name: nameValue
|
||||
securityContext:
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
fsGroup: 5
|
||||
fsGroupChangePolicy: fsGroupChangePolicyValue
|
||||
runAsGroup: 6
|
||||
|
|
|
|||
|
|
@ -768,6 +768,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1058,6 +1062,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1348,6 +1356,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1401,6 +1413,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"imagePullSecrets": [
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -339,6 +339,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -550,6 +553,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -763,6 +769,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -850,6 +859,9 @@ spec:
|
|||
schedulingGates:
|
||||
- name: nameValue
|
||||
securityContext:
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
fsGroup: 5
|
||||
fsGroupChangePolicy: fsGroupChangePolicyValue
|
||||
runAsGroup: 6
|
||||
|
|
|
|||
|
|
@ -777,6 +777,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1067,6 +1071,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1357,6 +1365,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1410,6 +1422,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"imagePullSecrets": [
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -345,6 +345,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -556,6 +559,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -769,6 +775,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -856,6 +865,9 @@ spec:
|
|||
schedulingGates:
|
||||
- name: nameValue
|
||||
securityContext:
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
fsGroup: 5
|
||||
fsGroupChangePolicy: fsGroupChangePolicyValue
|
||||
runAsGroup: 6
|
||||
|
|
|
|||
|
|
@ -778,6 +778,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1068,6 +1072,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1358,6 +1366,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1411,6 +1423,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"imagePullSecrets": [
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -355,6 +355,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -566,6 +569,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -779,6 +785,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -866,6 +875,9 @@ spec:
|
|||
schedulingGates:
|
||||
- name: nameValue
|
||||
securityContext:
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
fsGroup: 5
|
||||
fsGroupChangePolicy: fsGroupChangePolicyValue
|
||||
runAsGroup: 6
|
||||
|
|
|
|||
|
|
@ -779,6 +779,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1069,6 +1073,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1359,6 +1367,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"stdin": true,
|
||||
|
|
@ -1412,6 +1424,10 @@
|
|||
"seccompProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
},
|
||||
"appArmorProfile": {
|
||||
"type": "typeValue",
|
||||
"localhostProfile": "localhostProfileValue"
|
||||
}
|
||||
},
|
||||
"imagePullSecrets": [
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -345,6 +345,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -556,6 +559,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -769,6 +775,9 @@ spec:
|
|||
restartPolicy: restartPolicyValue
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
capabilities:
|
||||
add:
|
||||
- addValue
|
||||
|
|
@ -856,6 +865,9 @@ spec:
|
|||
schedulingGates:
|
||||
- name: nameValue
|
||||
securityContext:
|
||||
appArmorProfile:
|
||||
localhostProfile: localhostProfileValue
|
||||
type: typeValue
|
||||
fsGroup: 5
|
||||
fsGroupChangePolicy: fsGroupChangePolicyValue
|
||||
runAsGroup: 6
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ status:
|
|||
type: PIDPressure
|
||||
- lastHeartbeatTime: "2019-09-20T19:32:50Z"
|
||||
lastTransitionTime: "2019-07-09T16:17:49Z"
|
||||
message: kubelet is posting ready status. AppArmor enabled
|
||||
message: kubelet is posting ready status
|
||||
reason: KubeletReady
|
||||
status: "True"
|
||||
type: Ready
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ status:
|
|||
type: PIDPressure
|
||||
- lastHeartbeatTime: "2019-09-20T19:32:50Z"
|
||||
lastTransitionTime: "2019-07-09T16:17:49Z"
|
||||
message: kubelet is posting ready status. AppArmor enabled
|
||||
message: kubelet is posting ready status
|
||||
reason: KubeletReady
|
||||
status: "True"
|
||||
type: Ready
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by applyconfiguration-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
v1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
// AppArmorProfileApplyConfiguration represents an declarative configuration of the AppArmorProfile type for use
|
||||
// with apply.
|
||||
type AppArmorProfileApplyConfiguration struct {
|
||||
Type *v1.AppArmorProfileType `json:"type,omitempty"`
|
||||
LocalhostProfile *string `json:"localhostProfile,omitempty"`
|
||||
}
|
||||
|
||||
// AppArmorProfileApplyConfiguration constructs an declarative configuration of the AppArmorProfile type for use with
|
||||
// apply.
|
||||
func AppArmorProfile() *AppArmorProfileApplyConfiguration {
|
||||
return &AppArmorProfileApplyConfiguration{}
|
||||
}
|
||||
|
||||
// WithType sets the Type field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the Type field is set to the value of the last call.
|
||||
func (b *AppArmorProfileApplyConfiguration) WithType(value v1.AppArmorProfileType) *AppArmorProfileApplyConfiguration {
|
||||
b.Type = &value
|
||||
return b
|
||||
}
|
||||
|
||||
// WithLocalhostProfile sets the LocalhostProfile field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the LocalhostProfile field is set to the value of the last call.
|
||||
func (b *AppArmorProfileApplyConfiguration) WithLocalhostProfile(value string) *AppArmorProfileApplyConfiguration {
|
||||
b.LocalhostProfile = &value
|
||||
return b
|
||||
}
|
||||
|
|
@ -35,6 +35,7 @@ type PodSecurityContextApplyConfiguration struct {
|
|||
Sysctls []SysctlApplyConfiguration `json:"sysctls,omitempty"`
|
||||
FSGroupChangePolicy *corev1.PodFSGroupChangePolicy `json:"fsGroupChangePolicy,omitempty"`
|
||||
SeccompProfile *SeccompProfileApplyConfiguration `json:"seccompProfile,omitempty"`
|
||||
AppArmorProfile *AppArmorProfileApplyConfiguration `json:"appArmorProfile,omitempty"`
|
||||
}
|
||||
|
||||
// PodSecurityContextApplyConfiguration constructs an declarative configuration of the PodSecurityContext type for use with
|
||||
|
|
@ -129,3 +130,11 @@ func (b *PodSecurityContextApplyConfiguration) WithSeccompProfile(value *Seccomp
|
|||
b.SeccompProfile = value
|
||||
return b
|
||||
}
|
||||
|
||||
// WithAppArmorProfile sets the AppArmorProfile field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the AppArmorProfile field is set to the value of the last call.
|
||||
func (b *PodSecurityContextApplyConfiguration) WithAppArmorProfile(value *AppArmorProfileApplyConfiguration) *PodSecurityContextApplyConfiguration {
|
||||
b.AppArmorProfile = value
|
||||
return b
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ type SecurityContextApplyConfiguration struct {
|
|||
AllowPrivilegeEscalation *bool `json:"allowPrivilegeEscalation,omitempty"`
|
||||
ProcMount *corev1.ProcMountType `json:"procMount,omitempty"`
|
||||
SeccompProfile *SeccompProfileApplyConfiguration `json:"seccompProfile,omitempty"`
|
||||
AppArmorProfile *AppArmorProfileApplyConfiguration `json:"appArmorProfile,omitempty"`
|
||||
}
|
||||
|
||||
// SecurityContextApplyConfiguration constructs an declarative configuration of the SecurityContext type for use with
|
||||
|
|
@ -131,3 +132,11 @@ func (b *SecurityContextApplyConfiguration) WithSeccompProfile(value *SeccompPro
|
|||
b.SeccompProfile = value
|
||||
return b
|
||||
}
|
||||
|
||||
// WithAppArmorProfile sets the AppArmorProfile field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the AppArmorProfile field is set to the value of the last call.
|
||||
func (b *SecurityContextApplyConfiguration) WithAppArmorProfile(value *AppArmorProfileApplyConfiguration) *SecurityContextApplyConfiguration {
|
||||
b.AppArmorProfile = value
|
||||
return b
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4401,6 +4401,21 @@ var schemaYAML = typed.YAMLObject(`types:
|
|||
- name: podAntiAffinity
|
||||
type:
|
||||
namedType: io.k8s.api.core.v1.PodAntiAffinity
|
||||
- name: io.k8s.api.core.v1.AppArmorProfile
|
||||
map:
|
||||
fields:
|
||||
- name: localhostProfile
|
||||
type:
|
||||
scalar: string
|
||||
- name: type
|
||||
type:
|
||||
scalar: string
|
||||
default: ""
|
||||
unions:
|
||||
- discriminator: type
|
||||
fields:
|
||||
- fieldName: localhostProfile
|
||||
discriminatorValue: LocalhostProfile
|
||||
- name: io.k8s.api.core.v1.AttachedVolume
|
||||
map:
|
||||
fields:
|
||||
|
|
@ -6720,6 +6735,9 @@ var schemaYAML = typed.YAMLObject(`types:
|
|||
- name: io.k8s.api.core.v1.PodSecurityContext
|
||||
map:
|
||||
fields:
|
||||
- name: appArmorProfile
|
||||
type:
|
||||
namedType: io.k8s.api.core.v1.AppArmorProfile
|
||||
- name: fsGroup
|
||||
type:
|
||||
scalar: numeric
|
||||
|
|
@ -7614,6 +7632,9 @@ var schemaYAML = typed.YAMLObject(`types:
|
|||
- name: allowPrivilegeEscalation
|
||||
type:
|
||||
scalar: boolean
|
||||
- name: appArmorProfile
|
||||
type:
|
||||
namedType: io.k8s.api.core.v1.AppArmorProfile
|
||||
- name: capabilities
|
||||
type:
|
||||
namedType: io.k8s.api.core.v1.Capabilities
|
||||
|
|
|
|||
|
|
@ -613,6 +613,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} {
|
|||
// Group=core, Version=v1
|
||||
case corev1.SchemeGroupVersion.WithKind("Affinity"):
|
||||
return &applyconfigurationscorev1.AffinityApplyConfiguration{}
|
||||
case corev1.SchemeGroupVersion.WithKind("AppArmorProfile"):
|
||||
return &applyconfigurationscorev1.AppArmorProfileApplyConfiguration{}
|
||||
case corev1.SchemeGroupVersion.WithKind("AttachedVolume"):
|
||||
return &applyconfigurationscorev1.AttachedVolumeApplyConfiguration{}
|
||||
case corev1.SchemeGroupVersion.WithKind("AWSElasticBlockStoreVolumeSource"):
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import (
|
|||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/pod-security-admission/api"
|
||||
)
|
||||
|
||||
|
|
@ -35,6 +36,14 @@ profile, or restrict overrides to an allowed set of profiles.
|
|||
metadata.annotations['container.apparmor.security.beta.kubernetes.io/*']
|
||||
|
||||
**Allowed Values:** 'runtime/default', 'localhost/*', empty, undefined
|
||||
|
||||
**Restricted Fields:**
|
||||
spec.securityContext.appArmorProfile.type
|
||||
spec.containers[*].securityContext.appArmorProfile.type
|
||||
spec.initContainers[*].securityContext.appArmorProfile.type
|
||||
spec.ephemeralContainers[*].securityContext.appArmorProfile.type
|
||||
|
||||
**Allowed Values:** 'RuntimeDefault', 'Localhost', undefined
|
||||
*/
|
||||
func init() {
|
||||
addCheck(CheckAppArmorProfile)
|
||||
|
|
@ -55,25 +64,78 @@ func CheckAppArmorProfile() Check {
|
|||
}
|
||||
}
|
||||
|
||||
func allowedProfile(profile string) bool {
|
||||
func allowedAnnotationValue(profile string) bool {
|
||||
return len(profile) == 0 ||
|
||||
profile == corev1.AppArmorBetaProfileRuntimeDefault ||
|
||||
strings.HasPrefix(profile, corev1.AppArmorBetaProfileNamePrefix)
|
||||
profile == corev1.DeprecatedAppArmorBetaProfileRuntimeDefault ||
|
||||
strings.HasPrefix(profile, corev1.DeprecatedAppArmorBetaProfileNamePrefix)
|
||||
}
|
||||
|
||||
func allowedProfileType(profile corev1.AppArmorProfileType) bool {
|
||||
switch profile {
|
||||
case corev1.AppArmorProfileTypeRuntimeDefault,
|
||||
corev1.AppArmorProfileTypeLocalhost:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func appArmorProfile_1_0(podMetadata *metav1.ObjectMeta, podSpec *corev1.PodSpec) CheckResult {
|
||||
var forbiddenValues []string
|
||||
for k, v := range podMetadata.Annotations {
|
||||
if strings.HasPrefix(k, corev1.AppArmorBetaContainerAnnotationKeyPrefix) && !allowedProfile(v) {
|
||||
forbiddenValues = append(forbiddenValues, fmt.Sprintf("%s=%q", k, v))
|
||||
var badSetters []string // things that explicitly set appArmorProfile.type to a bad value
|
||||
badValues := sets.NewString()
|
||||
|
||||
if podSpec.SecurityContext != nil && podSpec.SecurityContext.AppArmorProfile != nil {
|
||||
if !allowedProfileType(podSpec.SecurityContext.AppArmorProfile.Type) {
|
||||
badSetters = append(badSetters, "pod")
|
||||
badValues.Insert(string(podSpec.SecurityContext.AppArmorProfile.Type))
|
||||
}
|
||||
}
|
||||
if len(forbiddenValues) > 0 {
|
||||
sort.Strings(forbiddenValues)
|
||||
|
||||
var badContainers []string // containers that set apparmorProfile.type to a bad value
|
||||
visitContainers(podSpec, func(c *corev1.Container) {
|
||||
if c.SecurityContext != nil && c.SecurityContext.AppArmorProfile != nil {
|
||||
if !allowedProfileType(c.SecurityContext.AppArmorProfile.Type) {
|
||||
badContainers = append(badContainers, c.Name)
|
||||
badValues.Insert(string(c.SecurityContext.AppArmorProfile.Type))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if len(badContainers) > 0 {
|
||||
badSetters = append(
|
||||
badSetters,
|
||||
fmt.Sprintf(
|
||||
"%s %s",
|
||||
pluralize("container", "containers", len(badContainers)),
|
||||
joinQuote(badContainers),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
var forbiddenAnnotations []string
|
||||
for k, v := range podMetadata.Annotations {
|
||||
if strings.HasPrefix(k, corev1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix) && !allowedAnnotationValue(v) {
|
||||
forbiddenAnnotations = append(forbiddenAnnotations, fmt.Sprintf("%s=%q", k, v))
|
||||
}
|
||||
}
|
||||
|
||||
badValueList := badValues.List()
|
||||
if len(forbiddenAnnotations) > 0 {
|
||||
sort.Strings(forbiddenAnnotations)
|
||||
badValueList = append(badValueList, forbiddenAnnotations...)
|
||||
badSetters = append(badSetters, pluralize("annotation", "annotations", len(forbiddenAnnotations)))
|
||||
}
|
||||
|
||||
// pod or containers explicitly set bad apparmorProfiles
|
||||
if len(badSetters) > 0 {
|
||||
return CheckResult{
|
||||
Allowed: false,
|
||||
ForbiddenReason: pluralize("forbidden AppArmor profile", "forbidden AppArmor profiles", len(forbiddenValues)),
|
||||
ForbiddenDetail: strings.Join(forbiddenValues, ", "),
|
||||
ForbiddenReason: pluralize("forbidden AppArmor profile", "forbidden AppArmor profiles", len(badValueList)),
|
||||
ForbiddenDetail: fmt.Sprintf(
|
||||
"%s must not set AppArmor profile type to %s",
|
||||
strings.Join(badSetters, " and "),
|
||||
joinQuote(badValueList),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,69 +24,145 @@ import (
|
|||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestCheckAppArmor(t *testing.T) {
|
||||
|
||||
func TestCheckAppArmor_Allowed(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
metaData *metav1.ObjectMeta
|
||||
podSpec *corev1.PodSpec
|
||||
expectedResult *CheckResult
|
||||
name string
|
||||
metaData *metav1.ObjectMeta
|
||||
podSpec *corev1.PodSpec
|
||||
}{
|
||||
{
|
||||
name: "container with default AppArmor + extra annotations",
|
||||
metaData: &metav1.ObjectMeta{Annotations: map[string]string{
|
||||
corev1.AppArmorBetaProfileNamePrefix + "test": "runtime/default",
|
||||
corev1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "test": "runtime/default",
|
||||
"env": "prod",
|
||||
},
|
||||
},
|
||||
podSpec: &corev1.PodSpec{},
|
||||
expectedResult: &CheckResult{Allowed: true},
|
||||
}},
|
||||
podSpec: &corev1.PodSpec{},
|
||||
},
|
||||
{
|
||||
name: "container with local AppArmor + extra annotations",
|
||||
metaData: &metav1.ObjectMeta{Annotations: map[string]string{
|
||||
corev1.AppArmorBetaProfileNamePrefix + "test": "localhost/sec-profile01",
|
||||
corev1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + "test": "localhost/sec-profile01",
|
||||
"env": "dev",
|
||||
},
|
||||
},
|
||||
podSpec: &corev1.PodSpec{},
|
||||
expectedResult: &CheckResult{Allowed: true},
|
||||
}},
|
||||
podSpec: &corev1.PodSpec{},
|
||||
},
|
||||
{
|
||||
name: "container with no AppArmor annotations",
|
||||
metaData: &metav1.ObjectMeta{Annotations: map[string]string{
|
||||
"env": "dev",
|
||||
},
|
||||
},
|
||||
podSpec: &corev1.PodSpec{},
|
||||
expectedResult: &CheckResult{Allowed: true},
|
||||
}},
|
||||
podSpec: &corev1.PodSpec{},
|
||||
},
|
||||
{
|
||||
name: "container with no annotations",
|
||||
metaData: &metav1.ObjectMeta{},
|
||||
podSpec: &corev1.PodSpec{},
|
||||
expectedResult: &CheckResult{Allowed: true},
|
||||
name: "container with no annotations",
|
||||
metaData: &metav1.ObjectMeta{},
|
||||
podSpec: &corev1.PodSpec{},
|
||||
},
|
||||
{
|
||||
name: "pod with runtime default",
|
||||
metaData: &metav1.ObjectMeta{},
|
||||
podSpec: &corev1.PodSpec{
|
||||
SecurityContext: &corev1.PodSecurityContext{
|
||||
AppArmorProfile: &corev1.AppArmorProfile{
|
||||
Type: corev1.AppArmorProfileTypeRuntimeDefault,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "container with localhost profile",
|
||||
metaData: &metav1.ObjectMeta{},
|
||||
podSpec: &corev1.PodSpec{
|
||||
Containers: []corev1.Container{{
|
||||
Name: "foo",
|
||||
SecurityContext: &corev1.SecurityContext{
|
||||
AppArmorProfile: &corev1.AppArmorProfile{
|
||||
Type: corev1.AppArmorProfileTypeRuntimeDefault,
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
result := appArmorProfile_1_0(testCase.metaData, nil)
|
||||
if result.Allowed != testCase.expectedResult.Allowed {
|
||||
t.Errorf("Expected result was Allowed=%v for annotations %v",
|
||||
testCase.expectedResult.Allowed, testCase.metaData.Annotations)
|
||||
result := appArmorProfile_1_0(testCase.metaData, testCase.podSpec)
|
||||
if !result.Allowed {
|
||||
t.Errorf("Should be allowed")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppArmorProfile(t *testing.T) {
|
||||
func TestCheckAppArmor_Forbidden(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
pod *corev1.Pod
|
||||
expectReason string
|
||||
expectDetail string
|
||||
}{
|
||||
{
|
||||
name: "unconfined pod",
|
||||
pod: &corev1.Pod{
|
||||
Spec: corev1.PodSpec{
|
||||
SecurityContext: &corev1.PodSecurityContext{
|
||||
AppArmorProfile: &corev1.AppArmorProfile{
|
||||
Type: corev1.AppArmorProfileTypeUnconfined,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectReason: "forbidden AppArmor profile",
|
||||
expectDetail: `pod must not set AppArmor profile type to "Unconfined"`,
|
||||
},
|
||||
{
|
||||
name: "unconfined container",
|
||||
pod: &corev1.Pod{
|
||||
Spec: corev1.PodSpec{
|
||||
SecurityContext: &corev1.PodSecurityContext{
|
||||
AppArmorProfile: &corev1.AppArmorProfile{
|
||||
Type: corev1.AppArmorProfileTypeRuntimeDefault,
|
||||
},
|
||||
},
|
||||
Containers: []corev1.Container{{
|
||||
Name: "foo",
|
||||
SecurityContext: &corev1.SecurityContext{
|
||||
AppArmorProfile: &corev1.AppArmorProfile{
|
||||
Type: corev1.AppArmorProfileTypeUnconfined,
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
expectReason: "forbidden AppArmor profile",
|
||||
expectDetail: `container "foo" must not set AppArmor profile type to "Unconfined"`,
|
||||
},
|
||||
{
|
||||
name: "unconfined init container",
|
||||
pod: &corev1.Pod{
|
||||
Spec: corev1.PodSpec{
|
||||
SecurityContext: &corev1.PodSecurityContext{
|
||||
AppArmorProfile: &corev1.AppArmorProfile{
|
||||
Type: corev1.AppArmorProfileTypeRuntimeDefault,
|
||||
},
|
||||
},
|
||||
Containers: []corev1.Container{{
|
||||
Name: "foo",
|
||||
}},
|
||||
InitContainers: []corev1.Container{{
|
||||
Name: "bar",
|
||||
SecurityContext: &corev1.SecurityContext{
|
||||
AppArmorProfile: &corev1.AppArmorProfile{
|
||||
Type: corev1.AppArmorProfileTypeUnconfined,
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
expectReason: "forbidden AppArmor profile",
|
||||
expectDetail: `container "bar" must not set AppArmor profile type to "Unconfined"`,
|
||||
},
|
||||
{
|
||||
name: "multiple containers",
|
||||
pod: &corev1.Pod{
|
||||
|
|
@ -102,11 +178,11 @@ func TestAppArmorProfile(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
expectReason: `forbidden AppArmor profiles`,
|
||||
expectDetail: strings.Join([]string{
|
||||
`container.apparmor.security.beta.kubernetes.io/="bogus"`,
|
||||
`container.apparmor.security.beta.kubernetes.io/e="unconfined"`,
|
||||
`container.apparmor.security.beta.kubernetes.io/f="unknown"`,
|
||||
expectReason: "forbidden AppArmor profiles",
|
||||
expectDetail: "annotations must not set AppArmor profile type to " + strings.Join([]string{
|
||||
`"container.apparmor.security.beta.kubernetes.io/="bogus""`,
|
||||
`"container.apparmor.security.beta.kubernetes.io/e="unconfined""`,
|
||||
`"container.apparmor.security.beta.kubernetes.io/f="unknown""`,
|
||||
}, ", "),
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,10 +32,10 @@ func init() {
|
|||
// container with localhost/foo annotation
|
||||
tweak(pod, func(copy *corev1.Pod) {
|
||||
containerName := copy.Spec.Containers[0].Name
|
||||
copy.Annotations[corev1.AppArmorBetaContainerAnnotationKeyPrefix+containerName] = "runtime/default"
|
||||
copy.Annotations[corev1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix+containerName] = "runtime/default"
|
||||
|
||||
initContainerName := copy.Spec.Containers[0].Name
|
||||
copy.Annotations[corev1.AppArmorBetaContainerAnnotationKeyPrefix+initContainerName] = "localhost/foo"
|
||||
copy.Annotations[corev1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix+initContainerName] = "localhost/foo"
|
||||
}),
|
||||
}
|
||||
},
|
||||
|
|
@ -45,13 +45,13 @@ func init() {
|
|||
// container with unconfined annotation
|
||||
tweak(pod, func(copy *corev1.Pod) {
|
||||
name := copy.Spec.Containers[0].Name
|
||||
copy.Annotations[corev1.AppArmorBetaContainerAnnotationKeyPrefix+name] = "unconfined"
|
||||
copy.Annotations[corev1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix+name] = "unconfined"
|
||||
}),
|
||||
|
||||
// initContainer with unconfined annotation
|
||||
tweak(pod, func(copy *corev1.Pod) {
|
||||
name := copy.Spec.InitContainers[0].Name
|
||||
copy.Annotations[corev1.AppArmorBetaContainerAnnotationKeyPrefix+name] = "unconfined"
|
||||
copy.Annotations[corev1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix+name] = "unconfined"
|
||||
}),
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@ func LoadAppArmorProfiles(ctx context.Context, nsName string, clientset clientse
|
|||
// CreateAppArmorTestPod creates a pod that tests apparmor profile enforcement. The pod exits with
|
||||
// an error code if the profile is incorrectly enforced. If runOnce is true the pod will exit after
|
||||
// a single test, otherwise it will repeat the test every 1 second until failure.
|
||||
func CreateAppArmorTestPod(ctx context.Context, nsName string, clientset clientset.Interface, podClient *e2epod.PodClient, unconfined bool, runOnce bool) *v1.Pod {
|
||||
profile := "localhost/" + appArmorProfilePrefix + nsName
|
||||
func AppArmorTestPod(nsName string, unconfined bool, runOnce bool) *v1.Pod {
|
||||
localhostProfile := appArmorProfilePrefix + nsName
|
||||
testCmd := fmt.Sprintf(`
|
||||
if touch %[1]s; then
|
||||
echo "FAILURE: write to %[1]s should be denied"
|
||||
|
|
@ -64,7 +64,6 @@ elif [[ $(< /proc/self/attr/current) != "%[3]s" ]]; then
|
|||
fi`, appArmorDeniedPath, appArmorAllowedPath, appArmorProfilePrefix+nsName)
|
||||
|
||||
if unconfined {
|
||||
profile = v1.AppArmorBetaProfileNameUnconfined
|
||||
testCmd = `
|
||||
if cat /proc/sysrq-trigger 2>&1 | grep 'Permission denied'; then
|
||||
echo 'FAILURE: reading /proc/sysrq-trigger should be allowed'
|
||||
|
|
@ -94,17 +93,25 @@ done`, testCmd)
|
|||
},
|
||||
}
|
||||
|
||||
profile := &v1.AppArmorProfile{}
|
||||
if unconfined {
|
||||
profile.Type = v1.AppArmorProfileTypeUnconfined
|
||||
} else {
|
||||
profile.Type = v1.AppArmorProfileTypeLocalhost
|
||||
profile.LocalhostProfile = &localhostProfile
|
||||
}
|
||||
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
GenerateName: "test-apparmor-",
|
||||
Annotations: map[string]string{
|
||||
v1.AppArmorBetaContainerAnnotationKeyPrefix + "test": profile,
|
||||
},
|
||||
Labels: map[string]string{
|
||||
"test": "apparmor",
|
||||
},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
SecurityContext: &v1.PodSecurityContext{
|
||||
AppArmorProfile: profile,
|
||||
},
|
||||
Affinity: loaderAffinity,
|
||||
Containers: []v1.Container{{
|
||||
Name: "test",
|
||||
|
|
@ -115,20 +122,24 @@ done`, testCmd)
|
|||
},
|
||||
}
|
||||
|
||||
return pod
|
||||
}
|
||||
|
||||
func RunAppArmorTestPod(ctx context.Context, pod *v1.Pod, clientset clientset.Interface, podClient *e2epod.PodClient, runOnce bool) *v1.Pod {
|
||||
if runOnce {
|
||||
pod = podClient.Create(ctx, pod)
|
||||
framework.ExpectNoError(e2epod.WaitForPodSuccessInNamespace(ctx,
|
||||
clientset, pod.Name, nsName))
|
||||
clientset, pod.Name, pod.Namespace))
|
||||
var err error
|
||||
pod, err = podClient.Get(ctx, pod.Name, metav1.GetOptions{})
|
||||
framework.ExpectNoError(err)
|
||||
} else {
|
||||
pod = podClient.CreateSync(ctx, pod)
|
||||
framework.ExpectNoError(e2epod.WaitTimeoutForPodReadyInNamespace(ctx, clientset, pod.Name, nsName, framework.PodStartTimeout))
|
||||
framework.ExpectNoError(e2epod.WaitTimeoutForPodReadyInNamespace(ctx, clientset, pod.Name, pod.Namespace, framework.PodStartTimeout))
|
||||
}
|
||||
|
||||
// Verify Pod affinity colocated the Pods.
|
||||
loader := getRunningLoaderPod(ctx, nsName, clientset)
|
||||
loader := getRunningLoaderPod(ctx, pod.Namespace, clientset)
|
||||
gomega.Expect(pod.Spec.NodeName).To(gomega.Equal(loader.Spec.NodeName))
|
||||
|
||||
return pod
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue