Always-On Vulnerability Scanning

August 30, 2028 · 14 min read

DevOps Engineer Pro · DOP-C02 · part of The Exam Room

The situation

A security team inherits vulnerability management for:

  • ~600 EC2 instances across Amazon Linux 2023, Amazon Linux 2, Ubuntu, RHEL, and Windows Server.
  • ~300 Lambda functions, Node/Python/Java, zip-packaged and container-image-packaged.
  • ~80 ECR repositories, ~50 new image pushes a day across the Organization.

Existing tooling:

  • Nessus scans EC2 instances weekly, sends findings to a SIEM. Coverage lag: up to 7 days.
  • Quarterly pen-test covers Lambda and a sample of ECR images. Coverage lag: up to 90 days.
  • ECR basic scanning enabled on some repositories, Clair-based, CVE database updated nightly.
  • No runtime scanning on instances between Nessus runs.

The asks:

  • Continuous scanning. As soon as a new instance launches, image pushes, or function deploys, it gets scanned within minutes.
  • Comprehensive CVE source. NIST NVD plus vendor-specific advisories (RHEL, Amazon Linux, Ubuntu).
  • Code-level scanning for Lambda. Static analysis of function code plus dependency CVE checks.
  • Org-wide aggregation. Findings from every account land in one place, keyed by resource.
  • Integration with Security Hub. Findings flow into the existing security-posture dashboard.
  • Automated remediation hooks for low-severity findings (trigger patch, trigger image rebuild) with human review for high-severity.

What actually matters

Vulnerability scanning has two axes.

When does the scan run? Options range from periodic (weekly Nessus) to event-driven (scan on image push) to continuous (scan every time the CVE database updates, re-score every resource). Continuous means “the set of findings reflects both the current resource state and the current CVE database state, freshness bounded to minutes rather than days.”

What does the scan cover? Operating-system packages, application dependencies, container image layers, function code, network configuration, IAM. A single tool rarely covers everything; the question is what a native scanner covers and where it quietly hands off.

The CVE-vs-inventory scanner is one job: match installed package versions against the known-vulnerable database. Adjacent jobs (runtime threat detection, IAM misuse, network exposure analysis) belong on separate services. The architecture that scales puts each job on the service designed for it and routes findings into a common aggregation layer.

The decisions worth making deliberately:

  • Org-wide aggregation. A scanner that runs per account with findings scattered across thirty consoles is no better than a quarterly spreadsheet. Aggregation under a delegated administrator is what makes findings reviewable.
  • Depth per workload type. OS packages, application dependencies, and source code are different scan targets. Some scanners cover all three; some cover only the surface. “All three turned on by default” is the operationally honest setup.
  • Scan frequency. The interesting metric isn’t how often the scanner runs, it’s how soon a new CVE in the database shows up against affected resources. A scanner that re-scores against the current database when an image is pushed and when a new CVE lands turns “weekly Nessus” into “fifteen-minute end-to-end”.
  • Finding suppression. Some CVEs are known to be not applicable (the fix is upstream-only, the vulnerable function isn’t called). Suppression rules filter findings permanently; individual findings can be marked suppressed with an expiry. Suppression rules are the key to keeping the dashboard actionable.

What we’ll filter on

Filtering:

  1. Event-driven continuous scanning. Scan happens at resource-change time, not on a schedule.
  2. Coverage breadth. EC2 OS/app, ECR containers, Lambda code and dependencies.
  3. Org-wide aggregation. Findings consolidate across accounts.
  4. Security Hub integration. Findings surface in the Org security dashboard.
  5. Low operational overhead. No agents to manage separately from SSM.

The vulnerability-scanning landscape

1. Weekly Nessus + quarterly pen-test (status quo). Scheduled, periodic, labour-intensive for the Lambda side. Fails event-driven.

2. ECR basic scanning (Clair) + periodic EC2 scans. Works for ECR on push; fails for Lambda and for continuous EC2 scanning. Clair’s CVE coverage is narrower than Inspector’s.

3. Amazon Inspector, EC2 scanning only. Enable Inspector for EC2 in each account; instances with SSM agent get scanned on launch and daily thereafter. Coverage for OS packages; enable deep scanning for app packages.

4. Amazon Inspector, all three (EC2 + ECR + Lambda). Enable Inspector for all scan targets in each account. Continuous scanning across EC2 OS/app, ECR container images on push, Lambda on deploy. Findings aggregate in Inspector’s console.

5. Amazon Inspector delegated admin + Organizations integration. Delegated admin account manages Inspector across every member account; findings from every account aggregate into the delegated admin console and flow into Security Hub.

