buildx で push したマルチアーキテクチャイメージの Amazon Inspector 検出結果をタグで追跡する

docker buildx で push したマルチアーキテクチャイメージの Amazon Inspector の検出結果を、イメージタグから追跡できるようにする

ogino・November 9, 2026

はじめに

コンテナイメージの脆弱性管理に Amazon Inspector を使用している方も多いのではないでしょうか。

当社でも Amazon ECR で管理しているコンテナイメージに対して Amazon Inspector による脆弱性管理を実施しているケースがあります。

Inspector の検出結果を確認していたところ、ECR にはイメージタグをつけて push したはずが、Inspector では <untagged> と表示される場合があることに気がつきました。

Inspector の検出結果一覧。イメージタグが untagged と表示されている

この状態では、どのバージョン (タグ) のイメージに対する検出結果なのか、Inspector 側から判断ができません。

調査したところ、docker buildx でマルチアーキテクチャイメージを push した際のイメージの構造が関係していることが分かりました。

今回の記事では、buildx で push したマルチアーキテクチャのイメージについて、Inspector の検出結果をタグから追跡する方法を検証した結果をご紹介します。

検証環境

本記事の内容は、以下の環境で確認しています。

  • Amazon ECR のスキャン設定は拡張スキャン (Amazon Inspector) を有効にしている
  • イメージは linux/amd64 と linux/arm64 の 2 つのアーキテクチャ向けにビルドする
  • ビルドには docker-container ドライバーの buildx ビルダーを使用する
  • 検証用のイメージは、検出結果が出るように、サポートが終了したベースイメージを使用する
FROM node:16-bullseye-slim

なお、以降のコマンド例に含まれるアカウント ID は 123456789012 に置き換えています。

何が起きているか

まず、一般的な方法でマルチアーキテクチャのイメージを push します。

docker buildx build --platform linux/amd64,linux/arm64 -t $REPO:v1 --push .

push したイメージの構造を docker buildx imagetools inspect で確認すると、以下のようになっています。

$ docker buildx imagetools inspect $REPO:v1
Name:      123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/verify-index:v1
MediaType: application/vnd.oci.image.index.v1+json
Digest:    sha256:eb425caf55fbe61845a183d9fe78494eebb44a7238d8cdfcdbda717d11df19cf

Manifests:
  Name:        123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/verify-index:v1@sha256:a98a56059acdfd657355a178e765ba35e7ca979a90365354d6d786719c528110
  MediaType:   application/vnd.oci.image.manifest.v1+json
  Platform:    linux/amd64

  Name:        123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/verify-index:v1@sha256:bf8103057072081b4a264bfc3670b4abaa232b5d1521520ef1c96e0a32d7a653
  MediaType:   application/vnd.oci.image.manifest.v1+json
  Platform:    linux/arm64

  Name:        123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/verify-index:v1@sha256:390152150fe4242a51760f70ef6717a68fdf7828eafd6bdef1e5272fa6720b43
  MediaType:   application/vnd.oci.image.manifest.v1+json
  Platform:    unknown/unknown
  Annotations:
    vnd.docker.reference.digest: sha256:a98a56059acdfd657355a178e765ba35e7ca979a90365354d6d786719c528110
    vnd.docker.reference.type:   attestation-manifest

  Name:        123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/verify-index:v1@sha256:578e52194d313be54a400b21963fb818815fd5211057100cb1a1de30afd8429c
  MediaType:   application/vnd.oci.image.manifest.v1+json
  Platform:    unknown/unknown
  Annotations:
    vnd.docker.reference.digest: sha256:bf8103057072081b4a264bfc3670b4abaa232b5d1521520ef1c96e0a32d7a653
    vnd.docker.reference.type:   attestation-manifest

タグ v1 がついているのはイメージインデックス (application/vnd.oci.image.index.v1+json) で、その中に以下の 4 つのマニフェストが含まれています。

  • linux/amd64 のイメージ (sha256:a98a...)
  • linux/arm64 のイメージ (sha256:bf81...)
  • 各イメージのアテステーション (unknown/unknown)
    • buildx が push 時にデフォルトで付与する provenance (ビルドの来歴) です
    • vnd.docker.reference.digest で、どのイメージのアテステーションかを示しています

イメージインデックスは、アーキテクチャごとのイメージを digest で参照する「目次」のようなものです。タグはイメージインデックスにのみついており、アーキテクチャごとのイメージにはタグがついていません。

Inspector の検出結果一覧に表示されていたのは、このうち sha256:a98a... と sha256:bf81... の 2 つでした。つまり、検出結果はタグのついていないアーキテクチャごとのイメージに紐づいていたことになります。

タグを指定して検出結果を取得した場合

push したタグを指定して aws ecr describe-image-scan-findings を実行すると、以下の結果が返ります。

