Amazon Inspectorを使ったECRスキャンでスキャン結果にイメージを使用しているECSタスク・EKS Pod情報がマッピングされるようになりました

Amazon Inspectorを使ったECRスキャンでスキャン結果にイメージを使用しているECSタスク・EKS Pod情報がマッピングされるようになりました

Clock Icon2025.05.20

お疲れさまです。とーちです。

What's Newを眺めていたらAmazon Inspectorに関する面白そうなアップデートがありました。

https://aws.amazon.com/jp/about-aws/whats-new/2025/05/amazon-inspector-container-security-images/

Amazon Inspectorを使ったECRスキャンで、スキャン結果にそのイメージを実際に使用しているECSタスク・EKS Podの場所最後にそのイメージを使用した日時がデータとして含まれるようになったというアップデートです。

検証してみたので、その結果をお伝えします。

アップデート内容について

今回のアップデートですが、以下の複数の要素を含んだものとなっています

  1. ECR 再スキャン期間の設定に Last in-use date (最終使用日時)を起点とした設定が追加

    • 従来はpushとpullを起点とした設定だったが、これに最終使用日時を起点とした設定が追加
  2. 実際に実行されているECSタスク・EKS Podの情報を検出結果に自動的にマッピング

    • 最後にイメージを使用した日時、そのイメージを実行しているクラスター等を特定できる情報をAmazon Inspector コンソールまたは APIで取得できるようになった
  3. 最終使用日時等の情報をEventBridgeへ転送

    • 上記の情報はEventBridgeで転送することも可能

それぞれについて、検証結果も交えて解説していきます。

ECR 再スキャン期間の設定に Last in-use date (最終使用日時)を起点とした設定が追加

