【入門編】 Dockerイメージの脆弱性スキャンとベースイメージの選定基準 – オフェンシブセキュリティ & リバースエンジニアリング防御ガイド

こんにちは!システム開発やインフラの管理、毎日本当にお疲れ様です。

「Dockerを使ってアプリを動かそう!」となったとき、便利な反面、こんな不安を感じたことはありませんか?
「ネットで見つけた便利なベースイメージ、中身は本当に安全なのだろうか……」
「脆弱性スキャンツールで赤色(重大な警告)がたくさん出て、どこから手をつければいいか分からない!」

今回は、初めてセキュリティに触れる開発者の方や、新米IT担当者の方に向けて、コンテナのセキュリティの仕組みを身近な「おうちの防犯」に例えながら、一緒に優しく紐解いていきたいと思います。一歩ずつ、確実に安全な環境を作れるようになりましょう!

—

1. なぜDockerイメージの「中身」まで気にしなきゃいけないの?

皆さんは、自分の家を建てるときや引っ越したとき、鍵をちゃんと選びますよね。でも、もし「誰が作ったか分からない頑丈そうなドア」を丸ごともらってきて、家の入口にポンと取り付けたらどうでしょう?

  • ドアノブの内側に、知らない合鍵が隠されているかもしれない
  • 蝶番(ちょうつがい)がボロボロで、ちょっと押したら外れてしまうかもしれない

Dockerイメージもこれと全く同じです。私たちが普段「ベースイメージ」として何気なく使っている ubuntu や debian などの公式イメージには、OSを動かすための便利なツールやパッケージ(ファイルの解凍ソフトやネットワーク診断ツールなど)が最初からたくさん入っています。

しかし、この「便利さ」の裏側で、使ってもいない古いツールに「既知の脆弱性(セキュリティの穴)」が含まれていることがよくあります。泥棒(攻撃者)は、私たちが使ってもいないその古いツールの隙を突いて、コンテナの中に侵入してくるのです。

—

2. 脆弱性スキャンって何をするもの?

「じゃあ、うちのドアや窓に隙間がないか、どうやって調べればいいの?」という疑問が湧きますよね。ここで登場するのが脆弱性スキャンツールです。

イメージとしては、「おうちのセキュリティ診断士さんが、合鍵の持ち主や鍵の壊れやすさを一軒一軒チェックして回る」ようなものです。

例えば、代表的なスキャンツールである Trivy(トリビー) というツールを使うと、Dockerイメージの中にどんな古いライブラリが入っていて、どれが危険なのかを一瞬で暴き出してくれます。

実際に、ターミナルでスキャンを実行するコマンドを見てみましょう。

# 自分の作ったDockerイメージ(例: my-app:latest)に脆弱性がないかスキャンする
trivy image my-app:latest

このコマンドを実行すると、以下のような結果が表示されます。

==================================================================
Trivy Scan Results
==================================================================
Target: my-app:latest (debian 11.6)

Library: openssl
Vulnerability: CVE-2023-XXXX (HIGH) -> 対策済みバージョン: 1.1.1n-0+deb11u4
Description: OpenSSLに悪意ある第三者が暗号を解読できる脆弱性が発見されています...

「おっと、openssl という通信を守るための大事な部品に、古い穴が見つかっていますよ!」とスキャンツールが教えてくれました。このように、目に見えないコンテナの中身をレントゲン写真のように透視して、危険な部品を見つけるのが脆弱性スキャンの役割です。

—

3. 攻撃対象領域を極限まで減らす「Distroless(ディストレス)」という考え方

脆弱性スキャンで「直せ」と言われた部品を一つひとつアップデートするのも大切ですが、そもそも「最初から使わないものは、家の中に置かない」というのが、最も強力でスマートな防犯対策です。

ここで登場するのが、Googleが開発した「Distroless(ディストレス)」という特別なベースイメージです。

Distrolessってなに?

一言でいうと、「OSのパッケージ管理ツール(aptやyum)や、シェル(bashやsh)、テキストエディタなどを一切削ぎ落とした、アプリケーションを動かすための最低限の部品だけが入ったイメージ」です。

「えっ、bash すらないの? コンテナに入って中身を確認できないなんて不便じゃない?」と思われるかもしれません。まさにその通りです。開発中は少し不便ですが、「攻撃者にとっても、侵入した後に暴れるための道具(シェルやコマンド)が一切ない」という最強の状況を作り出せます。

家に例えるなら、「ドアも窓もなくて、郵便受けの隙間すらない金庫のような部屋」です。泥棒が入る隙間そのものがありません。

—

4. 実践!Distrolessを使った安全なDockerfileの書き方

それでは実際に、Go言語で書かれたアプリケーションを例に、普通のイメージからDistrolessイメージへ乗り換える手順を見てみましょう。ここでは、ビルド用と実行用を分ける「マルチステージビルド」という技術を使います。

以下の Dockerfile を見てください。

# ==========================================
# ステージ1: アプリケーションのビルド(重たい道具箱を使う場所)
# ==========================================
# ここでは開発やビルドに必要なツールが揃っている普通のイメージを使います
FROM golang:1.21 AS builder

# 作業ディレクトリを作る
WORKDIR /app

# ソースコードをコンテナの中にコピーする
COPY . .

# アプリケーションをコンパイルして一つの実行ファイル(main)にする
RUN CGO_ENABLED=0 GOOS=linux go build -o main .

# ==========================================
# ステージ2: 実行環境(攻撃対象を極限まで減らしたDistroless)
# ==========================================
# ここがポイント!余計なものが一切入っていないGoogle製の安全なイメージを採用します
FROM gcr.io/distroless/static-debian12

WORKDIR /app

# ステージ1で作った「実行ファイルだけ」を、安全な部屋にポツンと持ち込む
COPY --from=builder /app/main .

# コンテナが起動したときに実行するコマンドを指定する
ENTRYPOINT ["/main"]

この設定の嬉しいポイント

1. 無駄なものが一切ない: apt-get や bash すら入っていないため、万が一アプリに別のバグがあっても、攻撃者がOSのコマンドを使ってサーバーを乗っ取る(リモートコード実行など)のが非常に難しくなります。
2. スキャンの結果がピカピカに: Trivyなどの脆弱性スキャンツールでこのイメージをスキャンすると、検知される脆弱性の数が「ゼロ」または極めて少ない状態を維持しやすくなります。

—

まとめ:今日からできる一歩

コンテナのセキュリティと聞くと難しそうに感じるかもしれませんが、基本の考え方はとてもシンプルです。

  • 「自分のアプリが本当に必要としているものは何か?」を見極める
  • 使っていない古いツールやOSの機能は、そもそもコンテナに入れない(Distrolessの活用)
  • 定期的にスキャンツールを使って、健康診断(脆弱性チェック)を行う

まずは、今お使いの Dockerfile の FROM 行を見直すところから始めてみませんか?
一歩ずつ、安全で強いシステムを作っていきましょう!応援しています!

コメント

タイトルとURLをコピーしました