1. はじめに
Microsoft Defender for Containers では Kubernetes 用の Azure ポリシーをクラスター環境に適用することで、Microsoft Defender for Cloud の推奨事項にクラスター構成のセキュリティベストプラクティスのチェックを行うことが出来るようになっています。
設定方法やチューニングなどが若干必要になっており、見方などが分かり難いので本記事でまとめています。詳細は以下公式 Docs を参照してください。
2. 事前準備 - AKS クラスターに Azure ポリシーを適用する
AKS クラスターに Azure ポリシーを適用する方法は 2 つありますが、前者の設定が簡単なのでお勧めです。
-
Microsoft Defender for Cloud の「環境設定」で Azure ポリシー適用を有効にしておく
-
特定のクラスターに関する推奨事項を使用して、アドオンをクラスターに手動でデプロイする
- 複数のクラスターが存在しており、特定のクラスターに対して有効化する場合は、以下の推奨事項より、手動で設定することが出来ます。
3. Kubernetes 向け推奨事項を理解する
3.1 クラスター向け Azure ポリシーのリスト
Kubernetes クラスターに提供されている Azure ポリシーはパラメータチューニング不要で動くものと、自社環境に合ったパラメータを入れて成立する推奨事項が提供されています。ケースによっては自社環境にとって監視不要な項目も判断して、必要な推奨事項を採択しましょう。
推奨事項の名前 | 重大度 | セキュリティ制御 | パラメータ構成が必要 |
---|---|---|---|
コンテナーの CPU とメモリの制限を強制する必要がある | 中 | DDoS 攻撃からのアプリケーションの保護 | 必要 |
コンテナー イメージは信頼されたレジストリからのみデプロイする必要がある | 高 | 脆弱性の修復 | 必要 |
コンテナーで最小限の特権を持つ Linux 機能を適用する必要がある | 中 | アクセスおよびアクセス許可の管理 | 必要 |
コンテナーでは、許可されている AppArmor プロファイルのみを使用する | 高 | セキュリティ構成の修復 | 必要 |
サービスは許可されたポートでのみリッスンする必要がある | 中 | 承認されていないネットワーク | 必要 |
ホストネットワークとポートの使用を制限する必要がある | 中 | 承認されていないネットワークアクセスの制限 | 必要 |
ポッド HostPath ボリューム マウントの使用は既知のリストに制限する必要がある | 中 | アクセスおよびアクセス許可の管理 | 必要 |
特権エスカレーションを含むコンテナーは避ける必要がある | 中 | アクセスおよびアクセス許可の管理 | 不要 |
機密性の高いホストの名前空間を共有するコンテナーは避ける必要がある | 中 | アクセスおよびアクセス許可の管理 | 不要 |
コンテナーで不変 (読み取り専用) のルートファイル システムを適用する必要がある | 中 | アクセスおよびアクセス許可の管理 | 不要 |
Kubernetes クラスターは HTTPS 経由でのみアクセス可能である必要がある | 高 | 転送中のデータを暗号化する | 不要 |
Kubernetes クラスターで API 資格情報の自動マウントを無効にする必要がある | 高 | アクセスおよびアクセス許可の管理 | 不要 |
Kubernetes クラスターでは既定の名前空間を使用しない | 低 | セキュリティのベストプラクティスを実装する | 不要 |
Kubernetes クラスターでは CAPSYSADMIN セキュリティ機能を許可しない | 高 | アクセスおよびアクセス許可の管理 | 不要 |
特権コンテナーの使用を避ける | 中 | アクセスおよびアクセス許可の管理 | 不要 |
コンテナーをルート ユーザーとして実行しない | 高 | アクセスおよびアクセス許可の管理 | 不要 |
3.2 推奨事項をテストするためのテンプレート
Azure ポリシーの推奨事項を判定するためのサンプルの YAML テンプレートが公開されています。
実際に検知した際の動作や、自社環境で検知する理由の原因分析・判定に利用しましょう。
- 正常なデプロイのサンプル.yaml ファイル
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis-healthy-deployment
labels:
app: redis
spec:
replicas: 3
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
annotations:
container.apparmor.security.beta.kubernetes.io/redis: runtime/default
spec:
containers:
- name: redis
image: <customer-registry>.azurecr.io/redis:latest
ports:
- containerPort: 80
resources:
limits:
cpu: 100m
memory: 250Mi
securityContext:
privileged: false
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
runAsNonRoot: true
runAsUser: 1000
---
apiVersion: v1
kind: Service
metadata:
name: redis-healthy-service
spec:
type: LoadBalancer
selector:
app: redis
ports:
- port: 80
targetPort: 80
-
異常なデプロイのサンプル.yaml ファイル (構成に以下が含まれています)
- レポジトリを用いていない
- Pod 側での CPU / Memory 制限を用いていない
- apparmor 未使用
- 特権コンテナー
privileged: true
- ReadOnly ではない
readOnlyRootFilesystem: false
- 特権エスカレーションが含まれる
allowPrivilegeEscalation: true
- root ユーザーでの実行
runAsUser: 0
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis-unhealthy-deployment
labels:
app: redis
spec:
replicas: 3
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
hostNetwork: true
hostPID: true
hostIPC: true
containers:
- name: redis
image: redis:latest
ports:
- containerPort: 9001
hostPort: 9001
securityContext:
privileged: true
readOnlyRootFilesystem: false
allowPrivilegeEscalation: true
runAsUser: 0
capabilities:
add:
- NET_ADMIN
volumeMounts:
- mountPath: /test-pd
name: test-volume
readOnly: true
volumes:
- name: test-volume
hostPath:
# directory location on host
path: /tmp
---
apiVersion: v1
kind: Service
metadata:
name: redis-unhealthy-service
spec:
type: LoadBalancer
selector:
app: redis
ports:
- port: 6001
targetPort: 9001
3.3 詳細
個々の推奨事項の詳細は公式 Docs を参照ください。
コンテナーの CPU とメモリの制限を強制する必要がある
resources:
limits:
cpu: 100m # Pod の CPU を制限
memory: 250Mi # Pod の Memory を制限
コンテナーの起動に対して制限をかけるパラメータ項目です。
CPU とメモリの制限を適用することでリソース枯渇攻撃 (サービス拒否攻撃の一種) を防ぐことができます。
コンテナーに制限を設定し、設定された制限を超えてリソースがコンテナーで使用されないように、ランタイムによって防ぐことをお勧めします。
パラメータとしては以下項目を設定する必要がありますので、自社環境に合ったパラメータを検討しましょう。
パラメータ | 説明 | デフォルト値 |
---|---|---|
Max allowed CPU units in Kubernetes cluster | コンテナーに許可される最大 CPU ユニット数を定義します。詳細については、https://aka.ms/k8s-policy-pod-limits を参照してください。 | 32 |
Max allowed memory bytes in Kubernetes cluster | Kubernetes クラスターで許可される最大メモリ バイト数 | 64Gi |
Kubernetes namespaces to exclude from monitoring of memory and CPU limits | 評価から除外する Kubernetes 名前空間のリスト。 複数の名前空間をリストするには、セミコロン (;) を使用して名前空間を区切ります。 システム名前空間「kube-system」、「gatekeeper-system」、および「azure-arc」は、設計により常に除外されます。 | [ "kube-system", "gatekeeper-system", "azure-arc", "azuredefender", "mdc", "azure-extensions-usage-system"] |
Kubernetes image to exclude from monitoring of all container related polices | Kubernetes コンテナ関連のポリシー評価から除外する InitContainers とコンテナのリスト。 これは、「コンテナ イメージは信頼できるレジストリからのみデプロイする必要がある」と「Kubernetes クラスタは脆弱なイメージのデプロイをゲートする必要がある」を除く、すべてのコンテナ関連のポリシーに適用されます。 | [] |
Defender for Cloud のポリシー画面からは以下設定画面が表示されます。
コンテナー イメージは信頼されたレジストリからのみデプロイする必要がある
spec:
containers:
image: <customer-registry>.azurecr.io/redis:latest # レジストリ指定
Azure Container Registory (ACR) からの AKS クラスターへ Pod デプロイする際に「信頼された」レジストリーからのみに限定するようにポリシーを適用することが出来ます。
Kubernetes クラスターで実行されているイメージは、監視対象になっている既知のコンテナー イメージ レジストリのものである必要があります。信頼できるレジストリにより、不明な脆弱性、セキュリティの問題、悪意のあるイメージが持ち込まれる可能性が制限され、クラスターが危険にさらされるリスクが減ります。
正規表現 (regex) を用いて、ACR の名称を定義する設定が必要になります。
パラメータ | 説明 | デフォルト値 |
---|---|---|
Allowed registry or registries regex | Kubernetes クラスターで許可されているコンテナー イメージ フィールドと一致するために使用される正規表現。 たとえば、部分パスを一致させることで任意の Azure Container Registry イメージを許可するには: ^[^\/]+\.azurecr\.io\/.+$ 、複数のレジストリの場合: ^([^\/]+\.azurecr\.io|registry\.io)\/.+$
|
^(.+){0}$ |
Kubernetes namespaces to exclude from monitoring of allowed container images | 評価から除外する Kubernetes 名前空間のリスト。 複数の名前空間をリストするには、セミコロン (;) を使用して名前空間を区切ります。 システム名前空間「kube-system」、「gatekeeper-system」、および「azure-arc」は、設計により常に除外されます。 | [ "kube-system", "gatekeeper-system", "azure-arc", "azuredefender", "mdc", "azure-extensions-usage-system"] |
Defender for Cloud のポリシー画面からは以下設定画面が表示されます。
コンテナーで最小限の特権を持つ Linux 機能を適用する必要がある
コンテナーの攻撃面を減らすには、Linux の機能を制限し、ルート ユーザーのすべての特権をコンテナーに付与するのではなく、特定の特権を付与してください。
パラメータとしては以下項目を設定する必要があります。
パラメータ | 説明 | デフォルト値 |
---|---|---|
Kubernetes namespaces to exclude from monitoring of containers use only allowed capabilities | Kubernetes クラスターで許可された機能のみを使用するコンテナーの評価から監視から除外する Kubernetes 名前空間のリスト。 複数の名前空間をリストするには、セミコロン (;) を使用して名前空間を区切ります。 システム名前空間「kube-system」、「gatekeeper-system」、および「azure-arc」は、設計により常に除外されます。 | [ "kube-system", "gatekeeper-system", "azure-arc", "azuredefender", "mdc", "azure-extensions-usage-system"] |
Allowed capabilities | コンテナへの追加が許可されている機能のリスト。 すべてをブロックするには、入力として空のリストを指定します。 | [] |
Required drop capabilities | コンテナーによって削除される必要がある機能のリスト。 | [] |
Kubernetes image to exclude from monitoring of all container related polices | 評価から除外する InitContainers とコンテナのリスト。 これは、「コンテナ イメージは信頼できるレジストリからのみデプロイする必要がある」と「Kubernetes クラスタは脆弱なイメージのデプロイをゲートする必要がある」を除く、すべてのコンテナ関連のポリシーに適用されます。 識別子はコンテナのイメージです。 接頭辞一致は「*」で表すことができます。 例: myregistry.azurecr.io/istio:* 。 信頼できないリポジトリからイメージが予期せず除外されることを避けるために、ユーザーは完全修飾された Docker イメージ名 (ドメイン名で始まるなど) を使用することをお勧めします。 |
[] |
Defender for Cloud のポリシー画面からは以下設定画面が表示されます。
コンテナーでは、許可されている AppArmor プロファイルのみを使用する
# AppArmor プロファイルの例
annotations:
container.apparmor.security.beta.kubernetes.io/redis: runtime/default
Kubernetes クラスターで実行されているコンテナーは、許可されている AppArmor プロファイルのみに制限してください。AppArmor (Application Armor) は、オペレーティング システムとそのアプリケーションをセキュリティの脅威から保護する Linux セキュリティ モジュールです。これを使用するには、システム管理者が AppArmor セキュリティ プロファイルを各プログラムに関連付けます。
サービスは許可されたポートでのみリッスンする必要がある
ports:
- port: 80
targetPort: 80 # サービスのポート指定例
Kubernetes クラスターの攻撃面を減らすために、サービスのアクセスを構成済みポートに制限して、クラスターへのアクセスを制限します。事前にパラメータ設定が必要です。
パラメータ | 説明 | デフォルト値 |
---|---|---|
Allowed service ports list in Kubernetes cluster | Kubernetes クラスターで許可されるサービス ポートのリスト。 配列は文字列のみを受け入れます。 例: ["443", "80"]
|
初期値は無効状態[ "-1"]
|
Kubernetes namespaces to exclude from monitoring of allowed service ports | 対象外とする名前区間 | [ "kube-system", "gatekeeper-system", "azure-arc", "azure-extensions-usage-system"] |
Defender for Cloud のポリシー画面からは以下設定画面が表示されます。
ホストネットワークとポートの使用を制限する必要がある
ports:
- containerPort: 80
ポッドのアクセスを、Kubernetes クラスター内のホスト ネットワークおよび許容されるホスト ポート範囲に制限します。 hostNetwork 属性を有効にして作成されたポッドの間では、ノードのネットワーク領域が共有されます。 セキュリティ侵害を受けたコンテナーによってネットワーク トラフィックがスニッフィングされるのを防ぐため、ホスト ネットワークにはポッドを配置しないことをお勧めします。
コンテナー ポートをノード ネットワークに公開する必要があり、Kubernetes Service ノード ポートを使用してもニーズが満たされない場合は、ポッド仕様のコンテナーに対して hostPort を指定することもできます。
パラメータ | 説明 | デフォルト値 |
---|---|---|
Kubernetes namespaces to exclude from monitoring of containers host networking and ports | 除外対象とする名前空間 | [ "kube-system", "gatekeeper-system", "azure-arc", "azure-extensions-usage-system"] |
Allow host network usage | ポッドがホスト ネットワークの使用を許可されている場合はこの値を true に設定し、それ以外の場合は false に設定します。 | false |
Min host port for pod in Kubernetes cluster | ポッドがホスト ネットワーク名前空間で使用できる、許容されるホスト ポート範囲の最小値。 | 0 |
Max host port for pod in Kubernetes cluster | ポッドがホスト ネットワーク名前空間で使用できる、許容されるホスト ポート範囲の最大値。 | 0 |
Kubernetes image to exclude from monitoring of all container related polices | Kubernetes コンテナ関連のポリシー評価から除外する InitContainers とコンテナのリスト。 これは、「コンテナ イメージは信頼できるレジストリからのみデプロイする必要がある」と「Kubernetes クラスタは脆弱なイメージのデプロイをゲートする必要がある」を除く、すべてのコンテナ関連のポリシーに適用されます。 識別子はコンテナのイメージです。 接頭辞一致は「*」で表すことができます。 例: myregistry.azurecr.io/istio:* 。 信頼できないリポジトリからイメージが予期せず除外されることを避けるために、ユーザーは完全修飾された Docker イメージ名 (ドメイン名で始まるなど) を使用することをお勧めします。 |
[] |
Defender for Cloud のポリシー画面からは以下設定画面が表示されます。
ポッド HostPath ボリューム マウントの使用は既知のリストに制限する必要がある
volumes:
- name: test-volume
hostPath:
# directory location on host
path: /tmp
Kubernetes クラスター内のポッドの HostPath ボリューム マウントを、構成済みの許可されているホスト パスに制限することをお勧めします。 侵害を受けた場合は、コンテナーからのコンテナー ノード アクセスを制限する必要があります。
特権エスカレーションを含むコンテナーは避ける必要がある
securityContext:
allowPrivilegeEscalation: false # 特権昇格は利用させない
Kubernetes クラスター内のポッドの HostPath ボリューム マウントを、構成済みの許可されているホスト パスに制限することをお勧めします。 侵害を受けた場合は、コンテナーからのコンテナー ノード アクセスを制限する必要があります。
機密性の高いホストの名前空間を共有するコンテナーは避ける必要がある
Kubernetes クラスター内のポッドの HostPath ボリューム マウントを、構成済みの許可されているホスト パスに制限することをお勧めします。 侵害を受けた場合は、コンテナーからのコンテナー ノード アクセスを制限する必要があります。
コンテナーで不変 (読み取り専用) のルートファイル システムを適用する必要がある
securityContext:
readOnlyRootFilesystem: true # Pod のルートファイルシステムを読み取り専用にする
お使いの Kubernetes クラスターでは、読み取り専用のルート ファイル システムを使用してコンテナーを実行してください。 不変のファイル システムは、PATH に追加された悪意のあるバイナリによる実行時の変更から、コンテナーを保護します。
Kubernetes クラスターは HTTPS 経由でのみアクセス可能である必要がある
HTTPS を使用すると、認証が確実に実行され、転送中のデータがネットワーク層の傍受攻撃から保護されます。
Kubernetes クラスターで API 資格情報の自動マウントを無効にする必要がある
侵害された可能性のある Pod リソースが Kubernetes クラスターに対して API コマンドを実行するのを防ぐために、API 資格情報の自動マウントを無効にします。
Kubernetes クラスターでは既定の名前空間を使用しない
ConfigMap、Pod、Secret、Service、および ServiceAccount という種類のリソースを無許可アクセスから保護するために、Kubernetes クラスターで既定 (Default) の名前空間を使用しないようにします。
Kubernetes クラスターでは CAPSYSADMIN セキュリティ機能を許可しない
コンテナーに対する攻撃面を縮小するには、Linux 機能 CAP_SYS_ADMIN を制限します。CAP_SYS_ADMIN は最も特権のある機能であり、常に回避する必要があります。
特権コンテナーの使用を避ける
securityContext:
privileged: false
無制限のホスト アクセスを制限するには、できる限り特権コンテナーは使わないようにします。
特権コンテナーには、ホスト マシンのすべてのルート機能が含まれています。 これらは攻撃のエントリ ポイントとして使用されたり、侵害されたアプリケーション、ホスト、ネットワークに悪意のあるコードやマルウェアを拡散させるために使用されたりする可能性があります。
コンテナーをルート ユーザーとして実行しない
runAsNonRoot: true
runAsUser: 1000
お使いの Kubernetes クラスターでは、ルート ユーザーとしてコンテナーを実行しないでください。 コンテナー内でプロセスをルート ユーザーとして実行すると、それはホスト上のルートとして実行されます。 侵害を受けた場合、攻撃者はコンテナーのルート権限を持つことになり、構成ミスを悪用しやすくなります。
システム系の namespace はパラメータで除外されていますが、誤検知するようであればパラメータ設定を見直してみてください。
パラメータ | 説明 | デフォルト値 |
---|---|---|
Kubernetes namespaces to exclude from monitoring of containers host networking and ports | 除外対象とする名前空間 | [ "kube-system", "gatekeeper-system", "azure-arc", "azure-extensions-usage-system"] |
Kubernetes image to exclude from monitoring of all container related polices | Kubernetes コンテナ関連のポリシー評価から除外する InitContainers とコンテナのリスト。 これは、「コンテナ イメージは信頼できるレジストリからのみデプロイする必要がある」と「Kubernetes クラスタは脆弱なイメージのデプロイをゲートする必要がある」を除く、すべてのコンテナ関連のポリシーに適用されます。 識別子はコンテナのイメージです。 接頭辞一致は「*」で表すことができます。 例: myregistry.azurecr.io/istio:* 。 信頼できないリポジトリからイメージが予期せず除外されることを避けるために、ユーザーは完全修飾された Docker イメージ名 (ドメイン名で始まるなど) を使用することをお勧めします。 |
[] |
参考情報など
4. まとめ
以上、Microsoft Defender for Containers 適用時に設定可能な Azure ポリシーのまとめでした。K8s のセキュリティベストプラクティスが基準になっており、仕組みや内容を理解して推奨事項の判断を適切に行う必要がありますが、自社の AKS 環境のチェックにうまくご活用いただければと思います。本記事がどなたかの参考になれば幸いです。
*本稿は、個人の見解に基づいた内容であり、所属する会社の公式見解ではありません。また、いかなる保証を与えるものでもありません。正式な情報は、各製品の販売元にご確認ください。