Oracle Cloud Hangout Cafe Season5 #3「Kubernetes のセキュリティ」(2022年3月9日開催)
Minimize Microservice Vulnerabilities
ここでは、マイクロサービスの脆弱性を最小限に抑えるという観点から、最初にContainerおよびPodにおけるSecurityContextについて解説します。次にPodSecurityPolicyの後継となるPod Security StandardsとPod Security Admissionについて解説し、最後にコンテナランタイムセキュリティにおけるgVisor およびKata Containersの概要を理解して、実際にRuntimeClassを利用してgVisorの環境を構築します。
SecurityContext
SecurityContextは、Pod全体およびPod内の各コンテナにアクセス制御を設定できる仕組みです。マニフェストで定義します。
Podに設定できるSecurityContextの主な設定項目を下表に示します。
設定項目 | 概要 |
---|---|
privileged | Podの特権実行 |
readOnlyRootFilesystem | RootファイルシステムをReadOnlyとするかの制御 |
drunAsUser | 実行するユーザ |
runAsGroup | 実行するグループ |
runAsNonRoot | rootでの実行を拒否 |
fsGroup | ファイルシステムのグループ指定 |
runtimeClass | Podで許可するruntimeClassを指定 |
supplementalGroups | プライマリGIDに追加付与するGIDリストを指定 |
以下は、「runAsNonRoot」によりNginx Podが作成できないマニフェストの例です。
apiVersion: v1 kind: Pod metadata: name: pod-sc spec: securityContext: runAsNonRoot: true containers: - name: nginx-container image: nginx:1.21
コンテナに設定できるSecurityContextの主な設定項目を下表に示します。
設定項目 | 概要 |
---|---|
privileged | 特権コンテナ実行 |
capabilities | Capabilitiesの追加/削除 |
allowPrivilegeEscalation | コンテナ実行時に親プロセス以上の権限を与えるか制御 |
readOnlyRootFilesystem | RootファイルシステムをReadOnlyとするかの制御 |
runAsUser | 実行するユーザ |
runAsGroup | 実行するグループ |
runAsNonRoot | rootでの実行を拒否 |
seLinuxOptions | コンテナで使用するSELinuxオプション |
seccompProfile | コンテナで使用するseccompオプション |
windowsOptions | コンテナ(windows)で使用するWindows固有の設定 |
以下は、「runAsNonRoot」によりNginx Podが作成できないマニフェストの例です。
apiVersion: v1 kind: Pod metadata: name: container-sc spec: containers: - name: nginx-container image: nginx:1.21 securityContext: runAsNonRoot: true
Podおよびコンテナの両方にSecurityContextを定義した場合は、コンテナのSecurityContextが優先されます。
apiVersion: v1 kind: Pod metadata: name: both-test spec: securityContext: runAsUser: 1000 containers: - name: ubuntu image: ubuntu:21.10 securityContext: runAsUser: 1001 command: - sleep - infinity
Podに対するsecurityContextは、コンテナ間で共有されるリソースやコンテナの動作に関する制限を定義するのに適しています。一方、コンテナに対するsecurityContextは、個々のコンテナの動作に関する制限を定義するのに適しています。
Pod Security Standards & Pod Security Admission
PodSecurityPolicyはβ版として提供され続けてきましたが、Kubernetes v1.21から非推奨となりv1.25で廃止されました。発表時は、この過渡期にあたりPodSecurityPolicyの説明とデモを実施しました。執筆時は既にv1.25がリリースされているので、ここではPodSecurityPolicyの後継となるPod Security StandardsとPod Security Admission について解説します。
Pod Security Standardsは、PodセキュリティにおけるKubernetes公式のガイドラインです。以下3種類のポリシーがあります。
ポリシー | 概要 |
---|---|
Privileged | 無制限ポリシー |
Baseline | 最小限の制限ポリシー |
Restricted | 最も厳しい制限ポリシー |
【参考】「Pod Security Standards」
上記の通り、Pod Security Standardsはガイドラインです。このガイドラインに準拠しているかを検証して、対象となるKubernetesクラスタに適用する/しない仕組みが必要となります。その仕組みがPod Security Admissionです。Admission ControllerとしてValidate機能(執筆時点でMutation機能は未提供)を提供します。そして、以下3つのモードを実装しています。
モード | 概要 |
---|---|
enforce | 違反したPodの作成を拒否 |
audit | 違反したらKubernetesのAudit Logのアノテーションとして記録(作成拒否はされない) |
warn | 違反したら警告表示(作成拒否はされない) |
【参考】「Pod Security Admission」
Pod Security StandardsのポリシーとPod Security Admissionのモードを組み合わせて、対象となるKubernetesクラスタのNamespaceに紐づけることで、Podのセキュリティを強化します。そのため、PodSecurityPolicyのように専用のリソースはありません。
Namespaceのマニフェストで、以下のように定義します。
apiVersion: v1 kind: Namespace metadata: labels: pod-security.kubernetes.io/enforce: privileged pod-security.kubernetes.io/audit: privileged pod-security.kubernetes.io/warn: baseline name: sample
以下のようにバージョンも設定できます。
apiVersion: v1 kind: Namespace metadata: labels: pod-security.kubernetes.io/enforce: baseline pod-security.kubernetes.io/enforce-version: v1.26 pod-security.kubernetes.io/audit: restricted pod-security.kubernetes.io/audit-version: v1.26 pod-security.kubernetes.io/warn: restricted pod-security.kubernetes.io/warn-version: v1.26 name: sample
マニフェストに定義しない場合、つまりデフォルト設定はenforce、audit、warn全てにおいてprivilegedです。バージョンはlatestです。Namespace毎に適用するのではなく、Kubernetesクラスタのデフォルトポリシーとして定義したい場合は「AdmissionConfiguration」としてマニフェストを作成し、kube-apiserverに設定できます。
kubectlコマンドにおいてdry-run実行できるため、適用前に検証できます。
Container Runtime Sandboxes
コンテナランタイムに関するセキュリティについて、コンテナランタイムをおさらいしながらgVisorとKata Containersを説明します。そして、Kubernetesクラスタ上でRuntime Classを利用してgVisorをコンテナランタイムとして利用する方法を学びます。
1. コンテナランタイム
Kubernetesにおけるコンテナランタイムは、ノード上のコンテナとコンテナイメージを管理します。コンテナランタイムには、高レベルコンテナランタイムと低レベルコンテナランタイムがあります。
高レベルコンテナランタイムは、イメージの取得や展開、ローカルイメージの管理を行います。そして、低レベルコンテナランタイムにコンテナの実行命令を受け渡します。主な高レベルコンテナランタイムはcontainerd、cri-oです。
低レベルコンテナランタイムは、高レベルコンテナランタイムからの実行命令を受け、Linuxカーネルの機能(namespace、cgroups)を使用してコンテナを作成します。低レベルコンテナランタイムの実体はバイナリです。主な低レベルコンテナランタイムはrunC、gVisor、Kata Containersです。
※CRI(Container Runtime Interface)は、kubeletがコンテナランタイムを操作するためのインタフェース。
2. gVisor
gVisorはGoogle LLCが開発したコンテナランタイム(低レベルコンテナランタイム)です。コンテナ内のプロセスをサンドボックス化することで、高いセキュリティと信頼性を実現します。そして、Linuxカーネルのnamespaceとcgroups機能を利用してコンテナ内のプロセスを分離し、さらにLinuxのユーザーランドにおいて再実装することで、より強固なサンドボックス化を実現します。
Linuxユーザーランドでは、SentryというGoで作られたプログラムがカーネルとしてアプリケーションからのsyscallを処理するため、Linux カーネルに到達するsyscallが大幅に縮小し、攻撃対象を狭めることでよりセキュリティを強化します。
【参考】「What is gVisor?」
3. Kata Containers
Kata Containersは、仮想化技術を利用して作成した軽量なハイパーバイザー上で動作し、コンテナ個別にカーネルを動作させることでコンテナ間の分離を図り、セキュリティを強化するコンテナランタイム(低レベルコンテナランタイム)です。
【参考】「Kata Containers」
3. Runtime Class
Runtime Classは、KubernetesにおいてgVisorやKata ContainersなどのコンテナランタイムをPod起動時に選択できる仕組みです。Runtime Classを利用することで、コンテナランタイムレベルでセキュリティを強化できます。
実際に、Runtime ClassでcontainerdをgVisorに変更し、Nginx Podを起動する流れを見ていきます。
- kube-apiserverのAdmission ControlでRuntimeClassを有効化する
- gVisorのRuntimeClassマニフェストの作成および適用
※事前にgVisorインストールおよびcontainerdへの設定は完了前提 - Nginx PodをgVisorに指定して起動
1. kube-apiserverのAdmission ControlでRuntimeClassを有効化する
コントロールプレーンのノードにログインし、kube-apiserverのAdmission ControlでRuntimeClassを有効化します。「--enable-admission-plugins」に「RuntimeClass」を設定します。
$ vim /etc/kubernetes/manifests/kube-apiserver.yaml ・ ・(省略) ・ spec: containers: - command: - kube-apiserver - --advertise-address=10.0.0.2 - --allow-privileged=true - --authorization-mode=Node,RBAC - --client-ca-file=/etc/kubernetes/pki/ca.crt - --enable-admission-plugins=NodeRestriction,RuntimeClass ・ ・(省略) ・
2. gVisorのRuntimeClassマニフェストの作成および適用
事前にgVisorインストールおよびcontainerdへの設定が必要となります。以下参考サイトです。
【gVisor Install】
【Containerd Quick Start】
RuntimeClassのマニフェストを作成します。
【マニフェスト:runtimeclass.yaml】apiVersion: node.k8s.io/v1beta1 kind: RuntimeClass metadata: name: gvisor handler: runsc
マニフェストを適用します。
$ kubectl apply -f runtimeclass.yaml
runtimeclass.node.k8s.io/gvisor created
3. Nginx PodをgVisorに指定して起動
「pod.spec.runtimeClassName」にRuntimeClass名を定義したマニフェストを作成します。
apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: run: gvisor-nginx name: gvisor-nginx spec: runtimeClassName: gvisor containers: - image: nginx:1.21 name: gvisor-nginx resources: {} dnsPolicy: ClusterFirst restartPolicy: Never status: {}
マニフェストを適用します。
$ kubectl apply -f gvisor-nginx.yaml
pod/gvisor-nginx created
「gvisor-nginx」Podに接続し、「Starting gVisor…」としてgVisorで起動していることを確認します。
$ kubectl exec -it gvisor-nginx -- /bin/bash dmesg [ 0.000000] Starting gVisor... [ 0.168305] Creating cloned children... [ 0.433689] Creating bureaucratic processes... [ 0.491369] Daemonizing children... [ 0.798069] Mounting deweydecimalfs... [ 0.897569] Searching for needles in stacks... [ 0.967286] Reading process obituaries... [ 1.027207] Synthesizing system calls... [ 1.342101] Checking naughty and nice process list... [ 1.749487] Recruiting cron-ies... [ 2.123900] Singleplexing /dev/ptmx... [ 2.534325] Ready!
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- 「Inspektor Gadget」でKubernetesクラスタをデバッグする
- Kubernetesの基礎
- 認定Kubernetesアプリケーション開発者を目指そう!
- Oracle Cloud Hangout Cafe Season7 #1「Kubnernetes 超入門」(2023年6月7日開催)
- NGINX Ingress Controllerの柔軟なアプリケーション制御、具体的なユースケースと設定方法を理解する
- Kubernetes環境を構築して、実際にコンテナを動かしてみよう
- KubernetesのマニフェストをMagnumで実行する
- Oracle Cloud Hangout Cafe Season 4 #2「Kubernetesのネットワーク」(2021年5月12日開催)
- Kubernetes上のアプリケーション開発を加速させるツール(2) Telepresence
- kustomizeで復数環境のマニフェストファイルを簡単整理