Trending keywords: security, cloud, container,

Kubernetes セキュリティコンテキストを使用してポッドを保護する理由とその方法

SHARE:

Kubernetes の各リソースに必要な権限を割り当てると同時に、権限の過剰な付与を回避するにはどうすればよいでしょうか。つまり、最小権限の原則に従って権限を細かく定義するにはどうすればよいでしょうか。

その解決策は、Kubernetes セキュリティコンテキストです。セキュリティコンテキストとは、管理者がセキュリティ関連のパラメータをリソース単位で定義するためのツールです。そのため、ホストサーバー上のリソースへのアクセスに必要な特定の権限を各リソースに割り当てながら、特に必要のないリソースへのアクセスを拒否することができます。

この記事では、Kubernetes セキュリティコンテキストの仕組み、セキュリティコンテキストの定義方法、Kubernetes でセキュリティコンテキストを使用する際に留意すべき制限事項など、Kubernetes セキュリティコンテキストの概要について説明します。

Kubernetes セキュリティコンテキストとは

Kubernetes では、個々のポッドやコンテナ権限をセキュリティコンテキストで定義します。セキュリティコンテキストを使用すると、外部ファイルへのアクセス権や特権モードで実行する権限などをコンテナやポッドに付与できます。

内部セキュリティコンテキストと外部セキュリティコンテキスト

Kubernetes セキュリティコンテキストは、定義できるルールに応じて Kubernetes 自体の内部で適用されるものと、外部のセキュリティコンテキストツール(AppArmor や SELinux など)に統合されるものがあるという点が少し複雑です。

そのため、Kubernetes セキュリティコンテキストは、ポッドやコンテナの特定の権限を定義したり、Kubernetes 自体ではなく、ホスト上で実行される外部のセキュリティツールと Kubernetes とを統合したりする手段として考えることができます。

セキュリティコンテキストと RBAC

セキュリティコンテキストと Kubernetes ロールベースのアクセス制御(RBAC)は、似て非なるものです。主な違いは次のとおりです。

  • リソースの範囲: RBAC はポッドやノード、クラスター全体など、さまざまな Kubernetes リソースに適用できます。一方、セキュリティコンテキストはポッドにのみ権限を割り当てます。
  • アクション: RBAC は、管理者が RBAC ポリシー内で定義できる「動詞」に基づいてさまざまな権限を付与できます。セキュリティコンテキストは、特権モードでの実行のように事前に定義された特定の種類の機能のみを割り当てるため、RBAC よりも限定的です(ただし、SELinux や AppArmor を使用してルールを定義する場合はセキュリティコンテキストの方が柔軟です)。
  • 拡張性: 前述のとおり、セキュリティコンテキストは SELinux や AppArmor などの外部フレームワークと統合することによって拡張できます。Kubernetes RBAC では、外部ツールを使用してポリシーを定義することはできません。

つまり、セキュリティコンテキストは、RBAC では管理できないコンテナやポッドのセキュリティ権限を追加で定義する手段であると考えられます。ほとんどの Kubernetes 環境では、セキュリティコンテキストと RBAC を同時に使用することによって相互に補完することができます。

セキュリティコンテキストと Pod Security Policies

セキュリティコンテキストで定義できるセキュリティルールのほとんどはPod Security Policies でも構成できますが、これらは異なるツールです。

Kubernetes がセキュリティコンテキストと Pod Security Policies の両方をサポートしている理由は、セキュリティコンテキストが本来、Pod Security Policies の代替品であるためです。Pod Security Policies を使用すれば、クラスター内で実行されているすべてのポッドの権限を構成できますが、個々のポッドに適用できるセキュリティコンテキストの方が細かい制御が可能です。

Kubernetes バージョン1.21 では、Pod Security Policies は非推奨とされていますが、現時点では引き続きサポートされています。Pod Security Policies は Kubernetes 1.25 で 完全に削除されるため、定義済みの Pod Security Policies はその時点で無視されることになります。

Kubernetes セキュリティコンテキストの使用方法

Kubernetes では、セキュリティコンテキストを簡単に使用できます(SELinux や AppArmorと 統合せず、内部のセキュリティコンテキストのみ使用している場合はさらに簡単です)。ポッドのデプロイ時に作成するデプロイメントファイル内に、セキュリティコンテキストコードのブロックを含めるだけです。

たとえば、次のブロックでは、Kubernetes にユーザー ID が「1000」のポッドを実行するよう指示しています。また、ポッド内のすべてのコンテナに「2000」のグループ ID を割り当てています。

Spec:
  securityContext:
    runAsUser: 1000
    fsGroup: 2000

RBAC とは異なり、セキュリティコンテキストでは、セキュリティルールを適用するために複数の種類のファイル(Role や RoleBinding など)を定義する必要はありません。デプロイメントを宣言する際に必要なセキュリティコンテキストコードを追加するだけです。そこから先は Kubernetes が自動的にルールを適用します。

セキュリティコンテキストで割り当て(または拒否)が可能な権限の種類の概要については、Kubernetes のドキュメントを参照してください。ほとんどの管理者は、ユーザー ID やグループ ID に関する権限に加え、ポッドやコンテナを特権モードで実行できるパラメータの価値に気付くでしょう。特権モードで実行しているコンテナは、ホスト上のカーネルレベルのリソースに対して、root として実行するプロセスとほぼ同じアクセス権を持つため、通常は特権モードを許可しません。代わりに、コンテナやポッドによる特定のポートへのバインド、または特定の外部バイナリの実行を許可し、それ以外はコンテナ外のリソースへのアクセスを拒否するなど、権限を細かく定義します。