6. Third-party (Wiz, Prisma Cloud, Aqua). Broader coverage including Kubernetes runtime, infrastructure-as-code scanning, posture management. Licence cost. Valid alongside Inspector; not a replacement when AWS-native is the requirement.

Side by side

Option Event-driven Coverage breadth Org aggregation Security Hub Ops overhead
Nessus + pen-test EC2 (some) Manual Manual High
ECR basic + periodic EC2 Partial (ECR only) ECR, EC2 Partial Medium
Inspector (EC2 only) ✓ (EC2) EC2 Partial Low
Inspector all-three EC2, ECR, Lambda Partial Low
Inspector delegated admin EC2, ECR, Lambda Low
Third-party (Wiz, Prisma) Wide Partial Medium

Inspector with delegated administrator covers the AWS surface continuously, aggregates findings org-wide, and flows into Security Hub. The pick.

What Inspector scans and when

Scan targets Inspector Outputs EC2 instances SSM agent + InspectorInstanceProfile OS packages + (deep scan) app packages trigger: launch, daily, CVE update ECR repositories enhanced scanning enabled per repo OS layers + language deps trigger: push, CVE update, manual Lambda functions zip + container deployments dependencies + (code scan) static analysis trigger: create, update, CVE update Coverage notes not covered: K8s runtime, IaC, IAM GuardDuty handles runtime threats IAM Access Analyzer handles IAM Delegated admin account aggregates findings from member accounts one console, one API surface CVE data sources NIST NVD (base) vendor advisories (RHEL, Amazon, Ubuntu) continuous refresh Suppression rules filter by CVE, severity, resource tag manual suppression with expiry Inspector Scores Inspector Score: 0-10 per finding modifiers: reachability, exploit availability SBOM export CycloneDX, SPDX for each scan target S3 per delegated admin config Security Hub findings in ASFF format org-aggregated security dashboard EventBridge Inspector Finding events → Lambda, Step Functions, SNS S3 archive findings + SBOMs partition by account / date Remediation hooks low-severity: auto-patch via SSM high-severity: page security Reporting Athena over S3, weekly exec summary
Three scan surfaces, one Inspector service, three categories of output. The event triggers are what make it continuous rather than periodic.

The pick in depth

Delegated administrator setup. The Organization’s management account delegates Inspector administration to the security account: inspector2 enable-delegated-admin-account. The security account now sees findings from every member account with Inspector enabled. The management account stays out of day-to-day operations.

Enabling scan targets. From the delegated admin account, inspector2 enable --resource-types EC2 ECR LAMBDA LAMBDA_CODE --account-ids <all>. Each enabled type turns on scanning in every specified account:

  • EC2: instances with SSM agent are enrolled automatically; Inspector uses the SSM agent to collect package inventory, scans against the CVE database. Deep scanning (enabled by default from 2022) covers application packages in addition to OS packages.
  • ECR: enhanced scanning enabled on repositories; each image push triggers a scan; rescans happen continuously as CVEs update. Scanning can be configured as SCAN_ON_PUSH only or CONTINUOUS (the default, and the one you want).
  • LAMBDA: function dependencies scanned on create/update.
  • LAMBDA_CODE: static analysis of function source using CodeGuru Security engines. Opt-in, detects common injection and logic patterns.

Finding flow to Security Hub. Security Hub integration with Inspector is a one-line enable. Inspector findings automatically appear in Security Hub in ASFF (AWS Security Finding Format). The Org-aggregated Security Hub view in the delegated admin account shows findings from every account. Filters by ProductName=Inspector, by severity, by resource tag keep the dashboard workable.

EventBridge for automation. A default EventBridge rule in each account (or in the delegated admin account, with cross-account events enabled) matches Inspector Finding events:

{
  "source": ["aws.inspector2"],
  "detail-type": ["Inspector2 Finding"],
  "detail": {
    "severity": [{"anything-but": "INFORMATIONAL"}]
  }
}

Targets: Lambda for low-severity auto-remediation (trigger SSM Patch Manager for EC2 OS CVEs, trigger a CodePipeline to rebuild an ECR image), SNS for high-severity pages to the security team, and a Firehose that archives every finding to S3 for long-term analytics.

Suppression rules. Inspector findings include CVEs that are technically present but not relevant (the vulnerable function isn’t called, the fix is upstream-unavailable, the exposure is behind multiple layers of defence). Suppression rules filter these out of the primary view without deleting the underlying finding. Rules match on finding-criteria (CVE ID, package name, resource tag, resource ARN) and apply automatically to existing and future findings.

Example suppression:

