← Policy catalog
</> ValidatingAdmissionPolicy · Apache-2.0

Runs With an Unconfined AppArmor Profile

ephemeralcontainer-apparmor-profile

severityModerate resourceEphemeralContainers productKubernetes bundles2

An Unconfined AppArmor profile strips the mandatory access controls over file, capability and mount operations in the ephemeral container, usually one attached with kubectl debug, widening what a compromised process can reach on the host.

Rejects unless

!has(object.spec.ephemeralContainers) || object.spec.ephemeralContainers.all(ec,
  !has(ec.securityContext) ||
  !has(ec.securityContext.appArmorProfile) ||
  !has(ec.securityContext.appArmorProfile.type) ||
  variables.allowedAppArmorTypes.exists(t, t == ec.securityContext.appArmorProfile.type)
)

spec.ephemeralContainers[*].securityContext.appArmorProfile.type must be undefined, RuntimeDefault, or Localhost.

Variables

allowedAppArmorTypes

["RuntimeDefault","Localhost"]

Remediation

Replace Unconfined with RuntimeDefault, or with Localhost naming a profile loaded on the node. Field: spec.ephemeralContainers[*].securityContext.appArmorProfile.type.

Applies to

  • pods/ephemeralcontainers · v1 · CREATE, UPDATE

Manifest

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: ephemeralcontainer-apparmor-profile
  annotations:
    kubeapt.io/uuid: "80cb224d-33f7-4f74-a469-07be87fcb3ac"
    security.kubeapt.io/displayName: "Runs With an Unconfined AppArmor Profile"
    security.kubeapt.io/description: "An Unconfined AppArmor profile strips the mandatory access controls over file, capability and mount operations in the ephemeral container, usually one attached with kubectl debug, widening what a compromised process can reach on the host."
    security.kubeapt.io/resource: "EphemeralContainers"
    security.kubeapt.io/severity: "Moderate"
    security.kubeapt.io/remediation: "Replace Unconfined with RuntimeDefault, or with Localhost naming a profile loaded on the node. Field: spec.ephemeralContainers[*].securityContext.appArmorProfile.type."
    security.kubeapt.io/product: "Kubernetes"
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
    - apiGroups:
      - ''
      apiVersions:
      - v1
      operations:
      - CREATE
      - UPDATE
      resources:
      - pods/ephemeralcontainers
  variables:
  - name: allowedAppArmorTypes
    expression: |
      ["RuntimeDefault","Localhost"]
  validations:
  - expression: |
      !has(object.spec.ephemeralContainers) || object.spec.ephemeralContainers.all(ec,
        !has(ec.securityContext) ||
        !has(ec.securityContext.appArmorProfile) ||
        !has(ec.securityContext.appArmorProfile.type) ||
        variables.allowedAppArmorTypes.exists(t, t == ec.securityContext.appArmorProfile.type)
      )
    message: |
      spec.ephemeralContainers[*].securityContext.appArmorProfile.type must be undefined, RuntimeDefault, or Localhost.

Save it as ephemeralcontainer-apparmor-profile.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 ./ephemeralcontainer-apparmor-profile.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 ephemeralcontainer-apparmor-profile -r ./manifests

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

$ kubeapt validate --policy-name ephemeralcontainer-apparmor-profile -A