ECR基本スキャンがコンテナイメージをpushした際に一度だけスキャンするのに対して、Amazon Inspectorを使ったECRスキャンでは、対象のECR上のイメージを継続的にスキャンするという動作になっています。継続的なスキャンでは、Amazon Inspectorが持つデータベースに新しい脆弱性 (CVE) が追加されたタイミングで、対象のECR上のイメージをスキャンします。(参考

以下はECRレジストリのスキャン設定の画面ですが、これが拡張スキャンとなっている場合には、Amazon Inspectorを使ったECRスキャンが行われます。

alt text

さて、この継続的なスキャンですが、全てのイメージが永続的にスキャンされるというわけではなく、ある条件に従ってスキャンされるようになっています。

従来は以下の2つの条件を設定できました

  • イメージがアップロード(プッシュ)されてからの期間:ECRにイメージをプッシュしてからどれだけ時間が経ったか
  • イメージが最後にpullされてからの期間: ECS等のサービスでECRからイメージをダウンロード(プル)してから、どれだけ時間が経ったか

今回のアップデートにより上記の2つに加えて以下の条件が設定できるようになりました

  • イメージが最後に使用されてからの期間: ECS等のサービスでイメージを最後に使用してから、どれだけ時間が経ったか

上記の設定は、以下のAmazon Inspectorの設定画面で設定します。

alt text

Image re-scan mode で、Last in-use date(最終使用日時) か Last pull date(最終pull日時) かを選択できます。

またその下の Image last in use date で最後に使用されてからどのくらい日数が経過するまで継続的にスキャンするかを指定します。

ちなみに、更にその下のECR再スキャン期間の項目はpushされてからの日数の設定です。

なお、Image last in use date の最小設定が14日です。

最終使用日時はAmazon Inspectorが対象イメージの使用を確認した日時である点に注意

「イメージが最後に使用されてからの期間」についてもう少し詳しく解説します。私の感覚だと、対象コンテナイメージがECS等で利用されている限りほぼリアルタイムで「最後に使用された日時」を更新し続けるのかなと思っていたのですが、実際には異なります。

この後、詳しく説明しますが、Amazon Inspector検出結果画面に表示される Last in use はリアルタイムに更新されるわけではなく、1日に1回程度の頻度で情報が更新されるようになっているようです(具体的な頻度についてはドキュメント上で明確な記載がないのでわからず)。

つまり、対象イメージを使用するECSタスクが動き続けていたとしても、「最後に使用された日時」はInspcetorがECSタスク等でイメージが使用されていることの確認を行ったタイミングになります。

例えば現在時刻が15:00、Inspcetorがイメージ使用を確認した時刻が14:00だとすると、Amazon Inspector検出結果画面に表示される Last in useは14:00になり、イメージスキャン実行条件としてLast in-use date(最終使用日時)を使用している場合、この日時に基づき継続スキャン有効か否かが判断されるということです。

これでなにかが困るということはあまり考えられませんが、こういう動作だということは覚えておいたほうがいいかもしれません。

実際に実行されているECSタスク・EKS Podの情報を検出結果に自動的にマッピング

実際に検証して分かったのですが、この機能は即座にAmazon Inspectorの検出結果に反映されるものではないということです。

ドキュメントに以下のように記載があります。

You can monitor container images currently in use and when container images were last used on an Amazon ECS or Amazon EKS cluster in the past 24 hours.
(日本語訳:Amazon ECSまたはAmazon EKSクラスターで過去24時間以内に使用されたコンテナイメージを監視し、そのコンテナイメージが最後に使用された時刻を確認できます。)

これを読んだとき、私は日本語訳のとおりに24時間以内に使用されたコンテナイメージであれば即座に検出されると思ったのですが、実際の動作としては 24時間以内に結果を表示 するというのが正しい解釈のようでした。

「24時間以内に結果が表示」されるのではないかと考えた理由として、検証した内容と確認できた事象をお伝えします。

直近24時間以内に対象ECSタスクを停止している場合の検出結果への表示のされ方

実際に以下のように検証を行いました。なお構成としては一般的なパブリックなALB ⇒ ECSといった構成です

  1. AWSアカウント上で、ECSタスクを作成
  2. 作成したECSタスクを使ってECSサービスを作成
  3. ECRに新しいコンテナイメージをpush
  4. ECSタスクを更新し、ECSサービスもタスク定義の部分を更新
  5. 更新後すぐに Amazon Inspectorの検出結果の画面を確認
  6. ECSサービスの設定を変え、ECSタスク数を0に変更
  7. 約24時間経過後に 再度、Amazon Inspectorの検出結果の画面を確認

まず、AWSアカウント上でECSサービスを起動し、ECSタスクが立ち上がったことを確認しました。

alt text

この状態で、Amazon Inspectorの検出結果の画面を確認しましたが、以下のような状態でした。上記のDeployed Pods/TasksにデプロイされているECSタスクに関する情報が表示され、Last in useには最後に使用された日時が表示されるのが期待する動作だったのですが、実際には空になっています。

vscode-paste-1748040487560-4aucfgxysbe.png

このECSサービスは 2025年5月20日 06:49 (UTC+9:00)に立ち上げており、停止する 2025年5月20日 09:52 (UTC+9:00) までの約3時間ほど、何度かAmazon Inspectorの検出結果を見に行きましたが、表示結果は変わりませんでした。

この後、上記の通り、 2025年5月20日 09:52 (UTC+9:00) に対象のECSサービスのタスク数を0にすることでECSタスクを停止させました。

vscode-paste-1748038912053-5dhq89bdyqa.png

一応、コンテナログも記載しておきます。

alt text

翌日にAmazon Inspectorの検出結果の画面を確認したところ以下の表示となっていることが確認できました。

vscode-paste-1748039032770-14en0hoxpym.png

Last in use が、May 20, 2025 9:54 AM (UTC+09:00) となっており、これはECSタスクを停止した時間とほぼ一致します(1分ズレてるのが謎ですが)

翌日の何時頃確認したかまでは正直なところ覚えていないのですが、上記の通り翌日になって初めて表示されたことから、ドキュメントの記載内容と合わせて「24時間以内に表示されるということではないか」と判断した理由になります。

なお、 Deployed ECS Tasks/EKS Pods の数字はクリックできるようになっています。クリックしましたが、以下の通り何も表示されない状態でした。

alt text

更に、1日以上経過して再度確認したところ、以下の状態になっていました。Deployed ECS Tasks/EKS Pods の数字が0に変わっています。最初に Deployed ECS Tasks/EKS Pods の数字が表示された時点でECSタスクは停止していたので、0でなかった理由がよく分かりませんが、やはり1日ごとに更新されているのかなという印象を受けました。

vscode-paste-1748041617110-0q6j3ikmjdu.png

直近24時間内に対象ECSタスクが起動し続けている場合の検出結果への表示のされ方

また、上記の例では、ECSタスクを途中で停止させていますが、上記の 6.ECSサービスの設定を変え、ECSタスク数を0に変更 を行わず、ECSタスクが起動し続けた場合にどのような表示結果となるかも確認しました。

2025/05/24 08:25 頃に対象のイメージを使用するECSタスクを起動し、そのまま起動しっぱなしにします。その状態で翌日2025/05/25 06:00 頃にAmazon Inspectorの検出結果の画面を確認したところ以下の表示となりました。

alt text

上記の通り、Last in use は、 2025/5/25 AM 1:49(UTC+9:00) となっていますね。もちろん対象ECSタスクは起動し続けています。この時間はおそらくAmazon Inspectorが対象イメージが使用されているかどうかを確認した時間でしょう。

また、Deployed ECS Tasks/EKS Pods の数字(1)をクリックしてみるとちゃんと結果が表示されていました。

alt text

なお、2025/05/25 16:00 頃にも再度Amazon Inspectorの検出結果の画面を確認しましたが、上記の状態から変わっていませんでした。(ECSタスクは起動しっぱなしの状態)

更にその翌日、2025/05/26 05:00 に確認したところ以下の結果でした。2025/5/26 AM 1:49(UTC+9:00) となっています。

vscode-paste-1748203168669-og7pmkxffmp.png

この結果から、Amazon Inspectorは日次でLast in use を更新していそうということがわかりました。

検出結果画面で新たに利用できるようになったフィルタについて

画面下の検出結果の部分では新たに Image in use countImage last in use at でフィルタができるようになっています。

alt text

こちらも、ECSタスク起動直後に試した際は、Image last in use at で7日でフィルタ(過去7日以内に使用されたイメージのみを表示)しても、何も表示されない状態でしたが、

alt text

Last in use 等のデータが反映された後に試すと、ちゃんとフィルタ結果として表示されるようになっていました。

vscode-paste-1748042253768-lubbrevkpdp.png

最終使用日時等の情報をEventBridgeへ転送

What'sNewによると最終使用日時等の情報は、findings と resource coverage detailsに含まれEventBridgeへ転送されると記載があります。

you can use Amazon Inspector console or APIs to identify your actively used container images, when you last used an image, and which clusters are running the image. This information will be included in your findings and resource coverage details, and will be routed to EventBridge.

また、Amazon Inspectorのドキュメントを見ると、以下のように記載があります。

You can use Amazon Inspector to publish events for findings, coverage, and scans.

このことから、最終使用日時等の情報は、以下のイベントのときに含まれるものと思われます。

  • "detail-type": "Inspector2 Finding" :Amazon Inspector がリソースの 1 つでソフトウェアの脆弱性またはネットワークの問題を検出したときに作成されるイベント
  • "detail-type": "Inspector2 Coverage" :リソースの Amazon Inspector スキャンカバレッジが変更されたときに作成されるイベント

そこで、以下のようなTerraformコードでEventBridgeとLambdaを作成して、"Inspector2 Finding"イベントを取得してみました。

# Lambda関数用のIAMロール
resource "aws_iam_role" "lambda_role" {
  name = "ecr_scan_lambda_role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "lambda.amazonaws.com"
        }
      }
    ]
  })
}

