Snykでコンテナのセキュリティハードニング 【Snykテクニカルサポートを使ってみた】

# はじめに
こちらの記事はアドベントカレンダー[Snykを使ってセキュリティにまつわる記事を投稿しよう！【PR】Snyk](https://qiita.com/advent-calendar/2021/snyk)の9日目として投稿しています。

Snykは脆弱性スキャンが簡単に自動化でき、修復まで可能なセキュリティプロダクトです。単純なソースコード検査だけでなく、依存しているライブラリの脆弱性やコンテナイメージそのものをスキャンすることができ、非常に強力なツールとなっています。

この記事では、わざと脆弱性を入れ込んだコンテナイメージを作り、Snykで検知できるかどうか試しました。
また、人気のあるOSSライブラリを検査し、見つかった脆弱性にパッチできるPRを自動でSnykから生成してみます。

# Snykの脆弱性スキャンの仕組み

## ルールベース＋機械学習モデルでの精度向上
メインの脆弱性スキャン自体はルールベースの一般的なやり方です。それにフィルタとして、**機械学習ベースのモデルで偽陽性・偽陰性を少なくし、検知精度を上げている**ようです。

また、脆弱性の検知ルールとして、CVEを元に独自のデータベースで管理しており、**各CVEに対してわかりやすく説明を加えたり、PRのメッセージをひと目でわかるようにメタデータを付加**しているようです。

## コンテナイメージスキャン
コンテナイメージを検査するには、実際に動かして検査する方法もあるが、Snykではイメージを動かさずに静的に検査できるため、非常に安全です。静的検査では、イメージ内で使われている依存パッケージとバージョンを検出し、脆弱性を分析してくれます。[こちらの公式ドキュメント](https://docs.snyk.io/products/snyk-container/snyk-container-security-basics/how-snyk-container-works)で詳しい仕組みが書かれてます。

実はDocker scanコマンドで公式に使われてるのがSnykエンジンとのこと！いつの間にかデファクトになってますね。

>Docker Scan runs on Snyk engine, providing users with visibility into the security posture of their local Dockerfiles and local images.
https://docs.docker.com/engine/scan/ より


# 実際にスキャンしてみる

## 初期登録
Snykの公式の記事があるので、[こちら](https://qiita.com/SnykSec/items/aa80a976eb17299fff62)を見てみてください。無料でほとんどの機能が使用できます。GoogleかGitHubアカウント連携ですぐアカウントを作れます。

## わざと脆弱性を入れたコンテナをスキャンしてみる【コンテナイメージスキャン】
PythonのウェブアプリフレームワークであるFlaskの古いバージョンを使って、脆弱なサーバーのコンテナイメージを作成し、それをSnykでスキャンしてみます。**0.12.0**という古いバージョンのFlaskでは、**DoSとInput Validationの既知の重大レベルの脆弱性**があります。SnykのDBでは[こちらのリンク](https://security.snyk.io/vuln/SNYK-PYTHON-FLASK-451637)でトラックされています。

以下のDockerfileで`RUN pip3 install flask==0.12.0`の部分が、脆弱性のあるライブラリをインストールしている部分になります。

```Dockerfile
# Test to create vulnerable docker image
# Using vulnerable Python library: flask 0.12.0
# https://security.snyk.io/vuln/SNYK-PYTHON-FLASK-451637
FROM python
RUN pip3 install flask==0.12.0
COPY flask_server.py /
CMD python flask_server.py
```

```python
### flask_server.py ###
from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello():
    name = "Hello World"
    return name

if __name__ == "__main__":
    app.run()
```

今回はGoogle Cloudのコンテナレジストリにコンテナイメージをアップロードし、それをSnykで脆弱性スキャンしてみます。[こちらの公式ドキュメント](https://docs.snyk.io/products/snyk-container/image-scanning-library/gcr-image-scanning/container-security-with-gcr)通りの流れとなります。

1. コンテナイメージをビルドし、Google CloudのコンテナレジストリにPush（アップロード）します。ウェブUI上でコンテナイメージがアップロードされたことを確認できると思います。

```shell
docker build -t vulnerable-flask .
docker tag vulnerable-flask gcr.io/<自分のGoogle CloudのプロジェクトID>/vulnerable-flask
docker push gcr.io/<自分のGoogle CloudのプロジェクトID>/vulnerable-flask
```
![Screen Shot 2021-12-07 at 22.28.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62311/d8f20986-cb81-05bc-3fb1-58321f7d7ed7.png)

2.Snykがコンテナレジストリのイメージを読めるよう、Google Cloudでサービスアカウントのキーを作成して、Snykで登録します。
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62311/1b46ad0b-0ed1-6988-fa6b-ad3d9bd68421.png">
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62311/fce204cc-4dd9-c3c7-3041-3d7ced2df135.png">

3.接続できたら対象のコンテナイメージを選びます。
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62311/7cca0c3c-bb39-0681-2e31-0008e5e447ba.png">
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62311/161298c7-9182-6f6d-f8dc-7cb907cb60dc.png">

4.数秒ほど待つと、検知結果がUI上で出てくるので、開いてみましょう。結果は以下の通り、[SNYK-PYTHON-FLASK-451637]((https://security.snyk.io/vuln/SNYK-PYTHON-FLASK-451637))の脆弱性がしっかり検知されている事がわかります。
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62311/51e917f2-a722-e87b-d44a-9369b9334224.png">
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62311/27bb6783-7ffc-0b1d-8ef4-4dffee6a75c8.png">



今回はクラウド上のレジストリからコンテナイメージのスキャンを行いましたが、CLIで行うことも可能です！
ただ、その場合は[公式ドキュメント](https://docs.snyk.io/products/snyk-container/getting-around-the-snyk-container-ui/detecting-application-vulnerabilities-in-container-images)にあるとおり、Node、Golang、Javaのみが対応しており、Pythonは2021年12月9日現在ではまだ非対応です。

公式サポートに問い合わせたところ、Pythonは今後対応していく予定があるとのことです。

>Unfortunately, Python dependency analysis is indeed not yet supported from the CLI, but only from the CR integrations. See as well the docs from here:
https://docs.snyk.io/products/snyk-container/getting-around-the-snyk-container-ui/detecting-application-vulnerabilities-in-container-images
>It is on the roadmap to have it supported as well from the CLI.

>（参考訳）残念ですが、コンテナイメージのPythonの依存分析については、CLIツールではまだサポートされておりません。その代替案として、コンテナレポジトリからであれば、分析することができます。こちらのドキュメントを参考にして下さいね。今後CLIツールからスキャンできるように、開発計画（ロードマップ）を立ててるよ！


## BootstrapのOSSレポジトリをスキャンしてみる【OSSコードスキャン】
Bootstrapはウェブのフロントエンド開発では最もよく使われているOSSライブラリの一つです。ウェブ開発をやっていればどこの開発チームも使ってそうなBootstrapに対して、脆弱性スキャンをしてみました。

1. まずはGitHubの公式レポを自分のGitHubアカウントにForkし、Snykの画面でスキャンを実行します。
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62311/a4f4cfff-682e-9dc0-667b-96580920c559.png">

1. 数秒ほど待つと、こんな感じでスキャン結果を出してくれます。
![Screen Shot 2021-11-05 at 19.26.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62311/04f3b4a5-e4e3-29e8-ee4d-159fd2517595.png)

1. 脆弱性の詳細をみると、かなり見やすくで脆弱性の内容やリスクを説明してくれますね。さらに、この脆弱性をパッチするコードをSnykから自動でPRを作ることができます。
![Screen Shot 2021-11-05 at 19.30.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62311/0b1b9803-364f-9fc4-6e87-4acc0cf5f154.png)

4.Snykから自動作成されたPRを見てみると、自動作成された件名に、脆弱性の中身と修正内容をまとめてくれてるので、PRを承認しやすく、脆弱性管理がかなり簡単になります。（ただ、今回のPRの自動メッセージ作成機能では0.5.2のところが0.5.1になっていたり、まだ不完全なところもあります）
![Screen Shot 2021-11-05 at 19.19.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62311/13f40ffe-e566-56f1-0e6b-a5d8826f6293.png)
5. 中身はしっかり0.5.2へのアップグレードとなっています。これらをすべて自動でやってくれるのは本当にいいですね！
![Screen Shot 2021-11-05 at 19.20.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62311/cf2e484f-0cae-c57a-a43d-a5ccc82ec998.png)

あとはこのPRをマージすれば脆弱性対応は完了です。ここまで労力が要らないとなると、どの開発チームでも導入しやすく、開発マインドが「Secure by Default」（最初からセキュアに開発していく）に移りやすく、開発チームの底上げになりそうです。


# Snykのサポート対応がとてもしっかりしてる
今回の脆弱性検査を行うにあたり、PythonベースのコンテナイメージをCLIからスキャンしようとして、依存の脆弱性を検知できずSnykのサポートを使ってみました。（これは結論として、2021年12月現在でCLIでのPythonベースのイメージスキャンは非対応だからです。ドキュメントでもちゃんと明記してあるので、ちゃんとドキュメントは読みましょう・・・）

本件をSnykサポートで問い合わせしたときの対応とサポートの早さが素晴らしかったです。
Snykでの検査結果と、対象となるレポを共有すると、**サポートの方で再現テストを行って下さり、それを元にすぐに開発チームにエスカレーションしてくれました。**また、開発チームのレスポンスも迅速でした。ここまでしっかりしてると、実運用でも困らないだろうな、と思います。

以下にサポート内容の一部を共有するので、サポートの良さを見てみて下さい。（個人情報はマスクしてあります）

![Screen Shot 2021-12-08 at 10.08.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62311/3c220e9c-2fc0-5687-193f-16f9f264c349.png)



# サマリ
SnykはすでにDocker Scanでデフォルトで使われていたりするように、導入がかなり簡単なのに強力です。
一番大変な脆弱性管理についても、わかりやすい件名をつけてPRを自動作成してくれるので、かなり運用が楽そうですね。

ここまでハードルが低いと、どのサイズの開発チームでも導入しやすく、開発マインドが「Secure by Default」（最初からセキュアに開発していく）にしやすいので、お手軽に開発チームの底上げになりそうです。

## 参考文献
- [Snykの脆弱性データベース](https://security.snyk.io/)
- [Snyk社、新しいコンテナレジストリとの統合を発表](https://licensecounter.jp/devops-hub/blog/190814-gdep01/)
- [Google CloudのコンテナレジストリへのPushのやり方](https://cloud.google.com/container-registry/docs/pushing-and-pulling)
- [Snykについての日本語のTechCrunch記事](https://jp.techcrunch.com/2021/03/12/2021-03-10-snyk-raises-300-million-at-a-4-7-billion-valuation-as-employees-cash-in-and-the-security-company-beefs-up/)
- [Docker ScanによるイメージスキャンではSnykエンジンが実行されている](https://matsuand.github.io/docs.docker.jp.onthefly/engine/scan/)