Snyk で稼働中の Kubernetes ワークロードをテストする

## はじめに
この記事は、Qiita エンジニアフェスタ 2022 [**「Snykを使って開発者セキュリティに関する記事を投稿しよう！」**](https://qiita.com/official-events/786b978e4a1a28fad312) の参加記事です。

https://qiita.com/official-events/786b978e4a1a28fad312

Snyk の Kubernetes Integration を Amazon EKS 環境で試してわかったことなどをまとめます。

今回は以下の構成で検証しています。

* Amazon EKS: Kubernetes 1.22
* Snyk controller: 1.92.2

:::note info
Kubernetes Integration は Business plan または Enterprise plan で利用できます。Business plan は 14 日間の Free trial を利用することもできます。
:::

## Kubernetes Integration と Snyk controller 
Snyk の Kubernetse Integration を利用すると、実行中のワークロードリソースをインポートして構成や脆弱性の分析を行うことができます。対象は稼働中のコンテナではなく、あくまでコンテナイメージです。つまり Snyk Container が動作します。

:::note inf
Sysdig Integration を利用することで Sysdig が提供するランタイムデータを使用してワークロードの検出を強化できるようです。本記事では触れません。
:::

コンテナイメージのスキャンは大前提として開発工程や CI/CD の中で行なっていくべきと考えますが、Kubernetes Integration を使うことで

* 本番環境にデプロイ済みのワークロードに脆弱性が含まれているか確認したい
* イメージスキャンを行なっていない既存のワークロードを対象とした分析

といった観点、用途での利用にメリットがあると考えます。

Snyk controller は Kubernetes クラスター上で稼働するワークロードを監視し、使用されているイメージの脆弱性スキャンを実行するためのコントローラーです。スキャン結果は Snyk に送信され、Web UI で確認することができます。

Snyk controller で検出可能な Kubernetes のワークロードリソースは以下のとおりです。2022 年 6 月現在でカスタムリソースには対応していませんので、その点は注意が必要かと思います。

* Deployment
* ReplicaSet
* ReplicationController
* DaemonSet
* StatefulSet
* Job
* CronJob
* DeploymentConfig (OpenShift)
* Pod

その他サポートされているコンテナレジストリやプログラミング言語などはドキュメントを参照ください。

https://docs.snyk.io/products/snyk-container/kubernetes-workload-and-image-scanning/kubernetes-integration-overview/supported-container-registry

## Snyk controller のインストール
:::note warn
Snyk controller はベースイメージとして Red Hat UBI (Universal Base Image) を使用します。利用前に RedHat ライセンス契約の END USER LICENSE AGREEMENT に同意する必要があります。
:::

### 導入方法
Amazon EKS 環境の場合、Snyk controller の導入方法は 2 つあります。

* AWS クイックスタートで提供される CloudFormation テンプレートを使用する
　
  以下の3パターンのテンプレートが公開されています。

  1. 新しい VPC と EKS クラスターにデプロイ
  1. 既存の VPC の 新しい EKS クラスターにデプロイ
  1. 既存の EKS クラスターにデプロイ

https://aws.amazon.com/jp/quickstart/architecture/eks-snyk/


* 既存の EKS クラスターに Helm Chart からインストールする

https://docs.snyk.io/products/snyk-container/kubernetes-workload-and-image-scanning/installation-page/install-the-snyk-controller-on-amazon-elastic-kubernetes-service-amazon-eks#installation-steps

今回は Helm Chart から導入を行いました。基本的にドキュメント通りに進めれば OK です。

### Helm Chart からインストール
snyk-charts リポジトリを追加します。

```shell-session
$ helm repo add snyk-charts https://snyk.github.io/kubernetes-monitor --force-update
"snyk-charts" has been added to your repositories
```

Snyk controller 用の Namespace を作成します。

```shell-session
$ kubectl create namespace snyk-monitor
namespace/snyk-monitor created
```

`dockercfg.json` を以下の内容で作業環境に作成します。

```dockercfg.json
{
  "credsStore": "ecr-login"
}
```

dockercfg.json はプライベートコンテナレジストリにアクセスするためのクレデンシャルを Snyk controller に提供するためのファイルです。ECR 以外のプライベートコンテナレジストリを使用している場合は、以下のドキュメントを参照して作成してください。

https://docs.snyk.io/products/snyk-container/kubernetes-workload-and-image-scanning/installation-page/install-the-snyk-controller-with-helm


`dockercfg.json` と `Integration ID` を指定して Secret を作成します。

```shell-session
$ kubectl create secret generic snyk-monitor \
>        -n snyk-monitor --from-file=dockercfg.json \
>        --from-literal=integrationId=abcd1234-abcd-1234-abcd-1234abcd1234
secret/snyk-monitor created
```

`Integration ID` は Snyk の Web UI で Org Settings から Kubernetes Integration を有効化すると確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/97a07ac6-e88c-46de-adff-e0ea7bf77e5d.png)

