Certified Kubernetes Security Specialist (CKS) #14: イメージスキャン: Trivy、Kubesec、KubeLinter

CKS シリーズ はドメイン Supply Chain Security を扱っている途中です。先の #13 Minimal images: distroless、scratch でイメージに入るものを最小に減らして攻撃面を狭めたなら、この記事は そのイメージの中にどんな脆弱性が残っているのかをどう見つけるか を整理します。

イメージをいくら小さく作っても、その中の OS パッケージや言語ライブラリに既知の脆弱性 (CVE) が埋め込まれていれば、そのイメージは危険です。サプライチェーンセキュリティの核心は 何が入っているのかを知り、既知の脆弱性をデプロイ前に取り除く ことです。この記事ではイメージの CVE を見つける Trivy、マニフェストのセキュリティ設定をスコアで評価する Kubesec、マニフェストのアンチパターンを静的解析する KubeLinter を扱います。

2 種類のスキャン: イメージ vs マニフェスト #

イメージスキャンとひとまとめに呼びますが、CKS で扱うツールは検査する対象が 2 つに分かれます。この区別をまず掴んでおくと、どの作業にどのツールを取り出すかで迷いません。

検査対象何を見つけるかツール
イメージの内容OS パッケージ・ライブラリに埋め込まれた既知の脆弱性 (CVE)Trivy
マニフェストの設定securityContext・権限など危険なワークロード設定Kubesec、KubeLinter

Trivy はイメージの中に入った ソフトウェアのバージョンを脆弱性データベースと照合 して CVE を見つけます。一方 Kubesec と KubeLinter はイメージ自体ではなく YAML マニフェストの設定 を見ます。同じ nginx イメージでも Trivy はその中の CVE を見て、Kubesec はそれをどんな securityContext で動かすかを見ます。この 2 つは互いを置き換えるのではなく補完します。

Trivy: イメージ脆弱性スキャナー #

Trivy は Aqua Security が作ったオープンソースのスキャナーで、CKS 試験でイメージ脆弱性を扱う標準ツールです。速く、インストールが単純で、結果が読みやすいので試験環境によく合います。

何をスキャンするか #

Trivy は 1 つではなく複数の対象をスキャンします。試験では主に最初の image スキャンが出ますが、残りも一度ずつ見ておくとよいです。

サブコマンド対象用途
trivy imageコンテナイメージOS パッケージ・言語ライブラリの CVE
trivy filesystemローカルディレクトリ・ファイルソースツリーや抽出したルートファイルシステム
trivy repoGit リポジトリリモート・ローカルリポジトリの依存関係
trivy configIaC・マニフェストDockerfile・Kubernetes 設定の誤設定

基本のイメージスキャン #

最も基本的な形はイメージ名だけを渡すものです。

trivy image nginx:1.18

こうするとそのイメージに入ったすべてのパッケージの脆弱性を全部出力します。ところが LOW や UNKNOWN まで全部出ると結果が長すぎて、肝心な重要なものを見逃しやすくなります。そのため試験ではほぼ常に 深刻度を絞って 見ます。

trivy image --severity HIGH,CRITICAL nginx:1.18

--severity で HIGH と CRITICAL だけに絞れば、すぐに対処が必要な脆弱性だけが残ります。深刻度の値は UNKNOWNLOWMEDIUMHIGHCRITICAL の 5 段階です。

結果を読む #

Trivy の出力はイメージに入った ターゲット (例: OS パッケージ、言語ライブラリ) ごとに 表を分けて見せます。各行の核心となる列は次のとおりです。

意味
Library脆弱性のあるパッケージ名
VulnerabilityCVE 識別子 (例: CVE-2023-12345)
Severity深刻度の等級
Installed Version現在イメージにインストールされたバージョン
Fixed Version脆弱性が修正されたバージョン (空ならまだパッチなし)

ここで最も重要なのは Severity で危険を見積もり、Fixed Version で対処可能かを判断する ことです。Fixed Version があればそのバージョン以上にパッケージやベースイメージを上げればよく、空ならまだパッチがない脆弱性なので別の緩和策が必要です。

出力形式と件数だけ数える #

デフォルトは人が読みやすい表 (table) ですが、自動化には JSON が便利です。試験で「脆弱性の件数」を求められたら形式を変えて数えるのが速いです。