$ aws ecr describe-image-scan-findings --repository-name verify-index --image-id imageTag=v1
{
    "imageScanFindings": {
        "findings": []
    },
    "registryId": "123456789012",
    "repositoryName": "verify-index",
    "imageId": {
        "imageDigest": "sha256:eb425caf55fbe61845a183d9fe78494eebb44a7238d8cdfcdbda717d11df19cf",
        "imageTag": "v1"
    },
    "imageScanStatus": {
        "status": "UNSUPPORTED_IMAGE",
        "description": "UnsupportedImageError: The media type, operating system and/or package manager are not supported."
    }
}

コマンド自体はエラーにならず、imageScanStatus.status が UNSUPPORTED_IMAGE となり、検出結果は空で返ります。タグが指しているイメージインデックスはスキャンの対象外となっているためです。

Inspector のカバレッジ (aws inspector2 list-coverage) でも、イメージインデックスとアテステーションは UNSUPPORTED_MEDIA_TYPE としてスキャンの対象外になっていることが確認できます。

タグから検出結果を辿る方法

タグからイメージインデックスを取得し、目的のアーキテクチャのイメージの digest を取り出せば、検出結果を取得できます。

REPO_NAME=...
TAG=...
 
# イメージインデックスから linux/amd64 のイメージの digest を取り出す
DIGEST=$(aws ecr batch-get-image \
  --repository-name "$REPO_NAME" --image-ids imageTag="$TAG" \
  --accepted-media-types \
    application/vnd.oci.image.index.v1+json \
    application/vnd.docker.distribution.manifest.list.v2+json \
  --query 'images[0].imageManifest' --output text \
  | jq -r '.manifests[] | select(.platform.os=="linux" and .platform.architecture=="amd64") | .digest')
 
# 深刻度ごとの件数を集計する
aws ecr describe-image-scan-findings --repository-name "$REPO_NAME" \
  --image-id imageDigest="$DIGEST" \
  --query 'imageScanFindings.enhancedFindings[].severity' --output json \
  | jq 'group_by(.) | map({(.[0]): length}) | add'

上記を実行すると、linux/amd64 のイメージの検出結果を取得できます。アテステーションは platform が unknown/unknown となっているため、プラットフォームで絞り込むことで自然に除外されます。

{
  "CRITICAL": xx,
  "HIGH": xx,
  "LOW": xx,
  "MEDIUM": xx,
  "UNTRIAGED": xx
}

このような方法でタグに関連する検出結果を取得することができますが、Inspector のコンソールからもタグで追跡ができるのかが気になり、アーキテクチャごとのイメージにもタグをつける方法を検証しました。

アーキテクチャごとにタグをつける

イメージインデックスは、アーキテクチャごとのイメージを digest で参照しているだけです。そのため、アーキテクチャごとのイメージを先にタグつきで push し、それらを参照するイメージインデックスを後から作成することができます。

まず、アーキテクチャごとにタグをつけて push します。

docker buildx build --platform linux/amd64 --provenance=false \
  -t $REPO:v1-amd64 --push .
docker buildx build --platform linux/arm64 --provenance=false \
  -t $REPO:v1-arm64 --push .

ここでは --provenance=false を指定して、アテステーションをつけずに push しています。アテステーションをつけると、アーキテクチャごとのタグもイメージインデックスにつき、スキャンされるイメージにタグがつかなくなるためです。詳しくは後述します。

次に、上記のイメージを参照するイメージインデックスを作成します。

docker buildx imagetools create -t $REPO:v1 $REPO:v1-amd64 $REPO:v1-arm64

docker buildx imagetools create は、イメージの再ビルドやダウンロードは行わず、指定したイメージの digest とプラットフォームを並べたイメージインデックスをレジストリに push します。

--provenance=false が必要な理由

--provenance=false を指定せずに、同じ手順でアーキテクチャごとに push した場合の結果も確認しました。なお、この検証では別のイメージを使用しているため、digest は前述のものとは異なります。

v1-amd64 の中身を確認すると、amd64 のイメージとそのアテステーションを含むイメージインデックスになっていました。

$ docker buildx imagetools inspect $REPO:v1-amd64 --raw
{
  "schemaVersion": 2,
  "mediaType": "application/vnd.oci.image.index.v1+json",
  "manifests": [
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "digest": "sha256:d0463ce4ef72e3c095a3b098f1acfe7ec96542c9799692948a7cb63a73fd523d",
      "size": 480,
      "platform": {
        "architecture": "amd64",
        "os": "linux"
      }
    },
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "digest": "sha256:b34a51fea10bae53913c55959d7fd71533d6eefca640c3c09d15b32da10fba49",
      "size": 836,
      "annotations": {
        "vnd.docker.reference.digest": "sha256:d0463ce4ef72e3c095a3b098f1acfe7ec96542c9799692948a7cb63a73fd523d",
        "vnd.docker.reference.type": "attestation-manifest"
      },
      "platform": {
        "architecture": "unknown",
        "os": "unknown"
      }
    }
  ]
}

この状態で imagetools create を実行し、Inspector のカバレッジを確認した結果は以下のとおりです。

