Amazon Web Services ブログ

Bottlerocket を利用した Amazon EKS 上の Deployment を KubeArmor でよりセキュアにしよう

この記事は Secure Bottlerocket deployments on Amazon EKS with KubeArmor (記事公開日: 2022 年 10 月 20 日) の翻訳記事です。

Introduction

Bottlerocket はセキュリティに焦点を当てたオペレーティングシステム (OS) イメージです。ホストまたはワーカーノードを保護するために、すぐに利用可能なセキュリティオプションを提供します。セキュリティを考慮する上で Bottlerocket は便利ですが、Pod やコンテナのセキュリティは依然としてアプリケーション開発者やプロバイダーの責任です。CNCF (Cloud Native Computing Foundation) のサンドボックスプロジェクトである KubeArmor は、extended Berkeley Packet Filter (eBPF) とBerkeley Packet Filter-Linux Security Module (BPF-LSM) を活用して Pod やコンテナを保護するランタイムセキュリティエンジンです。

KubeArmor はポリシーの適用に Linux セキュリティモジュール (LSM) を使用します。LSM は数十年前からホストの強化に伝統的に使用されてきたカーネルテクノロジーです。どの Linux プラットフォーム (例: Alpine Linux や、Ubuntu、Bottlerocket のようなコンテナに最適化された OS) でも動作します。LSM は設定が非常に難しく、その複雑さからセキュリティ管理者は無効化してしまうことがよくあります。KubeArmor の主な目的の 1 つは、ユーザーが LSM 自体について心配することなく、LSM の使用を簡素化して必要なポリシーを適用することです。つまり KubeArmor は LSM 自体の利点を活用しながら LSM の複雑さを抽象化します。

ソリューション概要

図1. KubeArmor のアーキテクチャ

ポリシー適用のための BPF-LSM のカーネルサポート

バージョン 0.5 では、KubeArmor は BPF-LSM と統合してPod やコンテナベースのポリシーを適用できるようになりました。BPF-LSM は、新しいカーネル (バージョン > 5.7) で導入された新しい LSM (Linux セキュリティモジュール) です。BPF-LSM を使用すると、KubeArmor はユーザー指定のポリシーコントロールを含む LSM フックに bpf-bytecode をアタッチできます。これによってすべてが変わります。bpf-bytecode はより豊富な情報とカーネルコンテキストにアクセスできるようになり、SELinux や AppArmor ポリシー言語の制約内で動作する必要がなくなりました。例えば、SELinux はポリシー定義言語を定義する Common Intermediate Language (CIL) を使用しています。そして、このポリシー言語のセマンティクスに厳密に従わなければならないセキュリティルールがあります。同様に、AppArmor は明示的なポリシー言語構文を指定しており、ユーザー指定のルールもこれらの構造に従う必要があります。

図2. BPF-LSM と KubeArmor

どのプラットフォームが BPF-LSM をサポートしていますか?

  • Bottlerocket
  • Amazon Linux 2 の最新イメージ。注: デフォルトの Amazon Linux 2 はカーネルバージョン 5.4 のままなので、bpf-lsm を併用することはできません。カーネルバージョン 5.10 にアップグレードすれば bpf-lsm で使用できます。デフォルトのカーネルを 5.10 にアップグレードするには、このガイドに従ってください
  • 詳細なリストについては、こちらをご確認ください。

KubeArmor が Bottlerocket のセキュリティを改善する方法

Bottlerocket は SELinux を使用してホストをロックダウンし、コンテナ間の限定的な分離を提供します。