# JSON で出力
trivy image --format json --output result.json nginx:1.18

# CRITICAL だけ絞って表で
trivy image --severity CRITICAL nginx:1.18

exit-code で CI ゲートを作る #

Trivy の真価は CI パイプラインで 脆弱性があればビルドを止める ところにあります。--exit-code を与えると、条件に合う脆弱性が見つかったときに Trivy が 0 でない終了コードを返します。

trivy image --exit-code 1 --severity HIGH,CRITICAL myapp:1.0

このコマンドは HIGH または CRITICAL の脆弱性が 1 つでもあれば終了コード 1 で終わります。CI でこの終了コードを検査すれば、脆弱なイメージがデプロイ段階へ進むのを自動的に防げます。--ignore-unfixed を一緒に与えると、まだパッチがない脆弱性はゲートから除外して、今すぐ直せるものだけにビルドを止めさせられます。

trivy image --exit-code 1 --ignore-unfixed --severity CRITICAL myapp:1.0

DB 更新とオフライン #

Trivy は最初に実行するとき脆弱性 DB をダウンロードします。試験環境ではネットワークが制限されることがあるので、DB がすでにダウンロードされているかを確認する感覚が必要です。--skip-db-update で更新をスキップすれば、ダウンロード済みの DB だけでスキャンします。

Kubesec: マニフェストのセキュリティスコア #

Kubesec はイメージではなく Kubernetes マニフェストのセキュリティ設定をスコアで評価する ツールです。マニフェストを入れるとスコアとともに、スコアを下げた危険項目とスコアを上げる推奨項目を教えてくれます。

kubesec scan pod.yaml

出力は JSON で、核心は次のとおりです。

  • score。マニフェストのセキュリティスコア。高いほど安全
  • scoring.advise。スコアを上げるなら足すとよい設定 (推奨)
  • scoring.passed。すでにうまく適用された設定
  • scoring.critical。すぐに直すべき危険な設定

Kubesec がスコアをつける基準はほとんどが securityContext の強化項目 です。例えば次のような設定がスコアを上げます。

設定効果
runAsNonRoot: trueroot で実行しない
readOnlyRootFilesystem: trueルートファイルシステムを読み取り専用に
capabilities.drop: ["ALL"]すべての Linux capability を削除
allowPrivilegeEscalation: false権限昇格を遮断
privileged: true (減点)特権コンテナは大きな減点

つまり Kubesec の推奨に従っていくと、#9 Pod Security Admission で見た securityContext 強化と同じ方向にマニフェストが固くなります。Trivy が「イメージの中に何が危険か」を見るなら、Kubesec は「このワークロードをどれだけ安全に動かすか」を見ます。

KubeLinter: マニフェストの静的解析 #

KubeLinter は StackRox が作ったツールで、マニフェストと Helm チャートを 静的解析 してセキュリティ・運用のアンチパターンを捕まえます。Kubesec がスコアをつけるなら、KubeLinter はリンターらしく ルール違反をリストで 見せます。

kube-linter lint deployment.yaml

デフォルトのルールには次のような項目が含まれます。

  • コンテナが root で実行されるか
  • readOnlyRootFilesystem が設定されていないか
  • resource requests・limits が抜けているか
  • latest タグを使っているか
  • 危険な capability を持っているか

KubeLinter は CI に付けてマニフェストがマージされる前にアンチパターンを取り除く用途によく合います。違反があれば終了コードが 0 でないので、Trivy の exit-code と同じやり方でゲートを作れます。

3 つのツールの役割の違い #

この記事で扱った 3 つのツールを 1 つの表に整理すると、試験で作業のキーワードだけを見てどのツールを取り出すかをすぐ判断できます。

ツール検査対象見つけるもの出力形態ゲート
TrivyコンテナイメージOS・ライブラリの CVE脆弱性の表/JSON--exit-code
KubesecマニフェストsecurityContext 強化の程度セキュリティスコアスコアしきい値
KubeLinterマニフェスト・Helmセキュリティ・運用のアンチパターン違反リスト終了コード

