kube-benchを利用してKubernetesクラスタの健康診断を実施した

# はじめに

[kube-bench](https://github.com/aquasecurity/kube-bench)は[AquaSecurity社](https://www.aquasec.com/)が開発しているOSSです。
名前から推測できる通り、Kubernetes用のツールで役割は後述しますが、Kubernetsクラスタのセキュリティ強化に利用できるツールです。

今年初めて利用したので、導入ステップと検証結果をまとめてみました。

## kube-benchについて
Kubernetesクラスタの設定が、[CIS](https://www.cisecurity.org/)が提唱する[Kubernetes Benchmark](https://www.cisecurity.org/benchmark/kubernetes)に準拠しているかを検査するツールです。
目的はクラスタの健全性の検査、人でいうところの健康診断に近いのかなと思っています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19911/4be9b9ac-e2de-8379-8b9e-5392ea3926bb.png)

なお、CIS Kubernetes Benchmarkへの準拠状況に関しては、公式にも記載ありますが可能な限りとあるので、完全な準拠は保証していないことに注意が必要です。

利用できるKubernetesのクラスタは、セルフホスティングしているものに限らず、PaaSが提供するマネージドのクラスタも含まれます。

それでは、前置きが長くなりましたが、以下から実際の導入ステップの紹介に入ります。

## 実行環境
対象環境: AWS EKS(Fargate)
Kubernetes　Version: 1.22

## 前提
- 稼働しているEKSクラスタが存在する
- JOBを稼働させるIAM Roleが作成済みである

## kube-benchの導入
kube-benchは先程少し触れましたが、各種PaaSのマネージドクラスタもサポートしており、job.yamlも用意されています。
今回は、Benchmarkの結果をSecurityHubに連携サポートをしてくれる[job-eks-asff.yaml](https://github.com/aquasecurity/kube-bench/blob/v0.6.6/job-eks-asff.yaml)を利用します。

kube-benchはjobで単発で稼働させることも可能ですが、今回は定期的に実行するCronJobを作成します。

環境が違ったり、詳しい導入ステップを把握したい方は[公式のドキュメント](https://github.com/aquasecurity/kube-bench/blob/v0.6.6/docs/running.md)見てください。

### Imageの準備
kube-benchのImageをECRに作成します
AWSアカウントやリージョンは各自の環境に置き換えてください
```shell
aws ecr create-repository --repository-name k8s/kube-bench
git clone https://github.com/aquasecurity/kube-bench.git
cd kube-bench
git checkout refs/tags/v0.6.6
docker build -t k8s/kube-bench:v0.6.6 .
docker tag k8s/kube-bench:v0.6.6 <AWS_ACCT_NUMBER>.dkr.ecr.<AWS_REGION>.amazonaws.com/k8s/kube-bench:v0.6.6
aws ecr get-login-password --region <AWS_REGION> | docker login --username AWS --password-stdin <AWS_ACCT_NUMBER>.dkr.ecr.<AWS_REGION>.amazonaws.com
docker push <AWS_ACCT_NUMBER>.dkr.ecr.<AWS_REGION>.amazonaws.com/k8s/kube-bench:v0.6.6
```

### SecurityHubとの連携
[AWSのSecurityHubの統合画面](https://ap-northeast-1.console.aws.amazon.com/securityhub/home?region=ap-northeast-1#/integrations)でkube-benchの結果受け入れを有効にします
![スクリーンショット 2022-12-08 11.27.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19911/2708dac8-d4be-eb9f-7aa4-729b1cd1bcfd.png)

### manifestの作成
1. CronJob作成
    ConfigMapでは対象のAWSアカウント、AWSのリージョン、EKSクラスタを指定します
    jobTemplateは公式のものを利用していますが、終了したJOBを削除する為にttlSecondsAfterFinishedを追加します
    ```yaml
    ---
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: kube-bench-eks-config
    data:
      config.yaml: |
        AWS_ACCOUNT: "<AWS_ACCT_NUMBER>"
        AWS_REGION: "<AWS_REGION>"
        CLUSTER_ARN: "<AWS_CLUSTER_ARN>"
    ---
    apiVersion: batch/v1
    kind: CronJob
    metadata:
      name: kube-bench
      namespace: kube-bench
    spec:
      schedule: "0 2 * * *" #UTCで設定
      jobTemplate:
        spec:
          ttlSecondsAfterFinished: 100
          template:
            spec:
              containers:
                - name: kube-bench
                  # Push the image to your ECR and then refer to it here
                  # image: <ID.dkr.ecr.region.amazonaws.com/aquasec/kube-bench:ref>
                  command: ["kube-bench", "run", "--targets", "node", "--benchmark", "eks-1.0.1", "--asff"]
                  volumeMounts:
                    - name: kube-bench-eks-config
                      mountPath: "/opt/kube-bench/cfg/eks-1.0.1/config.yaml"
                      subPath: config.yaml
                      readOnly: true
              restartPolicy: Never
              serviceAccountName: kube-bench
              volumes:
                - name: kube-bench-eks-config
                  configMap:
                    name: kube-bench-eks-config
                    items:
                      - key: config.yaml
                        path: config.yaml
    ```

1. ServiceAccountの作成
    JOBを動かすIAM Roleを指定します
    ```yaml
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: kube-bench
      labels:
        app.kubernetes.io/name: kube-bench
      annotations:
        eks.amazonaws.com/role-arn: arn:aws:iam::<AWS_ACCOUNT_ID>:role/<IAM_ROLE_NAME>
    ```

### IAM RoleにSecurityHub用の権限を追加
今回は検出結果をAWSのSecurityHubに連携するため、JOBを稼働させるIAM Roleに以下のポリシーを追加します
```yaml
Policies:
- PolicyName:'kube-bench'
 PolicyDocument:
   Id: default_policy_ID
   Version: "2012-10-17"
   Statement:
   - Sid: 'kubebench'
     Effect: 'Allow'
     Resource: 'arn:aws:securityhub:ap-northeast-1::product/aqua-security/kube-bench'
     Action: 'securityhub:BatchImportFindings'
```

## kube-benchの実行結果

実行したCronJobの結果はログに出力されますが、今回はSecurityHubと連携させたので、SecurityHub側で検出結果を確認できます。

重要度、Benchmarkのどの項目に抵触したか、対象リソース、などを確認することができます。

![スクリーンショット 2022-12-08 12.28.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19911/cf763dab-a8d9-8b01-d4f9-466a11e40ec4.png)

SecurityHubに検出結果を送る際には[ASFF](https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-findings-format.html)(AWS Security Finding Format)にフォーマットで送る必要があります。
kube-bench内部で、検出した結果をASFFにコンバートしてくれています。
https://github.com/aquasecurity/kube-bench/blob/a1e2870e83e9c2dfe0d24210712e69f8adeb6743/check/controls.go#L253-L287

# まとめ
今回は、kube-benchというOSSで提供されているツールを利用して、Kubernetsクラスタの健康診断を行いました。

マニフェストなどは公式から提供されており、定期実行も手軽にでき、SecurityHubと連携してくれるのでAWSを利用している方におすすめだと感じました。

検出項目に対する注意点としては、Fargateの場合は[AWSの責任共有モデル](https://aws.amazon.com/jp/blogs/containers/introducing-cis-amazon-eks-benchmark/)にある通り、検知されたものの対応が推奨されない項目もあるので、検知項目について調整が必要ということです。

上記のような注意点はありますが、手軽にクラスタの健全性をツールで確認し、結果をSecurityHubに連携できるので、是非試してみてください。