外部セキュリティコンテキストの使用

SELinux や AppArmor のような外部ツールに基づいてセキュリティコンテキストを適用するには、もう少し手間がかかります。ここでは、基本的な手順をご紹介します。

SELinux または AppArmor モジュールの読み込み

最初に、使用するフレームワーク(SELinux や AppArmor など)に関連付けられたカーネルモジュールが、コンテナやポッドをホストするノードにインストールされ、読み込まれていることを確認する必要があります。

ほとんどの場合、Kubernetes はポッドやコンテナを自動的にノードに割り当てるため、どのノードがどのコンテナやポッドをホストするかを事前に知ることはできません。そのため、これらのフレームワークを使用してセキュリティコンテキストを定義する場合、通常はクラスターのすべてのノードに AppArmor または SELinux をインストールする必要があります。

プロファイルの読み込み

モジュールを読み込んだら、権限の定義に使用する AppArmor または SELinux のプロファイルを読み込む必要があります。たとえば、この AppArmor プロファイルは、ファイルの書き込み機能を拒否します。

#include <tunables/global>

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

  file,

  # Deny all file writes.
  deny /** w,
}Code language: HTML, XML (xml)

ノードのファイルシステム内で、Kubernetes が読み込める場所にプロファイルを保存します。

ここでも、たいていはどのノードがどのコンテナやポッドを実行するかはわからないため、クラスター内の各ノードにプロファイルを読み込む必要があります。各ノードに SSH を設定してプロファイルを手動で適用するのを避けるためなど、これを効果的に行う方法については、ノードプロファイルに関する Kubernetes のドキュメントを参照してください。

Kubernetes でのプロファイルの適用

最後に、外部のセキュリティコンテキストプロファイルを参照し、デプロイメントに適用するよう Kubernetes に指示するセキュリティコンテキストブロックをデプロイメントファイルに追加します。

apiVersion: v1
kind: Pod
metadata:
  name: apparmor-demo
  annotations:
    container.apparmor.security.beta.kubernetes.io/hello: /path/to/policy-fileCode language: JavaScript (javascript)

次のコマンドで宣言を適用します。

kubectl create -f ./deployment.yml

これで、Kubernetes はデプロイメントファイル内で直接構成したセキュリティコンテキストと同じように、AppArmor や SELinux で構成したポリシーを適用するようになります。

セキュリティコンテキストの制約

Kubernetes セキュリティコンテキストは、特定の種類の権限を細かく定義するための強力なツールです。ただし、現時点ではいくつかの大きな制約があります。

Windows 非対応

まず、セキュリティコンテキストツールは現在、Linux ベースのサーバー上で有効な特権と権限にのみ対応しています。Kubernetes で Windows コンテナを実行する場合、セキュリティコンテキストは役に立ちません。

ポッド/コンテナレベルのセキュリティに限定

セキュリティコンテキストは、ポッドまたはコンテナの権限のみ定義することができます。スタックの他のレイヤの特権は制御できません。

当然ながら、セキュリティコンテキストで適用できるルールのほとんどは、コンテナまたはポッドに適用した場合にのみ意味を持ちます。たとえば、あるノードに非特権モードで実行するように指示しても意味はありません。

ここでは、セキュリティコンテキストがあくまでポッドまたはコンテナレベルのセキュリティ問題に対処するためのツールであることがポイントです。ノード、ユーザー、サービスアカウントなどを保護するには、RBAC などの他のツールが必要です。

進化する機能

セキュリティコンテキストは Kubernetes の比較的新しい機能であり、現在も進化し続けています。一部のパラメータ(Kubernetes 1.20 でベータ版が導入された fsGroupChangePolicy など)はまだ完全にサポートされておらず、今後さらに定義が追加される可能性があります。

そのため、現在、本番環境のクラスターでセキュリティコンテキストを使用することは確かに可能ですが、特定の種類の定義が今後のリリースで変更される可能性があるため、この機能の進化に注意深く目を向けることが重要です。

非効率なツール

ここまでに述べたとおり、一部の(特に SELinux や AppArmor プロファイルを使用する)セキュリティコンテキストの主な制約として、クラスターのすべてのノードには外部リソースをデプロイする必要があります。このプロセスを自動化する方法もありますが、自動化を設定するだけでもかなりの手間がかかります。また、異なる Linux ディストリビューションを実行しているノードがある場合、デプロイメントが複雑になる可能性があります。その場合、AppArmor や SELinux の設定をディストリビューションごとにカスタマイズしなければならなくなるでしょう。

将来的には、ノードをまたいだポリシープロファイルのデプロイメントを簡素化するツールの出現が期待されます。しかし、現時点では、ノードの設定にかかる労力を侮ってはいけません。

このような短所があるにもかかわらず、セキュリティコンテキストは、Kubernetes クラスターにおけるアクセス制御の潜在的な欠点を補う重要なリソースであると言えます。セキュリティコンテキストは範囲が限定されており、それ自体が完全なアクセス制御ソリューションというわけではありませんが、クラスター全体のセキュリティを強化する手段としてこのツールを活用することをおすすめします。