kubestronautへの道 ~CKS編 その5 killer coda「AppArmor」~

tech article

今日覚えて帰ること

AppArmorの概要

  • 実行ファイルごとに詳細なアクセス制御を設定するためことを目的とした、Linuxカーネルのセキュリティモジュールのこと
  • aa-statusでプロファイルのステータスが確認できる
  • apparmor_parsor -r <path> でプロファイルを読み込める

AppArmor

Check existing AppArmor profiles

You’re asked to verify if the following AppArmor profiles are available on node01 :

docker-default
snap.lxd.lxc
ftpd
/usr/sbin/tcpdump

Create file /root/profiles.txt on node controlplane . It should contain only these profile names that are available on node01 .

node01で有効化されているAppArmor profileを確認し、有効であるプロファイル名をcontrolplaneの
/root/profiles.txtに書き込めというお題です。

sshでnode01にログインし、apparmor_statusコマンドを実行して有効になっているプロファイルを確認します。

controlplane $ ssh node01
Last login: Mon Jul 29 12:40:31 2024 from 10.244.5.178
node01 $ apparmor_status 
apparmor module is loaded.
30 profiles are loaded.
30 profiles are in enforce mode.
   /snap/snapd/21759/usr/lib/snapd/snap-confine
   /snap/snapd/21759/usr/lib/snapd/snap-confine//mount-namespace-capture-helper
   /usr/bin/man
   /usr/lib/NetworkManager/nm-dhcp-client.action
   /usr/lib/NetworkManager/nm-dhcp-helper
   /usr/lib/connman/scripts/dhclient-script
   /usr/lib/snapd/snap-confine
   /usr/lib/snapd/snap-confine//mount-namespace-capture-helper
   /usr/sbin/tcpdump
   /{,usr/}sbin/dhclient
   cri-containerd.apparmor.d
   docker-default
   lsb_release
   man_filter
   man_groff
   nvidia_modprobe
   nvidia_modprobe//kmod
   snap-update-ns.lxd
   snap.lxd.activate
   snap.lxd.benchmark
   snap.lxd.buginfo
   snap.lxd.check-kernel
   snap.lxd.daemon
   snap.lxd.hook.configure
   snap.lxd.hook.install
   snap.lxd.hook.remove
   snap.lxd.lxc
   snap.lxd.lxc-to-lxd
   snap.lxd.lxd
   snap.lxd.migrate
0 profiles are in complain mode.
5 processes have profiles defined.
5 processes are in enforce mode.
   /usr/sbin/dhclient (656) /{,usr/}sbin/dhclient
   /usr/sbin/dhclient (769) /{,usr/}sbin/dhclient
   /usr/sbin/dhclient (1017) /{,usr/}sbin/dhclient
   /coredns (2232) cri-containerd.apparmor.d
   /coredns (2399) cri-containerd.apparmor.d
0 processes are in complain mode.
0 processes are unconfined but have a profile defined.
node01 $ 

問題文に記載されているprofileのうち、node01で有効化されているプロファイルは以下の3つです。

docker-default
snap.lxd.lxc
/usr/sbin/tcpdump

これをcontrolplaneの /root/profiles.txt に書き込めばOKです。

この設問はこれでOKですが、そもそもAppArmorとは何なのでしょうか?

AppArmor

AppArmorとは、実行ファイルごとに詳細なアクセス制御を設定するためことを目的とした、Linuxカーネルのセキュリティモジュールです。

CKSの試験対策記事を見てみると、一からプロファイルを設定できる必要はなさそうで、

  • プロファイルをAppArmorへ登録すること
  • プロファイルをPod上のコンテナへ適用すること

この2点を抑えておけばよさそうです。

apparmor-utilsをインストールすることで使えるようになる便利なコマンドがいくつかあります。
CKSで使用するエミュレータには最初からapparmor-utilsはインストールされています。

  • aa-status(ファイルやプロセスのプロファイルへの適用状態を確認できる)
  • apparmor-parser(AppArmorプロファイルを読み込み、解析し、カーネルにロードする)
    • -a <path> (<path>プロファイルを追加する。add。)
    • -r <path> (既存の<path>プロファイルを上書きする。replace。)
    • -p <path> (<path>プロファイルの前処理(プリプロセス)行う。preprocess。)

