Cart

    Sorry, we could not find any results for your search querry.

    Using AppArmor or SELinux in Kubernetes

    AppArmor and SELinux restrict what a container may do at node level, even if a process in the container tries to use additional permissions. This provides an additional layer of defence alongside RBAC, container image hardening, and NetworkPolicies.

    Which one you use mainly depends on your nodes' operating system. AppArmor is most common on Ubuntu and Debian nodes, which we also use on the TransIP Kubernetes platform, while SELinux is common on AlmaLinux, Rocky Linux, RHEL, and CentOS Stream.

    • Use AppArmor or SELinux for workloads with sensitive data, additional privileges, or strict compliance requirements.
       
    • Start with runtime defaults and create stricter custom profiles only when necessary.
       
    • Custom AppArmor profiles using `Localhost` and custom SELinux policies require node management. This is not always possible on managed clusters.
     

     

    Before you begin

     

    First determine which Linux security module your nodes use. Use kubectl to check your nodes' operating system:

    kubectl get nodes -o wide

    In practice, use:

    • AppArmor: on Ubuntu- or Debian-based nodes.
    • SELinux: on RHEL-, AlmaLinux-, Rocky Linux-, or CentOS Stream-based nodes.

     

    Start with AppArmor RuntimeDefault on Ubuntu and Debian nodes

     

    Step 1

    Create a .yaml file for a pod using AppArmor `RuntimeDefault`, for example:

    nano apparmor-demo.yaml

    Add the following configuration to the file:

    apiVersion: v1
    kind: Namespace
    metadata:
      name: kb-mac-test
    ---
    apiVersion: v1
    kind: Pod
    metadata:
      name: apparmor-runtime-default
      namespace: kb-mac-test
    spec:
      restartPolicy: Never
      containers:
        - name: busybox
          image: busybox:1.36
          command: ["/bin/sh", "-c", "sleep 3600"]
          securityContext:
            appArmorProfile:
              type: RuntimeDefault
            allowPrivilegeEscalation: false
            capabilities:
              drop:
                - ALL
            runAsNonRoot: true
            runAsUser: 65532
            seccompProfile:
              type: RuntimeDefault

    Save the changes and close the file (ctrl + x > y > enter).


     

    Step 2

    Create the resources and wait for the pod to run:

    kubectl apply -f apparmor-demo.yaml
    kubectl -n kb-mac-test wait --for=condition=Ready pod/apparmor-runtime-default --timeout=180s

     

    Step 3

    Check whether the container uses an AppArmor profile:

    kubectl -n kb-mac-test exec apparmor-runtime-default -- cat /proc/1/attr/current

    You should see a profile name instead of `unconfined`. This confirms that AppArmor is active for the workload.


     

    Use SELinux on RHEL-based nodes

     

    If your nodes use SELinux, replace appArmorProfile from the previous section with a `seLinuxOptions` block. A simple example looks like this:

    securityContext:
      seLinuxOptions:
        level: "s0:c123,c456"
      allowPrivilegeEscalation: false
      runAsNonRoot: true
      seccompProfile:
        type: RuntimeDefault

    Use `seLinuxOptions` only if you understand which labels and policies your nodes already use. On many platforms, the runtime default is sufficiently secure, and an incorrect label may prevent a workload from opening volumes or sockets.


     

    When do you use RuntimeDefault or a custom profile?

     

    • RuntimeDefault: choose this as a secure default for almost all workloads.
    • Custom AppArmor Localhost profile: use this only if you manage the nodes yourself and can load the same profile on every node.
    • Custom SELinux policy: use this only if you know exactly which SELinux contexts and type enforcement you need.

    For many environments, `RuntimeDefault` provides an immediate security improvement without significant management overhead.


     

    AppArmor and SELinux do not replace other security measures, but they provide an important additional layer. Start with runtime defaults, combine them with limited privileges, and use custom profiles only when there is a clear reason to do so.

    Need help?

    Receive personal support from our supporters

    Contact us