Skip to main content
emnode / learn
Compliance

Keep software and engines patched

One capability across databases, runtimes, clusters and instances: make sure no workload runs on an unsupported or unpatched version that has stopped receiving security fixes.

14 min·10 sections·AWS

Last reviewed

Keeping software patched: the basics

What does "unpatched" actually mean across managed AWS services?

"Managed" does not mean "automatically kept current." AWS manages the infrastructure, but whether a workload follows the supported version track is a setting your team chooses, and it shows up in many shapes. RDS, DMS and ElastiCache have an auto-minor-version-upgrade flag that, when off, freezes the engine on a version accumulating CVEs. Lambda runtimes, EKS Kubernetes versions, ECS Fargate platform versions, Elastic Beanstalk platforms, Glue versions, OpenSearch and Redshift engines all have a deprecation lifecycle: when the upstream project stops shipping security fixes, AWS follows, and a workload left behind runs on a frozen base. SSM patch compliance (SSM.2) tracks the same idea for the OS on managed EC2 instances. The risk is identical everywhere: code or an engine running on a version nobody is patching any more.

AWS Security Hub turns each of these into its own control, which is why a single estate can fail a dozen patching checks at once. RDS.13, RDS.35 and RDS.51 cover auto minor upgrades on instances and clusters, DMS.6 and ElastiCache.2 cover their engines, Redshift.6 covers major-version upgrades, Lambda.2 covers deprecated runtimes, EKS.2 and EKS.9 cover the cluster control plane and node groups, ECS.10 covers Fargate platform versions, ElasticBeanstalk.2 covers managed platform updates, Glue.4 covers supported Glue versions, Opensearch.10 covers the latest service software, EC2.24 covers paravirtual instance types, and SSM.2 covers OS patch compliance. They look like separate problems, but they are one capability: stay on a version that is still getting security fixes.

Most of this is drift, not intent. A launch template left the auto-upgrade flag off, a Lambda runtime quietly hit end-of-life, an EKS cluster slipped past standard support, an instance fell out of patch compliance. Unlike many findings, several of these have a hard expiry: AWS publishes deprecation dates 12 or more months in advance and will eventually force the change on its own schedule. The job is to find every workload on an unsupported or unpatched version, upgrade the production ones before the deadline, and enforce supported versions as the default so the finding stops recurring.

In this lesson you will learn how AWS expresses version support across databases, runtimes, clusters and instances, how to find every workload on an unsupported or unpatched version, and how to bring them current without breaking the few that legitimately pin a version. The Controls this lesson covers section lists every Security Hub control in this capability, each linking to a deep page with the exact check and a copy-and-paste fix.

Fun fact

The patch that arrived at 2 a.m. anyway

A team running a production PostgreSQL instance turned its auto-minor-version-upgrade flag off years earlier to avoid surprises, then never scheduled a manual upgrade, and the engine drifted toward end-of-support. AWS reserves the right to apply a minor upgrade even when the flag is off for a critical security issue or an end-of-support version, and that is exactly what happened: AWS forced the upgrade in the next maintenance window. The team got the surprise they had spent years trying to avoid, on AWS's schedule instead of their own. The pattern repeats across the capability: leave a Lambda runtime past its published deprecation date and AWS eventually blocks invocations, leave an EKS cluster past extended support and AWS auto-upgrades the control plane when it chooses. Falling behind does not avoid the upgrade; it just hands AWS the timing.

Finding unpatched workloads across an estate

Dev runs the security cadence at a mid-sized SaaS company mid-way through a SOC 2 and PCI renewal. Security Hub shows patching failures spread across RDS, Lambda and EKS in three accounts, and the auditor's pre-read has flagged unpatched systems as an area of focus.

Rather than work the findings one by one, he starts with the data tier, where an unpatched engine is the highest-impact and most audit-relevant, listing which RDS instances have automatic minor upgrades disabled so he can separate the production databases that must be fixed from the dev instances that the flag was simply left off on, before changing anything.