などなど。
困ったときは我らが -h コマンドでヘルプを求めることが出来ます。

Fix Deployment with wrong AppArmor config

There is an existing Deployment named spacecow in Namespace moon .

It should be configured to use AppArmor profile docker-default , but something seems wrong.

Fix it.

Developmentに対してAppArmorのプロファイルを使って権限の制御を行え、という問題です。
どこかに設定ミスがあるようです。

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    container.apparmor.security.beta.kubernetes.io/httpd: localhost/docker-default
    deployment.kubernetes.io/revision: "2"
  creationTimestamp: "2024-07-29T15:05:03Z"
  generation: 2
  name: spacecow


///


        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext:
        appArmorProfile:
          localhostProfile: docker
          type: Localhost
                               

長くなるので間は省略しています。

公式ページを読むと、PodでAppArmorを使用したいならannotationを設定する必要があると書いています。

AppArmorを使用してコンテナのリソースへのアクセスを制限する
FEATURE STATE: Kubernetes v1.4 AppArmorは、Linux標準のユーザー・グループをベースとしたパーミッションを補完するLinuxカーネルのセキュリティモジュールであり、プログラムのアクセスを限定されたリソースセットに制限するために利用されます。AppArmorを設定することで、任意の...

しかし、このシナリオではsecurityContextを編集するだけで良かったみたいです。
(解答にそう書いていた。)

アノテーションがあっても正解だったので、そちらで指定しても問題ないのかもしれないですね。
→ Kubernetes v1.30からアノテーションは廃止になったみたいです。やはり英語版を読むべきですね。

Restrict a Container's Access to Resources with AppArmor
FEATURE STATE: Kubernetes v1.4 This page shows you how to load AppArmor profiles on your nodes and enforce those profiles in Pods. To learn more about how Kuber...

修正出来たら、そのpodが実際に稼働しているワーカーノード(今回はnode01)にsshでログインして、そのpodに本当にapparmorが適用されているか確認します。

以下のようにすればよいです。

controlplane $ ssh node01
Last login: Sun Nov 13 17:27:09 2022 from 10.48.0.33

node01 $ crictl ps
CONTAINER           IMAGE               CREATED             STATE               NAME                ATTEMPT             POD ID              POD
e0e4bc7cf61b1       294cecd6c7790       39 seconds ago      Running             httpd               0                   111bd5424d3c8       spacecow-c4b49d8cc-7vrrl

///

c1d532ed0f305       a0bf559e280cf       6 minutes ago       Running             kube-proxy          1                   35f4ec0c9bf66       kube-proxy-nhmtq

