午前2時の悪夢:セキュリティ監査がやってきた時
午前2時、セキュリティチームから緊急のメールが届きました:「本番環境のイメージに50件以上の深刻な脆弱性(CVE)が見つかりました。至急修正してください。」眠気は一瞬で吹き飛び、代わりに、安定稼働していたはずのシステムが攻撃対象になってしまったという焦りがこみ上げてきます。
その時、ようやく気づきました。buildしてpushするだけでは不十分だということに。機能開発に夢中になるあまり、イメージサイズの肥大化や、node:latestのようなベースイメージが多くの古いライブラリを抱え込んでいることを忘れてしまいがちです。脆弱性がどのレイヤーにあるのか(自分が書いたコードなのか、それとも2年前のベースイメージなのか)分からない時、強い無力感に襲われます。
数千行に及ぶJSON形式のスキャンレポートを受け取った際、私はよくToolcraft의 JSON Formatterを使って整形しています。階層構造(レイヤー)を明確にすることで、混沌としたテキストの中から推測するのではなく、エラーの根本原因を突き止めることができます。
なぜあなたのイメージはこれほど「脆弱性だらけ」なのか?
脆弱性(CVE – Common Vulnerabilities and Exposures)は、通常あなたのコードロジックから発生するものではありません。実際には、主に以下の3つの場所に潜んでいます:
- 古いベースイメージ: 更新されていない
ubuntu:20.04には、すでに公開されている何百ものセキュリティホールが含まれている可能性があります。 - 依存関係(ライブラリ): npm、pip、または
apt-getでインストールされたシステムライブラリは、ハッカーにとっての「入り口」になりがちです。 - 不要なツール: 本番イメージに
curl、git、vimなどを入れておくとデバッグには便利ですが、意図せずハッカーに攻撃用ツールセットをプレゼントすることにもなります。
Docker Scout – 標準統合された救世主
以前はSnykやTrivy、あるいはDocker Bench for Securityを使っていましたが、Docker ScoutはDocker DesktopやCLIに組み込まれているため、よりスムーズな体験を提供してくれます. 単にエラーを羅列するだけではありません。Scoutはコンサルタントのようにアドバイスしてくれます。「ねえ、タグを20-alpineに変えてみて。そうすれば脆弱性の90%は消えるよ」といった具合に。
ステップ1:イメージの「健康状態」をクイックチェック
例えば、my-app:v1というイメージがあるとします。クラウドにプッシュして結果を待つ代わりに、ローカルで次のコマンドを叩いてみましょう:
docker scout quickview my-app:v1
結果は、Critical(緊急)、High(重要)、Medium(中)の要約テーブルで表示されます。もしCriticalの数値が上がっていたら、それはシステムにとっての「赤信号」です。
ステップ2:各CVEの詳細を調査する
その脆弱性が具体的に何なのか(例:OpenSSLライブラリにおけるリモートコード実行の脆弱性など)を知るには、次のコマンドを使用します:
docker scout cves my-app:v1
このコマンドは、影響を受ける各パッケージやDocker Socketのセキュリティリスク、そして修正済みバージョンを詳細にリストアップします。リストが長すぎる場合は、JSONファイルに出力してToolcraftにアップロードし、優先度順にフィルタリングすると効率的です。
ステップ3:推奨事項に従って修正する(最も価値のある機能)
安全なタグを探すためにDocker Hubをあさり回る必要はありません。Docker Scoutには非常に賢いrecommendationsコマンドがあります:
docker scout recommendations my-app:v1
ベースイメージをマイナーアップデートに更新するか、あるいはDockerSlimで最適化を行い、リスクを最小限に抑えるためにAlpineのような最小限のディストリビューションに切り替えるよう、具体的に指示してくれます。
GitHub Actionsで「汚れた」イメージを阻止する
ローカルで修正するのは良いことですが、脆弱性だらけのイメージがサーバーに「こっそり」プッシュされないように、GitHub ActionsなどのCI/CDの入り口でブロックする必要があります。以下は、プルリクエストのたびに自動スキャンを実行するための設定例です。
name: Docker Scout Scan
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build-and-scan:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Build Docker image
run: docker build -t my-app:${{ github.sha }} .
- name: Docker Login
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Docker Scout Scan
uses: docker/scout-action@v1
with:
command: cves
image: my-app:${{ github.sha }}
ignore-unchanged: true
only-fixed: true
write-comment: true
github-token: ${{ secrets.GITHUB_TOKEN }}
このワークフローを使用すると、Docker Scoutは自動的にプルリクエストにレポートをコメントします。セキュリティ指標が要件を満たさない場合、パイプラインは即座にfailとなり、脆弱なイメージの本番デプロイを徹底的に防ぎます。
イメージを常にクリーンに保つための標準プロセス
何晩も徹夜して修正を繰り返した結果、Docker Scoutを扱う上での4つの黄金律にたどり着きました:
- マルチステージビルドを使用する: 最終ステージには実行ファイルのみを残します。コンパイラやソースコードを完全に排除し、攻撃対象領域を最小化します。
- 最小限のベースイメージを優先する: 常に
-slimや-alpineタグを選択しましょう。イメージが軽量でファイルが少ないほど、脆弱性も少なくなります。 - 定期的にスキャンする: 新しい脆弱性は毎日発見されます。今日のイメージがクリーンだからといって、来週も安全だとは限りません。稼働中のイメージに対して週次スキャンのスケジュールを設定しましょう。
- アップグレード前に比較する:
docker scout compareコマンドを使用して新旧バージョンを比較し、アップデートによって新たな脆弱性が持ち込まれていないか確認します。
セキュリティは一度やって終わりではありません。docker scout quickviewを毎日の習慣にしましょう。攻撃を受けてから慌てて修正するのではなく、今すぐ自分の成果物を主体的に守り始めましょう。

