Oracle Cloud Hangout Cafe Season5 #3「Kubernetes のセキュリティ」(2022年3月9日開催)
CIS Benchmark
CIS(Center for Internet Security) Benchmarkは、インターネットセキュリティのベストプラクティスを標準化することを目的としたガイドラインです。システムやアプリケーションのセキュリティを強化するための様々な指針やベストプラクティスを確立し、共通の規約としてまとめられています。さらに、政府機関や企業など多様な組織に提供されているため、組織のセキュリティ体制を改善する手引きとして利用されています。
CIS Kubernetes Benchmarkは、Kubernetesクラスタのセキュリティを向上させるために、Kubernetesクラスタを構成する各コンポーネントのセキュリティに対する推奨事項を定義しています。Kubernetesのコンポーネントを軸に章立てされています。
- Control Plane Components
- etcd
- Control Plane Configuration
- Worker Nodes
- Policies
OSSだけではなく、マネージドサービス(各クラウドベンダー)向けのベンチマークも公開されています。公式サイトからCIS Kubernetes BenchmarkのPDFをダウンロードできます。
CIS Kubernetes Benchmarkに記載されている推奨事項は、数も多く手動で確認するのは現実的ではありません。管理しているKubernetesクラスタが、このCIS Kubernetes Benchmarkの推奨事項に準拠しているかを効率的に確認できるツールがOSSとして公開されています。その代表的なツールがkube-benchです。kube-benchはAqua Security社が公開し、対象のKubernetesクラスタ上でJobとして簡単に実行できます。
発表時のデモでは、以下の流れでkube-benchを実行しました。
- 「job-master.yaml」の作成
- kube-benchの実行
- 結果の確認
最初に、kube-bench公式のGitHubで公開されているjob-master.yamlの一部を編集します。
【マニフェストファイル:job-master.yaml】apiVersion: batch/v1 kind: Job metadata: name: kube-bench-master spec: template: spec: hostPID: true nodeSelector: node-role.kubernetes.io/master: "" tolerations: - key: node-role.kubernetes.io/master operator: Exists effect: NoSchedule containers: - name: kube-bench image: aquasec/kube-bench:latest #command: ["kube-bench", "run", "--targets", "master"] command: ["kube-bench"] #変更 args: ["--version=1.23"] #追加 ・ ・(省略) ・
Kubernetesクラスタにjob-master.yamlを適用します。
$ kubectl apply -f job-master.yaml job.batch/kube-bench-master created
結果を確認する上で必要となる、Pod名を確認しておきます。
$ kubectl get pods NAME READY STATUS RESTARTS AGE kube-bench-master-64mwj 0/1 Completed 0 40s
結果を確認します。CIS Kubernetes Benchmarkの章立てベースに結果が表示されます。[FAIL]については設定方法まで出力されるので、その内容に従って管理しているKubernetesクラスタに適用するか検討します。この場合では、コントロールプレーンノードにある「/etc/kubernetes/manifests/kube-apiserver.yaml」の「--enable-admission-plugins」の箇所に「PodSecurityPolicy」を追加することになります。
$ kubectl logs kube-bench-master-64mwj ・ ・(省略) ・ [FAIL] 1.2.15 Ensure that the admission control plugin PodSecurityPolicy is set (Automated) ・ ・(省略) ・ == Remediations master == ・ ・(省略) ・ 1.2.15 Follow the documentation and create Pod Security Policy objects as per your environment. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the --enable-admission-plugins parameter to a value that includes PodSecurityPolicy: --enable-admission-plugins=...,PodSecurityPolicy,... Then restart the API Server. ・ ・(省略) ・ == Summary master == 42 checks PASS 11 checks FAIL 11 checks WARN 0 checks INFO ・ ・(省略) ・ == Summary etcd == 7 checks PASS 0 checks FAIL 0 checks WARN 0 checks INFO ・ ・(省略) ・ == Summary controlplane == 0 checks PASS 0 checks FAIL 3 checks WARN 0 checks INFO ・ ・(省略) ・ == Summary node == 19 checks PASS 1 checks FAIL 3 checks WARN 0 checks INFO ・ ・(省略) ・ == Summary policies == 0 checks PASS 0 checks FAIL 26 checks WARN 0 checks INFO == Summary total == 68 checks PASS 12 checks FAIL 43 checks WARN 0 checks INFO
※発表時はKubernetesクラスタ v1.25以前、CIS Kubernetes Benchmark v1.23の環境で実行したため、Kubernetes v1.25で廃止されたPodSecurityPolicyが提示される内容となっています。
Cluster Hardening
Kubernetesには、クラスタのセキュリティを強化する手段が実装されています。ここでは、Kubernetesにおける認証認可を整理して、RoleとRoleBinding、ClusterRoleとClusterRoleBindingを中心に、KubernetesのRBAC(Role-based Access Control)を理解します。
RBAC
1. Kubernetesにおける認証認可
Kubernetesにおける認証認可は、ユーザからKubernetesのAPI サーバにリクエスト送信後、以下の3フェーズを経由してリソースを登録します。
Authentication(認証)では、ユーザの正当性を確認します。Authorization(認可)では、ユーザがリクエストに対する権限を持っているかを確認します。Admission Controlでは、リクエスト内容が適切であるかを確認、設定に応じてリクエスト内容を処理します。
Kubernetesでは、認可方法の1つとしてRBACがあります。RBACについては「3. Kubenretesにおける認可」の箇所で説明します。
2. Kubernetesにおけるアカウントの種類
次に、Kubernetesに関連するServiceAccoutとUserAccoutの2つについて整理します。
ServiceAccountはKubernetesが管理するアカウントで、Namespaceに紐づいてPodで実行されるプロセスのために割り当てます。UserAccountは、Kubernetesが管理しないクラスタレベルの外部アカウントです。その特性からNamespaceの影響は受けません。例としては、クラウドプロバイダーやLDAPで管理されているアカウントです。
3. Kubernetesにおける認可
ここからは、さらにKubernetesにおける認可について解説します。
Kubernetesの認可方法は、Attribute-based Access Control(ABAC)とRole-based Access Control(RBAC)の2種類があります。ここではRBACを中心に見ていきます。
KubernetesにおけるRBACでは、RoleとRoleBindingの2種類のリソースを利用して権限を管理します。許可する操作を定めたRoleを作成し、Service AccountなどにそのRoleを紐づけるRoleBindingを利用して権限を付与します。
RoleとRoleBindingには、NamespaceとClusterレベルにおいて2種類のスコープがあり、各スコープのリソースに権限を設定できます。NamespaceスコープがRoleとRoleBindingで、ClusterスコープがClusterRoleとClusterRoleBindingです。Namespaceスコープの主なリソースはPod、Deployment、Service、ServiceAccout、PersistentVolumeClaimです。Clusterスコープの主なリソースはPersistentVolume、Namespace、Nodeです。
ClusterRoleとClusterRoleBindingは、全てのNamespaceに権限が付与されているため、Namespaceを横断して権限を管理できます。また、ClusterRoleはクラスタを横断して定義できるため、各クラスタのNamespaceからRoleBindingでClusterRoleを参照できます。クラスタ管理者が共通の定義を各クラスタのNamespaceに適用することで効率的に管理できます。
4. マニフェストを作成して適用する
ここからは、実際にKubernetesクラスタに適用することをベースに理解します。RoleとRoleBinding 、ClusterRoleとClusterRoleBindingをKubernetesクラスタに適用する場合は、PodやDeploymentなどと同様にマニフェストを作成します。
以下は、ServiceAccountを作成して、そのServiceAccountに特定の権限を定義したRole/ClusterRoleをRoleBinding/ClusterRoleBindingで紐づけるマニフェスト適用の流れと、マニフェストの適用例です。
a. RoleとRoleBindingのマニフェスト適用例
「$ kubectl get pods」による一覧取得(list)はOK、それ以外はNGという条件のRole(pod-role)を作成して、ServiceAccount(pod-sa)にRoleBinding(pod-rolebinding)で紐づけるまでの流れを見ていきます。
最初に、ServiceAccount(pod-sa)を作成します。
$ kubectl create serviceaccount pod-sa serviceaccount/pod-sa created
ServiceAccount(pod-sa)が作成できたことを確認します。
$ kubectl get serviceaccounts NAME SECRETS AGE default 1 3h28m pod-sa 1 9s
次に、条件とするRole(pod-role)のマニフェストを作成します。
$ kubectl create role pod-role --resource pods --verb list -o yaml --dry-run=client > pod-role.yaml
このマニフェストの内容は、以下です。
apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: creationTimestamp: null name: pod-role rules: - apiGroups: - "" resources: - pods verbs: - list
「apiGroups」「resources」「verbs」の3つを指定し、「apiGroups」「resources」で指定するリソースに「verbs」の権限を定義します。RoleとClusterRoleの定義方法は基本的に同じです。
「verbs」については、表にまとめておきます。
種別 | 内容 |
---|---|
* | 全ての処理 |
create | 作成 |
delete | 削除 |
get | 取得 |
list | 一覧取得 |
patch | 一部変更 |
update | 更新 |
watch | 変更の監視 |
マニフェストを適用します。
$ kubectl apply -f pod-role.yaml role.rbac.authorization.k8s.io/pod-role created
適用されたことを確認します。
$ kubectl get roles NAME CREATED AT pod-role 2022-03-02T08:15:22Z
最後に、このRole(pod-role)をServiceAccount(pod-sa)にRoleBinding(pod-rolebinding)で紐づけます。最初にマニフェストを作成します。
$ kubectl create rolebinding pod-rolebinding --role pod-role --serviceaccount default:pod-sa -o yaml --dry-run=client > pod-rolebinding.yaml
このマニフェストの内容は、以下です。
apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: creationTimestamp: null name: pod-rolebinding roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: pod-role subjects: - kind: ServiceAccount name: pod-sa namespace: default
「roleRef」でClusterRoleに紐づける1ClusterRoleBindingに対して1ClusterRoleを指定、「subjects」でClusterRoleに紐づける複数のUserやServiceAccountを指定する仕様です。
マニフェストを適用します。
$ kubectl apply -f pod-rolebinding.yaml rolebinding.rbac.authorization.k8s.io/pod-rolebinding created
適用されたことを確認します。
$ kubectl get rolebindings NAME ROLE AGE pod-rolebinding Role/pod-role 45s
実際に動作を確認してみます。ServiceAccout pod-saはPodの一覧取得のみ許可されているため、Podの一覧を取得できます。
$ kubectl --as=system:serviceaccount:default:pod-sa get pods No resources found in default namespace.
Podを作成しようとすると、エラーが出て実行できません。
$ kubectl --as=system:serviceaccount:default:pod-sa run nginx --image=nginx Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:default:pod-sa" cannot create resource "pods" in API group "" in the namespace "default"
b. ClusterRoleとClusterRoleBindingのマニフェスト適用例
「$ kubectl get namespaces」による一覧取得(list)はOK、それ以外はNGという条件の ClusterRole(namespace-clusterrole)を作成し、ServiceAccount(namespace-sa)にClusterRoleBinding(namespace-clusterrolebinding)で紐づけるまでの流れを見ていきます。
最初に、ServiceAccount(namespace-sa)を作成します。
$ kubectl create serviceaccount namespace-sa serviceaccount/namespace-sa created
作成できたことを確認します。
$ kubectl get serviceaccounts NAME SECRETS AGE default 1 4h namespace-sa 1 9s pod-sa 1 32m
次に、条件とするClusterRole(namespace-clusterrole)のマニフェストを作成します。
$ kubectl create clusterrole namespace-clusterrole --resource namespaces --verb list -o yaml --dry-run=client > namespace-clusterrole.yaml
このマニフェストの内容は、以下です。
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: creationTimestamp: null name: namespace-clusterrole rules: - apiGroups: - "" resources: - namespaces verbs: - list
マニフェストを適用します。
$ kubectl apply -f namespace-clusterrole.yaml clusterrole.rbac.authorization.k8s.io/namespace-clusterrole created
適用されたことを確認します。
$ kubectl get clusterroles | grep namespace-clusterrole namespace-clusterrole 2022-03-02T08:49:55Z
最後に、このClusterRole(namespace-role)をServiceAccount(namespace-sa)にClusterRoleBinding(namespace-rolebinding)で紐づけます。最初にマニフェストを作成します。
$ kubectl create clusterrolebinding namespace-clusterrolebinding \ --clusterrole namespace-clusterrole \ --serviceaccount default:namespace-sa \ -o yaml \ --dry-run=client > namespace-clusterrolebinding.yaml
このマニフェストの内容は、以下です。
kind: ClusterRoleBinding metadata: creationTimestamp: null name: namespace-clusterrolebinding roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: namespace-clusterrole subjects: - kind: ServiceAccount name: namespace-sa namespace: default
「roleRef」でClusterRoleに紐づける1ClusterRoleBindingに対して1ClusterRoleを指定、「subjects」でClusterRoleに紐づける複数のUserやServiceAccountを指定する仕様です。
マニフェストを適用します。
$ kubectl apply -f namespace-clusterrolebinding.yaml clusterrolebinding.rbac.authorization.k8s.io/namespace-clusterrolebinding created
適用されたことを確認します。
$ kubectl get clusterrolebindings | grep namespace-clusterrolebinding namespace-clusterrolebinding ClusterRole/namespace-clusterrole
実際に動作を確認します。ServiceAccout namespace-saは、defaultのNamespaceでNamespaceの一覧のみ取得が許可されているため、Namespaceの一覧を取得できます。
kubectl --as=system:serviceaccount:default:namespace-sa get namespaces NAME STATUS AGE calico-apiserver Active 4h15m calico-system Active 4h16m default Active 4h18m kube-node-lease Active 4h18m kube-public Active 4h18m kube-system Active 4h18m tigera-operator Active 4h16m
Namespaceを作成しようとすると、エラーが出て実行できません。
kubectl --as=system:serviceaccount:default:namespace-sa create namespace mynamespace Error from server (Forbidden): namespaces is forbidden: User "system:serviceaccount:default:namespace-sa" cannot create resource "namespaces" in API group "" at the cluster scope
連載バックナンバー
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で復数環境のマニフェストファイルを簡単整理