Start with the data tier. RDS instances with auto minor version upgrade off will sit on an old engine accumulating CVEs until a human intervenes.

$ aws rds describe-db-instances --query 'DBInstances[?AutoMinorVersionUpgrade==`false`].[DBInstanceIdentifier,Engine,EngineVersion]' --output table
------------------------------------------------
| prod-orders | mysql | 8.0.35 |
| prod-billing | postgres | 15.4 |
| dev-sandbox | mysql | 8.0.35 |
------------------------------------------------
# Two production databases frozen on old minor versions; the dev sandbox can follow later.

Auto-upgrade-off production databases are the highest-value target in this group, especially anything in audit scope. Fix the production ones first, then document any deliberate version pin as an exception.

How AWS decides a version is unsupporteddeep dive

Most patching controls resolve to one of two mechanisms. The first is an opt-in upgrade flag: RDS, DMS and ElastiCache expose an AutoMinorVersionUpgrade boolean (Redshift has an equivalent for major versions, Elastic Beanstalk a managed-platform-updates setting) that, when on, applies recommended backwards-compatible upgrades during the maintenance window. A minor upgrade never crosses a major boundary, so it is safe to enable broadly: it cannot silently jump you to a version your application has not been tested against. The second is a published deprecation lifecycle: Lambda runtimes, EKS Kubernetes versions, ECS Fargate platforms, Glue versions and OpenSearch service software each have dated end-of-support, after which AWS stops patching and eventually forces or blocks the workload. SSM.2 is a third shape entirely: it reads OS patch compliance reported by the SSM agent on managed EC2 instances.

The lifecycle services share a hard edge that the flag-based ones soften. Lambda deprecates runtimes in three phases roughly 60 days apart, ending in blocked invocations and a failure mode that is silent except in CloudWatch. EKS gives roughly 14 months of standard support, then about a year of extended support at a per-cluster-hour surcharge, then a forced auto-upgrade. In both cases the schedule is published 12 or more months ahead, so a missed deadline is a planning gap, not a surprise. Upgrades are also often sequential and irreversible: EKS moves one minor version at a time and cannot roll back, so deprecated-API pre-flight checks matter.

Several capabilities split control plane from workers because they version independently, which is why EKS.2 (the cluster) and EKS.9 (node groups) are scored separately and almost always fail together: you upgrade the control plane first, then bring the nodes up to match. Read replicas carry their own auto-upgrade flag independent of the primary. The strongest end state is not just upgrading today but enforcing supported versions as a provisioning default through infrastructure-as-code and AWS Config rules (for example rds-automatic-minor-version-upgrade-enabled), backed by SNS or EventBridge alerts on the published deprecation events so upgrades are scheduled while a version is still supported.

What is the impact of running unpatched versions?

The direct impact is unpatched security vulnerabilities on systems that often hold or process sensitive data. Minor versions and supported runtimes are where engine and language CVEs get fixed: privilege-escalation bugs, denial-of-service flaws, authentication weaknesses. With upgrades off or a runtime deprecated, a workload can sit for months on a version with publicly documented, exploitable holes. NIST 800-53 SI-2 (flaw remediation) and PCI DSS 6.3.3 exist specifically because unpatched data stores and runtimes are a top-tier breach vector.

The second-order impact is operational risk concentrated into the worst possible moment. Falling behind does not exempt you from the upgrade: AWS forces RDS minor upgrades for critical issues, blocks Lambda invocations at the end of the deprecation lifecycle, and auto-upgrades EKS clusters past extended support. So the realistic outcome of "leave it" is not "never upgrade," it is "upgrade on AWS's emergency timeline, often with little room to test, possibly during your peak." You trade many small, scheduled, low-risk upgrades for a few large, unscheduled, high-stress ones, and the lifecycle failures (blocked Lambda invocations, an EKS auto-upgrade) tend to surface as silent outages.