KubeArmor は BPF-LSM を使用して プロセス、ファイル、プリミティブなネットワークの使用などに関するシステム動作を制限し、Bottlerocket でホストされている k8s Pod を保護することでセキュリティを強化します。たとえば、Pod 内にマウントされた k8s セキュリティアクセストークンは、デフォルトでその Pod 内のすべてのコンテナからアクセス可能です。
KubeArmor は、このようなトークンへのアクセスを特定のプロセスにのみ制限できます。同様に、KubeArmor はコンテナ内の機密情報(k8s Secret、x509 証明書など)を保護するために使用されます。KubeArmor は、任意の証明書のフォルダ (/etc/ssl//etc/pki//usr/local/share/ca-certificates/) 内のルート証明書を更新しようとする動作をブロックするようにポリシールールを指定できます。さらに、KubeArmor はコンテナ内の特定のバイナリの実行を制限することができます。

図3. Kubearmor が Bottlerocket のセキュリティを向上

なぜ Pod を保護することが重要なのでしょうか?

k8s Pod は Ingress コントローラーを介して外部からアクセスされることがあるエンティティです。そのため Pod 内のワークロードまたはアプリケーションが脆弱であれば、危険にさらされる可能性が高くなります。攻撃者がコンテナエスケープを利用してホストを危険にさらす可能性があります。Pod には別システムへの攻撃を行ったり、データを盗み出したりする可能性がある攻撃ベクトルがあります。

NSA-CISA K8s Hardening Guide の引用:

「クラスター内で実行されるアプリケーションは一般的なターゲットです。これらのアプリケーションはクラスターの外部から頻繁にアクセスされるため、リモートのサイバー攻撃者も到達可能な状態です。攻撃者は既に侵害された Pod を軸に、公開されたアプリケーションの内部アクセス可能なリソースを使用してクラスター内の権限を昇格させたりすることができます。」

AWS の責任分担モデルでは、Pod とアプリケーションのセキュリティは、ワークロードを実行するお客様の範囲内にあります。何十年にもわたってホストとノードが強化されてきたのと同じように、KubeArmor は Pod を強化する方法を提供します。

KubeArmor のポリシーは、ワークロードがデプロイされて実行された後のランタイムに適用されます。KubeArmor のポリシー管理は同様の方法で処理されるべきであり、ネットワークポリシーもランタイムに適用されます。

現実世界のユースケース

コンテナ化されたワークロードの多くでベースイメージとして使用される alpine イメージには、基本的にパッケージ管理ツールである /sbin/apk バイナリ が付属しています。これには、Pod 内の攻撃対象領域 (Attack Surface)を増やすツールを使用する、新しいバイナリがインストールされる可能性があります。本番環境では、これらのツールの実行を無効にするのが最善です。KubeArmor は、このようなバイナリの実行をブロックすることで攻撃対象領域を縮小します。

次のポリシー例は、その方法を示しています。

apiVersion: security.kubearmor.com/v1
kind: KubeArmorPolicy
metadata:
  name: alpine-pol
spec:
  selector:
    matchLabels:
      app: alpine
  process:
    matchPaths:
    - path: /sbin/apk
  action:
    Block

もう 1 つの方法として、k8s クラスターに Pod をデプロイする場合が挙げられます。これは、どのアプリケーションも Pod 内でアクセスする必要がない場合でも、その Pod はデフォルトで /var/run/secrets/kubernetes.io/serviceaccount のパスに Service Account トークンとともにマウントされるためです。攻撃者はトークンを利用して k8s のAPI サーバーにアクセスし、クラスター内の別のアプリケーションに移動可能になります。

NSA-CISA K8s Hardening Guide in the context の引用:

「デフォルトでは、Kubernetes は Pod の作成時に自動的に Service Account をプロビジョニングし、実行時にアカウントのシークレットトークンを Pod 内にマウントします。Kubernetes のオーケストレーションはバックグラウンドで透過的に行われるため、コンテナ化されたアプリケーションの多くは Service Account に直接アクセスする必要はありません。アプリケーションが侵害された場合、サイバー攻撃者は Pod 内のアカウントトークンを収集し、クラスターをさらに侵害するために使用される可能性があります。」

KubeArmor には、Pod 内の Service Account トークンパスへのアクセスを無効にすることで、Pod 内の Service Account トークンパスへのアクセスを制限する方法があります。

apiVersion: security.kubearmor.com/v1
kind: KubeArmorPolicy
metadata:
  name: block-token-access
spec:
  selector:
    matchLabels:
      app: alpine
  file:
    matchDirectories:
    - dir: /var/run/secrets/kubernetes.io/serviceaccount/
      recursive: true
  action:
    Block

ウォークスルー

Bottlerocket AMI を使用した Amazon EKS でのデプロイ手順

Bottlerocket を利用した Amazon Elastic Kubernetes Service (EKS) クラスターの実装に関するクイックスタートガイドに従ってください。クラスターが構築されたら、以下の手順に従って KubeArmor をインストールしてください。

Step 0. インストールの前提条件

eksctlkubectl、curl、jq をインストールします。このガイドでは、インストールを実行するホストが Linux マシンであることを前提としています。

Step 1. karmor の CLI ツールをダウンロードしてインストール

$ curl -sfL http://get.kubearmor.io/ | sh -s -- -b /usr/local/bin

Step 2. KubeArmor のインストール

$ karmor install

k8s クラスターがすでに存在し、必要な前提条件を満たしていて、ユーザーが Service Account と ClusterRoleBinding を作成する権利を持っていると仮定しています。

Step 3. サンプルアプリとポリシーの導入

a. サンプルアプリ (multiubuntu app) のデプロイ

$ kubectl apply -f https://raw.githubusercontent.com/kubearmor/KubeArmor/main/examples/multiubuntu/multiubuntu-deployment.yaml

b. サンプルポリシー のデプロイ

$ kubectl apply -f https://raw.githubusercontent.com/kubearmor/KubeArmor/main/examples/multiubuntu/security-policies/ksp-group-1-proc-path-block.yaml 

このサンプルポリシーは、ubuntu-1 Pod での sleep コマンドの実行をブロックします。

apiVersion: security.kubearmor.com/v1
kind: KubeArmorPolicy
metadata:
  name: ksp-group-1-proc-path-block
  namespace: multiubuntu
spec:
  severity: 5
  message: "block /bin/sleep"
  selector:
    matchLabels:
      group: group-1
  process:
    matchPaths:
    - path: /bin/sleep
  action:
    Block

上記のポリシーでは、process にバイナリのリスト (この場合は /bin/sleep のみ) を示す matchPaths のセットを定義し、action を Block にしています。そのため、/bin/sleep が実行されるとポリシーが有効になり、コマンドの実行が拒否されます。

Step c. ポリシー違反をシミュレート

$ POD_NAME=$(kubectl get pods -n multiubuntu -l "group=group-1,container=ubuntu-1" -o jsonpath='{.items[0].metadata.name}') && kubectl -n multiubuntu exec -it $POD_NAME -- bash
# sleep 1
(Permission Denied)

Step 4. KubeArmor からのアラートとテレメトリの取得

a. KubeArmor のポート転送を有効にする

$ kubectl port-forward -n kube-system svc/kubearmor 32767:32767

b. karmor CLI を使ってログを確認する

$ karmor logs –json | jq .
{
  "Timestamp": 1661286176,
  "UpdatedTime": "2022-08-23T20:22:56.286246Z",
  "ClusterName": "default",
  "HostName": " ip-192-168-18-137.ec2.internal",
  "NamespaceName": "multiubuntu",
  "PodName": "ubuntu-3-deployment-6d8587dc77-x5lxd",
  "ContainerID": "fb531f48f12a29623bf8629f63b5a21abe9ac7007b83aecff7c29c38ca52c37a",
  "ContainerName": "fb531f48f12a",
  "HostPPID": 926656,
  "HostPID": 926756,
  "PPID": 14,
  "PID": 75,
  "ParentProcessName": "/bin/dash",
  "ProcessName": "/bin/sleep",
  "PolicyName": "ksp-group-1-proc-path-block",
  "Severity": "5",
  "Message": "block /bin/sleep",
  "Type": "MatchedPolicy",
  "Source": "/bin/dash",
  "Operation": "Process",
  "Resource": "/bin/sleep 1",
  "Data": "syscall=SYS_EXECVE",
  "Enforcer": "BPFLSM",
  "Action": "Block",
  "Result": "Permission denied"
}

アラートイベントは、/bin/sleep の実行がブロックされたことを示し、このイベントにはコンテキスト情報 (関連するコンテナ、Pod、名前空間、ノードなど) が含まれます。また、アクションの適用者が「BPFLSM」だったことも分かります。

Step 5. 外部ロギングツールとの統合

KubeArmor は k8s DaemonSet として動作します。つまり、ポリシーを適用する Pod はワーカーノードごとにインストールされます。KubeArmor のデプロイの一部として kubearmor-relay-service がインストールされており、すべての KubeArmor の Pod に接続し、ログとイベントを処理するための単一のインターフェースポイントを提供します。以下の方法は、KubeArmor からのこれらのログとイベントを消費します。

  1. Prometheus へのイベントをエクスポートする。KubeArmor は、Prometheus へのイベントのエクスポートを使用する Prometheus exporter adapter を提供しています。
  2. elk-adapter を使ってイベントを ELK にエクスポートする。
  3. kubearmor-relay-service もイベントを標準出力にダンプします。これらのイベントは、Fluentd などのサードパーティ製の汎用 k8s ロギングバックエンドによって消費することも可能です。

Step 6. 後片付け

KubeArmor を k8s クラスターからアンインストールするには、以下を実行します。

$ karmor uninstall

不要なコストを避けるため、忘れずにクラスターを削除してください。Amazon EKS リソースの削除については、クリーンアップのセクションを参照してください。

まとめ

この記事では、Bottlerocket 上で動作するクラウドネイティブソリューションである KubeArmor を使用して、BPF-LSM を使用して Pod とコンテナを保護する方法を説明しました。k8s の場合、Pod は実行単位であり、外部エンティティに公開されることもあります。したがって、攻撃者がシステムプリミティブを使用して脆弱性を悪用する能力を制限できるように、Pod 内に防御層を設けることが不可欠です。KubeArmor は、Bottlerocket 上の Linux カーネルプリミティブを使用して Pod を強化する k8s ネイティブのソリューションです。

翻訳はソリューションアーキテクトの加治が担当しました。原文はこちらです。