node01 $ crictl inspect e0e4bc7cf61b1 | grep apparmor
          "apparmor": {
          "apparmor_profile": "localhost/docker-default"
        "apparmorProfile": "docker-default",
node01 $ 

k logs でチェックしようと思いましたが、大したログは出てきませんでした。

controlplane $ k logs -n moon spacecow-c4b49d8cc-7vrrl 
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 192.168.1.9. Set the 'ServerName' directive globally to suppress this message
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 192.168.1.9. Set the 'ServerName' directive globally to suppress this message
[Mon Jul 29 16:06:02.014348 2024] [mpm_event:notice] [pid 1:tid 140677577182024] AH00489: Apache/2.4.52 (Unix) configured -- resuming normal operations
[Mon Jul 29 16:06:02.014526 2024] [core:notice] [pid 1:tid 140677577182024] AH00094: Command line: 'httpd -D FOREGROUND'

回答に記載されてる確認方法は

  • podが動いているnodeにログイン(今回はnode01)
  • crictl psでcontainerIDを検索
  • crictl logsでログを確認

という手順でしたが、k logsと同じログが出ただけでした。

公式サイトではk execで入り込んで cat /proc/1/attr/current をすれば確認できるとのことでした。

Restrict a Container's Access to Resources with AppArmor
FEATURE STATE: Kubernetes v1.4 This page shows you how to load AppArmor profiles on your nodes and enforce those profiles in Pods. To learn more about how Kuber...

実際にやってみたらドンピシャで確認できました。

controlplane $ k exec -n moon spacecow-c4b49d8cc-9xcmn -- cat /proc/1/attr/current
docker-default (enforce)

Install AppArmor profile on nodes

There is an AppArmor profile at /root/profile .

It should be referenced by name docker-nginx-custom , change the profile if needed.

Install it on nodes controlplane and node01 .

プロファイルの名前を変更し、各ノードにインストールせよ、という問題ですね。

まずはプロファイルの中身を確認します。

controlplane $ cat /root/profile
#include <tunables/global>

profile docker-nginx flags=(attach_disconnected,mediate_deleted) {
  #include <abstractions/base>

  network inet tcp,
 
///

  deny /sys/firmware/** rwklx,
  deny /sys/kernel/security/** rwklx,
}
controlplane $ 

先頭の #include <tunables/global> はいわゆるおまじないで、/etc/apparmor.d/tunables/globalに記述されている環境変数などをインクルード(読み込み)します。

プロファイルの名前がdocker-nginxとなっているので、docker-nginx-customに変更します。

controlplane $ cat /root/profile
#include <tunables/global>

profile docker-nginx-custom flags=(attach_disconnected,mediate_deleted) {
  #include <abstractions/base>

  network inet tcp,
 
///

  deny /sys/firmware/** rwklx,
  deny /sys/kernel/security/** rwklx,
}
controlplane $ 

変更後は apparmor_parsarコマンド を使ってプロファイルを読み込みなおします。
-r オプションは本来 repalce を意味し、既存のプロファイルを読み込みなおすために使用します。
しかし、新規ファイルを読み込むこともできるのでとりあえず -r オプションを使うのが良いと思います。

controlplane $ apparmor_parser -r /root/profile

aa-statusでプロファイルの状況を確認します。

controlplane $ aa-status
apparmor module is loaded.
38 profiles are loaded.
38 profiles are in enforce mode.
   /snap/snapd/21759/usr/lib/snapd/snap-confine

///

   /{,usr/}sbin/dhclient
   cri-containerd.apparmor.d
   docker-default
   docker-nginx-custom

///

   /usr/bin/local-path-provisioner (4179) cri-containerd.apparmor.d
0 processes are in complain mode.
0 processes are unconfined but have a profile defined.

読み込まれています。

プロファイルの読み込みは node 毎に行う必要があるので node01 でもプロファイルを読み込みます。
scpでcontrolplaneからnode01にファイルをコピーします。

controlplane $ scp /root/profile node01:/root/profile

先ほどと同様のコマンドを実行します。

controlplane $ ssh node01
Last login: Tue Jul 30 10:47:08 2024 from 10.244.6.33
node01 $ apparmor_parser -r /root/profile 
node01 $ aa-status
apparmor module is loaded.
31 profiles are loaded.
31 profiles are in enforce mode.
   /snap/snapd/21759/usr/lib/snapd/snap-confine
   /snap/snapd/21759/usr/lib/snapd/snap-confine//mount-namespace-capture-helper

///

   /{,usr/}sbin/dhclient
   cri-containerd.apparmor.d
   docker-default
   docker-nginx-custom

///

   /usr/local/apache2/bin/httpd (4465) docker-default
0 processes are in complain mode.
0 processes are unconfined but have a profile defined.
node01 $ 

Kubernetes 1.30 には、AppArmor プロファイルをノードにロードするための組み込みメカニズムは用意されていないので、実運用の際には何らかの仕組みで全てのノードにプロファイルをロードする仕組みが必要です。

Restrict a Container's Access to Resources with AppArmor
FEATURE STATE: Kubernetes v1.4 This page shows you how to load AppArmor profiles on your nodes and enforce those profiles in Pods. To learn more about how Kuber...

参考

第798回 Ubuntuのセキュリティを支えるAppArmor入門 | gihyo.jp
今回はあまり意識することのないものの、知っておくといつか役に立つかもしれない、実際に役に立つ時はあまり来てほしくないAppArmorについて紹介します。
AppArmor - Qiita
AppArmor とは、Linux で一般的に使われている user / group を使ったセキュリティ機能(DAC)に加えて、実行ファイルごとにより細かく権限を設定する仕組みです。AppArmo…
【 更新者も必見 】 CKS 攻略ガイド ( 2023 年 6 月版 )
【対策メモ】Certified Kubernetes Security Specialist (CKS)試験 - Qiita
はじめに本記事は、Certified Kubernetes Security Specialist (CKS)試験の対策をしている上で覚えておくべきだと感じたことをメモとして残しておくものです。…
タイトルとURLをコピーしました