kakakakakku blog

Weekly Tech Blog: Keep on Learning!

Kubernetes と AppArmor を組み合わせてファイル操作を制限する

AppArmor (Application Armor) とは Linux Security Modules の1つで,プログラムに対して「ファイル操作」「マウント操作」などを制限する.詳しくは以下のドキュメントに載っている.

ubuntu.com

コンテナワークロードのセキュリティ対策として,AppArmor を Kubernetes でも多層防御として使える.今まで試したことがなく,今回は以下の検証環境を使って「Kubernetes と AppArmor」を組み合わせた基本的な制限を試していく!

  • Kubernetes v1.23.0
  • ワーカーノード : Ubuntu 20.04.3 LTS

AppArmor プロファイル

AppArmor では「AppArmor プロファイル」を作って読み込ませる必要がある.今回は Kubernetes ドキュメントに載っている以下のサンプルを使う.構文は少し複雑に見えるけど w = writedeny なので「全てのディレクトリでファイル操作(書き込み)を制限するプロファイル」と言える.

#include <tunables/global>

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

  file,

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

kubernetes.io

準備 : AppArmor 適用前

AppArmor を適用する前に通常の動作確認をする.以下のマニフェストを使って Ubuntu Pod を起動する.

apiVersion: v1
kind: Pod
metadata:
  name: ubuntu
spec:
  containers:
    - name: ubuntu
      image: ubuntu:21.10
      command:
        - sleep
        - infinity

Ubuntu Pod に接続をしてファイル操作(書き込み)を試す.期待通りに書き込めた.

  • /hello.txt : OK
  • /tmp/hello.txt : OK
$ kubectl apply -f ubuntu.yaml

$ kubectl exec -it ubuntu -- /bin/sh

# echo 'hello' > hello.txt
# cat hello.txt
hello

# echo 'hello' > /tmp/hello.txt
# cat /tmp/hello.txt
hello

検証 : 全てのディレクトリでファイル操作(書き込み)を制限する

さっそく AppArmor を適用する.まず,ワーカーノードに「AppArmor プロファイル」を読み込ませる.さっき紹介したプロファイルを k8s-apparmor-example-deny-write として保存して,apparmor_parser コマンドを使って読み込ませる.読み込ませたら aa-status コマンドを使って確認できる.

$ sudo apparmor_parser k8s-apparmor-example-deny-write

$ sudo aa-status | egrep 'profiles|k8s-apparmor-example-deny-write'
38 profiles are loaded.
36 profiles are in enforce mode.
   k8s-apparmor-example-deny-write
2 profiles are in complain mode.
5 processes have profiles defined.

次にマニフェストを更新して Ubuntu Pod を起動し直す.Pod に AppArmor プロファイルを適用する場合は annotations を追加する.今回は container.apparmor.security.beta.kubernetes.io/ubuntu: localhost/k8s-apparmor-example-deny-write とした.ubuntu はコンテナ名で localhost/k8s-apparmor-example-deny-write は AppArmor プロファイル名を意味している.

apiVersion: v1
kind: Pod
metadata:
  name: ubuntu
  annotations:
    container.apparmor.security.beta.kubernetes.io/ubuntu: localhost/k8s-apparmor-example-deny-write
spec:
  containers:
    - name: ubuntu
      image: ubuntu:21.10
      command:
        - sleep
        - infinity

もう一度 Ubuntu Pod に接続をしてファイル操作(書き込み)を試す.今度は AppArmor によって制限されているため失敗した.エラー内容としては Permission denied になった.

  • /hello.txt : NG
  • /tmp/hello.txt : NG
$ kubectl apply -f ubuntu.yaml

$ kubectl exec -it ubuntu -- /bin/sh

# echo 'hello' > hello.txt
/bin/sh: 1: cannot create hello.txt: Permission denied

# echo 'hello' > /tmp/hello.txt
/bin/sh: 3: cannot create /tmp/hello.txt: Permission denied

検証 : /tmp でファイル操作(書き込み)を制限する

今度は AppArmor プロファイルを更新して,/tmp に限定してファイル操作(書き込み)を制限する.更新箇所は deny /** w, から deny /tmp/** w, とした.

#include <tunables/global>

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

  file,

  # Deny all file writes.
  deny /tmp/** w,
}

改めてワーカーノードで「AppArmor プロファイル」を読み込ませる.同じく apparmor_parser コマンドを使うけど,更新するときは apparmor_parser -r コマンドを使う.

$ sudo apparmor_parser -r k8s-apparmor-example-deny-write

もう一度 Ubuntu Pod に接続をしてファイル操作(書き込み)を試す.今度は AppArmor によって制限されているため /tmp のみ失敗した.

  • /hello.txt : OK
  • /tmp/hello.txt : NG
$ kubectl apply -f ubuntu.yaml

$ kubectl exec -it ubuntu -- /bin/sh

# echo 'hello' > hello.txt
# cat hello.txt
hello

# echo 'hello' > /tmp/hello.txt
/bin/sh: 5: cannot create /tmp/hello.txt: Permission denied

参考 : AppArmor プロファイルを生成する

今回は Kubernetes ドキュメントに載っているサンプルを使ったけど,ファイル操作以外も制限できる.AppArmor の apparmor-easyprof コマンド(簡易的な雛形のみ)や aa-genprof コマンド(プロファイリングもする)を使うと「AppArmor プロファイル」を生成できる.

aa-genprof コマンドを使うと自動的に /etc/apparmor.d/ に AppArmor プロファイルが生成されるので,例えば /usr/bin/curl を制限する場合は /etc/apparmor.d/usr.bin.curl というプロファイルになる.今回は w 以外に m = memory map executabler = read が追加されている.

$ sudo apt install -y apparmor-utils
$ sudo apt install -y apparmor-easyprof

$ sudo aa-easyprof /usr/bin/curl
# vim:syntax=apparmor
# AppArmor policy for curl
# ###AUTHOR###
# ###COPYRIGHT###
# ###COMMENT###

#include <tunables/global>

# No template variables specified

"/usr/bin/curl" {
  #include <abstractions/base>

  # No abstractions specified

  # No policy groups specified

  # No read paths specified

  # No write paths specified
}

$ sudo aa-genprof /usr/bin/curl

(中略)

[(S)can system log for AppArmor events] / (F)inish

(中略)

Finished generating profile for /usr/bin/curl.

$ cat /etc/apparmor.d/usr.bin.curl
# Last Modified: Fri Apr  8 04:20:37 2022
#include <tunables/global>

/usr/bin/curl {
  #include <abstractions/base>

  /usr/bin/curl mr,

}

まとめ

コンテナワークロードのセキュリティ対策として,AppArmor と Kubernetes の組み合わせを試した.実際にファイル操作を制限した Pod を起動できた!

関連記事

システムコールを制限するなら seccomp と組み合わせる案もある.詳しくは以下の記事にまとめてある!

kakakakakku.hatenablog.com