KubeScapeでKubernetesのセキュリティスキャンを行う

# はじめに

[CNCF Blog](https://www.cncf.io/blog/)を徘徊していたら[Kubescape: The first open source tool for running NSA and CISA Kubernetes hardening tests](https://www.cncf.io/blog/2021/09/03/kubescape-the-first-open-source-tool-for-running-nsa-and-cisa-kubernetes-hardening-tests/)という記事を見つけました。

**The first open source tool**と書かれていて気になったので[アドベントカレンダー](https://qiita.com/advent-calendar/2021/nri-openstandia)21日目は[Kubescape](https://github.com/armosec/kubescape)を取り上げます。

Kubernetesのみならずコンテナをプロダクション環境で利用しているとやはりセキュリティは気になります。
ところがコンテナとなると仮想環境ということでしっかりとセキュリティ対策ができているといえるプロジェクトは少ないのではないでしょうか。
[CVE Details](https://www.cvedetails.com/vulnerability-list/vendor_id-15867/product_id-34016/Kubernetes-Kubernetes.html)のページを確認するとKubernetes関連の脆弱性は予想以上に多くあります。
Kubernetesのセキュリティチェックを行うツールはすでにいくつか存在していますが、[Kubescape](https://github.com/armosec/kubescape)もセキュリティチェックツールを検討する際の選択肢の1つに加わりました。

# 1. Kubescapeとは

## 1.1 概要

冒頭で述べたように、[Kubescape](https://github.com/armosec/kubescape)は[Armo社](https://www.armosec.io/about-us/)が提供するKubernetesのセキュリティチェックツールです。
Goで実装されており、[Apache-2.0 License](https://github.com/armosec/kubescape/blob/master/LICENSE)で配布されています。
2021年8月に[v0.0.5](https://github.com/armosec/kubescape/releases/tag/v0.0.5)がファーストリリースされており、2021年12月には[v1.0.135](https://github.com/armosec/kubescape/releases/tag/v1.0.135)がリリースされています。githubのリリースノートを見ると、数日〜１週間のスパンでリリースされており開発スピードの速さが伺えます。

Armo社の公式ブログでは[1つのツールで複数のフレームワークを用いてセキュリティスキャンできる](https://www.armosec.io/blog/kubescape-the-first-tool-for-running-nsa-and-cisa-kubernetes-hardening-tests/)という点で、first toolであると書かれています。
また、CICDパイプラインへの組み込みを考慮して開発されており、JenkinsやCircleCI、Github、Gitlabのワークフローへも容易に組み込めます。

## 1.2 Kubescapeでできること

KubescapeではKubernetesのセキュリティスキャンを実施できます。
スキャン対象となるものは以下の3つです。

1. Kubernetesクラスタ
1. Kubernetesマニフェスト（yamlファイル）
1. Helm Chart

また、スキャンする際に指定できるフレームワークとして、現時点では以下の3つがあります。

1. `nsa`：[NSA-CISA Kubernetes Hardening Guidance](https://www.nsa.gov/Press-Room/News-Highlights/Article/Article/2716980/nsa-cisa-release-kubernetes-hardening-guidance/)
1. `mitre`：[MITRE ATT&CK®](https://attack.mitre.org/)※
1. `armobest`：[ARMOBest](https://www.armosec.io/blog/armobest-kubernetes-framework/)

※[Armo社の公式ブログ](https://www.armosec.io/blog/kubescape-the-first-tool-for-running-nsa-and-cisa-kubernetes-hardening-tests/)では[MITRE ATT&CK®](https://attack.mitre.org/)の表を拡張したMicrosoft社の[threat matrix for Kubernetes](https://www.microsoft.com/security/blog/2021/03/23/secure-containerized-environments-with-updated-threat-matrix-for-kubernetes/)の方が紹介されています。

複数フレームワークを利用してセキュリティスキャンできることも含め、下記のような点がKubescapeの特徴として挙げられています。

- Kubernetesのリスクスコアを数値で出せるため、リスクトレンドを可視化できる
- 複数フレームワークを使用してセキュリティチェックできる
- 独自のフレームワークを作成して利用できる
- スキャン結果をExceptionとして受け取り、ハンドリングできる
- DevOpsツール（Jenkins等）への組み込みが容易
- Kuberntesクラスタへのインストールが不要

## 1.3 KubescapeとOpen Policy Agent

アドベントカレンダー5日目では[Open Policy Agent (OPA) のユースケース4選](https://qiita.com/yoshimi0227/items/84d809890c73727d734a)を紹介していますが、
KubescapeでもOpen Policy Agentが用いられています。

Kubescapeは、Kubernetesクラスタ上にリソースを作成する必要はなく、kube-apiserverから取得したKubernetesのリソース情報に対してregoで記述したポリシーを適用しています。

> Kubescape based on OPA engine: https://github.com/open-policy-agent/opa and ARMO's posture controls.
> The tools retrieves Kubernetes objects from the API server and runs a set of regos snippets developed by ARMO.
> 出典：https://github.com/armosec/kubescape

Armo社のgithubレポジトリに[armosec/regolibrary](https://github.com/armosec/regolibrary)というものがあり、regoで記述された[ポリシー](https://github.com/armosec/regolibrary/tree/master/rules)を見ることができます。
公式な記載は見当たりませんが、Kubescapeによるスキャンでもこちらのポリシー用いられていると思われます。

例えばhostpathが利用されているPodに対しては[alert-any-hostpath](https://github.com/armosec/regolibrary/blob/master/rules/alert-any-hostpath/raw.rego)という下記のようなPolicyによりチェックさされています。

```rego:hostpathのチェック
deny[msga] {
    pod := input[_]
    pod.kind == "Pod"
    volumes := pod.spec.volumes
    volume := volumes[i]
	begginingOfPath := "spec."
	result  := isDangerousHostPath(volume, begginingOfPath, i)
    podname := pod.metadata.name


	msga := {
		"alertMessage": sprintf("pod: %v has: %v as hostPath volume", [podname, volume.name]),
		"packagename": "armo_builtins",
		"alertScore": 7,
		"failedPaths": [result],
		"alertObject": {
			"k8sApiObjects": [pod]
		}
	}
}
```

# 2. Kubescapeを使ってみる

## 2.1 インストール

kubescapeは簡単にインストールすることができます。
[githubレポジトリ](https://github.com/armosec/kubescape)に書かれてある通り、インストール用のシェルを実行しても良いですが、ここでは直接実行ファイルをダウンロードします。
今回は、[v1.0.135](https://github.com/armosec/kubescape/releases/tag/v1.0.135)を使用します。

```:kubescapeの実行ファイルダウンロードと権限設定
$ curl -L -o kubescape https://github.com/armosec/kubescape/releases/download/v1.0.135/kubescape-ubuntu-latest
$ chmod 755 kubescape
```

Kubeescapeのインストールは以上で完了です。
必要であればPATHを通しておきましょう。
kubescapeの基本的な使用方法やオプション引数については[githubレポジトリ](https://github.com/armosec/kubescape)に記載されています。

## 2.2 Kubernetesクラスタのスキャン

実際にkubescapeを用いてKubernetesクラスタのスキャンを行ってみます。
スキャンする際は下記のようにフレームワークを指定できます。

- `kubescape scan framework nsa`
- `kubescape scan framework mitre`
- `kubescape scan framework armobest`

以下は、kubeadmで作成した直後のクラスタに対してnsaのフレームワークを用いてスキャンした結果です。

```
$  ./kubescape scan framework nsa
~中略~
NSA FRAMEWORK
+-----------------------------------------------------------------------+------------------+--------------------+---------------+-----------+
|                             CONTROL NAME                              | FAILED RESOURCES | EXCLUDED RESOURCES | ALL RESOURCES | % SUCCESS |
+-----------------------------------------------------------------------+------------------+--------------------+---------------+-----------+
| Allow privilege escalation                                            |        0         |         0          |       8       |   100%    |
| Allowed hostPath                                                      |        4         |         0          |       7       |    42%    |
| Applications credentials in configuration files                       |        0         |         0          |      18       |   100%    |
| Automatic mapping of service account                                  |        39        |         0          |      39       |    0%     |
| CVE-2021-25741 - Using symlink for arbitrary host file system access. |        0         |         0          |       8       |   100%    |
| CVE-2021-25742-nginx-ingress-snippet-annotation-vulnerability         |        0         |         0          |       0       |    NaN    |
| Cluster internal networking                                           |        4         |         0          |       4       |    0%     |
| Cluster-admin binding                                                 |        1         |         0          |      68       |    98%    |
| Container hostPort                                                    |        0         |         0          |       7       |   100%    |
| Control plane hardening                                               |        0         |         0          |       1       |   100%    |
| Dangerous capabilities                                                |        0         |         0          |       7       |   100%    |
| Exec into container                                                   |        1         |         0          |      68       |    98%    |
| Exposed dashboard                                                     |        0         |         0          |       0       |    NaN    |
| Host PID/IPC privileges                                               |        0         |         0          |       7       |   100%    |
| Immutable container filesystem                                        |        6         |         0          |       7       |    14%    |
| Ingress and Egress blocked                                            |        7         |         0          |       7       |    0%     |
| Insecure capabilities                                                 |        0         |         0          |       7       |   100%    |
| Linux hardening                                                       |        2         |         0          |       7       |    71%    |
| Non-root containers                                                   |        0         |         0          |       7       |   100%    |
| Privileged container                                                  |        1         |         0          |       7       |    85%    |
| Resource policies                                                     |        5         |         0          |       7       |    28%    |
| hostNetwork access                                                    |        6         |         0          |       7       |    14%    |
+-----------------------------------------------------------------------+------------------+--------------------+---------------+-----------+
|                           RESOURCE SUMMARY                            |        51        |         0          |      131      |    61%    |
+-----------------------------------------------------------------------+------------------+--------------------+---------------+-----------+
```

スキャン結果には以下の項目が表示されます。

`CONTROL NAME`：スキャン項目（Control）
`FAILED RESOURCES`：スキャンでNGとなった項目数
`EXCLUDED RESOURCES`：除外したリソース数（オプション引数で除外設定ができます）
`ALL RESOURCES`：対象となるすべてのリソース数
`% SUCCESS`：OKとなった割合

Kubeadmにより作成した直後のKuebrnetesクラスタですが、下記のような項目でNGとなっているようです。

- Allowed hostPath：ホストパスをマウントしているPodがある
- Automatic mapping of service account：サービスアカウントの自動マッピングを有効にしている
- Cluster internal networking：ネットワークポリシーが定義されていないため、コンテナへの侵入した攻撃者がクラスタ内のコンテナを移動可能になる可能性がある
- Cluster-admin binding：クラスタのadmin権限を有しているリソースが存在しており、悪意のある挙動操作を実行可能な状態である
- Exec into container：kubectl execコマンドで悪意のあるコマンドを実行可能なコンテナが存在する
- Immutable container filesystem：コンテナのファイスシステムとしてミュータブル（read-write）なものが使用されている
- Ingress and Egress blocked：Pod間で任意のIngress/Egress通信が可能となっている
- Linux hardening：コンテナそのものに必要以上の権限を与えている可能性がある
- Privileged container：特権モードのコンテナが存在する
- Resource policies：CPUやMemory制限がないため、リソースが過剰に消費される可能性がある
- hostNetwork access：Podへ侵入した攻撃者がホストネットワークを利用できる可能性がある

作成直後のクラスタなのでほとんど何も出ないだろうと思っていたら、予想外に多くで驚きでした。
ここでスキャンNGとなっている項目はetcdやkube-proxyなどコントロールプレーンの構成要素です。
マネージドなKubernetesサービスではコントロールプレーンがマネージドなため、ユーザがこれらを意識する必要はありませんが、独自でクラスタを構築する際は上記のような危険をはらむコンテナを所有しているという点を意識しておく必要がありそうです。

## 2.3 yamlファイルのスキャン

Kubernetesクラスタと同様にマニフェスト（yamlファイル）のセキュリティスキャンも行ってみます。
スキャン対象として[Guestbook](https://github.com/kubernetes/examples/tree/master/guestbook)を利用します。
Kubernetesクラスタのスキャンと同様のコマンドを利用し、スキャン対象を引数として与えることで実行できます。

- `kubescape scan framework nsa <スキャン対象>`
- `kubescape scan framework mitre <スキャン対象>`
- `kubescape scan framework armobest <スキャン対象>`

```
$  ./kubescape scan framework nsa examples-master/guestbook/*.yaml
~中略~
NSA FRAMEWORK
+-----------------------------------------------------------------------+------------------+--------------------+---------------+-----------+
|                             CONTROL NAME                              | FAILED RESOURCES | EXCLUDED RESOURCES | ALL RESOURCES | % SUCCESS |
+-----------------------------------------------------------------------+------------------+--------------------+---------------+-----------+
| Allow privilege escalation                                            |        3         |         0          |       3       |    0%     |
| Allowed hostPath                                                      |        0         |         0          |       3       |   100%    |
| Applications credentials in configuration files                       |        0         |         0          |       3       |   100%    |
| Automatic mapping of service account                                  |        0         |         0          |       0       |    NaN    |
| CVE-2021-25741 - Using symlink for arbitrary host file system access. |        0         |         0          |       3       |   100%    |
| CVE-2021-25742-nginx-ingress-snippet-annotation-vulnerability         |        0         |         0          |       0       |    NaN    |
| Cluster internal networking                                           |        0         |         0          |       0       |    NaN    |
| Cluster-admin binding                                                 |        0         |         0          |       0       |    NaN    |
| Container hostPort                                                    |        0         |         0          |       3       |   100%    |
| Control plane hardening                                               |        0         |         0          |       0       |    NaN    |
| Dangerous capabilities                                                |        0         |         0          |       3       |   100%    |
| Exec into container                                                   |        0         |         0          |       0       |    NaN    |
| Exposed dashboard                                                     |        0         |         0          |       0       |    NaN    |
| Host PID/IPC privileges                                               |        0         |         0          |       3       |   100%    |
| Immutable container filesystem                                        |        3         |         0          |       3       |    0%     |
| Ingress and Egress blocked                                            |        3         |         0          |       3       |    0%     |
| Insecure capabilities                                                 |        0         |         0          |       3       |   100%    |
| Linux hardening                                                       |        3         |         0          |       3       |    0%     |
| Non-root containers                                                   |        0         |         0          |       3       |   100%    |
| Privileged container                                                  |        0         |         0          |       3       |   100%    |
| Resource policies                                                     |        0         |         0          |       3       |   100%    |
| hostNetwork access                                                    |        0         |         0          |       3       |   100%    |
+-----------------------------------------------------------------------+------------------+--------------------+---------------+-----------+
|                           RESOURCE SUMMARY                            |        3         |         0          |       3       |    0%     |
+-----------------------------------------------------------------------+------------------+--------------------+---------------+-----------+
```

上記の出力結果では省略していますが、スキャンでNGとなった項目については下記のようにNG項目と対象を教えてくれます。
ただし、何をどう修正してよいかは教えてくれないため、是正するにはKubernetesやコンテナの知識が必要となります。

```
[control: Allow privilege escalation] failed 😥
Description: Attackers may gain access to a container and uplift its privilege to enable excessive capabilities.
Failed:
      Deployment - frontend 
      Deployment - redis-master 
      Deployment - redis-slave 
```

Guestbookでは以下のような項目がNGとなっていることが分かります。

- Allow privilege escalation：攻撃者が特権モードへ昇格可能
- Immutable container filesystem：コンテナのファイスシステムとしてミュータブル（read-write）なものが使用されている
- Ingress and Egress blocked：Pod間で任意のIngress/Egress通信が可能となっている
- Linux hardening：コンテナそのものに必要以上の権限を与えている可能性がある

# おわりに

Kubernetes関連のOSSは無数にあり、有名どころだけに絞ったとしても有限時間でキャッチアップすることは難しいです。
幸い、今回取り上げたKubescapeはインストールや使用方法が非常に簡単（実質何もしてない）でした。
しかし、セキュリティスキャンということでスキャン結果を理解して是正していくにはそれなりの知識が必要になります。
また、KubescapeではOpen Policy Agentが利用されていたということもあり、応用的なツールをさわるのも良いですが、それ以前にやはりKubernetesそのものや、Open Policy Agentなどベースとなる技術を習得していくことが重要だと改めて気づかされました。

本記事では、Kubescapeの概要と実行結果だけを示しましたが、それぞれのチェック項目が具体的に何をチェックしていて、NGとなった際にどう対処すればよいのかなども記事にできると良いなと思います（未来の自分に期待）。

# 参考資料

- [Kubescape: The first open source tool for running NSA and CISA Kubernetes hardening tests](https://www.cncf.io/blog/2021/09/03/kubescape-the-first-open-source-tool-for-running-nsa-and-cisa-kubernetes-hardening-tests/)
- [Kubescape](https://github.com/armosec/kubescape)
- [kubescape-the-first-tool-for-running-nsa-and-cisa-kubernetes-hardening-tests](https://www.armosec.io/blog/kubescape-the-first-tool-for-running-nsa-and-cisa-kubernetes-hardening-tests/)
- [CVE Details](https://www.cvedetails.com/vulnerability-list/vendor_id-15867/product_id-34016/Kubernetes-Kubernetes.html)