KubesecでKubernetes マニフェストのStatic Analysis

数あるKubernetesのマニフェストファイルに対する静的セキュリティ解析ツールの中からKubesecを紹介。

Kubesecとは

  • Static Analysisツールの一種。Kubernetes リソースに対するSecurity Risk Analysisができる。公式サイトGithubcontrolplaneという会社が中心。
  • Opensource
  • Security Best Practiceにのっとったルールのチェック(Fixed set of rules)
  • バイナリ、Docker Container、Kubectl plugin、Admission Controllerとして動作が可能

Static Analysisとは

ソースコードやテキストファイルをチェックし、ルールに対して適合しているかをチェックし、場合によってはルールを強制する。CI/CDツールの中ではCode Commit前、コンテナイメージビルド前等に使われる。KubesecはKubernetesのマニフェスト(Yaml)をチェックするツール。

Static Analysis ルールの例

  • 常に resource.limit を強制する
  • デフォルトのサービスアカウントを使ってはいけない

簡易的な使い方(公式サイト上でのYamlチェック)

公式サイトのトップページにあるLive Demoで使い方のイメージがつかめる。まずはhttps://kubesec.io/ にアクセスし、Live Demoの下にある”Submit this Yaml to Kubesec”をクリックする。

Image for post
Image for post

[
{
"object": "Pod/kubesec-demo.default",
"valid": true,
"message": "Passed with a score of 1 points",
"score": 1,
"scoring": {
"passed": [
{
"selector": "containers[] .securityContext .readOnlyRootFilesystem == true",
"reason": "An immutable root filesystem can prevent malicious binaries being added to PATH and increase attack cost",
"points": 1
}
],
"advise": [
{
"selector": ".metadata .annotations .\"container.apparmor.security.beta.kubernetes.io/nginx\"",
"reason": "Well defined AppArmor policies may provide greater protection from unknown threats. WARNING: NOT PRODUCTION READY",
"points": 3
},
{
"selector": ".spec .serviceAccountName",
"reason": "Service accounts restrict Kubernetes API access and should be configured with least privilege",
"points": 3
},
{
"selector": ".metadata .annotations .\"container.seccomp.security.alpha.kubernetes.io/pod\"",
"reason": "Seccomp profiles set minimum privilege and secure against unknown threats",
"points": 1
},
{
"selector": "containers[] .resources .limits .cpu",
"reason": "Enforcing CPU limits prevents DOS via resource exhaustion",
"points": 1
},
{
"selector": "containers[] .resources .limits .memory",
"reason": "Enforcing memory limits prevents DOS via resource exhaustion",
"points": 1
},
{
"selector": "containers[] .resources .requests .cpu",
"reason": "Enforcing CPU requests aids a fair balancing of resources across the cluster",
"points": 1
},
{
"selector": "containers[] .resources .requests .memory",
"reason": "Enforcing memory requests aids a fair balancing of resources across the cluster",
"points": 1
},
{
"selector": "containers[] .securityContext .capabilities .drop",
"reason": "Reducing kernel capabilities available to a container limits its attack surface",
"points": 1
},
{
"selector": "containers[] .securityContext .capabilities .drop | index(\"ALL\")",
"reason": "Drop all capabilities and add only those required to reduce syscall attack surface",
"points": 1
},
{
"selector": "containers[] .securityContext .runAsNonRoot == true",
"reason": "Force the running image to run as a non-root user to ensure least privilege",
"points": 1
},
{
"selector": "containers[] .securityContext .runAsUser -gt 10000",
"reason": "Run as a high-UID user to avoid conflicts with the host's user table",
"points": 1
}
]
}
}
]
"object": "Pod/kubesec-demo.default",
"valid": true,
"message": "Passed with a score of 1 points",
"score": 1,
"passed": [
{
"selector": "containers[] .securityContext .readOnlyRootFilesystem == true",
"reason": "An immutable root filesystem can prevent malicious binaries being added to PATH and increase attack cost",
"points": 1
"advise": [
{
"selector": ".metadata .annotations .\"container.apparmor.security.beta.kubernetes.io/nginx\"",
"reason": "Well defined AppArmor policies may provide greater protection from unknown threats. WARNING: NOT PRODUCTION READY",
"points": 3
},
{
"selector": ".spec .serviceAccountName",
"reason": "Service accounts restrict Kubernetes API access and should be configured with least privilege",
"points": 3
},
...

実際の環境での使い方(Docker イメージの場合)

手元のKinDで実行。結果は一部省略しているところもあり。Docker イメージ以外の使い方はこちらのGithubを参照。

$ kubectl version
Client Version: version.Info{Major:"1", Minor:"19", GitVersion:"v1.19.3",...
Server Version: version.Info{Major:"1", Minor:"19", GitVersion:"v1.19.1",...
$ k get node
NAME STATUS ROLES AGE VERSION
kind-control-plane Ready master 17h v1.19.1
kind-worker Ready <none> 17h v1.19.1
kind-worker2 Ready <none> 17h v1.19.1
kind-worker3 Ready <none> 17h v1.19.1
$ kubectl run pod --image=nginx --dry-run=client -oyaml |tee pod.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: pod
name: pod
spec:
containers:
- image: nginx
name: pod
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
$ ls pod.yaml
pod.yaml
$ docker run -i kubesec/kubesec:512c5e0 scan /dev/stdin <pod.yaml
[
{
"object": "Pod/pod.default",
"valid": true,
"message": "Passed with a score of 0 points",
"score": 0,
"scoring": {
"advise": [
{
"selector": "containers[] .resources .requests .cpu",
"reason": "Enforcing CPU requests aids a fair balancing of resources across the cluster"
},
{
"selector": ".metadata .annotations .\"container.apparmor.security.beta.kubernetes.io/nginx\"",
"reason": "Well defined AppArmor policies may provide greater protection from unknown threats. WARNING: NOT PRODUCTION READY"
...
$ cat pod.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: pod
name: pod
spec:
containers:
- image: nginx
name: pod
resources: {}
securityContext:
readOnlyRootFilesystem: true
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
$ docker run -i kubesec/kubesec:512c5e0 scan /dev/stdin <pod.yaml
[
{
"object": "Pod/pod.default",
"valid": true,
"message": "Passed with a score of 1 points",
"score": 1,

まとめ

Kubernetesにデプロイする前のYamlファイルをチェックするため、現在動いているクラスタに影響を与えずにセキュリティのチェックができる。結果として表示されるスコアやadviceの結果を用いること、またそれを実行する手段も複数用意されていることから、遵守させたいポリシーがYamlに記載されているかどうかのチェックも比較的簡単にCI/CDツールに組み込みすることができる。

Work for Hewlett Packard Enterprise as Solution Architect / Write on IT / Infrastructure / Cloud Native / Kubernetes / OpenShift / Japanese|English

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store