System Hardening
System Hardening
ここでは、システムの強化という観点から、Kubernetesクラスタを支えるノード(ホスト)とKubernetesのセキュリティについて学びます。ノード(ホスト)のOSにおいて、カーネルのセキュリティモジュールであるAppArmorとseccompを利用してKubernetesのセキュリティを強化することを理解します。
AppArmor
AppArmorはLinuxカーネルのセキュリティモジュールです。プロファイルを作成して読み取り、書き込み、プログラムの実行やファイルシステムのマウントなどシステム機能を制御できます。例えば、コンテナからノード(ホスト)のディレクトリをbind-mountした場合に、ディレクトリ全体ではなく個別のファイルやディレクトリに権限を設定できます。
AppArmorとKubernetesクラスタとのセキュリティを理解するために、AppArmorの制御プロファイルを作成し、Kubernetesクラスタ上のPodからファイルの書き込みができない環境を構築します。
- Kubernetes Version 1.4以上であること
- ノード(ホスト)のLinuxでAppArmor Kernel moduleが有効であること
- ContainerRuntimeがAppArmorをサポートしていること
- 参考: AppArmorを使用してコンテナのリソースへのアクセスを制限する
1. AppArmorの有効確認
最初にノード(ホスト)のOSにログインし、AppArmorが有効であるかを確認します。「Y」と表示されれば有効です。
$ cat /sys/module/apparmor/parameters/enable
Y
2. AppArmorプロファイルの作成
次に、AppArmorプロファイルを「/etc/apparmor.d/k8s-apparmor-example-deny-write」として作成します。
$ vim /etc/apparmor.d/k8s-apparmor-example-deny-write
#include <tunables/global>
profile k8s-apparmor-example-deny-write flags=(attach_disconnected) {
#include <abstractions/base>
file,
# Deny all file writes.
deny /** w,
}
3. AppArmorプロファイルの登録
apparmor_parserコマンドを実行して、AppArmorプロファイルを作成します。
$ apparmor_parser -q /etc/apparmor.d/k8s-apparmor-example-deny-write
登録できたことを確認します。
$ aa-status | grep k8s-apparmor-example-deny-write
k8s-apparmor-example-deny-write
/usr/bin/sleep (92896) k8s-apparmor-example-deny-write
以上で、ノード(ホスト)側での作業は完了です。
4. AppArmorプロファイルを定義したマニフェストの作成
登録したAppArmorプロファイルをannotationsに定義したPodのマニフェストを作成します。
apiVersion: v1
kind: Pod
metadata:
name: hello-apparmor
annotations:
# Tell Kubernetes to apply the AppArmor profile "k8s-apparmor-example-deny-write".
# Note that this is ignored if the Kubernetes node is not running version 1.4 or greater.
container.apparmor.security.beta.kubernetes.io/hello: localhost/k8s-apparmor-example-deny-write
spec:
containers:
- name: hello
image: busybox
command: [ "sh", "-c", "echo 'Hello AppArmor!' && sleep 1h" ]
5. マニフェストの適用と確認
$ kubectl apply -f hello-apparmor.yaml
pod/hello-apparmor created
Pod(hello-apparmor)がRunningであるかを確認します。
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-apparmor 1/1 Running 0 26s
hello-apparmorに接続し、定義したAppArmorプロファイルで実行されていることを確認します。
$ kubectl exec hello-apparmor -- cat /proc/1/attr/current
k8s-apparmor-example-deny-write (enforce)
「k8s-apparmor-example-deny-write(enforce)」と表示されれば問題ありません。
6. ファイル書き込みによる動作確認
hello-apparmorに接続し、touchコマンドを実行してファイル作成を試みます。
$ kubectl exec hello-apparmor -- touch /tmp/test
touch: /tmp/file: Permission denied
command terminated with exit code 1
Permission deniedとなり、ファイルを作成できません。
seccomp
seccompもLinuxカーネルのセキュリティモジュールです。プロファイルを作成して、コンテナが呼び出せるシステムコール(プロセス)を制御できます。不要なシステムコールを制限することで、カーネルの脆弱性を狙った攻撃を防ぎます。
例えば、chmodに関連するシステムコールを拒否するプロファイルを作成して、「$ docker run」コマンド実行時にオプションとしてプロファイル名を指定します。起動したコンテナ内でchmodコマンドを実行するとエラーとなり、権限設定ができません。
seccompとKubernetesクラスタとのセキュリティを理解するために、seccompの制御プロファイルを作成し、Kubernetesクラスタ上のPodからmkdirコマンドを実行してもディレクトリを作成できない環境を構築します。
1. seccompの有効確認
最初にノード(ホスト)のOSにログインし、seccompが有効であるかを確認します。「CONFIG_SECCOMP=y」と表示されれば有効です。
$ grep CONFIG_SECCOMP= /boot/config-$(uname -r)
CONFIG_SECCOMP=y
2. seccompプロファイルの作成
次に、専用ディレクトリを作成してからプロファイルを作成します。
$ mkdir -p /var/lib/kubelet/seccomp/profiles
$ vim /var/lib/kubelet/seccomp/profiles/prohibit-mkdir.json
{
"defaultAction": "SCMP_ACT_ALLOW",
"syscalls": [
{
"names": ["mkdir","mkdirat"],
"action": "SCMP_ACT_ERRNO"
}
]
}
以上で、ノード(ホスト)側での作業は完了です。
3. seccompプロファイルを定義したマニフェストの作成と適用
作成したseccompプロファイルを定義したPodのマニフェストを作成します。
apiVersion: v1
apiVersion: v1
kind: Pod
metadata:
name: prohibit-mkdir
spec:
securityContext:
seccompProfile:
type: Localhost
localhostProfile: profiles/prohibit-mkdir.json
containers:
- name: ubuntu
image: ubuntu:21.10
command:
- sleep
- infinity
「spec.securityContext.seccompProfile」では、以下を定義できます。
- localhostProfile:ノード(ホスト)上の「/var/lib/kubelet/seccomp」ディレクトリ内のファイルをProfileとして指定
※Kubernetes 1.19以前はannotationで指定、1.19以降はsecurityContextで指定 - RuntimeDefault:CRIランタイムのデフォルトプロファイル指定
- unconfined:seccomp不使用(デフォルト)
seccompにおいて、ホワイトリストでプロファイルをカスタマイズして作成することはセキュリティを高められますが、運用の煩雑さにつながるところもあります。場合によっては、ある程度コンテナアプリケーションで利用しないsyscallを制限したProfile(RuntimeDefault)の利用を検討する余地もあります。
マニフェストを適用します。
$ kubectl apply -f prohibit-mkdir.yaml
pod/prohibit-mkdir created
Pod(prohibit-mkdir)がRunningであるかを確認します。
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
prohibit-mkdir 1/1 Running 0 16s
4. 動作確認
prohibit-mkdirに接続して、ディレクトリ作成ができないことを確認します。
$ kubectl exec -it prohibit-mkdir -- mkdir test
mkdir: cannot create directory 'test': Operation not permitted
command terminated with exit code 1
Kubernetes v1.25からSeccompDefaultという機能が追加され、Podのspecでprofileを指定しなかった場合にRuntimeDefaultでコンテナを動かすことができます。
- この記事のキーワード