静的解析ツールを使ってHelm Chartを解析する
はじめに
アプリケーションコードと比べて、Helm Chart など IaC のテストコードを書く機会は少ないと思います。そのためレビュー時に、yaml ファイルの設定を見落とす、といった懸念があります。
こういった懸念を解消する手段として静的解析ツールがあります。
業務で Helm Chart を静的解析してみたので、学んだことを書いていきます。
使用する解析ツール
今回使ってみた静的解析ツールは以下の3つです。
- Trivy
- Kics
- Checkov
選定理由は以下の通りです。
-
静的解析に API key を前提としないこと CI やローカルで実行することを前提としており、API key の発行や管理で導入のハードルが上がる可能性があるためです。 たとえば、snyk(スニーク) は、CLI を使用するために API key を設定する必要があります。
-
解析項目が多いこと 解析項目の数が少ないと、自分たちで解析項目を作成、メンテナンスをする必要があるためです。
Trivy
Kics
Checkov
-
カスタムした解析項目を追加できること 組織やチームによっては解析項目を追加したい場合があると思います。その場合、解析項目を自分たちでカスタマイズする必要が出てくる可能性があるためです。
-
定期的にメンテナンスがされていること 解析項目の追加や修正が行われていない場合、自分たちで脆弱性などの情報をキャッチアップし、かつ解析項目の追加をしないといけなくなるからです。
-
eslint のように、コメントを書くと指摘事項を無視することができる機能があること 解析するコードによっては、修正する必要のない項目があり、何もしないと指摘され続けます。
そのため細かく解析項目を制御したいケースがあると嬉しいと思ったからです。 Using configuration comments - eslint.org
Trivy の概要と特徴
バージョン | |
---|---|
Trivy | 0.43.1 |
defsec | v0.90.3 |
Trivy とポリシー
Trivy では、解析項目を「ポリシー」と呼び、Rego 言語でポリシーを定義しています。
具体的なポリシー定義は、aquasecurity/defsecリポジトリに記述されています。
Trivy のバージョンに対応した defsec のバージョンは、Trivyのリポジトリにあるgo.mod に記載されています。
Trivy がサポートしているプラットフォーム
Trivy では以下の IaC をサポートしています。
- Helm
- Kustomization
- Docker
- Terraform
- CloudFormation
- その他
ポリシーの重要度(severity)
各ポリシーには、以下の重要度(severity)が割り当てられています。ポリシーをフィルタリングをコマンドのオプションで設定できます。(例: severity: CRITICAL
のみ解析に使用する)
CRITICAL
HIGH
MEDIUM
LOW
UNKNOWN
Terraform や Helm の解析オプション
とくに Terraform や Helm の解析では、変数を上書きできるオプションが存在します。これにより、特定の値を上書きして解析することが可能です。ただし、Kics にこのようなオプションはありません。
Terraform における変数の上書きに関する詳細は、こちらのドキュメントを参照してください。
Trivy ができないこと
trivy conf
コマンドでできないことを紹介します。
-
特定のクエリのみ解析に使用することはできない
.trivyignore
ファイルを作成することで、解析に使用するポリシーを除外できます。しかし、あらかじめ用意されたポリシーを CLI のオプションに指定して解析に使用することはできません By Finding IDs -
CLI のオプションで、特定のポリシーを解析から外すことはできない
--exclude-policies
のようなオプションはありません。.trivyignore
ファイルでしか実現できません。 -
コメントを使用したポリシーのフィルタリング By Inline Comments のページでは、コードにインラインコメント(
#trivy:ignore:
)を書くことでポリシーのフィルターが可能である旨が書いてありますが、手元の Helm Chart で試したところ機能しませんでした。2023年8月現在、以下の Issue が Open のままでしたが、将来的にはできそうです。 Support Inline Filtering #2961
-
Helm Chart を解析対象に指定した場合、拡張子
yml
は解析できない 拡張子がyaml
なら解析できます -
ポリシーの一覧を表示するCLI のコマンドはない
Trivyのポリシーの一覧をテーブル形式で取得する
CLI のオプションが存在しないので、defsec のリポジトリから shell で取り出します。
以下のコマンドは severity: CRITICAL
である Kubernetes のポリシーの一覧をマークダウン形式のテーブルで作成できます。
出力結果
テーブルのヘッダーは自分で作成する必要がありますが、ヘッダーのすぐ下に、先ほどの git grep
コマンドの結果をコピペすると、以下のような見た目になります。
ヘッダー
完成した severity: CRITICAL
である Kubernetes のポリシー一覧
id | avd_id | title | description |
---|---|---|---|
KSV044 | AVD-KSV-0044 | No wildcard verb and resource roles | Check whether role permits wildcard verb on wildcard resource |
KSV046 | AVD-KSV-0046 | No wildcard resource roles | Check whether role permits specific verb on wildcard resources |
KSV045 | AVD-KSV-0045 | No wildcard verb roles | Check whether role permits wildcard verb on specific resources |
KSV043 | AVD-KSV-0043 | Do not allow impersonation of privileged groups | Check whether role permits impersonating privileged groups |
KSV050 | AVD-KSV-0050 | Do not allow management of RBAC resources | An effective level of access equivalent to cluster-admin should not be provided. |
KSV041 | AVD-KSV-0041 | Do not allow management of secrets | Check whether role permits managing secrets |
KSV102 | AVD-KSV-0102 | Tiller Is Deployed | Check if Helm Tiller component is deployed. |
Trivy 使い方
Kubernetes のマニフェストは helm を使います。
基本的な使い方
trivy conf <DIR>
で実行します。
"trivy conf example" の出力結果
seveiry: CRITICAL,HIGH のポリシーを使用する
-s, --severity
オプションを使用します。
Trivy の出力形式を json にする
-f, --format
オプションを使用します。
設定できるフォーマットは以下の通りです。
- table
- json
- template
- sarif
- cyclonedx
- spdx
- spdx-json
- github
- cosign-vuln
Kics の概要と特徴
バージョン | |
---|---|
Kics | v1.7.4 |
Kicsがサポートしているプラットフォーム
Kics では以下の IaC をサポートしています。
- Terraform
- Kubernetes
- Helm
- Docker
- Ansible
- その他
Supported Platforms - docs.kics.io
Kics とクエリ
Kics では解析項目のことをクエリ
と呼び、Rego 言語で書かれています。
クエリ一覧は Query List から確認できます。
クエリの分類
Kics は Tricy や Checkov と異なり、クエリに severity
と category
という2つの分類がある点が特徴です。
--exclude-categories
、--exclude-severities
2つのオプションがあるので要件に合わせて柔軟にクエリのフィルターを実現できます。
severity
- High
- Medium
- Low
- Info
category
- Access Control
- Availability
- Backup
- Best Practices
- Build Process
- Encryption
- Insecure Configurations
- Insecure Defaults
- Networking and Firewall
- Observability
- Resource Management
- Secret Management
- Structure and Semantics
- Supply-Chain
Query Categories - docs.kics.io
exit コード
Kics は解析した結果 exit コードが変わります。そのため CI で実行に失敗したとき、exit コードに 0 以外が出ます。
コード | 説明 |
---|---|
0 | 結果がない = 異常がない |
50 | severity: High の結果がある |
40 | severity: Medium の結果がある |
30 | severity: Low の結果がある |
20 | severity: Info の結果がある |
Exit Status Code - docs.kics.io
クエリをスキップする
以下のように ignore
のコメントを書くと、解析時に特定のブロック、ファイルを解析対象から外します。
実際に試してみます。
Helm で example チャートを作成した後、severity: HIGH のクエリを実行します。
すると、Kics からクエリID:5572cc5e-1e4c-4113-92a6-7a8a3bd25e6d
を指摘されました。
このクエリを無視してもらうため、チャートのテンプレートにコメントを書いてみます。
ignore のコメントを追加したので、もう一度同じコマンドを実行してみます。
意図した通り、Kics に指摘されなくなりました。
Using commands on scanned files as comments - docs.kics.io
Kics ができないこと
-
Mac を開発で使用している場合、Homebrew でインストールできない 厳密には可能ですが、最新バージョンはありません。docker イメージの使用を推奨。 Installation - docs.kics.io
-
Trivy と違い、Terraform や Helm を解析する場合、オプションで値を上書きすることができない
-
Trivy と同様 CLI でクエリの一覧を取得する方法はない クエリ一覧は Query List から確認できます。
Kics のクエリ一覧をテーブル形式で取得する
Kics にはドキュメントにクエリ一覧があります。
チームによっては、README やドキュメントツールで、使用するクエリを管理したい場合もあると思ったので、サンプルの shell スクリプトを作成しました。
以下のコマンドは、カテゴリーが Secret Management
である Kubernetes のクエリをテーブル形式で出力するコマンドです。
出力結果
テーブルのヘッダーは自分で作成する必要がありますが、ヘッダーのすぐ下に、先ほどのコマンドの結果をコピペすると、以下のような見た目になります。
ヘッダー
完成したカテゴリーが Secret Management
である Kubernetes のクエリ一覧
id | severity | query name | description |
---|---|---|---|
ae8827e2-4af9-4baa-9998-87539ae0d6f0 | HIGH | Peer Auto TLS Set To True | When using etcd commands, the ‘—peer-auto-tls’ should be set to false |
98ce8b81-7707-4734-aa39-627c6db3d84b | HIGH | Auto TLS Set To True | When using etcd commands, the ‘—auto-tls’ should be set to false |
9391103a-d8d7-4671-ac5d-606ba7ccb0ac | MEDIUM | Etcd Client Certificate Authentication Set To False | When using etcd commands, the ‘—client-cert-auth’ flag should be defined |
36a27826-1bf5-49da-aeb0-a60a30c0e834 | MEDIUM | Kubelet Client Certificate Or Key Not Set | When using kube-apiserver command, the ‘kubelet-client-key’ and ‘kubelet-client-certificate’ flags should be set |
ec18a0d3-0069-4a58-a7fb-fbfe0b4bbbe0 | MEDIUM | Kubelet Certificate Authority Not Set | When using kube-apiserver command, the ‘kubelet-certificate-authority’ flag should be set |
dab4ec72-ce2e-4732-b7c3-1757dcce01a1 | MEDIUM | Service Account Key File Not Properly Set | When using kube-apiserver command, the ‘—service-account-key-file’ flag should be defined |
b7d0181d-0a9b-4611-9d1c-1ad4f0b620ff | MEDIUM | Etcd Peer Client Certificate Authentication Set To False | When using etcd commands, the ‘—peer-client-cert-auth’ flag should be set to true |
056ac60e-fe07-4acc-9b34-8e1d51716ab9 | MEDIUM | ServiceAccount Allows Access Secrets | Roles and ClusterRoles when binded, should not use get, list or watch as verbs |
1c621b8e-2c6a-44f5-bd6a-fb0fb7ba33e2 | MEDIUM | Rotate Kubelet Server Certificate Not Active | The RotateKubeletServerCertificate argument should be true |
52d70f2e-3257-474c-b3dc-8ad9ba6a061a | MEDIUM | Kubelet Client Periodic Certificate Switch Disabled | Kubelet argument —rotate-certificates should be true |
3f5ff8a7-5ad6-4d02-86f5-666307da1b20 | MEDIUM | Etcd Client Certificate File Not Defined | When using kube-apiserver commands, the ‘—etcd-cafile’ flag should be defined |
c1032cf7-3628-44e2-bd53-38c17cf31b6b | MEDIUM | Shared Service Account | A Service Account token is shared between workloads |
cb7e695d-6a85-495c-b15f-23aed2519303 | MEDIUM | Not Unique Certificate Authority | Certificate Authority should be unique for etcd |
3d658f8b-d988-41a0-a841-40043121de1e | LOW | Secrets As Environment Variables | Container should not use secrets as environment variables |
Kics 使い方
Kics の基本的な使い方
kics scan -p <DIRS>
で実行します。カンマ区切りで複数ディレクトリを指定できます。
"kics scan" の出力結果
特定のクエリのみ使用する
特定のクエリのみを使用したい場合は、-i, --include-queries strings
オプションを指定します。
カンマ区切りでクエリ ID を指定します。
seveiry: HIGH のクエリを使用する
--exclude-severities
を使用します。 オプションは exclude
と書いているので、この場合は HIGH 以外の info,low,medium
を指定します。
Kicsの出力形式を json にする
--report-formats strings
と -o, --output-path string
を使用します。
Kics は -o
オプションで指定したディレクトリ配下に results.json
を自動的に作成します。
コマンドの最後にある /charts
はコンテナ内のパスであることに注意
Checkov の概要と特徴
バージョン | |
---|---|
Checkov | 2.3.330 |
Checkov とポリシー
Checkov では、解析項目のことを”ポリシー”と呼びます。
bridgecrew.cloud を利用すると、API key を取得でき、CLI のオプションに設定できます。
Checkov は API key を利用しなくても解析はできます。
インストール方法
pip または homebrew を使ってインストールできます。
Installing Checkov - checkov.io
Checkov ができないこと
- API key を発行しないとポリシーのフィルターができない
Trivy では
--severiry HIGH
、 Kics では--excluder-severities info,low
オプションを使用することで解析項目をフィルタリングできます。
同じくCheckov にも-c, --check
オプションがありますが、このオプションを使用して severity を指定した項目のフィルタリングは API key を設定しないと使用できません。
Checkov の使い方
Checkov の基本的な使い方
ディレクトリを指定するときは -d <DIR>, --director <DIR>
を使用します。
特定のパス配下を解析しない —skip-path
--skip-path <ファイル名、ディレクトリ名>
たとえば、helm create
コマンドで作成したチャートにはデフォルトで tests
ディレクトリができます。
Checkov はこのディレクトリ配下の yaml も解析対象に入れてしまうため、コマンドを実行するときは対象外にしたいです。
このとき --skip-path
を使用して、解析対象から外すことができます。
--skip-path
は複数回指定できます。
以下は template/deployment.yaml
を解析対象から外した例です。
失敗した項目のみ出力する —quiet
Checkov で解析を実行すると、コンソールに大量の結果を出力します。
--quiet
オプションを設定すると、失敗した結果のみを出力できます。
ちなみに --compact
オプションを設定するとコードブロックを出力しなくなります。
--compact オプション
Checkov のポリシーをフィルタリングする
Terraform や Dockerfile などは、Kics と同じようにコメントを書くことで解析の対象にしない方法があります。
Kubernetes のマニフェストでは annotations
に設定を追加することで、解析対象から外すことができます。
解析項目の CKV_K8S_21
は “デフォルトの namespace を使うな” という指摘です。
今回は Deployment のみ、解析に引っかからないようにします。
意図した通り、Deployment リソースのみ指摘されなくなりました。
Suppressing/skipping - checkov.io
Checkov の出力形式を json にする
Checkov のポリシー一覧を取得する
Trivy や Kics と違い Checkov は CLI でポリシーの一覧を取得できます。
一覧を取得するには、-l, --list
を指定します。
まとめ
静的解析ツールを触ってみた知ったを書いてみました。実際にツールを触ってみないと良し悪しはわからない、と感じました。
今回紹介した3つはローカル環境でも実施できるツールなので、まずは興味を持ったツールから使い始めることをオススメします。