核心となる区別は Trivy はイメージ CVE、残りの 2 つはマニフェストの設定 です。作業の問題文に「CVE」「脆弱性」「深刻度」「イメージスキャン」が出れば Trivy で、「securityContext」「セキュリティスコア」「マニフェスト検査」が出れば Kubesec か KubeLinter です。

試験の定番作業 #

1) 特定の深刻度の脆弱性を持つイメージを見つける #

複数のイメージが与えられ、そのうち CRITICAL 脆弱性があるイメージ を選び出せという型がよく出ます。各イメージを深刻度を絞ってスキャンすればよいです。

trivy image --severity CRITICAL nginx:1.18
trivy image --severity CRITICAL nginx:1.27

CRITICAL が出るイメージが危険なイメージです。「脆弱性が最も少ないイメージを選べ」という変形もあるので、結果の件数を比較する感覚が必要です。

2) 脆弱なイメージを安全なバージョンに差し替える #

危険なイメージを見つけたら、そのイメージを使う Deployment を CVE がないか、より少ないバージョンに変える のが次の作業です。

# 候補バージョンをスキャンして安全なものを確認
trivy image --severity HIGH,CRITICAL nginx:1.27

# マニフェストのイメージタグを安全なバージョンに差し替えて適用
kubectl set image deployment/web nginx=nginx:1.27

差し替えた後は新しいイメージをもう一度スキャンして、意図したとおり深刻度の高い脆弱性が消えたかを確認するとよいです。

3) マニフェストをスコアで点検する #

マニフェストが与えられてセキュリティスコアを確認したり、推奨項目を適用してスコアを上げよという型もあります。

kubesec scan pod.yaml

scoring.advise に出た項目 (runAsNonRootreadOnlyRootFilesystem など) を securityContext に足すとスコアが上がります。

試験ポイント #

  • Trivy はイメージ CVE スキャナー です。trivy image --severity HIGH,CRITICAL <イメージ> が基本形で、--severity で深刻度を絞ることが試験のほぼすべての作業に使われます。
  • 結果は Severity と Fixed Version で 読みます。Fixed Version があればそのバージョン以上に上げて対処し、空ならまだパッチがない脆弱性です。
  • --exit-code 1 で CI ゲート を作ります。指定した深刻度の脆弱性があれば 0 でない終了コードで終わり、脆弱なイメージのデプロイを防ぎます。--ignore-unfixed でパッチのない脆弱性は除外できます。
  • Kubesec はマニフェストのセキュリティスコア です。kubesec scan が securityContext 強化の程度をスコアでつけ、scoring.advise が推奨を与えます。
  • KubeLinter はマニフェストの静的解析 です。kube-linter lint が root 実行・読み取り専用の未設定・latest タグのようなアンチパターンを違反リストで見せます。
  • 検査対象でツールを区別 します。CVE・脆弱性なら Trivy、securityContext・マニフェスト設定なら Kubesec か KubeLinter です。

まとめ #

この記事で押さえたこと:

  • イメージスキャンは 2 種類 です。Trivy はイメージの内容の CVE を、Kubesec・KubeLinter はマニフェストの設定を見ます。
  • Trivyimagefilesystemrepoconfig をスキャンし、--severity で深刻度を絞り --exit-code で CI ゲートを作ります。
  • Kubesec はマニフェストの securityContext 強化の程度をスコアで評価し推奨を与えます。
  • KubeLinter はマニフェストと Helm チャートを静的解析してアンチパターンを違反リストで捕まえます。
  • 試験の定番は 特定の深刻度の脆弱性を持つイメージを見つけ、安全なバージョンに差し替える 作業です。

#13 Minimal images でイメージを減らし、この記事でそのイメージの脆弱性を見つけました。ここで残った問いは そのイメージが本当に自分が作ったものなのか、そして その中に何が入っているのかをどう証明するか です。

次へ — イメージ署名 #

イメージをスキャンして脆弱性を取り除いたとしても、誰かが途中でイメージをすり替えればスキャンは無意味になります。次の記事ではイメージの出所と完全性を証明する仕組みを扱います。

#15 イメージ署名: cosign、SBOM では cosign でイメージに署名し admission 段階で署名を検証して署名されていないイメージのデプロイを防ぐ方法、そしてイメージに入ったすべての構成要素のリストである SBOM (Software Bill of Materials) を生成・活用する方法まで直接作ってみながら整理します。

X