2025年11月、Kubernetes上でオープンソースのLLM観測可能性プラットフォームであるLangfuseをセルフホストするチームが、本番準備の一環としてClickHouseイメージをAWS ECRにアップロードしました。パイプラインスキャナーが3つの重大な脆弱性を検出したことが判明しました。それはClickHouseではなく、ベース画像の中でした。彼らのセキュリティチームはその調査結果を確認し、本番環境に入る前に展開を阻止しました。
「我々のセキュリティチームが本番環境に持ち込むことを許可していない。代替案を提案してください。」
ヴィナイゴエル586
GitHub Issue #286、2025年 11 月 28日
もし最近エンタープライズ環境にコンテナを出荷したことがあるなら、この状況は見覚えがあるでしょう。完璧に機能するデプロイがブロックされるのは、何かが壊れているからではなく、スキャナーがアプリケーションが全く触れないパッケージにCVEを見つけたからです。調査に1日かかり、リスク例外が報告されますが、セキュリティチームはそれを却下します。なぜなら、脆弱性は技術的には実在するものであり、実際にはあなたの業務負荷には関係がなくてもです。
この投稿は、セキュリティチームがCVEを持つコンテナのデプロイをブロックした際に、Docker Hardened Images(DHI)がどのようにしてあなたを困りから解放するかについてです。今回は特にClickHouseの画像を見ます。ClickHouseはDocker Hubで最も広く取得されているデータベースイメージの一つです。
ClickHouseについて一言
ClickHouse は、大規模な分析ワークロード向けに構築されたオープンソースのカラム型データベースです。数十億行をクエリし、ミリ秒単位で結果を返すことが可能で、従来の行指向データベースでは全く及ばない。Cloudflare、Uber、Spotifyなどの企業が本格稼働で運用しています。Docker Hubからの 100 百万件以上のプルが行われ、本格的な分析スループットを必要とするチームのデフォルトのインフラ選択となっています。しかし、画像のデフォルトのセキュリティ体制は、エンタープライズ本番環境が求めるハード化ではなく、開発者の使いやすさを重視して設計されており、そのギャップこそが問題の始まりです。
図:ClickHouseの層状アーキテクチャ
ClickHouseの構成方法
ClickHouseは多層的なアーキテクチャを採用しています。大規模に分析速度を追求するために設計されています。SQLクエリはHTTP(ポート 8123)またはTCP(ポート 9000)経由で届き、オプティマイザーを通過し、抽象構文木に解析されてプルーニングされます。パイプラインエキューターが処理を受けて並列スレッドに処理を渡します。クエリ層の下にはMergeTreeストレージエンジンがあり、ClickHouseの中心であり、カラム形式でデータを保存します .binファイル。スパースプライマリインデックスを使って、カラム全体を読み込まずに無関係な粒をスキップし、バックグラウンドマージ処理を実行して部分を圧縮し、クエリ性能を時間経過にわたって維持します。
最下位にはストレージがプラグイン可能で、ローカルディスク、S3、HDFS、Azure Blobなどがあり、コストとレイテンシのバランスを取るために階層的なホット/ウォーム/コールドポリシーが用意されています。分散型デプロイでは、ClickHouse Keeper(またはZooKeeper)がレプリカ間でのレプリケーションを調整し、シャーディングはデータをノード間で水平に分割し、クラスタが独立して読み書きをスケールできるようにします。その結果、サーバーあたり毎秒数億行を処理するデータベースが生まれ、本格的な分析ワークロードを運用するチームにとってデフォルトの選択肢となっています。
本当の問題は、ClickHouseではなくパッケージです
標準 clickhouse/clickhouse-server イメージは完全なUbuntu 2204 ベース上に構築されています。ベースには、Perlやシステムユーティリティ、apt自体、そしてUbuntuが古いパッケージを持ち込んだために存在する多数の遷移依存関係など、ClickHouseには不要な多くのものが搭載されています。多くの場合、Ubuntuのメンテナは上流からの修正をバックポートしないことを決定しています。
ClickHouseはほとんどのシステムユーティリティを使いません。しかし、それらのパッケージに含まれる CVE は実在します。それらはTrivyやGrype、AWS ECRでは、一度も読み込まれていない脆弱なライブラリと、本番環境で稼働しているライブラリを区別する方法がありません。セキュリティチームは重要な発見を察知し、展開を阻止します。これはスキャナーの指示を踏まえる正しい対応です。
この時点で本能的に主張し、なぜ各CVEがワークロードに適用されないのかを文書化し、リスク例外を書き、エスカレーションするのが本能ですが、それは遅いプロセスです。唯一の解決策は、不要なパッケージを完全に取り除くことです。それがDockerのHardened Imagesの役割です。
DHIが実際に変えること
ClickHouse用のDocker Hardened Imagesは、単純明快な問いを中心に構築されています:データベースは実際に何を動かす必要があるのか?完全なUbuntuベースから始めてCVE数を管理可能にするのではなく、DHIはClickHouseが必要とするものだけを出荷し、それ以外は除外しています。
その最も直接的な結果は、ランタイムでの apt の欠如です。パッケージマネージャーがなければ、コンテナに足場を得た攻撃者はツールをインストールしたり永続性を確立したりする明確な経路を持ちません。curlやwgetのようなネットワークユーティリティも同じ理由で消えています。標準clickhouse/clickhouse-serverイメージは、2021年からwgetを搭載しており、CVE-2021-31879はパッチが適用されていません。これはUbuntuのメンテナが指摘したように、上流の修正がないためです。これはClickHouseが最初から必要としなかったツールの脆弱性です。DHIはパッチを適用しません。単純に wget は含まれていません。運用作業にはシェルもまだ利用可能ですが、パッケージマネージャーやネットワークツールがなければ、攻撃者が実際にできることはほとんどありません。
パイプラインの異なる段階で実用的にするために、DHIは2つのバリアントを出荷しています。開発イメージ(dev)には、ローカルテストやデバッグをより快適にするための追加ツールが含まれています。本番イメージ(ランタイム)はそれを最小限に削ぎ落とし、実際に世界に直面するワークロードに対して可能な限り最小の攻撃対象となります。意図は、チームが開発バリアントをパイプラインの早い段階で採用し、強化された本番イメージを展開まで推進させることであり、最も重要な段階で違いを発見するのではなく、
また、このイメージは uid=65532 出してから非rootユーザーとして動作し、追加のDockerfile設定は不要です。出所面では、すべてのDHI画像にはSLSAレベル 3 認証が付属しており、ビルドに何が入り、どのように作成されたかを暗号学的に証明します。Dockerのセキュリティチームは積極的にCVEを追跡・パッチ適用しており、DHIの調査結果に 2026 CVE IDが存在することは、公開フィードに対してではなく、公開フィードよりも先に修復が行われていることの証拠です。
始める
DHIイメージを取得する前に、まずそれを組織の名前空間にDocker Hubでミラーリングする必要があります。これはタグごとにではなく画像ごとに一度きりの設定で、今後のすべての更新が自動的に名前空間に流れます。
- Docker HubにログインしてDHIカタログを開きます
clickhouse-serverを見つけて「リポジトリにミラー」を選択します- 画面上の指示に従ってください
- ローカル認証:
docker login dhi.io
それが終われば、同じ画像、同じタグ、同じClickHouseで自分の名前空間から取得できますが、強化されただけです。
あなたの初めてのDHI ClickHouseコンテナ
docker run --name my-clickhouse-server -d \
--ulimit nofile=262144:262144 \
dhi.io/clickhouse-server:26.2-debian13
--ulimit nofile=262144:262144フラグはDHIではなくClickHouseの要件です。ClickHouseは正しく動作するために高いファイルディスクリプタ制限が必要です。すべてのランコマンドに必ず残してください。
起動を確認しましょう:
docker exec my-clickhouse-server clickhouse-client \
--query "SELECT 'Hello from DHI ClickHouse!'"
永続的ストレージを用いた本番環境
ローカルテスト以外の場合は、ボリュームとパスワードが必要です:
docker run -d \
--name my-clickhouse-server \
--ulimit nofile=262144:262144 \
-e CLICKHOUSE_PASSWORD=mysecretpassword \
-v clickhouse-data:/var/lib/clickhouse \
-v clickhouse-logs:/var/log/clickhouse-server \
-p 8123:8123 -p 9000:9000 \
dhi.io/clickhouse-server:26.2-debian13
ネットワーク経由でClickHouseにアクセスしたい場合は、 CLICKHOUSE_PASSWORD が必要です。DHIは認証されていないネットワークアクセスをデフォルトで無効化しており、これは本番環境での適切な対応です。
HTTP経由でテストしてください:
curl "http://localhost:8123/?query=SELECT%20version()&user=default&password=mysecretpassword"
カスタム構成
すでにカスタムXML設定でClickHouseを使っているなら、何も変わりません。同じフォーマット、同じマウント経路:
cat > custom-config.xml << EOF
<clickhouse>
<logger>
<level>information</level>
<console>true</console>
</logger>
<listen_host>0.0.0.0</listen_host>
</clickhouse>
EOF
docker run -d \
--name my-clickhouse-server \
--ulimit nofile=262144:262144 \
-v $(pwd)/custom-config.xml:/etc/clickhouse-server/config.d/custom.xml:ro \
-p 8123:8123 -p 9000:9000 \
dhi.io/clickhouse-server:26.2-debian13
Kubernetes上でDHI ClickHouseを動かす方法
Kubernetesに関しては、ポッド仕様に重要な追加要素があります。DHIはrootユーザーでないため、永続的なボリュームデータにアクセスできるように fsGroup を設定する必要があります:
spec:
template:
spec:
securityContext:
runAsNonRoot: true
runAsUser: 65532 # DHI nonroot user
fsGroup: 65532 # makes mounted volumes accessible to the nonroot user
containers:
- name: clickhouse-server
image: dhi.io/clickhouse-server:26.2-debian13
ports:
- containerPort: 8123
- containerPort: 9000
volumeMounts:
- name: clickhouse-data
mountPath: /var/lib/clickhouse
- name: clickhouse-logs
mountPath: /var/log/clickhouse-server
resources:
limits:
cpu: "2"
memory: "4Gi"
一つ付け加えておくべき点は、ClickHouseのデフォルトのポート 8123 と 9000 が 1024 特権ポート境界より上にあるため、非rootで実行してもポートバインディングの問題は起きません。
メトリクスの輸出者
もしKubernetes上でClickHouseを実行し、Prometheusの指標が必要なら、Dockerは clickhouse-metrics-exporter も提供しています。これはClickHouse Operatorと連携して /metrics エンドポイントを公開するハード化されたイメージです。標準の輸出機より 65%小さいです(10。3MBと 29。4MB)で、層数が 75%少ない(5 と 20)です。同じデータですが、表面は劇的に小さくなりました。
containers:
- name: metrics-exporter
image: dhi.io/clickhouse-metrics-exporter:0-debian13
ports:
- name: metrics
containerPort: 8888
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 50m
memory: 64Mi
通常のツールを使わずにデバッグする
デバッグの話は見た目よりも単純です。docker debug Bash、Curl、Strace、Vimなど必要なものを含む一時的なレイヤーをランニングコンテナに付与し、制作画像自体を変更せずに対応できます。退出するとレイヤーは消え、コンテナは元のままになります。これは本番コンテナに直接シェルを送るよりもクリーンなアプローチであり、実際には単一のコマンドで実行されます:
docker debug my-clickhouse-server
または、コンテナと一緒にデバッグイメージをマウントすることもできます:
docker run --rm -it --pid container:my-clickhouse-server \
--mount=type=image,source=<your-namespace>/dhi-busybox,destination=/dbg,ro \
dhi.io/clickhouse-server:26.2-debian13 /dbg/bin/sh
CVEの数を超えた、より広範なセキュリティ上の利点もあります。もし本番環境で何か問題が起きた場合、コンテナに侵入した攻撃者はツールをインストールするパッケージマネージャーも、データを漏洩させるためのcurlやwgetも見つからず、ネットワークに連絡する明確な経路も見つからず、侵害が実際に何に及ぶかを大幅に制限します。
ClickHouse:非硬化画像と硬化画像の比較
両方の画像をDocker Scout でスキャンすると、その差は単純な数値で分かります。ubuntu:22.04を基盤にした標準イメージは、8111パッケージにまたがって中程度から11低重大度の脆弱性を含みます。これには、企業パイプラインでセキュリティブロックを引き起こす可能性が最も高いwgetやtarの発見も含まれています。DHIイメージは中程度の重大度の検出を完全に排除し、低重度項目 14 表示しますが、これらはModel glibc や openssl のようなコアシステムライブラリにあり、いかなるディストリビューションにも修正がなく、イメージに存在しない不要なユーティリティには含まれていません。3、Scoutの表面はすでに評価され、VEX認証によって抑制されており、その画像はSLSAレベル3出所の一部として出荷されています
他のイメージのバージョンの違いを見るには、Docker Scoutで自分でスキャンを行い、次のコマンドを使って素早く比較できます:
docker scout quickview clickhouse/clickhouse-server:latest
docker pull dhi.io/clickhouse-server:26.2-debian13
docker tag dhi.io/clickhouse-server:26.2-debian13 clickhouse-dhi:latest
docker scout quickview clickhouse-dhi:latest
|
非硬化ClickHouse画像 |
Docker Hardened Image(Docker Hardened Image) |
|
|---|---|---|
|
デフォルトユーザー |
root(エントリポイント経由で実行時にclickhouse userにステップダウンしますが、DockerfileにはCLICKHOUSE_RUN_AS_ROOT=1でオーバーライド可能なUSER指令はありません) |
非root(イメージレベルでUSER指令によって強制されるものは実行時にオーバーライドできません) |
|
シェルアクセス |
フルシェル(bash/sh)が利用可能です |
bashは存在しますが、ネットワークツールやパッケージマネージャーはありません |
|
パッケージマネージャー |
アパートが利用可能です |
パッケージマネージャーはありません |
|
CVEへの露出 |
船はwget(CVE-2021-31879、 2021年以降パッチ未修正)、tar(CVE-2025-45582) |
wgetもタールもなし――不要な荷物は完全に取り除かれます |
|
CVEパッチ適用 |
2021の未修正の発見 –2025、Ubuntuのベースイメージからの上流修正がないためです。 |
積極的に追跡されている 2026 、CVE IDは積極的な修復を示します |
|
出自 |
標準 |
SLSAレベル 3 認証 |
|
コンプライアンス |
手動硬化が必要です |
CIS、NIST、FedRAMPに連動 |
|
デバッグ |
従来のシェルデバッグ |
トラブルシューティングにはdockerデバッグかイメージマウントを使いましょう |
セキュリティチームの対話
2025年11月にAWS ECRでブロックされたチームはClickHouseの問題ではなく、ベースイメージの問題でした。彼らのデータベースは問題なかった。スキャナーが検出したのは、PerlのCVE、システムユーティリティ、そしてDebianベースに導入されていたがアプリケーションでは使われなかった他のパッケージでした。スキャナーの出力にはその区別がなかったため、セキュリティチームはまさにやるべきことをして展開を阻止しました。
DHIを使えば、セキュリティチームとの会話がずっとスムーズになります。特定の CVE がワークロードに適用されない理由を説明する代わりに、Dockerのセキュリティチームが最低限必要なコンポーネントから構築し、SLSAレベルの 3 プロヴィナンスとSRLabsによる独立した検証を持つイメージを挙げることができます。ClickHouseのランタイム自体は変わっていません~クエリ、ポート、設定ファイル、パフォーマンスはすべて引き継がれるので、実際に変えているのはこのイメージが本番環境に送れるかどうかを尋ねられたときに返せる答えだけです。より強力な保証が必要なチーム向けに、DHI EnterpriseはSLA支援による7日以内のCVE修復、FIPSおよびSTIGのバリアント、そして延長されたライフサイクルサポートを追加します。ほとんどのチームにとって、 無料のエンタープライズトライアル は適切な出発点です。何かにコミットする前に本当に重要な問いに答えてくれます。もっと知りたいですか?まずはこのブログから始めましょう。試練を 辿り、 成功への準備を整えてくれます。
移住チェックリスト
☐ Mirror clickhouse-server DHI image to your Docker Hub namespace (one-time setup)
☐ Update your image reference to dhi.io/clickhouse-server:26.2-debian13
☐ Set CLICKHOUSE_PASSWORD (required for network access in DHI)
☐ Keep --ulimit nofile=262144:262144 on all run commands
☐ In Kubernetes: add fsGroup: 65532 to your pod securityContext
☐ Switch from kubectl exec to kubectl debug for troubleshooting
☐ Run trivy against both images to see the difference yourself:
trivy image clickhouse/clickhouse-server:latest
trivy image dhi.io/clickhouse-server:26.2-debian13
移行範囲は見た目より狭く、ボリュームマウント、ポートマッピング、既存のXML設定ファイルはすべて変更なしで引き継がれ、KubernetesではfsGroupセキュリティコンテキストのみが構造化されています。それ以外はすべてイメージの参照変更です。