コンテナはホストのカーネルを共有するため、コンテナエスケープが発生すると攻撃者がノードおよびその上で実行されているすべてのリソースに直接アクセスできるようになります。ACK では、この攻撃対象領域を縮小するために、組み込みのアドミッションコントローラーから Open Policy Agent (OPA) ベースのポリシー適用まで、複数のコントロール機能を提供しています。本トピックで説明する構成を適用して、クラスター内の Pod セキュリティを強化してください。
背景情報
Pod セキュリティの構成が重要な理由として、Kubernetes のデフォルト動作が以下の 2 点挙げられます。
コンテナはデフォルトで root として実行されます。 コンテナ内部のプロセスは、Linux の root ユーザーのコンテキストで実行されます。Docker は各コンテナに Linux ケーパビリティのサブセットを割り当てることで root レベルの操作を制限していますが、デフォルトのケーパビリティセットは広範であり、権限昇格や Secrets や ConfigMap などの機密性の高いホストリソースへのアクセスを許してしまう可能性があります。デフォルトのケーパビリティは以下のとおりです。
cap_chown, cap_dac_override, cap_fowner, cap_fsetid, cap_kill, cap_setgid, cap_setuid, cap_setpcap, cap_net_bind_service, cap_net_raw, cap_sys_chroot, cap_mknod, cap_audit_write, cap_setfcap
特権 Pod の実行は、絶対に必要な場合を除き避けてください。特権 Pod はホストの root ユーザーが持つすべての Linux ケーパビリティを継承します。
ノードオーソライザーは広範なアクセス権を付与します。 すべての Kubernetes ワーカーノードはノードオーソライザーを使用しており、各 Kubelet に対して以下の操作権限を付与します。
読み取り: 当該ノード上でスケジュールされた Pod に関連する Services、Endpoints、Nodes、Pods、Secrets、ConfigMaps、PersistentVolumes (PV)、および PersistentVolumeClaims (PVC)。
書き込み: Nodes およびノードステータス、Pods および Pod ステータス、Events。
認証関連: TLS ブートストラッピング用の CertificateSigningRequest (CSR) API に対する読み取り/書き込みアクセス権、およびデリゲートされた認証・権限付与チェックのために TokenReview および SubjectAccessReview を作成する機能。
ACK クラスターでは、NodeRestriction アドミッションコントローラーがデフォルトで有効になっており、各 Kubelet が自身のノードオブジェクトおよびバインドされた Pod のみを変更できるように制限しています。ただし、それでも攻撃者がホストにアクセスした場合、Kubernetes API をクエリして機密性の高いクラスター情報を取得できる可能性があります。詳細については、「NodeRestriction admission controller」をご参照ください。
セキュリティ推奨事項
特権コンテナの制限
特権コンテナはホストの root ユーザーが持つすべての Linux ケーパビリティを継承します。ほとんどのケースでは、コンテナにこれらの権限は不要です。指定された名前空間内で特権コンテナをブロックするには、ACKPSPPrivilegedContainer ポリシーインスタンスをデプロイしてください。
ACK の コンテナセキュリティポリシー は OPA および Gatekeeper 上に構築されています。このポリシーは、ユーザー定義のセキュリティルールに基づいて Pod の作成および更新リクエストを検証し、準拠しないリクエストを拒否します。
ACK クラスターでは NodeRestriction アドミッションコントローラーがデフォルトで有効になっています。これにより、Kubelet の操作は自身のノードおよびバインドされた Pod に限定されますが、特権コンテナのブロックは行われません。特権コンテナをブロックするには、ACKPSPPrivilegedContainer ポリシーを構成してください。
非 root ユーザーでのコンテナ実行
コンテナはデフォルトで root として実行されます。攻撃者が脆弱性をエクスプロイトして実行中のコンテナにシェルアクセスを獲得した場合、root 権限を継承することになります。これを軽減するには、以下の対策を講じてください。
コンテナイメージからシェルを削除してください。
Dockerfile に
USER命令を追加します。Pod 仕様で
spec.securityContext.runAsUserおよびrunAsGroupを設定し、プロセスを非 root ユーザーとして実行します。
指定された名前空間全体で非 root 実行を強制するには、ACKPSPAllowedUsers ポリシーインスタンスをデプロイしてください。
権限昇格の無効化
権限昇格により、プロセスは SUID または SGID ビットが設定されたバイナリを実行するなどして、自身のセキュリティコンテキストを変更できます。Pod の Security Context で allowPrivilegeEscalation: false を設定してください。
securityContext:
allowPrivilegeEscalation: false指定された名前空間でこの設定を強制するには、ACKPSPAllowPrivilegeEscalationContainer ポリシーインスタンスをデプロイしてください。
HostPath ボリュームマウントの制限
HostPath はホストディレクトリをコンテナに直接マウントします。root として実行される Pod は、デフォルトでマウントされたパスへの書き込みアクセス権を持ち、攻撃者はこれを利用して Kubelet 設定を変更したり、/etc/shadow などの機密ファイルへのシンボリックリンクを作成したり、SSH キーをインストールしたり、ホスト上にマウントされた Secrets を読み取ったりできます。
アプリケーションで HostPath が必要な場合は、ボリュームを読み取り専用でマウントし、許可されるパスプレフィックスを制限してください。
volumeMounts:
- name: hostpath-volume
readOnly: true
mountPath: /host-path指定された名前空間で Pod がマウントできるホストディレクトリを制限するには、ACKPSPHostFilesystem ポリシーインスタンスをデプロイしてください。
リソースリクエストおよび使用制限の設定
リソース制限が設定されていない Pod は、ノード上のすべての CPU およびメモリを消費し、Kubelet をクラッシュさせたり他の Pod をエビクトしたりする可能性があります。リクエストおよび使用制限を設定することで、リソース競合を最小限に抑え、暴走または悪意あるワークロードによる影響範囲を縮小できます。
名前空間ごとのリソース消費量の上限を設定するには ResourceQuota を、Pod およびコンテナ単位のデフォルト値および上限・下限を設定するには LimitRange を使用してください。
ResourceQuota: 名前空間に割り当てられた CPU およびメモリの総量を指定し、すべてのコンテナがリクエストおよび使用制限を宣言することを強制します。
LimitRange: コンテナまたは Pod レベルでリソースの最小値、最大値、およびデフォルト値を設定します。
指定された名前空間内のアプリケーションポッドにリソース使用制限を必須とするには、ACKContainerLimits ポリシーインスタンスをデプロイしてください。詳細については、「Managing resources for containers」をご参照ください。
Docker-in-Docker および Docker ソケットマウントの禁止
/var/run/docker.sock をマウントしたり Docker-in-Docker を実行したりすると、コンテナプロセスがノードのコンテナランタイムを制御できるようになります。このようなパターンは避けてください。Kubernetes 内でコンテナイメージをビルドする必要がある場合は、以下の代替手段のいずれかをご利用ください。
自動的なサービスアカウントトークンマウントの無効化
Kubernetes はデフォルトで、すべての Pod にサービスアカウントトークンをマウントします。Kubernetes API を呼び出す必要のない Pod については、トークン盗難のリスクを低減するためにこの機能を無効化してください。
# 特定の Pod に対して無効化
apiVersion: v1
kind: Pod
metadata:
name: pod-no-automount
spec:
automountServiceAccountToken: false# ServiceAccount を使用するすべての Pod に対して無効化
apiVersion: v1
kind: ServiceAccount
metadata:
name: sa-no-automount
automountServiceAccountToken: falseautomountServiceAccountToken を無効化しても、Kubernetes API へのネットワークアクセスはブロックされません。これをブロックするには、ACK クラスターエンドポイントのアクセス方法を変更し、ネットワークポリシーを適用してください。詳細については、「ACK クラスターでのネットワークポリシーの使用」をご参照ください。
指定された名前空間全体でこの設定を強制するには、ACKBlockAutomountToken ポリシーインスタンスをデプロイしてください。
サービス検出の制限
他のクラスターサービスを検出または呼び出す必要のない Pod については、DNS ポリシーを Default(CoreDNS ではなくノードの DNS リゾルバーを使用)に設定し、サービス環境変数の注入を無効化してください。
apiVersion: v1
kind: Pod
metadata:
name: pod-no-service-info
spec:
dnsPolicy: Default # CoreDNS ではなくノードの DNS を使用します。「Default」は実際のデフォルトではありません。デフォルトは「ClusterFirst」です。
enableServiceLinks: falseDNS ポリシーの変更およびサービスリンクの無効化によっても、クラスター内 DNS サービスへのネットワークアクセスはブロックされません。攻撃者は依然として CoreDNS に直接クエリを送信することでクラスターサービスを列挙できます(例:dig SRV *.*.svc.cluster.local @$CLUSTER_DNS_IP)。クラスター内サービス検出をブロックするには、ネットワークポリシーを使用してください。詳細については、「ACK クラスターでのネットワークポリシーの使用」をご参照ください。
DNS ポリシーの値に関する詳細は、「Kubernetes docs on pod DNS policy」をご参照ください。
読み取り専用ルートファイルシステムの使用
読み取り専用ルートファイルシステムにより、攻撃者がアプリケーションファイルを上書きしたり悪意のあるバイナリをインストールしたりするのを防げます。Security Context で readOnlyRootFilesystem: true を設定してください。
securityContext:
readOnlyRootFilesystem: trueアプリケーションでファイルの書き込みが必要な場合は、書き込みアクセスが必要なパスに一時ディレクトリ (emptyDir) または追加のボリュームをマウントしてください。
指定された名前空間でこの設定を強制するには、ACKPSPReadOnlyRootFilesystem ポリシーインスタンスをデプロイしてください。