ephemeralcontainer-seccomp-profile-restricted
An ephemeral container with no seccomp profile enforced at pod or ephemeral container level runs with no syscall filter, leaving the full kernel syscall surface reachable for container escape and privilege escalation.
(has(object.spec.os) &&
has(object.spec.os.name) &&
object.spec.os.name.lowerAscii() == "windows") ||
(variables.podTypeAllowed &&
(!has(object.spec.ephemeralContainers) ||
object.spec.ephemeralContainers.all(ec,
!has(ec.securityContext) ||
!has(ec.securityContext.seccompProfile) ||
!has(ec.securityContext.seccompProfile.type) ||
variables.allowedSeccompTypes.exists(t, t == ec.securityContext.seccompProfile.type)
)
)
) || (!variables.podTypePresent &&
(!has(object.spec.ephemeralContainers) ||
object.spec.ephemeralContainers.all(ec,
has(ec.securityContext) &&
has(ec.securityContext.seccompProfile) &&
has(ec.securityContext.seccompProfile.type) &&
variables.allowedSeccompTypes.exists(t, t == ec.securityContext.seccompProfile.type)
)
)
)
spec.ephemeralContainers[*].securityContext.seccompProfile.type must be "RuntimeDefault" or "Localhost". Ephemeral container fields may be undefined only when the Pod-level spec.securityContext.seccompProfile.type is set to "RuntimeDefault" or "Localhost"; otherwise every ephemeral container must set its own to one of those values.
allowedSeccompTypes
["RuntimeDefault","Localhost"]
podTypePresent
has(object.spec.securityContext) && has(object.spec.securityContext.seccompProfile) && has(object.spec.securityContext.seccompProfile.type)
podTypeAllowed
variables.podTypePresent && variables.allowedSeccompTypes.exists(t, t == object.spec.securityContext.seccompProfile.type)
Set the seccomp type to RuntimeDefault, or to Localhost naming a profile loaded on the node, on each ephemeral container or once at pod level. Fields: spec.ephemeralContainers[*].securityContext.seccompProfile.type, spec.securityContext.seccompProfile.type.
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: ephemeralcontainer-seccomp-profile-restricted
annotations:
kubeapt.io/uuid: "ae109ba1-7514-400c-bf0c-8f854a867722"
security.kubeapt.io/displayName: "Has No Seccomp Profile Set"
security.kubeapt.io/description: "An ephemeral container with no seccomp profile enforced at pod or ephemeral container level runs with no syscall filter, leaving the full kernel syscall surface reachable for container escape and privilege escalation."
security.kubeapt.io/resource: "EphemeralContainers"
security.kubeapt.io/severity: "Moderate"
security.kubeapt.io/remediation: "Set the seccomp type to RuntimeDefault, or to Localhost naming a profile loaded on the node, on each ephemeral container or once at pod level. Fields: spec.ephemeralContainers[*].securityContext.seccompProfile.type, spec.securityContext.seccompProfile.type."
security.kubeapt.io/product: "Kubernetes"
spec:
failurePolicy: Fail
matchConstraints:
resourceRules:
- apiGroups:
- ''
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- pods
- apiGroups:
- ''
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- pods/ephemeralcontainers
variables:
- name: allowedSeccompTypes
expression: |
["RuntimeDefault","Localhost"]
- name: podTypePresent
expression: |
has(object.spec.securityContext) && has(object.spec.securityContext.seccompProfile) && has(object.spec.securityContext.seccompProfile.type)
- name: podTypeAllowed
expression: |
variables.podTypePresent && variables.allowedSeccompTypes.exists(t, t == object.spec.securityContext.seccompProfile.type)
validations:
- expression: |
(has(object.spec.os) &&
has(object.spec.os.name) &&
object.spec.os.name.lowerAscii() == "windows") ||
(variables.podTypeAllowed &&
(!has(object.spec.ephemeralContainers) ||
object.spec.ephemeralContainers.all(ec,
!has(ec.securityContext) ||
!has(ec.securityContext.seccompProfile) ||
!has(ec.securityContext.seccompProfile.type) ||
variables.allowedSeccompTypes.exists(t, t == ec.securityContext.seccompProfile.type)
)
)
) || (!variables.podTypePresent &&
(!has(object.spec.ephemeralContainers) ||
object.spec.ephemeralContainers.all(ec,
has(ec.securityContext) &&
has(ec.securityContext.seccompProfile) &&
has(ec.securityContext.seccompProfile.type) &&
variables.allowedSeccompTypes.exists(t, t == ec.securityContext.seccompProfile.type)
)
)
)
message: |
spec.ephemeralContainers[*].securityContext.seccompProfile.type must be "RuntimeDefault" or "Localhost". Ephemeral container fields may be undefined only when the Pod-level spec.securityContext.seccompProfile.type is set to "RuntimeDefault" or "Localhost"; otherwise every ephemeral container must set its own to one of those values.Save it as ephemeralcontainer-seccomp-profile-restricted.yaml — the commands below assume that name.
Check a workload against this one policy, before anything is installed on a cluster.
$ kubeapt validate -p ./ephemeralcontainer-seccomp-profile-restricted.yaml -r ./workload.yamlOr without the file, from the published policy set — -r takes a directory too:
$ kubeapt policies download && kubeapt validate --policy-name ephemeralcontainer-seccomp-profile-restricted -r ./manifestsOr against every namespace in the cluster your kubeconfig points at:
$ kubeapt validate --policy-name ephemeralcontainer-seccomp-profile-restricted -A