
コンテナイメージ向けマルウェアスキャナー:デーモンレス、レイヤー対応、ClamAV と YARA
meles はコンテナイメージ向けのマルウェアスキャナです。イメージ参照に対してコマンド1つで実行でき、Docker デーモンは不要、CI フレンドリーな終了コードを備えています。Kubernetes では、ポッドが実行するすべてのイメージもスキャンし、必要に応じて新しいポッドのイメージがスキャンされるまでポッドを保留します。
meles は、イメージが実行される前にその内容を検査します。これは脆弱性スキャナや Falco のようなランタイム検出を補完するものであり、それらを置き換えるものではありません。
名前は Meles meles(ヨーロッパアナグマ)に由来します。レイヤーを掘り進むのです。
meles image <ref> はマルウェアを検出するとパイプラインを失敗させます。出力はテーブル、JSON、SARIF 形式に対応し、誤検知のための無視ルールも利用できます。MalwareReport を書き込みます。オプションで Prometheus アラートも利用できます。お使いのマシンで試してみてください(Linux amd64、Docker、bash):
curl -fsSL https://github.com/movray/meles/releases/download/v0.3.3/meles_0.3.3_linux_amd64.tar.gz | tar -xz meles
docker run -d --name clamd -p 127.0.0.1:3310:3310 clamav/clamav:1.4
export MELES_CLAMD=tcp://127.0.0.1:3310
until (exec 3<>/dev/tcp/127.0.0.1/3310 && printf 'zPING\0' >&3 && head -c4 <&3 | grep -q PONG) 2>/dev/null; do sleep 5; done
./meles selftest
./meles image alpine:3.20
またはクラスタ内(クラスタ管理者、デフォルトの StorageClass、ノード上に約 2 GB の空きメモリ):
kubectl create namespace meles
kubectl label namespace meles pod-security.kubernetes.io/enforce=baseline
helm install meles oci://ghcr.io/movray/charts/meles --version 0.3.3 -n meles --set operator.enabled=true
kubectl -n meles rollout status deploy/meles-clamd --timeout=15m
kubectl get malwarereports -A # every image running in your cluster
kubectl -n meles port-forward svc/meles-server 8080:80 # http://localhost:8080/
オペレーターは現在、すべての Pod のイメージをプルしてスキャンします。これはレジストリのプル制限にカウントされますが、レポートするだけで Pod には触れません。レポートは数分以内に表示されます。非常に大きなバイナリは Incomplete で終わることがあり、これは決してクリーンではありません:
結果の読み方を参照してください。
ポートフォワードは確認するための最も簡単な方法にすぎません。恒久的に使用する場合は、server.ingress または server.httpRoute で UI を公開し、server.oauth2Proxy でログインを前に置きます。これらはすべてチャートの values にあります:
Web UI のログイン。meles 自体にはログイン機能がないため、ログインなしで UI を公開しないでください。
後続のレイヤーによって隠されたファイルから Kubernetes のスキャンゲートまでのステップバイステップのツアー: docs/getting-started.md。
clamd によってソケットプロトコル経由で行われます。meles は libclamav にリンクせず、Apache-2.0 ライセンスのままです。デフォルトでは meles はレポートするだけで、何も削除しません。これはイメージ署名、SBOM、ランタイム検出の代替にはなりません。
各リリースには、Linux および macOS 用のバイナリ(amd64、arm64)、マルチアーキテクチャイメージ、Helm チャートが含まれています:
VERSION=0.3.3
# Binary
curl -fsSLO https://github.com/movray/meles/releases/download/v$VERSION/meles_${VERSION}_linux_amd64.tar.gz
tar -xzf meles_${VERSION}_linux_amd64.tar.gz meles
# Image (linux/amd64, linux/arm64; no shell, runs as non-root)
docker run --rm ghcr.io/movray/meles:$VERSION version
# Helm chart (see Kubernetes below)
helm install meles oci://ghcr.io/movray/charts/meles --version $VERSION -n meles -f my-values.yaml
# From source
go install github.com/movray/meles/cmd/meles@v$VERSION
バイナリ、イメージ、チャートは リリースワークフローによってビルドされ、 署名付きのビルド来歴が付与されます。イメージは公開前に meles と Trivy でスキャンされます。 GitHub CLI で来歴を確認してください:
gh attestation verify meles_${VERSION}_linux_amd64.tar.gz -R movray/meles
gh attestation verify oci://ghcr.io/movray/meles:$VERSION -R movray/meles
gh attestation verify oci://ghcr.io/movray/charts/meles:$VERSION -R movray/meles
イメージとチャートも cosign(キーレス)で署名されているため、Kyverno や Sigstore policy-controller などのアドミッションポリシーで検証できます。
署名は OCI リファラとして保存された Sigstore バンドルです。cosign 3 で検証してください(cosign 2 では --new-bundle-format が必要です):
cosign verify ghcr.io/movray/meles:$VERSION \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity-regexp '^https://github.com/movray/meles/\.github/workflows/release\.yml@refs/tags/v'
稼働中の clamd が必要です。apt install clamav-daemon を実行すると、meles はソケット(/run/clamav/clamd.ctl)を自動的に見つけます。clamav/clamav イメージも使用できます(TL;DR を参照。シグネチャの読み込みには1〜2分かかります)。
meles selftest # checks the whole chain with EICAR test images
# (--yara: also the default YARA rules, if loaded)
meles image alpine:3.20
meles image --format json --platform linux/amd64 ghcr.io/org/app:1.2
alpine:3.20 (d9e853e87e55)
engine: ClamAV 1.4.3, signatures 28159, scanned in 2.6s
PLATFORM LAYERS FILES FINDINGS SKIPPED
linux/amd64 1 87 0 0
linux/arm64/v8 1 87 0 0
No malware found.
| コード | 意味 |
|---|---|
0 | クリーン(または --exit-code 0 によるレポートのみのモードでの検出結果) |
1 | マルウェアを検出、またはファイルがスキャンされなかった(--exit-code と --skipped-exit-code で変更可能) |
2 | エラー: プル、エンジン、または設定。決してクリーンとして報告されない。 |
meles はデフォルトで検出結果があるとパイプラインを失敗させるため、追加のフラグなしでゲートとして機能します。
スキャンされなかったファイル(--max-file-size を超える、または clamd の制限のいずれかを超える)はスキップとして一覧表示され、レポートは不完全としてマークされます。テーブルには「No malware found.」の代わりに「Scan INCOMPLETE」と表示され、JSON レポートには "complete": false が含まれ、meles は検出時と同様に 1 で終了します。サイズ制限はファイルをそれより大きくすることで回避できるため、スキャンされていないファイルがセキュリティゲートを通過してはなりません。スキップされたファイルを報告するだけにするには --skipped-exit-code 0 を、エラーとして扱うには 2 を使用してください。