On the compliance side, these controls map to CIS, NIST and PCI DSS, so an unpatched workload is a direct audit finding, and a persistent High-severity finding past a published deprecation date is impossible to wave away as a recent oversight. The cost angle runs in your favour: most fixes are free, the EKS surcharge falls off once you upgrade, and newer runtimes bill less per invocation, so this is one of the highest-leverage-to-effort moves in the whole control set.

How do you bring workloads current safely?

Work the capability as one loop rather than chasing individual findings. The order matters: prioritise production and anything in audit scope or near a published deadline, pre-flight breaking changes, and enforce supported versions as the default so the finding stops recurring.

1. Inventory every workload by version and support status

Across services and every account and region, list the workloads that are behind: RDS, DMS and ElastiCache instances with auto-upgrade off (including read replicas, which have their own flag), Lambda functions on deprecated runtimes, EKS clusters and node groups past standard support, ECS Fargate platform versions, Glue versions, and EC2 instances out of SSM patch compliance. Map each against the published deprecation calendar, capture the environment tag, and flag anything already past end-of-support: those carry live, exploitable vulnerabilities right now.

2. Pre-flight breaking changes before upgrading the lifecycle services

Minor RDS, DMS and ElastiCache upgrades are backwards-compatible and safe to enable broadly. The lifecycle services are not free upgrades: a Lambda runtime bump can hit changed language APIs or native-binary layers, and an EKS upgrade can break workloads calling removed Kubernetes APIs. Test on the target version in staging with production-like input, check addon compatibility, and rebuild custom layers against the new base image before touching production.

3. Upgrade production first, on a planned window

For flag-based services, enable the auto-upgrade flag and leave the change to land in the maintenance window rather than mid-traffic. For lifecycle services, upgrade one minor version at a time where required (EKS), update Lambda runtimes through your IaC pipeline, and do it during a planned change window rather than waiting for AWS to force it on its own schedule. For a database or Kubernetes version that must stay pinned (vendor certification, a known regression), record it as a tracked exception with an owner and a re-review date, not a silent skip.

4. Ratchet it in with defaults and a deprecation calendar

Set the auto-upgrade flag and supported-version pins in your CloudFormation and Terraform modules so new workloads arrive current, add AWS Config rules to catch drift, and subscribe to the AWS Health Dashboard and EKS deprecation events via SNS or EventBridge. Put each published deprecation date on the team calendar with 90 days of lead time so upgrades are scheduled while a version is still supported, which keeps the EKS surcharge from ever starting and the Lambda invocation block from ever arriving.

# Enable auto minor version upgrade on every RDS instance that has it disabled.
for id in $(aws rds describe-db-instances \
    --query 'DBInstances[?AutoMinorVersionUpgrade==`false`].DBInstanceIdentifier' --output text); do
  aws rds modify-db-instance --db-instance-identifier "$id" \
    --auto-minor-version-upgrade --no-apply-immediately
done

# Move a deprecated Lambda function to a supported runtime.
aws lambda update-function-configuration --function-name auth-token-issuer \
  --runtime nodejs20.x

# Upgrade an out-of-support EKS control plane one minor version at a time (then catch up node groups).
aws eks update-cluster-version --name prod-payments --kubernetes-version 1.29

Quick quiz

Question 1 of 5

Security Hub shows patching failures across RDS, Lambda and EKS. What is the most efficient way to think about them?

You can now treat patching as one capability rather than a scatter of findings: inventory every workload by version and support status, pre-flight breaking changes on the lifecycle services, upgrade production first on a planned window (ahead of any published deadline), and ratchet the estate shut with supported-version defaults, Config rules and a deprecation calendar. The Controls this lesson covers section below links every control in this group to its deep page and fix.

Back to the library

Controls this lesson covers

One capability, many AWS Security Hub controls. This lesson is the shared playbook; each control below keeps its own deep page with the exact check, severity and a copy-and-paste fix.