
はじめに
こんにちは、エンジニアのoruiと申します。 普段は大手飲食チェーンに向けたプロダクトの開発/運用に携わっています。
近況として、5/14(木) ~ 15(金) に、クラウドネイティブ会議に参加しました。
そこで、Docker社のTadashi Nemotoさんのセッション「脆弱性を削減し、安全なコンテナイメージを作るための新しいアプローチ:Hardened Container Images」を聞き、脆弱性を最小化したコンテナイメージについて学びがあったので共有します。
セッションの概要
多数のOSSの依存関係を含むコンテナイメージはサプライチェーン攻撃の標的になりやすい一方、多くの依存関係故に脆弱性の解消が困難であるという問題があります。
それを解決する方法の一つに、依存関係、脆弱性を最小化したコンテナイメージを使用することがあります。その一例として、Docker社の提供するDocker Hardened Images を紹介されていました。
私も、Dockerのベースイメージに含まれる脆弱性が検知されて対応に頭を悩ませた経験があるため、かなり興味深いセッションでした。
Docker Hardened Imagesとは
Docker Hardened Imagesとは、Docker社が提供する、セキュリティが強化されたDockerイメージです。CVEを常時監視し、24時間以内に脆弱性に対してパッチ適用済みのバージョンをリリースしています (参考)。
使ってみた
通常のDockerイメージ
検証用に以下のDockerfileを使用します。
FROM ruby:4
RUN apt-get update -qq && apt-get install -y \
build-essential \
libpq-dev \
nodejs && \
gem install bundler
WORKDIR /app
COPY Gemfile Gemfile.lock /app/
RUN bundle install
COPY . /app
CMD ["rails", "server", "-b", "0.0.0.0"]
docker scout cves で、ビルドしたDockerfileの脆弱性を確認してみます。
- Critical: 4
- High: 28
- Medium: 26
- Low: 175
- Unspecified: 22
かなり検知されています。
Docker Hardened Images
Docker Hardened Imagesには、開発用イメージ、実行時イメージ、FIPS対応版があります (参考)。
- 開発用イメージ: 開発に必要なパッケージがあらかじめ含まれています。
- 実行時イメージ: 開発に必要なパッケージはなく、実行時に必要な最小のパッケージが含まれています。
- FIPS対応版: 米国連邦情報処理標準 (FIPS-140) の認定を受けた暗号化モジュールを使用できます、より厳格なセキュリティ要件を満たしています。
上記のうち、開発用イメージ、実行時イメージが無料で使用できたので、今回はこちらを試しに使ってみます。
開発用イメージ
基本はベースイメージを開発用イメージに変更すれば使用できます。
イメージの検索は簡単で、こちらから探すことができます。
ベースイメージに含まれるパッケージに変更があるので、必要に応じてパッケージを追加します。
# ベースイメージを開発用イメージに変更
FROM dhi.io/ruby:4-debian13-dev
# 必要なパッケージを追加
RUN apt-get update -qq && apt-get install -y \
build-essential \
default-libmysqlclient-dev \
libpq-dev \
nodejs && \
gem install bundler
WORKDIR /app
COPY Gemfile Gemfile.lock /app/
RUN bundle install
COPY . /app
CMD ["rails", "server", "-b", "0.0.0.0"]
docker scout cves で、ビルドしたDockerfileの脆弱性を確認してみます。
- Critical: 0
- High: 6
- Medium: 5
- Low: 99
- Unspecified: 5
半分以下に減っています。
実行時イメージ
開発用イメージと同様に、ベースイメージを変更してbuildをしたところ、以下のエラーが出ました。
ERROR: failed to build: failed to solve: process "/bin/sh -c apt-get update -qq && apt-get install -y build-essential default-libmysqlclient-dev libpq-dev nodejs && gem install bundler" did not complete successfully: exit code: 1
実行時イメージにはシェルが含まれておらず、パッケージのインストールで失敗したためです。
そこで、Dockerfileをマルチステージビルドに書き直し、ビルド用ステージでは開発用イメージを使用してパッケージのインストールを行い、実行時用ステージで実行時イメージを使用しました。
# ビルド用ステージ
FROM dhi.io/ruby:4-debian13-dev AS builder
RUN apt-get update -qq && apt-get install -y \
build-essential \
default-libmysqlclient-dev \
libpq-dev \
nodejs && \
gem install bundler
WORKDIR /app
COPY Gemfile Gemfile.lock /app/
RUN bundle install
COPY . /app
# 実行時用ステージ
FROM dhi.io/ruby:4
COPY --from=builder /usr/local/bundle /usr/local/bundle
COPY --from=builder /app /app
CMD ["rails", "server", "-b", "0.0.0.0"]
docker scout cves で、ビルドしたDockerfileの脆弱性を確認してみます。
- Critical: 0
- High: 0
- Medium: 0
- Low: 8
- Unspecified: 2
かなり減りました。上記で検知された脆弱性もFixed versionが出ていないもののみでした。
感想
Docker Hardened Imagesを使用してみた感想として、導入が簡単で、手軽にセキュリティを強化できる印象を感じました。
今後はチームで運用しているプロダクトにも導入していきたいです。