Files
website/docs/tutorials/clusters/apparmor.md
T
Jennifer Rondeau 409e77d3e5 Merge 1.10 to master for release (#7861)
* 1.10 update (#7151)

* Fix partition value expected behaviour explanation (#7123)

Fixes issue #7057

* Correct "On-Premise" to "On-Premises"

* Updates the Calico installation page (#7094)

* All files for Haufe Groups case study (#7051)

* Fix typo (#7127)

* fix typo of device-plugins.md (#7106)

* fix broken links (#7136)

* Updated configure-service-account (#7147)

Error from server resolved by escaping kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "myregistrykey"}]}' JSON string by '\'

* Remove docs related to 'require-kubeconfig' (#7138)

With kubernetes/kubernetes#58367 merged, v1.10 will not use the
"require-kubeconfig" flag. The flag has become a no-op solely to ensure
existing deployments won't break.

* Added Verification Scenario for a Pod that Uses a PVC in Terminating State (#7164)

The below PR:
https://github.com/kubernetes/kubernetes/pull/55873
modified scheduler in such a way that scheduling of a pod that uses a PVC in Terminating state fails.

That's why verification of such scenario was added to documentation.

* fix LimitPodHardAntiAffinityTopology name (#7221)

* Document the removal of the KubeletConfigFile feature gate (#7140)

With kubernetes/kubernetes#58978 merged, the said feature gate is
removed. This PR removes texts related to the gate and revises the
Feature Gates reference to reflect this change.

* deprecate three admission controller (#7363)

* Document the removal of Accelerators feature gate (#7389)

The `Accelerators` feature gate will be removed in 1.11. 1.10 will be
its last mile.
References: kubernetes/kubernetes#57384

* Update local storage docs for beta (#7473)

* Document that HugePages feature gate is Beta (#7387)

The `HugePages` feature gate has graduated to Beta in v1.10. This PR
documents this fact.

* Add HyperVContainer feature gates (#7502)

* Remove the beta reference from Taints and Tolerations doc (#7493)

* Kms provider doc (#7479)

* Kms provider doc

* issue# 7399, Create KMS-provider.md and update encrypt-data.md

* address review comments

* Document that Device Plugin feature is Beta (1.10) (#7512)

* Add docs for CRD features for 1.10 (#7439)

* Add docs for CRD features for 1.10

* Add CustomResourcesSubresources to list of feature gates

* Add latest changes to custom resources doc

* Add crds as abbreviated alias (#7437)

* Bring PVC Protection Feature to Beta (#7165)

* Bring PVC Protection Feature to Beta

The PR: https://github.com/kubernetes/kubernetes/pull/59052
brought PVC Protection feature to beta.

That's why the documentation is updated accordingly.

* The PVC Protection feature was renamed to Storage Protection. That's why the documentation is updated.

* promote PodNodeSelector to stable; document detailed behavior (#7134)

* promote PodNodeSelector to stable; document detailed behavior

* respond to feedback

* Update CPU manager feature enabling (#7390)

With `CPUManager` feature graduating to beta. No explicit enabling is
required starting v1.10.
References: kubernetes/kubernetes#55977

* Adding block volumeMode documentation for local volumes. (#7531)

Code review comments.

Changed property to field.

Address tech review comment.

* remove description kubectl --show-all (#7574)

--show-all has been deprecated and set to true by default.
https://github.com/kubernetes/kubernetes/pull/60210

* fix description about contribute style guide (#7592)

* fix description about KUBECONFIG (#7589)

s/envrionment/environment

* fix description about cni (#7588)

s/simultanously/simultaneously/

* fix description about MutatingAdmissionWebhook and ValidatingAdmissionWebhook (#7587)

* fix description about persistent volume binding (#7590)

s/slighty/slightly/

* Doc change for configurable pod resolv.conf Beta (#7611)

* fix description about out of resource handling (#7597)

s/threshhold/threshold

* fix description about zookeeper (#7598)

s/achive/achieve

* fix description about kubeadm (#7594)

s/compatability/compatibility/

* fix description about kubeadm (#7593)

* fix description about kubeadm implementation details (#7595)

* fix description about api concepts (#7596)

* Storage Protection was renamed to Storage Object in Use Protection (#7576)

* Storage Protection was renamed to Storage Object in Use Protection

The K8s PR: https://github.com/kubernetes/kubernetes/pull/59901
renamed Storage Protection to Storage Object in Use Protection.

That's why the same is also renamed in the documentation.

* Moved Storage Object in Use Protection admission plugin description down according to alphabetic order.

* Use PSP from policy API group. (#7562)

* update kubeletconfig docs for v1.10, beta (#7561)

* Update port-forwarding docs (#7575)

* add pv protection description (#7620)

* fix description about client library (#7634)

* Add docs on configuring NodePort IP (#7631)

* Document that LocalStorageCapacityIsolation is beta (#7635)

A follow-up to the kubernetes/kubernetes#60159 change which has promoted
the `LocalStorageCapacityIsolation` feature gate to Beta.

* Update CoreDNS docs for beta (#7638)

* Update CoreDNS docs for beta

* Review comments

* Fix typo (#7640)

* Update feature gates move to beta (#7662)

* Added the inability to use colon ':' character as environment variable names and described workaround (#7657)

* merge master to 1.10, with fixes (#7682)

* Flag names changed (s/admission-control/enable-admission-plugins); disable-admissions-plugin entry added; removed reference to admission controller/plugins requiring set order (for v1.10), redundant example enabling specific plugin, and redundant version-specific info (#7449)

* Documentation for MountPropagation beta (#7655)

* Remove job's scale-related operations (#7684)

* authentication: document client-go exec plugins (#7648)

* authentication: document client-go exec plugins

* Update authentication.md

* Update local ephemeral storage feature to beta (#7685)

Update local ephemeral storage feature to beta

* Update docs for windows container resources (#7653)

* add server-side print docs (#7671)

* Create a task describing Pod process namespace sharing (#7489)

* Add external metrics to HPA docs (#7664)

* Add external metrics to HPA docs

* Update horizontal-pod-autoscale-walkthrough.md

* Apply review comments to HPA walkthrough

* remove description about "scale jobs" (#7712)

* CSI Docs for K8s v1.10 (#7698)

* Add a warning about increased memory consumption for audit logging feature. (#7725)

Signed-off-by: Mik Vyatskov <vmik@google.com>

* Update Audit Logging documentation for 1.10 (#7679)

Signed-off-by: Mik Vyatskov <vmik@google.com>

* Fix stage names in audit logging documentation (#7746)

Signed-off-by: Mik Vyatskov <vmik@google.com>

* Feature gate update for release 1.10 (#7742)

* State in the docs that the value of default Node labels are not reliable. (#7794)

* Kill the reference to --admission-control option (#7755)

The `--admission-control` option has been replaced by two new options in
v1.10. This PR kills the last appearance of the old option in the doc.

* Pvcprotection toc (#7807)

* Refreshing installation instructions (#7495)

* Refreshing installation instructions

Added conjure-up. Updated displays and juju versions to current versions.

* Updated anchors

* Fixed image value version typo (#7768)

Was inconsistent with other values

* Update flocker reference to the github repo (#7784)

* Fix typo in federation document (#7779)

* an user -> a user (#7778)

* Events are namespaced (#7767)

* fix 'monitoring' link lose efficacy problem' (#7764)

* docs/concepts/policy/pod-security-policy.md: minor fix. (#7659)

* Update downward-api-volume-expose-pod-information.md (#7771)

* Update downward-api-volume-expose-pod-information.md

The pod spec puts the downward api files into /etc/podinfo, not directly in /etc. Updated docs to reflect this fact.

* Update downward-api-volume-expose-pod-information.md

One more spot needed fixing.

* Update downward-api-volume-expose-pod-information.md

Yet another fix, in the container example.

* Add Amadeus Case Study (#7783)

* Add Amadeus Case Study

* add Amadeus logo

* Fixed Cyrillic с in 'kube-proxy-cm' (#7787)

There was a typo (wrong character) in kube-proxy-cm.yaml - Cyrillic с (UTF-8 0x0441) was used instead of Latin c.

* install-kubectl: choose one installation method (#7705)

The previous text layout suggested that all installations had to be done, one after another.

* Update install-kubeadm.md (#7781)

Add note to kubeadm install instruction to help install in other arch i.e. aarch64, ppc64le etc.

* repair failure link (#7788)

* repair failure link

* repair failure link

* do change as required

* Update k8s201.md (#7777)

* Update k8s201.md

Change instructions to download yams files directly from the website (as used in other pages.)

Added instructions to delete labeled pod to avoid warnings in the subsequent deployment step.

* Update k8s201.md

Added example of using the exposed host from the a node running Kubernetes. (This works on AWS with Weave; not able to test it on other variations...)

* Gramatical fix to kompose introduction (#7792)

The original wording didn't through very well. As much of the original sentence has been preserved as possible, primarily to ensure the kompose web address is see both in text and as a href link.

* update amadeus.html (#7800)

* Fix a missing word in endpoint reconciler section (#7804)

* add toc entry for pvcprotection downgrade issue doc

* Pvcprotection toc (#7809)

* Refreshing installation instructions (#7495)

* Refreshing installation instructions

Added conjure-up. Updated displays and juju versions to current versions.

* Updated anchors

* Fixed image value version typo (#7768)

Was inconsistent with other values

* Update flocker reference to the github repo (#7784)

* Fix typo in federation document (#7779)

* an user -> a user (#7778)

* Events are namespaced (#7767)

* fix 'monitoring' link lose efficacy problem' (#7764)

* docs/concepts/policy/pod-security-policy.md: minor fix. (#7659)

* Update downward-api-volume-expose-pod-information.md (#7771)

* Update downward-api-volume-expose-pod-information.md

The pod spec puts the downward api files into /etc/podinfo, not directly in /etc. Updated docs to reflect this fact.

* Update downward-api-volume-expose-pod-information.md

One more spot needed fixing.

* Update downward-api-volume-expose-pod-information.md

Yet another fix, in the container example.

* Add Amadeus Case Study (#7783)

* Add Amadeus Case Study

* add Amadeus logo

* Fixed Cyrillic с in 'kube-proxy-cm' (#7787)

There was a typo (wrong character) in kube-proxy-cm.yaml - Cyrillic с (UTF-8 0x0441) was used instead of Latin c.

* install-kubectl: choose one installation method (#7705)

The previous text layout suggested that all installations had to be done, one after another.

* Update install-kubeadm.md (#7781)

Add note to kubeadm install instruction to help install in other arch i.e. aarch64, ppc64le etc.

* repair failure link (#7788)

* repair failure link

* repair failure link

* do change as required

* Update k8s201.md (#7777)

* Update k8s201.md

Change instructions to download yams files directly from the website (as used in other pages.)

Added instructions to delete labeled pod to avoid warnings in the subsequent deployment step.

* Update k8s201.md

Added example of using the exposed host from the a node running Kubernetes. (This works on AWS with Weave; not able to test it on other variations...)

* Gramatical fix to kompose introduction (#7792)

The original wording didn't through very well. As much of the original sentence has been preserved as possible, primarily to ensure the kompose web address is see both in text and as a href link.

* update amadeus.html (#7800)

* Fix a missing word in endpoint reconciler section (#7804)

* add toc entry for pvcprotection downgrade issue doc

* revert TOC change

* Release 1.10 (#7818)

* Refreshing installation instructions (#7495)

* Refreshing installation instructions

Added conjure-up. Updated displays and juju versions to current versions.

* Updated anchors

* Fixed image value version typo (#7768)

Was inconsistent with other values

* Update flocker reference to the github repo (#7784)

* Fix typo in federation document (#7779)

* an user -> a user (#7778)

* Events are namespaced (#7767)

* fix 'monitoring' link lose efficacy problem' (#7764)

* docs/concepts/policy/pod-security-policy.md: minor fix. (#7659)

* Update downward-api-volume-expose-pod-information.md (#7771)

* Update downward-api-volume-expose-pod-information.md

The pod spec puts the downward api files into /etc/podinfo, not directly in /etc. Updated docs to reflect this fact.

* Update downward-api-volume-expose-pod-information.md

One more spot needed fixing.

* Update downward-api-volume-expose-pod-information.md

Yet another fix, in the container example.

* Add Amadeus Case Study (#7783)

* Add Amadeus Case Study

* add Amadeus logo

* Fixed Cyrillic с in 'kube-proxy-cm' (#7787)

There was a typo (wrong character) in kube-proxy-cm.yaml - Cyrillic с (UTF-8 0x0441) was used instead of Latin c.

* install-kubectl: choose one installation method (#7705)

The previous text layout suggested that all installations had to be done, one after another.

* Update install-kubeadm.md (#7781)

Add note to kubeadm install instruction to help install in other arch i.e. aarch64, ppc64le etc.

* repair failure link (#7788)

* repair failure link

* repair failure link

* do change as required

* Update k8s201.md (#7777)

* Update k8s201.md

Change instructions to download yams files directly from the website (as used in other pages.)

Added instructions to delete labeled pod to avoid warnings in the subsequent deployment step.

* Update k8s201.md

Added example of using the exposed host from the a node running Kubernetes. (This works on AWS with Weave; not able to test it on other variations...)

* Gramatical fix to kompose introduction (#7792)

The original wording didn't through very well. As much of the original sentence has been preserved as possible, primarily to ensure the kompose web address is see both in text and as a href link.

* update amadeus.html (#7800)

* Fix a missing word in endpoint reconciler section (#7804)

* Partners page updates (#7802)

* Partners page updates

* Update to ZTE link

* Make using sysctls a task instead of a concept (#6808)

Closes: #4505

* add a note when mount a configmap to pod (#7745)

* adjust a note format (#7812)

* Update docker-cli-to-kubectl.md (#7748)

* Update docker-cli-to-kubectl.md

Edited the document for adherence to the style guide and word usage.

* Update docker-cli-to-kubectl.md

* Incorporated the changes suggested.

* Mount propagation update to include docker config (#7854)

* update overridden config for 1.10 (#7847)

* update overridden config for 1.10

* fix config file per comments

* Update Extended Resource doc wrt cluster-level resources (#7759)
2018-03-26 18:33:11 -07:00

19 KiB

reviewers, title
reviewers title
stclair
AppArmor

{% capture overview %}

{% assign for_k8s_version="v1.4" %}{% include feature-state-beta.md %}

AppArmor is a Linux kernel security module that supplements the standard Linux user and group based permissions to confine programs to a limited set of resources. AppArmor can be configured for any application to reduce its potential attack surface and provide greater in-depth defense. It is configured through profiles tuned to whitelist the access needed by a specific program or container, such as Linux capabilities, network access, file permissions, etc. Each profile can be run in either enforcing mode, which blocks access to disallowed resources, or complain mode, which only reports violations.

AppArmor can help you to run a more secure deployment by restricting what containers are allowed to do, and/or provide better auditing through system logs. However, it is important to keep in mind that AppArmor is not a silver bullet and can only do so much to protect against exploits in your application code. It is important to provide good, restrictive profiles, and harden your applications and cluster from other angles as well.

{% endcapture %}

{% capture objectives %}

  • See an example of how to load a profile on a node
  • Learn how to enforce the profile on a Pod
  • Learn how to check that the profile is loaded
  • See what happens when a profile is violated
  • See what happens when a profile cannot be loaded

{% endcapture %}

{% capture prerequisites %}

Make sure:

  1. Kubernetes version is at least v1.4 -- Kubernetes support for AppArmor was added in v1.4. Kubernetes components older than v1.4 are not aware of the new AppArmor annotations, and will silently ignore any AppArmor settings that are provided. To ensure that your Pods are receiving the expected protections, it is important to verify the Kubelet version of your nodes:

    $ kubectl get nodes -o=jsonpath=$'{range .items[*]}{@.metadata.name}: {@.status.nodeInfo.kubeletVersion}\n{end}'
    gke-test-default-pool-239f5d02-gyn2: v1.4.0
    gke-test-default-pool-239f5d02-x1kf: v1.4.0
    gke-test-default-pool-239f5d02-xwux: v1.4.0
    
  2. AppArmor kernel module is enabled -- For the Linux kernel to enforce an AppArmor profile, the AppArmor kernel module must be installed and enabled. Several distributions enable the module by default, such as Ubuntu and SUSE, and many others provide optional support. To check whether the module is enabled, check the /sys/module/apparmor/parameters/enabled file:

    $ cat /sys/module/apparmor/parameters/enabled
    Y
    

    If the Kubelet contains AppArmor support (>= v1.4), it will refuse to run a Pod with AppArmor options if the kernel module is not enabled.

    Note: Ubuntu carries many AppArmor patches that have not been merged into the upstream Linux kernel, including patches that add additional hooks and features. Kubernetes has only been tested with the upstream version, and does not promise support for other features.

  3. Container runtime is Docker -- Currently the only Kubernetes-supported container runtime that also supports AppArmor is Docker. As more runtimes add AppArmor support, the options will be expanded. You can verify that your nodes are running docker with:

    $ kubectl get nodes -o=jsonpath=$'{range .items[*]}{@.metadata.name}: {@.status.nodeInfo.containerRuntimeVersion}\n{end}'
    gke-test-default-pool-239f5d02-gyn2: docker://1.11.2
    gke-test-default-pool-239f5d02-x1kf: docker://1.11.2
    gke-test-default-pool-239f5d02-xwux: docker://1.11.2
    

    If the Kubelet contains AppArmor support (>= v1.4), it will refuse to run a Pod with AppArmor options if the runtime is not Docker.

  4. Profile is loaded -- AppArmor is applied to a Pod by specifying an AppArmor profile that each container should be run with. If any of the specified profiles is not already loaded in the kernel, the Kubelet (>= v1.4) will reject the Pod. You can view which profiles are loaded on a node by checking the /sys/kernel/security/apparmor/profiles file. For example:

    $ ssh gke-test-default-pool-239f5d02-gyn2 "sudo cat /sys/kernel/security/apparmor/profiles | sort"
    apparmor-test-deny-write (enforce)
    apparmor-test-audit-write (enforce)
    docker-default (enforce)
    k8s-nginx (enforce)
    

    For more details on loading profiles on nodes, see Setting up nodes with profiles.

As long as the Kubelet version includes AppArmor support (>= v1.4), the Kubelet will reject a Pod with AppArmor options if any of the prerequisites are not met. You can also verify AppArmor support on nodes by checking the node ready condition message (though this is likely to be removed in a later release):

$ kubectl get nodes -o=jsonpath=$'{range .items[*]}{@.metadata.name}: {.status.conditions[?(@.reason=="KubeletReady")].message}\n{end}'
gke-test-default-pool-239f5d02-gyn2: kubelet is posting ready status. AppArmor enabled
gke-test-default-pool-239f5d02-x1kf: kubelet is posting ready status. AppArmor enabled
gke-test-default-pool-239f5d02-xwux: kubelet is posting ready status. AppArmor enabled

{% endcapture %}

{% capture lessoncontent %}

Securing a Pod

Note: AppArmor is currently in beta, so options are specified as annotations. Once support graduates to general availability, the annotations will be replaced with first-class fields (more details in Upgrade path to GA).

AppArmor profiles are specified per-container. To specify the AppArmor profile to run a Pod container with, add an annotation to the Pod's metadata:

container.apparmor.security.beta.kubernetes.io/<container_name>: <profile_ref>

Where <container_name> is the name of the container to apply the profile to, and <profile_ref> specifies the profile to apply. The profile_ref can be one of:

  • runtime/default to apply the runtime's default profile
  • localhost/<profile_name> to apply the profile loaded on the host with the name <profile_name>
  • unconfined to indicate that no profiles will be loaded

See the API Reference for the full details on the annotation and profile name formats.

Kubernetes AppArmor enforcement works by first checking that all the prerequisites have been met, and then forwarding the profile selection to the container runtime for enforcement. If the prerequisites have not been met, the Pod will be rejected, and will not run.

To verify that the profile was applied, you can look for the AppArmor security option listed in the container created event:

$ kubectl get events | grep Created
22s        22s         1         hello-apparmor     Pod       spec.containers{hello}   Normal    Created     {kubelet e2e-test-stclair-minion-group-31nt}   Created container with docker id 269a53b202d3; Security:[seccomp=unconfined apparmor=k8s-apparmor-example-deny-write]

You can also verify directly that the container's root process is running with the correct profile by checking its proc attr:

$ kubectl exec <pod_name> cat /proc/1/attr/current
k8s-apparmor-example-deny-write (enforce)

Example

This example assumes you have already set up a cluster with AppArmor support.

First, we need to load the profile we want to use onto our nodes. The profile we'll use simply denies all file writes:

{% include code.html language="text" file="deny-write.profile" ghlink="/docs/tutorials/clusters/deny-write.profile" %}

Since we don't know where the Pod will be scheduled, we'll need to load the profile on all our nodes. For this example we'll just use SSH to install the profiles, but other approaches are discussed in Setting up nodes with profiles.

$ NODES=(
    # The SSH-accessible domain names of your nodes
    gke-test-default-pool-239f5d02-gyn2.us-central1-a.my-k8s
    gke-test-default-pool-239f5d02-x1kf.us-central1-a.my-k8s
    gke-test-default-pool-239f5d02-xwux.us-central1-a.my-k8s)
$ for NODE in ${NODES[*]}; do ssh $NODE 'sudo apparmor_parser -q <<EOF
#include <tunables/global>

profile k8s-apparmor-example-deny-write flags=(attach_disconnected) {
  #include <abstractions/base>

  file,

  # Deny all file writes.
  deny /** w,
}
EOF'
done

Next, we'll run a simple "Hello AppArmor" pod with the deny-write profile:

{% include code.html language="yaml" file="hello-apparmor-pod.yaml" ghlink="/docs/tutorials/clusters/hello-apparmor-pod.yaml" %}

$ kubectl create -f ./hello-apparmor-pod.yaml

If we look at the pod events, we can see that the Pod container was created with the AppArmor profile "k8s-apparmor-example-deny-write":

$ kubectl get events | grep hello-apparmor
14s        14s         1         hello-apparmor   Pod                                Normal    Scheduled   {default-scheduler }                           Successfully assigned hello-apparmor to gke-test-default-pool-239f5d02-gyn2
14s        14s         1         hello-apparmor   Pod       spec.containers{hello}   Normal    Pulling     {kubelet gke-test-default-pool-239f5d02-gyn2}   pulling image "busybox"
13s        13s         1         hello-apparmor   Pod       spec.containers{hello}   Normal    Pulled      {kubelet gke-test-default-pool-239f5d02-gyn2}   Successfully pulled image "busybox"
13s        13s         1         hello-apparmor   Pod       spec.containers{hello}   Normal    Created     {kubelet gke-test-default-pool-239f5d02-gyn2}   Created container with docker id 06b6cd1c0989; Security:[seccomp=unconfined apparmor=k8s-apparmor-example-deny-write]
13s        13s         1         hello-apparmor   Pod       spec.containers{hello}   Normal    Started     {kubelet gke-test-default-pool-239f5d02-gyn2}   Started container with docker id 06b6cd1c0989

We can verify that the container is actually running with that profile by checking its proc attr:

$ kubectl exec hello-apparmor cat /proc/1/attr/current
k8s-apparmor-example-deny-write (enforce)

Finally, we can see what happens if we try to violate the profile by writing to a file:

$ kubectl exec hello-apparmor touch /tmp/test
touch: /tmp/test: Permission denied
error: error executing remote command: command terminated with non-zero exit code: Error executing in Docker Container: 1

To wrap up, let's look at what happens if we try to specify a profile that hasn't been loaded:

$ kubectl create -f /dev/stdin <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: hello-apparmor-2
  annotations:
    container.apparmor.security.beta.kubernetes.io/hello: localhost/k8s-apparmor-example-allow-write
spec:
  containers:
  - name: hello
    image: busybox
    command: [ "sh", "-c", "echo 'Hello AppArmor!' && sleep 1h" ]
EOF
pod "hello-apparmor-2" created

$ kubectl describe pod hello-apparmor-2
Name:          hello-apparmor-2
Namespace:     default
Node:          gke-test-default-pool-239f5d02-x1kf/
Start Time:    Tue, 30 Aug 2016 17:58:56 -0700
Labels:        <none>
Annotations:   container.apparmor.security.beta.kubernetes.io/hello=localhost/k8s-apparmor-example-allow-write
Status:        Pending
Reason:        AppArmor
Message:       Pod Cannot enforce AppArmor: profile "k8s-apparmor-example-allow-write" is not loaded
IP:
Controllers:   <none>
Containers:
  hello:
    Container ID:
    Image:     busybox
    Image ID:
    Port:
    Command:
      sh
      -c
      echo 'Hello AppArmor!' && sleep 1h
    State:              Waiting
      Reason:           Blocked
    Ready:              False
    Restart Count:      0
    Environment:        <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-dnz7v (ro)
Conditions:
  Type          Status
  Initialized   True
  Ready         False
  PodScheduled  True
Volumes:
  default-token-dnz7v:
    Type:    Secret (a volume populated by a Secret)
    SecretName:    default-token-dnz7v
    Optional:   false
QoS Class:      BestEffort
Node-Selectors: <none>
Tolerations:    <none>
Events:
  FirstSeen    LastSeen    Count    From                        SubobjectPath    Type        Reason        Message
  ---------    --------    -----    ----                        -------------    --------    ------        -------
  23s          23s         1        {default-scheduler }                         Normal      Scheduled     Successfully assigned hello-apparmor-2 to e2e-test-stclair-minion-group-t1f5
  23s          23s         1        {kubelet e2e-test-stclair-minion-group-t1f5}             Warning        AppArmor    Cannot enforce AppArmor: profile "k8s-apparmor-example-allow-write" is not loaded

Note the pod status is Failed, with a helpful error message: Pod Cannot enforce AppArmor: profile "k8s-apparmor-example-allow-write" is not loaded. An event was also recorded with the same message.

Administration

Setting up nodes with profiles

Kubernetes does not currently provide any native mechanisms for loading AppArmor profiles onto nodes. There are lots of ways to setup the profiles though, such as:

  • Through a DaemonSet that runs a Pod on each node to ensure the correct profiles are loaded. An example implementation can be found here.
  • At node initialization time, using your node initialization scripts (e.g. Salt, Ansible, etc.) or image.
  • By copying the profiles to each node and loading them through SSH, as demonstrated in the Example.

The scheduler is not aware of which profiles are loaded onto which node, so the full set of profiles must be loaded onto every node. An alternative approach is to add a node label for each profile (or class of profiles) on the node, and use a node selector to ensure the Pod is run on a node with the required profile.

Restricting profiles with the PodSecurityPolicy

If the PodSecurityPolicy extension is enabled, cluster-wide AppArmor restrictions can be applied. To enable the PodSecurityPolicy, the following flag must be set on the apiserver:

--enable-admission-plugins=PodSecurityPolicy[,others...]

The AppArmor options can be specified as annotations on the PodSecurityPolicy:

apparmor.security.beta.kubernetes.io/defaultProfileName: <profile_ref>
apparmor.security.beta.kubernetes.io/allowedProfileNames: <profile_ref>[,others...]

The default profile name option specifies the profile to apply to containers by default when none is specified. The allowed profile names option specifies a list of profiles that Pod containers are allowed to be run with. If both options are provided, the default must be allowed. The profiles are specified in the same format as on containers. See the API Reference for the full specification.

Disabling AppArmor

If you do not want AppArmor to be available on your cluster, it can be disabled by a command-line flag:

--feature-gates=AppArmor=false

When disabled, any Pod that includes an AppArmor profile will fail validation with a "Forbidden" error. Note that by default docker always enables the "docker-default" profile on non-privileged pods (if the AppArmor kernel module is enabled), and will continue to do so even if the feature-gate is disabled. The option to disable AppArmor will be removed when AppArmor graduates to general availability (GA).

Upgrading to Kubernetes v1.4 with AppArmor

No action is required with respect to AppArmor to upgrade your cluster to v1.4. However, if any existing pods had an AppArmor annotation, they will not go through validation (or PodSecurityPolicy admission). If permissive profiles are loaded on the nodes, a malicious user could pre-apply a permissive profile to escalate the pod privileges above the docker-default. If this is a concern, it is recommended to scrub the cluster of any pods containing an annotation with apparmor.security.beta.kubernetes.io.

Upgrade path to General Availability

When AppArmor is ready to be graduated to general availability (GA), the options currently specified through annotations will be converted to fields. Supporting all the upgrade and downgrade paths through the transition is very nuanced, and will be explained in detail when the transition occurs. We will commit to supporting both fields and annotations for at least 2 releases, and will explicitly reject the annotations for at least 2 releases after that.

Authoring Profiles

Getting AppArmor profiles specified correctly can be a tricky business. Fortunately there are some tools to help with that:

  • aa-genprof and aa-logprof generate profile rules by monitoring an application's activity and logs, and admitting the actions it takes. Further instructions are provided by the AppArmor documentation.
  • bane is an AppArmor profile generator for Docker that uses a simplified profile language.

It is recommended to run your application through Docker on a development workstation to generate the profiles, but there is nothing preventing running the tools on the Kubernetes node where your Pod is running.

To debug problems with AppArmor, you can check the system logs to see what, specifically, was denied. AppArmor logs verbose messages to dmesg, and errors can usually be found in the system logs or through journalctl. More information is provided in AppArmor failures.

API Reference

Pod Annotation

Specifying the profile a container will run with:

  • key: container.apparmor.security.beta.kubernetes.io/<container_name> Where <container_name> matches the name of a container in the Pod. A separate profile can be specified for each container in the Pod.
  • value: a profile reference, described below

Profile Reference

  • runtime/default: Refers to the default runtime profile.
    • Equivalent to not specifying a profile (without a PodSecurityPolicy default), except it still requires AppArmor to be enabled.
    • For Docker, this resolves to the docker-default profile for non-privileged containers, and unconfined (no profile) for privileged containers.
  • localhost/<profile_name>: Refers to a profile loaded on the node (localhost) by name.
  • unconfined: This effectively disables AppArmor on the container.

Any other profile reference format is invalid.

PodSecurityPolicy Annotations

Specifying the default profile to apply to containers when none is provided:

  • key: apparmor.security.beta.kubernetes.io/defaultProfileName
  • value: a profile reference, described above

Specifying the list of profiles Pod containers is allowed to specify:

  • key: apparmor.security.beta.kubernetes.io/allowedProfileNames
  • value: a comma-separated list of profile references (described above)
    • Although an escaped comma is a legal character in a profile name, it cannot be explicitly allowed here.

{% endcapture %}

{% capture whatsnext %}

Additional resources:

{% endcapture %}

{% include templates/tutorial.md %}