中身タグカバレッジの理由
イメージインデックス (imagetools create で作成)v1UNSUPPORTED_MEDIA_TYPE
イメージインデックス (amd64 + アテステーション)v1-amd64UNSUPPORTED_MEDIA_TYPE
イメージインデックス (arm64 + アテステーション)v1-arm64UNSUPPORTED_MEDIA_TYPE
amd64 のイメージなしスキャン済み
arm64 のイメージなしスキャン済み
アテステーションなしUNSUPPORTED_MEDIA_TYPE

アーキテクチャごとのタグ v1-amd64 / v1-arm64 は、アーキテクチャごとのイメージではなく、スキャンの対象外となるイメージインデックスについていました。スキャンされたイメージにはタグがつかないため、通常のマルチアーキテクチャの push と同じ状態になってしまいます。

アーキテクチャごとのイメージにタグをつけるためには、--provenance=false を指定して、アテステーションをつけずに push する必要があります。

Inspector で表示されるタグの変化

--provenance=false を指定して push したリポジトリ (verify-per-arch) のイメージを確認すると、アーキテクチャごとのイメージにタグがついていることが確認できます。

$ aws ecr describe-images --repository-name verify-per-arch \
  --query 'imageDetails[].[imageTags, imageDigest, imageManifestMediaType]' \
  --output table
-----------------------------------------------------------------------------
|                              DescribeImages                               |
+---------------------------------------------------------------------------+
|  v1                                                                       |
|  sha256:cb3c968e7de53cfd04672d0c2ffc5714b1592489c9285d549b9ffade38bf9891  |
|  application/vnd.oci.image.index.v1+json                                  |
|  v1-arm64                                                                 |
|  sha256:bf8103057072081b4a264bfc3670b4abaa232b5d1521520ef1c96e0a32d7a653  |
|  application/vnd.oci.image.manifest.v1+json                               |
|  v1-amd64                                                                 |
|  sha256:a98a56059acdfd657355a178e765ba35e7ca979a90365354d6d786719c528110  |
|  application/vnd.oci.image.manifest.v1+json                               |
+---------------------------------------------------------------------------+

v1-amd64 と v1-arm64 は、同じ Dockerfile からビルドしており、前述の verify-index リポジトリのイメージと同じ digest になっています。

Inspector の検出結果一覧では、同じ digest のイメージが、verify-index では <untagged>、アーキテクチャごとにタグをつけた verify-per-arch では v1-amd64 / v1-arm64 として表示されました。

Inspector の検出結果一覧。同じ digest のイメージに、アーキテクチャごとにタグをつけたリポジトリではアーキテクチャ別のタグが表示されている

CLI でも、タグを指定して検出結果を取得できます。

aws ecr describe-image-scan-findings --repository-name verify-per-arch \
  --image-id imageTag=v1-amd64 \
  --query 'imageScanFindings.enhancedFindings[].severity' --output json \
  | jq 'group_by(.) | map({(.[0]): length}) | add'

件数は linux/amd64、linux/arm64 ともに、digest を指定して取得した verify-index の結果と一致しました。

利用者側への影響

イメージを利用する側は、これまでどおりイメージインデックスのタグ v1 を pull するだけで、アーキテクチャに合ったイメージが選択されます。

$ docker pull --platform linux/arm64 $REPO:v1
v1: Pulling from verify-per-arch
...
Digest: sha256:cb3c968e7de53cfd04672d0c2ffc5714b1592489c9285d549b9ffade38bf9891
Status: Downloaded newer image for 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/verify-per-arch:v1

$ docker image inspect $REPO:v1 --format '{{.Os}}/{{.Architecture}}'
linux/arm64

アーキテクチャ別のタグは検出結果を追跡するためのもので、利用者が意識する必要はありません。

留意点

アーキテクチャごとにタグをつける方法には、以下の留意点があります。

  • provenance のアテステーションを付与しなくなる
    • ビルドの来歴の証跡が必要な場合は、cosign などを利用して別途署名やアテステーションを行う必要があります
  • アーキテクチャ別のタグを誤って利用しないようにする
    • アーキテクチャ別のタグを指定すると、実行環境に関わらずそのアーキテクチャのイメージが使用されます。通常はイメージインデックスのタグを使用します

また、Inspector には、ECR のイメージを Amazon ECS や Amazon EKS で実行中のコンテナに対応づける機能があります (ドキュメント)。稼働中のイメージの脆弱性を把握したい場合は、こちらの機能も有用です。ただし、この情報は 24 時間に 1 回の更新となるなどの制限があります。

おわりに

今回の記事では、docker buildx で push したマルチアーキテクチャのイメージについて、Amazon Inspector の検出結果をタグから追跡する方法を検証した結果をご紹介しました。

マルチアーキテクチャのイメージを扱う際は、タグがどのマニフェストについているのかを意識しておくと、今回のような事象に気づきやすくなると思います。