{
  "filterCriteria": {
    "vulnerabilityId": [{"comparison": "EQUALS", "value": "CVE-2024-12345"}],
    "resourceTags": [{"comparison": "EQUALS", "key": "Environment", "value": "dev"}]
  },
  "reason": "CVE-2024-12345 false positive; fix confirmed via vendor",
  "name": "cve-2024-12345-dev-suppressed"
}

Suppression without expiry stays until manually removed; suppressions should be reviewed quarterly to avoid building up debt.

SBOM export. Inspector can write Software Bill of Materials (SBOMs) for every scanned resource to an S3 bucket, in CycloneDX or SPDX format. Useful for supply-chain audit, license compliance, and forensics (“this CVE-vulnerable library was in these services six months ago”). Configuration is per delegated admin: a single S3 bucket, KMS key, and update frequency.

A worked finding

Developer pushes @acme/payment-service:v1.5.0 to ECR, Amazon Linux 2023 base image, Node.js dependencies via npm ci during build:

  1. ECR PutImage completes. ECR event fires Inspector scan.
  2. Inspector downloads the image layers, extracts the package inventory (RPM database, node_modules/**/package.json), matches against the CVE database.
  3. Finding: axios@1.3.4 has CVE-2028-5678 (severity HIGH). Inspector creates an Inspector finding with the vulnerable package, the image URI, the resource tags, and the Inspector Score.
  4. Security Hub receives the finding in ASFF within seconds. Dashboard shows “1 new HIGH severity in payment-service”.
  5. EventBridge rule matches the HIGH severity finding, invokes the SNS page to the security team.
  6. Security team views the finding, confirms axios is used in a code path, files a ticket with the application team. The ticket links to the ECR repo, the image tag, and the exact Node.js dependency.
  7. Application team updates package.json to axios@1.6.0, pushes v1.5.1. Inspector scans the new image, the finding is not present, the original finding on v1.5.0 remains open until that image is deleted (or can be explicitly resolved).

Without Inspector, the team finds the CVE at quarterly pen-test time. With Inspector, it’s in Security Hub before the developer has finished their coffee.

Inspector Score and the prioritisation question

The Inspector Score is a modified CVSS score. Base CVSS gives the vulnerability’s theoretical severity; Inspector Score modifies it based on:

  • Exploit availability. Known public exploit raises the score; no known exploit lowers it.
  • Reachability. The vulnerable function is called in the codebase (raises the score) vs the library is installed but the function is unreachable (lowers it). Inspector uses code-path analysis where available.
  • Resource exposure. A publicly exposed EC2 instance gets a higher effective score than a private-subnet database.
  • Active state. An ECR image currently running as a Lambda function vs a stale image nobody pulls.

The Inspector Score is what the dashboard sorts by; it correlates more closely to real risk than raw CVSS. Prioritisation by Inspector Score, not CVE count, is the difference between closing the five findings that matter this week and chasing the 500 that don’t.

What’s worth remembering

  1. Inspector covers EC2, ECR, and Lambda natively. One service, three scan targets, continuous scanning on each. Not a replacement for GuardDuty (runtime), IAM Access Analyzer (IAM), or Kubernetes runtime scanners.
  2. Delegated administrator aggregates org-wide. Enable from the management account via enable-delegated-admin-account; the security account sees findings from every member account.
  3. EC2 scans use the SSM agent. No separate Inspector agent; SSM agent + instance profile with the right permissions + Inspector enabled for EC2 type.
  4. ECR enhanced scanning covers OS + language dependencies. Basic scanning is Clair-based and OS-only; enhanced (Inspector) is the broader option. Continuous scanning re-runs as CVEs update.
  5. Lambda scanning covers dependencies by default. LAMBDA_CODE (opt-in) adds static analysis via CodeGuru Security. Both zip and container-image deployments.
  6. Findings flow to Security Hub in ASFF. Default integration; Org-aggregated view in the delegated admin account. EventBridge rules route findings to remediation automation.
  7. Inspector Score modifies CVSS with context. Exploit availability, reachability, resource exposure, active state. Prioritise by Inspector Score; chasing raw CVE counts drowns the dashboard.
  8. Suppression rules are essential. Without them, known-not-applicable findings clutter the dashboard and teams stop paying attention. With them, every visible finding is actionable. Review suppressions quarterly.

Continuous scanning across every surface AWS knows how to inspect, aggregated across the Organization, flowing into Security Hub, with context-aware prioritisation. The CVE that lands in NVD at 14:00 shows up against every affected image, instance, and function by 14:15, and the findings that matter are sorted to the top. Weekly Nessus scans stop being the detection layer; they become the corroboration layer for what Inspector already flagged.

These posts are LLM-aided. Backbone, original writing, and structure by Craig. Research and editing by Craig + LLM. Proof-reading by Craig.