Amazon Inspectorを使ったECRスキャンでスキャン結果にイメージを使用しているECSタスク・EKS Pod情報がマッピングされるようになりました
お疲れさまです。とーちです。
What's Newを眺めていたらAmazon Inspectorに関する面白そうなアップデートがありました。
Amazon Inspectorを使ったECRスキャンで、スキャン結果にそのイメージを実際に使用しているECSタスク・EKS Podの場所や最後にそのイメージを使用した日時がデータとして含まれるようになったというアップデートです。
検証してみたので、その結果をお伝えします。
アップデート内容について
今回のアップデートですが、以下の複数の要素を含んだものとなっています
-
ECR 再スキャン期間の設定に
Last in-use date
(最終使用日時)を起点とした設定が追加- 従来はpushとpullを起点とした設定だったが、これに最終使用日時を起点とした設定が追加
-
実際に実行されているECSタスク・EKS Podの情報を検出結果に自動的にマッピング
- 最後にイメージを使用した日時、そのイメージを実行しているクラスター等を特定できる情報をAmazon Inspector コンソールまたは APIで取得できるようになった
-
最終使用日時等の情報をEventBridgeへ転送
- 上記の情報はEventBridgeで転送することも可能
それぞれについて、検証結果も交えて解説していきます。
Last in-use date
(最終使用日時)を起点とした設定が追加
ECR 再スキャン期間の設定に ECR基本スキャンがコンテナイメージをpushした際に一度だけスキャンするのに対して、Amazon Inspectorを使ったECRスキャンでは、対象のECR上のイメージを継続的にスキャンするという動作になっています。継続的なスキャンでは、Amazon Inspectorが持つデータベースに新しい脆弱性 (CVE) が追加されたタイミングで、対象のECR上のイメージをスキャンします。(参考)
以下はECRレジストリのスキャン設定の画面ですが、これが拡張スキャンとなっている場合には、Amazon Inspectorを使ったECRスキャンが行われます。
さて、この継続的なスキャンですが、全てのイメージが永続的にスキャンされるというわけではなく、ある条件に従ってスキャンされるようになっています。
従来は以下の2つの条件を設定できました
- イメージがアップロード(プッシュ)されてからの期間:ECRにイメージをプッシュしてからどれだけ時間が経ったか
- イメージが最後にpullされてからの期間: ECS等のサービスでECRからイメージをダウンロード(プル)してから、どれだけ時間が経ったか
今回のアップデートにより上記の2つに加えて以下の条件が設定できるようになりました
- イメージが最後に使用されてからの期間: ECS等のサービスでイメージを最後に使用してから、どれだけ時間が経ったか
上記の設定は、以下のAmazon Inspectorの設定画面で設定します。
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といった構成です
- AWSアカウント上で、ECSタスクを作成
- 作成したECSタスクを使ってECSサービスを作成
- ECRに新しいコンテナイメージをpush
- ECSタスクを更新し、ECSサービスもタスク定義の部分を更新
- 更新後すぐに Amazon Inspectorの検出結果の画面を確認
- ECSサービスの設定を変え、ECSタスク数を0に変更
- 約24時間経過後に 再度、Amazon Inspectorの検出結果の画面を確認
まず、AWSアカウント上でECSサービスを起動し、ECSタスクが立ち上がったことを確認しました。
この状態で、Amazon Inspectorの検出結果の画面を確認しましたが、以下のような状態でした。上記のDeployed Pods/TasksにデプロイされているECSタスクに関する情報が表示され、Last in useには最後に使用された日時が表示されるのが期待する動作だったのですが、実際には空になっています。
この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タスクを停止させました。
一応、コンテナログも記載しておきます。
翌日にAmazon Inspectorの検出結果の画面を確認したところ以下の表示となっていることが確認できました。
Last in use
が、May 20, 2025 9:54 AM (UTC+09:00)
となっており、これはECSタスクを停止した時間とほぼ一致します(1分ズレてるのが謎ですが)
翌日の何時頃確認したかまでは正直なところ覚えていないのですが、上記の通り翌日になって初めて表示されたことから、ドキュメントの記載内容と合わせて「24時間以内に表示されるということではないか」と判断した理由になります。
なお、 Deployed ECS Tasks/EKS Pods
の数字はクリックできるようになっています。クリックしましたが、以下の通り何も表示されない状態でした。
更に、1日以上経過して再度確認したところ、以下の状態になっていました。Deployed ECS Tasks/EKS Pods
の数字が0に変わっています。最初に Deployed ECS Tasks/EKS Pods
の数字が表示された時点でECSタスクは停止していたので、0でなかった理由がよく分かりませんが、やはり1日ごとに更新されているのかなという印象を受けました。
直近24時間内に対象ECSタスクが起動し続けている場合の検出結果への表示のされ方
また、上記の例では、ECSタスクを途中で停止させていますが、上記の 6.ECSサービスの設定を変え、ECSタスク数を0に変更
を行わず、ECSタスクが起動し続けた場合にどのような表示結果となるかも確認しました。
2025/05/24 08:25
頃に対象のイメージを使用するECSタスクを起動し、そのまま起動しっぱなしにします。その状態で翌日2025/05/25 06:00
頃にAmazon Inspectorの検出結果の画面を確認したところ以下の表示となりました。
上記の通り、Last in use
は、 2025/5/25 AM 1:49(UTC+9:00)
となっていますね。もちろん対象ECSタスクは起動し続けています。この時間はおそらくAmazon Inspectorが対象イメージが使用されているかどうかを確認した時間でしょう。
また、Deployed ECS Tasks/EKS Pods
の数字(1)をクリックしてみるとちゃんと結果が表示されていました。
なお、2025/05/25 16:00
頃にも再度Amazon Inspectorの検出結果の画面を確認しましたが、上記の状態から変わっていませんでした。(ECSタスクは起動しっぱなしの状態)
更にその翌日、2025/05/26 05:00
に確認したところ以下の結果でした。2025/5/26 AM 1:49(UTC+9:00)
となっています。
この結果から、Amazon Inspectorは日次でLast in use
を更新していそうということがわかりました。
検出結果画面で新たに利用できるようになったフィルタについて
画面下の検出結果の部分では新たに Image in use count
と Image last in use at
でフィルタができるようになっています。
こちらも、ECSタスク起動直後に試した際は、Image last in use at
で7日でフィルタ(過去7日以内に使用されたイメージのみを表示)しても、何も表示されない状態でしたが、
Last in use
等のデータが反映された後に試すと、ちゃんとフィルタ結果として表示されるようになっていました。
最終使用日時等の情報を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の箇所に inUseCount
や lastInUseAt
といった情報が含まれていますね。てっきり、Cluster ARNやタスク定義等の「どこで使っているのか」といった情報も含まれてくると思っていたのですが、少なくとも"Inspector2 Finding"イベントには含まれていないようです。
inUseCount
で実際に使っているかどうかはわかるので、これを元に実際に使われているイメージだけを通知するといった条件分岐はできそうですね。
まとめ
ということで、「Amazon Inspectorを使ったECRスキャンでスキャン結果にそのイメージを実際に使用しているECSタスク・EKS Podがマッピングされるようになった」というアップデートの紹介でした。
日次で更新されるという点には注意ですが、実際に使われてるイメージかどうかがわかるようになったという点で大変有意義なアップデートではないかと思います。色々と使い道がありそうですね。
以上、とーちでした。