# Lambda基本実行権限とCloudWatch Logs権限をアタッチ
resource "aws_iam_role_policy_attachment" "lambda_basic" {
  role       = aws_iam_role.lambda_role.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

# Lambda関数用のコードをzipファイルとして準備
data "archive_file" "lambda_zip" {
  type        = "zip"
  output_path = "${path.module}/lambda_function.zip"
  
  source {
    content  = <<EOF
import json
import logging

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(event, context):
    """ECRスキャンイベントを受け取り、内容をログに出力する関数"""
    
    # イベント全体をログに出力
    logger.info("ECRスキャンイベント:")
    logger.info(json.dumps(event, indent=2, default=str))
    
    return {
        'statusCode': 200,
        'body': 'イベント処理完了'
    }
EOF
    filename = "lambda_function.py"
  }
}

# Lambda関数の作成
resource "aws_lambda_function" "ecr_scan_lambda" {
  function_name    = "ecr-scan-event-processor"
  role             = aws_iam_role.lambda_role.arn
  handler          = "lambda_function.lambda_handler"
  filename         = data.archive_file.lambda_zip.output_path
  source_code_hash = data.archive_file.lambda_zip.output_base64sha256
  runtime          = "python3.9"
  timeout          = 10
  
  tags = {
    Name = "ECRScanEventProcessor"
  }
}

# EventBridgeルールの作成
resource "aws_cloudwatch_event_rule" "ecr_scan_rule" {
  name        = "ecr-scan-events"
  description = "キャプチャするECRスキャンイベント"
  
  event_pattern = jsonencode({
    source      = ["aws.inspector2"]
    detail-type = ["Inspector2 Finding"]
  })
}

# EventBridgeルールのターゲットとしてLambda関数を設定
resource "aws_cloudwatch_event_target" "lambda_target" {
  rule      = aws_cloudwatch_event_rule.ecr_scan_rule.name
  target_id = "SendToLambda"
  arn       = aws_lambda_function.ecr_scan_lambda.arn
}

# EventBridgeがLambda関数を呼び出す権限を付与
resource "aws_lambda_permission" "allow_eventbridge" {
  statement_id  = "AllowExecutionFromEventBridge"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.ecr_scan_lambda.function_name
  principal     = "events.amazonaws.com"
  source_arn    = aws_cloudwatch_event_rule.ecr_scan_rule.arn
}

上記をデプロイしイベント発生を待ってみたところ、以下のようなイベントが発生しました。

[INFO]	2025-05-26T16:54:24.776Z	****************************
{
    "version": "0",
    "id": "feeedbd8-8cd6-9eac-150c-935c36c5ce45",
    "detail-type": "Inspector2 Finding",
    "source": "aws.inspector2",
    "account": "************",
    "time": "2025-05-26T16:54:15Z",
    "region": "us-east-1",
    "resources": [
        "arn:aws:ecr:us-east-1:************:repository/test-ecspresso-test/sha256:****************************"
    ],
    "detail": {
        "awsAccountId": "************",
        "description": "In libxml2 before 2.13.8 and 2.14.x before 2.14.2, xmlSchemaIDCFillNodeTables in xmlschemas.c has a heap-based buffer under-read. To exploit this, a crafted XML document must be validated against an XML schema with certain identity constraints, or a crafted XML schema must be used.",
        "epss": {
            "score": 0.0002
        },
        "exploitAvailable": "NO",
        "findingArn": "arn:aws:inspector2:us-east-1:************:finding/****************************",
        "firstObservedAt": "Tue May 20 00:04:00.754 UTC 2025",
        "fixAvailable": "YES",
        "inspectorScore": 7.5,
        "inspectorScoreDetails": {
            "adjustedCvss": {
                "adjustments": [],
                "cvssSource": "NVD",
                "score": 7.5,
                "scoreSource": "NVD",
                "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
                "version": "3.1"
            }
        },
        "lastObservedAt": "Mon May 26 16:54:15.761 UTC 2025",
        "packageVulnerabilityDetails": {
            "cvss": [
                {
                    "baseScore": 7.5,
                    "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
                    "source": "NVD",
                    "version": "3.1"
                }
            ],
            "referenceUrls": [
                "https://gitlab.gnome.org/GNOME/libxml2/-/issues/890",
                "https://nvd.nist.gov/vuln/detail/CVE-2025-32415"
            ],
            "relatedVulnerabilities": [],
            "source": "NVD",
            "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2025-32415",
            "vendorCreatedAt": "Thu Apr 17 17:15:33.000 UTC 2025",
            "vendorSeverity": "HIGH",
            "vendorUpdatedAt": "Wed Apr 23 18:17:52.000 UTC 2025",
            "vulnerabilityId": "CVE-2025-32415",
            "vulnerablePackages": [
                {
                    "arch": "AARCH64",
                    "epoch": 0,
                    "fixedInVersion": "2.13.4-r6",
                    "name": "libxml2",
                    "packageManager": "OS",
                    "release": "r5",
                    "remediation": "apk update && apk upgrade libxml2",
                    "sourceLayerHash": "sha256:****************************",
                    "version": "2.13.4"
                }
            ]
        },
        "remediation": {
            "recommendation": {
                "text": "None Provided"
            }
        },
        "resources": [
            {
                "details": {
                    "awsEcrContainerImage": {
                        "architecture": "arm64",
                        "imageHash": "sha256:****************************",
                        "imageTags": [
                            "v4"
                        ],
                        "inUseCount": 1,
                        "lastInUseAt": "Mon May 26 16:49:39.233 UTC 2025",
                        "platform": "ALPINE_LINUX_3_21",
                        "pushedAt": "Tue May 20 00:03:45.707 UTC 2025",
                        "registry": "************",
                        "repositoryName": "test-ecspresso-test"
                    }
                },
                "id": "arn:aws:ecr:us-east-1:************:repository/test-ecspresso-test/sha256:****************************",
                "partition": "aws",
                "region": "us-east-1",
                "type": "AWS_ECR_CONTAINER_IMAGE"
            }
        ],
        "severity": "HIGH",
        "status": "ACTIVE",
        "title": "CVE-2025-32415 - libxml2",
        "type": "PACKAGE_VULNERABILITY",
        "updatedAt": "Mon May 26 16:54:15.761 UTC 2025"
    }
}

awsEcrContainerImageの箇所に inUseCountlastInUseAt といった情報が含まれていますね。てっきり、Cluster ARNやタスク定義等の「どこで使っているのか」といった情報も含まれてくると思っていたのですが、少なくとも"Inspector2 Finding"イベントには含まれていないようです。

inUseCountで実際に使っているかどうかはわかるので、これを元に実際に使われているイメージだけを通知するといった条件分岐はできそうですね。

まとめ

ということで、「Amazon Inspectorを使ったECRスキャンでスキャン結果にそのイメージを実際に使用しているECSタスク・EKS Podがマッピングされるようになった」というアップデートの紹介でした。

日次で更新されるという点には注意ですが、実際に使われてるイメージかどうかがわかるようになったという点で大変有意義なアップデートではないかと思います。色々と使い道がありそうですね。

以上、とーちでした。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.