EKS のマネージドノードグループのノード IAM ロールに `AmazonEC2ContainerRegistryReadOnly` がアタッチされていることを確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/3c93b1b3-a80b-e38c-89fc-92159c0c7a1c.png)

以下のような内容で `values.yaml` を作成します。

* Snyk 上で表示されるクラスタ名を変更したい場合は `clusterName` を書き換えてください
* `Node IAM Role ARN` はノードグループに設定されているノード IAM ロールの ARN に書き換えてください
* `excludedNamespaces` を指定すると特定の Namespace を除外するよう Snyk controller を構成できます
    * `kube-system` などの内部の Namespace はデフォルトで除外されます

```values.yaml
clusterName: "Test cluster" 

excludedNamespaces:
  - "snyk-monitor"
  - "kube-system"
  - "kube-public"
  - "kube-node-lease"
  - "local-path-storage"

volumes:
  projected:
    serviceAccountToken: true
    
securityContext:
  fsGroup: 65534

rbac:
  serviceAccount:
    annotations:
      eks.amazonaws.com/role-arn: <Node IAM Role ARN>
```

Snyk controller をインストールします。

```shell-session
$ helm upgrade --install snyk-monitor snyk-charts/snyk-monitor \
>              --namespace snyk-monitor \
>              -f values.yaml
Release "snyk-monitor" does not exist. Installing it now.
W0621 08:33:51.791629    2383 warnings.go:67] spec.template.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchExpressions[1].key: beta.kubernetes.io/arch is deprecated since v1.14; use "kubernetes.io/arch" instead
NAME: snyk-monitor
LAST DEPLOYED: Tue Jun 21 08:33:51 2022
NAMESPACE: snyk-monitor
STATUS: deployed
REVISION: 1
TEST SUITE: None
```

snyk-monitor の pod が正常に起動していることを確認します。

```shell-session
$ kubectl get all -n snyk-monitor
NAME                                READY   STATUS    RESTARTS   AGE
pod/snyk-monitor-6d568f57df-pt559   1/1     Running   0          16s

NAME                           READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/snyk-monitor   1/1     1            1           16s

NAME                                      DESIRED   CURRENT   READY   AGE
replicaset.apps/snyk-monitor-6d568f57df   1         1         1       16s
```
インストールが正常に完了すれば Kubernetes Integration の設定で Snyk に接続済みの controller のバージョンが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/ea8e1d2c-20bf-ea45-9660-0b1966b2ca17.png)

## Kubernetes ワークロードを Snyk に追加する
### 手動インポート
Add project から Kuberenetes をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/316dac39-2bef-0450-8a1c-4d2adf3388ee.png)

テストを行いたいワークロードを選択し、Add selected workloads をクリックします。
Snyk に接続してからクラスター内のすべてのワークロードが表示されるまで少し時間がかかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/da00d4cc-cfd0-a52f-1ed3-d0edb731faa2.png)

Import が完了し、コンテナイメージのスキャンが実行されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/2f4fa55f-d5cb-38f5-f426-838005a0885e.png)

ログを確認すると Kubernetes からインポートされていることが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/6d939bf6-ec7d-7756-b484-29a893bc28dd.png)

### 自動インポート
Snyk controller インストール時に policyOrgs として Snyk の Organization ID を指定すると、job と pod を除くワークロードを自動でインポートおよび削除します。

```diff:values.yaml
+ policyOrgs:
+   - 19982df2-0ed5-4a16-b355-e6535cfc41ef
```

特定のワークロード単位で自動インポートを指定したい場合は、ワークロードのマニフェストファイルに以下のようなアノテーションを付けます。

```diff:deployment.yaml
  apiVersion: apps/v1
  kind: Deployment
  metadata:
  name: my-app-deployment
+   annotations:
+     orgs.k8s.snyk.io/v1: 19982df2-0ed5-4a16-b355-e6535cfc41ef
  spec:
    template:
      spec:
        containers:
        …
```

詳細はドキュメントを参照してください。

https://docs.snyk.io/products/snyk-container/kubernetes-workload-and-image-scanning/kubernetes-integration-features/automatic-import-deletion-of-kubernetes-workloads-projects


以上です。
参考になれば幸いです。