← Policy catalog
</> ValidatingAdmissionPolicy · Apache-2.0

Has No Seccomp Profile Set

pod-seccomp-profile-restricted

severityModerate resourcePods productKubernetes bundles2

A pod with no seccomp profile enforced at pod level, and containers that set none either, runs with no syscall filter, leaving the full kernel syscall surface reachable for container escape and privilege escalation.

Rejects unless

(has(object.spec.os) &&
 has(object.spec.os.name) &&
 object.spec.os.name.lowerAscii() == "windows") ||
variables.podTypeAllowed || (!variables.podTypePresent && variables.containersAllSetAndAllowed && variables.initAllSetAndAllowed && variables.ephAllSetAndAllowed)

spec.securityContext.seccompProfile.type must be "RuntimeDefault" or "Localhost". It may be undefined only if every container (including init and ephemeral) sets its own securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost".

Variables

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)

containersAllSetAndAllowed

object.spec.containers.all(c,
  has(c.securityContext) &&
  has(c.securityContext.seccompProfile) &&
  has(c.securityContext.seccompProfile.type) &&
  variables.allowedSeccompTypes.exists(t, t == c.securityContext.seccompProfile.type)
)

initAllSetAndAllowed

!has(object.spec.initContainers) || object.spec.initContainers.all(ic,
  has(ic.securityContext) &&
  has(ic.securityContext.seccompProfile) &&
  has(ic.securityContext.seccompProfile.type) &&
  variables.allowedSeccompTypes.exists(t, t == ic.securityContext.seccompProfile.type)
)

ephAllSetAndAllowed

!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)
)

Remediation

Set the pod-level seccomp type to RuntimeDefault, or to Localhost naming a profile loaded on the node. It may stay unset only when every container, init container and ephemeral container sets its own to one of those values. Fields: spec.securityContext.seccompProfile.type, spec.containers[*].securityContext.seccompProfile.type, spec.initContainers[*].securityContext.seccompProfile.type, spec.ephemeralContainers[*].securityContext.seccompProfile.type.

Applies to

  • pods · v1 · CREATE, UPDATE
  • pods/ephemeralcontainers · v1 · CREATE, UPDATE

Manifest

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: pod-seccomp-profile-restricted
  annotations:
    kubeapt.io/uuid: "9612c6ac-4f88-4f18-a415-b85286cf6c8f"
    security.kubeapt.io/displayName: "Has No Seccomp Profile Set"
    security.kubeapt.io/description: "A pod with no seccomp profile enforced at pod level, and containers that set none either, runs with no syscall filter, leaving the full kernel syscall surface reachable for container escape and privilege escalation."
    security.kubeapt.io/resource: "Pods"
    security.kubeapt.io/severity: "Moderate"
    security.kubeapt.io/remediation: "Set the pod-level seccomp type to RuntimeDefault, or to Localhost naming a profile loaded on the node. It may stay unset only when every container, init container and ephemeral container sets its own to one of those values. Fields: spec.securityContext.seccompProfile.type, spec.containers[*].securityContext.seccompProfile.type, spec.initContainers[*].securityContext.seccompProfile.type, spec.ephemeralContainers[*].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)
  - name: containersAllSetAndAllowed
    expression: |
      object.spec.containers.all(c,
        has(c.securityContext) &&
        has(c.securityContext.seccompProfile) &&
        has(c.securityContext.seccompProfile.type) &&
        variables.allowedSeccompTypes.exists(t, t == c.securityContext.seccompProfile.type)
      )
  - name: initAllSetAndAllowed
    expression: |
      !has(object.spec.initContainers) || object.spec.initContainers.all(ic,
        has(ic.securityContext) &&
        has(ic.securityContext.seccompProfile) &&
        has(ic.securityContext.seccompProfile.type) &&
        variables.allowedSeccompTypes.exists(t, t == ic.securityContext.seccompProfile.type)
      )
  - name: ephAllSetAndAllowed
    expression: |
      !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)
      )
  validations:
  - expression: |
      (has(object.spec.os) &&
       has(object.spec.os.name) &&
       object.spec.os.name.lowerAscii() == "windows") ||
      variables.podTypeAllowed || (!variables.podTypePresent && variables.containersAllSetAndAllowed && variables.initAllSetAndAllowed && variables.ephAllSetAndAllowed)
    message: |
      spec.securityContext.seccompProfile.type must be "RuntimeDefault" or "Localhost". It may be undefined only if every container (including init and ephemeral) sets its own securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost".

Save it as pod-seccomp-profile-restricted.yaml — the commands below assume that name.

Validate with kubeapt

Check a workload against this one policy, before anything is installed on a cluster.

$ kubeapt validate -p ./pod-seccomp-profile-restricted.yaml -r ./workload.yaml

Or without the file, from the published policy set — -r takes a directory too:

$ kubeapt policies download && kubeapt validate --policy-name pod-seccomp-profile-restricted -r ./manifests

Or against every namespace in the cluster your kubeconfig points at:

$ kubeapt validate --policy-name pod-seccomp-profile-restricted -A