話すこと
案件で Kubernetes のセキュリティについて調べることがあったので、各レイヤで何が必要かを検討しました。
- Node レイヤ
・Inspector
・(falco) - Pod レイヤ
・(falco)
・セキュリティポリシー - Network レイヤ
・Egress Security
その中で今回は、Pod のセキュリティポリシーについてお話していきたいと思います。
前提(話さないこと)
コンテナイメージが CI 上で脆弱性対策されていること。
(例えば https://github.com/aquasecurity/trivy など)
検討したこと
- Security Policy
クラスタでどうやって Pod セキュリティを合わせるか
Policy-as-Code(以下、PaC) ツールの比較 - SecurityContext
PaC ツールを利用した上でルールをどうするか - 振る舞い検知
対策した上で実際になにか起きた場合、どうやって検知するか
PaC の比較
対象にしたものは、下記の3つで今回の比較の結果 Kyverno を採用したいと考えました。
- OPA/Gatekeeper
- PodSecurityAdmission(以下、PSA)
- Kyverno
期待することは下記の通りです。
- Pod Security Standards(以下、PSS) に則り、導入/運用しやすいこと 追加でポリシーをできること
Kubernetes のコミュニティ(https://github.com/kubernetes/community/blob/master/sig-auth/README.md)によって推奨されている、Podの設定になります。
PSSは種別ごとに用意されており、必要に応じて使い分ける必要があります。
# 特権 - 制限のかかっていないポリシーで、可能な限り幅広い権限を提供します。このポリシーは既知の特権昇格を認めます。
特権ポリシーは意図的に開放されていて、完全に制限がかけられていません。この種のポリシーは通常、特権ユーザーまたは信頼されたユーザーが管理する、システムまたはインフラレベルのワークロードに対して適用されることを意図しています。
特権ポリシーは制限がないことと定義されます。gatekeeperのようにデフォルトで許可される仕組みでは、特権プロファイルはポリシーを設定せず、何も制限を適用しないことにあたります。 一方で、Pod Security Policyのようにデフォルトで拒否される仕組みでは、特権ポリシーでは全ての制限を無効化してコントロールできるようにする必要があります。
# ベースライン、デフォルト - 制限は最小限にされたポリシーですが、既知の特権昇格を防止します。デフォルト(最小の指定)のPod設定を許容します。
ベースライン、デフォルトのプロファイルは一般的なコンテナ化されたランタイムに適用しやすく、かつ既知の特権昇格を防ぐことを意図しています。 このポリシーはクリティカルではないアプリケーションの運用者または開発者を対象にしています。 次の項目は強制、または無効化すべきです。
# 制限 - 厳しく制限されたポリシーで、Podを強化するための現在のベストプラクティスに沿っています。
制限ポリシーはいくらかの互換性を犠牲にして、Podを強化するためのベストプラクティスを強制することを意図しています。 セキュリティ上クリティカルなアプリケーションの運用者や開発者、また信頼度の低いユーザーも対象にしています。 下記の項目を強制、無効化すべきです。
- PSA はできない
- validateではなく、監査のみができること
どれもできる - (mutate 機能があること)
優先度は低
PSA のみない
OPA/Gatekeeper
特徴
- Kubernetes 以外のリソースでも利用可能
- conftest と合わせて CI に組み込める
- 学習コストが高い (Rego)
Kubernetes を目的とし、学習コストが高いため見送りとしました。
PSA
特徴
- 導入しやすい
- 1.22 からのみ利用可能
- audit を利用した場合、監査ログを取り込む
- カスタムポリシーができない
- フィルタリングが弱い
・Usernames: 認証されていない(あるいは偽装された)ユーザー名を持つユーザーからの要求は無視されます。
・RuntimeClassNames: Pod とワークロードリソースで指定された除外ランタイムクラス名は、無視されます。
・Namespaces: 除外された名前空間の Pod とワークロードリソースは、無視されます。
Kyverno と比較し、audit 利用時の Keyverno の利用しやすさからこちらも見送りとしました。
Kyverno
特徴
- 様々な Policy の準備がある
PSS がある
・https://kubernetes.io/docs/concepts/security/pod-security-standards/
・https://kyverno.io/policies/?policytypes=Best%2520Practices - validate/mutate が可能
・PSA では mutate できない - Kubernetes 専用なこともあり、運用しやすい
・レポートが k8s resource
・policy も resource
今回は運用の効率面や設定の豊富さから Kyverno を採用しました。
Keyverno を触ってみる
Keyverno と PSS Policy のインストール
# kyverno
helm repo add kyverno https://kyverno.github.io/kyverno/
helm repo update
helm search repo kyverno -l
# バージョンはKubernetesと合わせる必要がある https://kyverno.io/docs/installation/#compatibility-matrix
helm install kyverno kyverno/kyverno -n kyverno --create-namespace --set replicaCount=1 --set metricsService.create=true --version v2.3.4
kubectl get po
NAME READY STATUS RESTARTS AGE
kyverno-64fbd6cc7b-pf6bt 1/1 Running 0 18h
# policy
helm install kyverno-policies kyverno/kyverno-policies -n kyverno --version v2.5.4
# 例えば
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-host-process
annotations:
policies.kyverno.io/title: Disallow hostProcess
policies.kyverno.io/category: Pod Security Standards (Baseline)
policies.kyverno.io/severity: medium
policies.kyverno.io/subject: Pod
kyverno.io/kyverno-version: 1.6.0
kyverno.io/kubernetes-version: "1.22-1.23"
policies.kyverno.io/description: >-
Windows pods offer the ability to run HostProcess containers which enables privileged
access to the Windows node. Privileged access to the host is disallowed in the baseline
policy. HostProcess pods are an alpha feature as of Kubernetes v1.22. This policy ensures
the `hostProcess` field, if present, is set to `false`.
spec:
validationFailureAction: audit # validate or audit
background: true # 既存のリソースも参照するか
failurePolicy: Fail # webhook(kyverno pod)が反応しない場合に、無視するか失敗とするか
rules:
- name: host-process-containers
match:
any:
- resources:
kinds: # namespace, labelなどでも可能
- Pod
validate:
message: >-
HostProcess containers are disallowed. The fields spec.securityContext.windowsOptions.hostProcess,
spec.containers[*].securityContext.windowsOptions.hostProcess, spec.initContainers[*].securityContext.windowsOptions.hostProcess,
and spec.ephemeralContainers[*].securityContext.windowsOptions.hostProcess must either be undefined
or set to `false`.
pattern:
spec:
=(ephemeralContainers):
- =(securityContext):
=(windowsOptions):
=(hostProcess): "false"
=(initContainers):
- =(securityContext):
=(windowsOptions):
=(hostProcess): "false"
containers:
- =(securityContext):
=(windowsOptions):
=(hostProcess): "false"
特権コンテナたててみる
% kubectl apply -f privileged.yaml
% cat privileged.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
name: privileged
name: privileged
namespace: default
spec:
containers:
- image: nginx:latest
name: nginx
securityContext:
privileged: true
% kubectl get policyreport -n default
NAME PASS FAIL WARN ERROR SKIP AGE
polr-ns-default 11 1 0 0 0 3m59s
% kubectl describe policyreport -n default
Name: polr-ns-default
Namespace: default
Labels: managed-by=kyverno
Annotations: <none>
API Version: wgpolicyk8s.io/v1alpha2
Kind: PolicyReport
Metadata:
Creation Timestamp: 2022-09-07T05:44:16Z
Generation: 7
Manager: kyverno
Operation: Update
Time: 2022-09-07T05:44:16Z
Owner References:
API Version: v1
Controller: true
Kind: Namespace
Name: kyverno
UID: d6d6c72d-c011-4ed6-be35-a822083029c1
Resource Version: 3156193
UID: a9bfa0ff-801f-41a4-a0a5-25f8ed42fbba
Results:
Category: Pod Security Standards (Baseline)
Message: validation error: Privileged mode is disallowed. The fields spec.containers[*].securityContext.privileged and spec.initContainers[*].securityContext.privileged must be unset or set to `false`. Rule privileged-containers failed at path /spec/containers/0/securityContext/privileged/
Policy: disallow-privileged-containers
Resources:
API Version: v1
Kind: Pod
Name: privileged
Namespace: default
UID: 2d8be830-fc0f-410b-8714-0a8cdc5b4a90
Result: fail
Rule: privileged-containers
Scored: true
Severity: medium
Source: Kyverno
Timestamp:
Nanos: 0
Seconds: 1662529458
Seconds: 1662529468
...
Summary:
Error: 0
Fail: 1
Pass: 11
Skip: 0
Warn: 0
NameSpaceごとにレポートがまとめられる
% kubectl get policyreport -A
NAMESPACE NAME PASS FAIL WARN ERROR SKIP AGE
default polr-ns-default 12 0 0 0 0 19h
harness polr-ns-harness 60 0 0 0 0 19h
kube-bench polr-ns-kube-bench 10 2 0 0 0 19h
policy-reporter polr-ns-policy-reporter 36 0 0 0 0 19h
prometheus polr-ns-prometheus 69 3 0 0 0 19h
監視
- Prometheus 用のエンドポイントがある
- Grafana もある
https://grafana.com/grafana/dashboards/15804-kyverno/ - policy reporter がある
https://github.com/kyverno/policy-reporter
これにより UI 上で結果の確認が可能です。下記 UI のイメージです。
- 通知
Slack, WebHook などが対応しています。 - (オンコールほどではなく) policy reporter、AlertManager よる Slack 通知などは利用したい
他セキュリティ
- NodeSecurity
・Inspector
・(falco) - EgressSecurity
・Istio
EgressGateway でアプリケーションの通信を一部 Node に寄せて可能な限り制限する - ポスチャ管理(EKS)
・kube-bench
kube-bench → SecurityHub → EventBridge → SNS → PagerDuty
まとめ
いかがでしょうか。
今回は、Pod のセキュリティポリシーについて PaC ツールの比較検討を交えながらお話してきました。
当記事が、Pod のセキュリティポリシーを検討する上での参考になれば幸いです。