<?xml version="1.0" encoding="UTF-8" standalone="no"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" version="2.0">

<channel>
	<title>AWS Compute Blog</title>
	<atom:link href="https://aws.amazon.com/blogs/compute/feed/" rel="self" type="application/rss+xml"/>
	<link>https://aws.amazon.com/blogs/compute/</link>
	<description/>
	<lastBuildDate>Thu, 29 Oct 2026 18:23:18 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	
	<item>
		<title>Unlocking full-stack observability for AWS Outposts</title>
		<link>https://aws.amazon.com/blogs/compute/unlocking-full-stack-observability-for-aws-outposts/</link>
		
		<dc:creator><![CDATA[Aishwariya Khiani]]></dc:creator>
		<pubDate>Thu, 29 Oct 2026 18:23:18 +0000</pubDate>
				<category><![CDATA[AWS Outposts]]></category>
		<category><![CDATA[Technical How-to]]></category>
		<guid isPermaLink="false">2255292e50734842343236fd56776a061584b037</guid>

					<description>Learn how to build end-to-end observability for AWS Outposts across four dimensions: network, storage, compute, and containers. This post uses AWS Systems Manager, Amazon CloudWatch, and Amazon EventBridge for unified visibility and automated incident response across hybrid infrastructure spanning your data center and an AWS Region.</description>
										<content:encoded>&lt;p&gt;Your team just deployed &lt;a href="https://aws.amazon.com/outposts/" target="_blank" rel="noopener"&gt;AWS Outposts&lt;/a&gt; to run latency-sensitive workloads on-premises, and now you need to monitor infrastructure that spans both your data center and an AWS Region. Some services run locally on the Outposts, and others depend on Regional endpoints. A network blip between the two can cause silent failures that traditional monitoring tools miss entirely.&lt;/p&gt; 
&lt;p&gt;AWS Outposts extends native AWS services to on-premises environments, but this hybrid topology introduces monitoring challenges that don’t exist in pure-cloud or pure-on-premises setups. Control planes are distributed, critical operations depend on AWS Region connectivity, and fixed, finite capacity requires proactive capacity planning.&lt;/p&gt; 
&lt;p&gt;In this post, you will learn how to build end-to-end observability for Outposts using &lt;a href="https://aws.amazon.com/systems-manager/" target="_blank" rel="noopener"&gt;AWS Systems Manager&lt;/a&gt;, &lt;a href="https://aws.amazon.com/cloudwatch/" target="_blank" rel="noopener"&gt;Amazon CloudWatch&lt;/a&gt;, and &lt;a href="https://aws.amazon.com/eventbridge/" target="_blank" rel="noopener"&gt;Amazon EventBridge&lt;/a&gt;, covering four monitoring dimensions:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Network – Connectivity status, BGP sessions, and Regional service dependency tracking&lt;/strong&gt;.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;For dependency tracking, watch each Regional service’s own CloudWatch metrics together with the service-link ConnectedStatus: that pairing tells a dependency failure apart from a connectivity drop. For example, AWS Directory Service (DirectoryReachability, AuthenticationFailures), Amazon Relational Database Service (Amazon RDS) (ReplicaLag, DatabaseConnections), and so on.&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Storage&lt;/strong&gt; – &lt;a href="https://aws.amazon.com/s3/" target="_blank" rel="noopener"&gt;Amazon Simple Storage Service (Amazon S3)&lt;/a&gt; on Outposts capacity, Amazon Elastic Block Store (Amazon EBS) volume utilization, and replication health.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Compute&lt;/strong&gt; – Instance-level metrics, micro-architectural performance, and enhanced networking.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Containers&lt;/strong&gt; – &lt;a href="https://aws.amazon.com/eks/" target="_blank" rel="noopener"&gt;Amazon Elastic Kubernetes Service (Amazon EKS)&lt;/a&gt; on Outposts with Prometheus-based Kubernetes monitoring.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;By the end, you will have a monitoring architecture that gives you unified visibility across your hybrid environment and catches issues before your users do.&lt;/p&gt; 
&lt;h2 id="building-a-monitoring-foundation-with-aws-systems-manager"&gt;Building a monitoring foundation with AWS Systems Manager&lt;/h2&gt; 
&lt;p&gt;The following sections detail how to configure each component of the Systems Manager foundation for your Outposts environment.&lt;/p&gt; 
&lt;h3 id="centralized-management-architecture"&gt;Centralized management architecture&lt;/h3&gt; 
&lt;p&gt;Systems Manager provides the foundation for Outposts monitoring with centralized management across hybrid environments. Configure it to span your cloud and on-premises infrastructure so you get unified visibility, automated operations, and consistent policy enforcement across your distributed AWS resources.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;SSM Agent deployment&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;The Systems Manager agent (SSM Agent) is the basis for monitoring. Use the following commands to install the SSM Agent on your Outpost servers.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;# OS-agnostic SSM Agent installation via user data
# For Amazon Linux/RHEL/CentOS
sudo yum update -y
sudo yum install -y amazon-ssm-agent
sudo systemctl enable amazon-ssm-agent
sudo systemctl start amazon-ssm-agent

# For Ubuntu/Debian
sudo apt-get update -y
sudo apt-get install -y amazon-ssm-agent
sudo systemctl enable amazon-ssm-agent
sudo systemctl start amazon-ssm-agent

# For Windows (PowerShell)
Invoke-WebRequest -Uri "https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/windows_amd64/AmazonSSMAgentSetup.exe" -OutFile "AmazonSSMAgentSetup.exe"
Start-Process -FilePath "AmazonSSMAgentSetup.exe" -ArgumentList "/quiet" -Wait&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;&lt;strong&gt;OpsCenter integration&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;Systems Manager OpsCenter provides incident management capabilities that extend beyond basic alerting:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Automated OpsItem creation&lt;/strong&gt;: Configure Amazon EventBridge to automatically create operational work items when specific conditions are met.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Runbook integration&lt;/strong&gt;: Link automated remediation runbooks directly to OpsItems for immediate response.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Cross-service correlation&lt;/strong&gt;: Aggregate related issues across multiple AWS services into single operational views.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Historical analysis&lt;/strong&gt;: Use OpsCenter’s data retention for trend analysis and continuous improvement.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;strong&gt;Patch management strategy&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;Implement a patch management approach that addresses the unique requirements of Outposts:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-json"&gt;{
  "PatchGroups": [
    {
      "Name": "OutpostsCriticalSystems",
      "MaintenanceWindow": "Sunday 02:00-04:00 UTC",
      "PatchBaseline": "Custom-Security-Critical"
    },
    {
      "Name": "OutpostsApplicationServers",
      "MaintenanceWindow": "Sunday 04:00-06:00 UTC",
      "PatchBaseline": "Custom-Application-Stable"
    }
  ]
}&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Systems Manager Patch Manager requires the SSM Agent to communicate with Regional endpoints through the service link. If the service link is degraded, patching operations will fail.&lt;/p&gt; 
&lt;h3 id="personal-health-dashboard-integration"&gt;Personal Health Dashboard integration&lt;/h3&gt; 
&lt;p&gt;The integration between AWS Personal Health Dashboard (PHD) and OpsCenter creates a proactive monitoring workflow. When an Outposts health event occurs, this rule automatically creates an OpsItem in Systems Manager, giving your operations team a single view for triage.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Automated event processing&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;Configure Amazon EventBridge rules to automatically process PHD events:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-json"&gt;{
  "Rules": [
    {
      "Name": "OutpostsPHDIntegration",
      "EventPattern": {
        "source": ["aws.health"],
        "detail-type": ["AWS Health Event"],
        "detail": {
          "service": ["OUTPOSTS"],
          "eventTypeCategory": ["issue", "scheduledChange"]
        }
      },
      "Targets": [
        {
          "Id": "CreateOpsItem",
          "Arn": "arn:aws:ssm:region:account:opsitem",
          "RoleArn": "arn:aws:iam::account:role/EventBridge-OpsCenter-Role"
        }
      ]
    }
  ]
}&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h2 id="monitoring-dimensions"&gt;Monitoring dimensions&lt;/h2&gt; 
&lt;p&gt;This section covers the four key monitoring dimensions for Outposts, with specific metrics, configurations, and alerting strategies for each.&lt;/p&gt; 
&lt;h3 id="network-monitoring-and-notification"&gt;1. Network monitoring and notification&lt;/h3&gt; 
&lt;p&gt;Network monitoring for Outposts requires approaches that account for the hybrid nature of the deployment:&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Multi-layer connectivity monitoring&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;Implement monitoring across multiple network layers:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Physical layer&lt;/strong&gt;: Monitor fiber-optic connections, network equipment health, and environmental factors. 
  &lt;ul&gt; 
   &lt;li&gt;&lt;strong&gt;ConnectedStatus&lt;/strong&gt;.&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-1.jpg" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-1.jpg" alt="CloudWatch graph of the ConnectedStatus metric for an Outposts service link" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 1: ConnectedStatus metric for the Outposts service link&lt;/p&gt;
&lt;/div&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Network layer&lt;/strong&gt;: Track routing, Border Gateway Protocol (BGP) sessions, and inter-rack connectivity. 
  &lt;ul&gt; 
   &lt;li&gt;&lt;strong&gt;VIF metrics&lt;/strong&gt;. 
    &lt;ul&gt; 
     &lt;li&gt;VifBgpSessionState.&lt;/li&gt; 
    &lt;/ul&gt; &lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-2.jpg" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-2.jpg" alt="CloudWatch graph of the VifBgpSessionState metric for an Outposts virtual interface" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 2: VifBgpSessionState metric for the Outposts virtual interface&lt;/p&gt;
&lt;/div&gt; 
&lt;ul&gt; 
 &lt;li&gt;VifConnectionStatus.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-3.jpg" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-3.jpg" alt="CloudWatch graph of the VifConnectionStatus metric for an Outposts virtual interface" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 3: VifConnectionStatus metric for the Outposts virtual interface&lt;/p&gt;
&lt;/div&gt; 
&lt;ul&gt; 
 &lt;li&gt;IfTrafficIn.&lt;/li&gt; 
 &lt;li&gt;IfTrafficOut.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-4.jpg" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-4.jpg" alt="CloudWatch graphs of the IfTrafficIn and IfTrafficOut metrics for Outposts network traffic" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 4: IfTrafficIn and IfTrafficOut metrics for Outposts network traffic&lt;/p&gt;
&lt;/div&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;CapacityExceptions&lt;/strong&gt;.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-5.jpg" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-5.jpg" alt="CloudWatch graph of the CapacityExceptions metric for an Outposts link" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 5: CapacityExceptions metric for the Outposts link&lt;/p&gt;
&lt;/div&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;LagStatus:&lt;/strong&gt;.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-6.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-6.png" alt="CloudWatch graph of the LagStatus metric for an Outposts link aggregation group" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 6: LagStatus metric for the Outposts link aggregation group&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;&lt;strong&gt;Regional service dependency mapping&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;Create detailed dependency maps for critical Regional services:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Amazon Elastic File System (Amazon EFS)&lt;/strong&gt;: Monitor mount target availability and performance across Availability Zones.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;AWS Directory Service&lt;/strong&gt;: Track authentication latency and success rates.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Amazon RDS&lt;/strong&gt;: Monitor cross-Region replication lag and connection pooling.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;AWS Lambda&lt;/strong&gt;: Track cold start times and execution duration for Region-dependent functions.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3 id="storage-monitoring-and-optimization"&gt;2. Storage monitoring and optimization&lt;/h3&gt; 
&lt;p&gt;Outposts provides CloudWatch metrics for both Amazon S3 and Amazon EBS storage resources. Monitor these metrics to track capacity utilization and plan for scaling.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;S3 metrics&lt;/strong&gt;:&lt;/p&gt; 
&lt;p&gt;The &lt;code&gt;S3Outposts&lt;/code&gt; namespace includes the following metrics for Amazon S3 on Outposts buckets. You can monitor the total number of S3 on Outposts bytes provisioned, the total available bytes for objects, and the total size of all objects for a given bucket. Bucket or account-related metrics exist for all direct S3 usage.&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;OutpostTotalBytes&lt;/strong&gt;: The total provisioned capacity in bytes for an Outpost.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-7.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-7.png" alt="CloudWatch graph of the OutpostTotalBytes metric for S3 on Outposts provisioned capacity" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 7: OutpostTotalBytes metric for S3 on Outposts provisioned capacity&lt;/p&gt;
&lt;/div&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;OutpostFreeBytes:&lt;/strong&gt; The count of available bytes on an Outpost to store customer data. &lt;strong&gt;BucketUsedBytes:&lt;/strong&gt; The total size of all objects for the given bucket.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-8.jpg" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-8.jpg" alt="CloudWatch graph of the OutpostFreeBytes metric for available S3 on Outposts capacity" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 8: OutpostFreeBytes metric for available S3 on Outposts capacity&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;Other key metrics to monitor include the following:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;AccountUsedBytes:&lt;/strong&gt; The total size of all objects for the specified Outposts account.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;BytesPendingReplication:&lt;/strong&gt; The total number of bytes of objects that are pending replication for a given replication rule. For more information about how to enable replication metrics, see &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/s3-outposts/replication-between-outposts.html" target="_blank" rel="noopener"&gt;Creating replication rules between Outposts&lt;/a&gt;.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;OperationsPendingReplication:&lt;/strong&gt; The total number of operations that are pending replication for a given replication rule.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;strong&gt;Amazon EBS performance deep dive&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;The following Amazon EBS metrics are available for Outposts volumes:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;EBSVolumeTypeCapacityUtilization:&lt;/strong&gt; The percentage of Amazon EBS volume type capacity in use.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-9.jpg" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-9.jpg" alt="CloudWatch graph of the EBSVolumeTypeCapacityUtilization metric for Outposts volumes" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 9: EBSVolumeTypeCapacityUtilization metric for Outposts Amazon EBS volumes&lt;/p&gt;
&lt;/div&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;EBSVolumeTypeCapacityAvailability:&lt;/strong&gt; The percentage of Amazon EBS volume type capacity available.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-10.jpg" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-10.jpg" alt="CloudWatch graph of the EBSVolumeTypeCapacityAvailability metric for Outposts volumes" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 10: EBSVolumeTypeCapacityAvailability metric for Outposts Amazon EBS volumes&lt;/p&gt;
&lt;/div&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;EBSVolumeTypeCapacityUtilizationGB:&lt;/strong&gt; The number of gigabytes in use for the Amazon EBS volume type.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-11.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-11.png" alt="CloudWatch graph of the EBSVolumeTypeCapacityUtilizationGB metric for Outposts volumes" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 11: EBSVolumeTypeCapacityUtilizationGB metric for Outposts Amazon EBS volumes&lt;/p&gt;
&lt;/div&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;EBSVolumeTypeCapacityAvailabilityGB:&lt;/strong&gt; The number of gigabytes of available capacity for the Amazon EBS volume type.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-12.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-12.png" alt="CloudWatch graph of the EBSVolumeTypeCapacityAvailabilityGB metric for Outposts volumes" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 12: EBSVolumeTypeCapacityAvailabilityGB metric for Outposts Amazon EBS volumes&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Second-generation AWS Outposts racks support both gp2 and gp3 Amazon EBS volume types, whereas first-generation racks support gp2 only.&lt;/p&gt; 
&lt;h3 id="compute-and-capacity-monitoring"&gt;3. Compute and capacity monitoring&lt;/h3&gt; 
&lt;p&gt;Outposts have a fixed capacity that doesn’t auto scale, so compute and capacity metrics are essential for planning. The following instance and capacity metrics are published to the &lt;code&gt;AWS/Outposts&lt;/code&gt; namespace.&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Instance metrics&lt;/strong&gt;.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;strong&gt;UsedInstanceType_Count&lt;/strong&gt;: The number of instance types that are currently in use, including any instance types used by managed services such as &lt;a href="https://aws.amazon.com/rds/" target="_blank" rel="noopener"&gt;Amazon RDS&lt;/a&gt; or &lt;a href="https://aws.amazon.com/elasticloadbalancing/" target="_blank" rel="noopener"&gt;Application Load Balancer&lt;/a&gt;. This metric doesn’t include capacity for any Dedicated Hosts configured on the Outpost.&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-13.jpg" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-13.jpg" alt="CloudWatch graph of the UsedInstanceType_Count metric for Outposts instance usage" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 13: UsedInstanceType_Count metric for Outposts instance usage&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;&lt;strong&gt;InstanceTypeCapacityUtilization:&lt;/strong&gt; The percentage of instance capacity in use. This metric does not include capacity for any Dedicated Hosts configured on the Outpost.&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-14.jpg" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-14.jpg" alt="CloudWatch graph of the InstanceTypeCapacityUtilization metric for Outposts instances" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 14: InstanceTypeCapacityUtilization metric for Outposts instances&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;&lt;strong&gt;InstanceTypeCapacityAvailability:&lt;/strong&gt; The percentage of instance capacity available. This metric doesn’t include capacity for any Dedicated Hosts configured on the Outpost.&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-15.jpg" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-15.jpg" alt="CloudWatch graph of the InstanceTypeCapacityAvailability metric for Outposts instances" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 15: InstanceTypeCapacityAvailability metric for Outposts instances&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;&lt;strong&gt;InstanceFamilyCapacityAvailability:&lt;/strong&gt; The percentage of instance capacity available. This metric does not include capacity for any Dedicated Hosts configured on the Outpost.&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-16.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-16.png" alt="CloudWatch graph of the InstanceFamilyCapacityAvailability metric for Outposts instances" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 16: InstanceFamilyCapacityAvailability metric for Outposts instances&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;&lt;strong&gt;InstanceFamilyCapacityUtilization:&lt;/strong&gt; The percentage of instance capacity in use. This metric doesn’t include capacity for any Dedicated Hosts configured on the Outpost.&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-17.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-17.png" alt="CloudWatch graph of the InstanceFamilyCapacityUtilization metric for Outposts instances" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 17: InstanceFamilyCapacityUtilization metric for Outposts instances&lt;/p&gt;
&lt;/div&gt; 
&lt;h2 id="monitoring-eks-containers-on-aws-outposts-with-amazon-cloudwatch"&gt;Monitoring EKS containers on AWS Outposts with Amazon CloudWatch&lt;/h2&gt; 
&lt;p&gt;AWS Outposts extends AWS infrastructure to your on-premises environment. When running containerized workloads using Amazon EKS (extended clusters) on Outposts, monitoring is critical because unlike the Region, Outposts has fixed capacity that doesn’t auto-scale. Without proper monitoring, pods can fail to schedule, workloads can get OOMKilled, and disk pressure can cause evictions. All of this happens without warning.&lt;/p&gt; 
&lt;p&gt;This section walks through setting up CloudWatch Container Insights for EKS on Outposts, the key metrics to track, and how to build a unified monitoring dashboard.&lt;/p&gt; 
&lt;h3 id="prerequisites"&gt;Prerequisites&lt;/h3&gt; 
&lt;ul&gt; 
 &lt;li&gt;An AWS Outposts rack deployed and connected to your parent Region.&lt;/li&gt; 
 &lt;li&gt;An EKS cluster with worker nodes running on the Outpost.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;kubectl&lt;/code&gt; configured to access your cluster.&lt;/li&gt; 
 &lt;li&gt;AWS Command Line Interface (AWS CLI) installed and configured.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3 id="step-1-launch-self-managed-worker-nodes-with-amazon-linux-2023-al2023-and-nodeadm"&gt;Step 1: Launch self-managed worker nodes with Amazon Linux 2023 (AL2023) and nodeadm&lt;/h3&gt; 
&lt;p&gt;Outpost subnets don’t support EKS managed node groups, so worker nodes come up as a self-managed node group launched from an EC2 launch template.&lt;/p&gt; 
&lt;p&gt;The AMI must be AL2023. Amazon EKS stopped publishing AL2 AMIs on November 26, 2025, and those images no longer receive security patches or bug fixes, as noted in the &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/eks-ami-deprecation-faqs.html" target="_blank" rel="noopener"&gt;Amazon EKS AMI deprecation FAQs&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;AL2023 also changes how a node initializes. It uses &lt;code&gt;nodeadm&lt;/code&gt; rather than the AL2 &lt;code&gt;bootstrap.sh&lt;/code&gt; script, so the user data becomes a YAML &lt;code&gt;NodeConfig&lt;/code&gt; document instead of a shell script. AL2023 expects the cluster endpoint, certificate authority, and service CIDR to be passed in explicitly where AL2 discovered them at boot. Missing them is a common reason nodes launch but don’t join the cluster.&lt;/p&gt; 
&lt;p&gt;&lt;code&gt;aws eks describe-cluster&lt;/code&gt; returns all three:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-yaml"&gt;apiVersion: node.eks.aws/v1alpha1
kind: NodeConfig
spec:
  cluster:
    name: &amp;lt;cluster-name&amp;gt;
    apiServerEndpoint: &amp;lt;from: aws eks describe-cluster&amp;gt;
    certificateAuthority: &amp;lt;from: aws eks describe-cluster&amp;gt;
    cidr: &amp;lt;service CIDR from: aws eks describe-cluster&amp;gt;&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h3 id="step-2-install-the-cloudwatch-observability-add-on"&gt;Step 2: Install the CloudWatch Observability add-on&lt;/h3&gt; 
&lt;p&gt;On an extended cluster, use the CloudWatch Observability EKS add-on to enable Container Insights. The add-on deploys the CloudWatch agent and Fluent Bit as DaemonSets on your Outpost worker nodes, and it collects container, pod, node, and cluster-level metrics automatically.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws eks create-addon \
  --cluster-name your-cluster-name \
  --addon-name amazon-cloudwatch-observability&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;You can also do this from the EKS Console under your cluster’s Add-ons tab.&lt;/p&gt; 
&lt;h3 id="step-3-verify-the-agent-is-running"&gt;Step 3: Verify the agent is running&lt;/h3&gt; 
&lt;p&gt;Confirm that the CloudWatch agent pods are running on each node:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;kubectl get pods -n amazon-cloudwatch&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Expected output:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-text"&gt;NAME                                  READY   STATUS    RESTARTS   AGE
cloudwatch-agent-xxxxx                1/1     Running   0          2m
cloudwatch-agent-yyyyy                1/1     Running   0          2m
fluent-bit-zzzzz                      1/1     Running   0          2m&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;You should see one cloudwatch-agent pod per worker node.&lt;/p&gt; 
&lt;h3 id="step-4-verify-metrics-in-cloudwatch"&gt;Step 4: Verify metrics in CloudWatch&lt;/h3&gt; 
&lt;p&gt;After 5–10 minutes, metrics start flowing into CloudWatch.&lt;/p&gt; 
&lt;ol type="1"&gt; 
 &lt;li&gt;Open the CloudWatch Console.&lt;/li&gt; 
 &lt;li&gt;Navigate to &lt;strong&gt;Metrics&lt;/strong&gt; → &lt;strong&gt;All metrics&lt;/strong&gt;.&lt;/li&gt; 
 &lt;li&gt;Look for the &lt;code&gt;ContainerInsights&lt;/code&gt; namespace.&lt;/li&gt; 
 &lt;li&gt;You will see metrics grouped by &lt;strong&gt;Cluster&lt;/strong&gt;, &lt;strong&gt;Node&lt;/strong&gt;, &lt;strong&gt;Pod&lt;/strong&gt;, &lt;strong&gt;Service&lt;/strong&gt;, and &lt;strong&gt;Namespace&lt;/strong&gt;.&lt;/li&gt; 
&lt;/ol&gt; 
&lt;h3 id="key-metrics-for-eks-containers-on-outposts"&gt;Key metrics for EKS containers on Outposts&lt;/h3&gt; 
&lt;p&gt;Here are the metrics that matter most, organized by level.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Cluster level&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;&amp;nbsp;&lt;/p&gt; 
&lt;table border="1px" width="100%" cellpadding="10px"&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Metric&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Unit&lt;/strong&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;1&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;cluster_node_count&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Total worker nodes in the cluster&lt;/td&gt; 
   &lt;td&gt;Count&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;2&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;cluster_failed_node_count&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Nodes in a failed state&lt;/td&gt; 
   &lt;td&gt;Count&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;p&gt;&lt;strong&gt;Example: cluster_node_count&lt;/strong&gt;&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-18.jpg" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-18.jpg" alt="CloudWatch Container Insights graph of the cluster_node_count metric for an EKS cluster" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 18: cluster_node_count metric in CloudWatch Container Insights&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;&lt;strong&gt;Node level&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;&amp;nbsp;&lt;/p&gt; 
&lt;table border="1px" width="100%" cellpadding="10px"&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Metric&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Unit&lt;/strong&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;1&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;node_cpu_utilization&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;% CPU used on each node&lt;/td&gt; 
   &lt;td&gt;Percent&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;2&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;node_cpu_reserved_capacity&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;% CPU reserved for system components (kubelet, kube-proxy)&lt;/td&gt; 
   &lt;td&gt;Percent&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;3&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;node_memory_utilization&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;% memory used on each node&lt;/td&gt; 
   &lt;td&gt;Percent&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;5&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;node_filesystem_utilization&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;% disk used on each node&lt;/td&gt; 
   &lt;td&gt;Percent&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;6&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;node_network_total_bytes&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Network throughput (rx + tx)&lt;/td&gt; 
   &lt;td&gt;Bytes/sec&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;7&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;node_number_of_running_pods&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Pod count per node&lt;/td&gt; 
   &lt;td&gt;Count&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;8&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;node_number_of_running_containers&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Container count per node&lt;/td&gt; 
   &lt;td&gt;Count&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-19.jpg" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-19.jpg" alt="CloudWatch Container Insights graph of node-level metrics for EKS worker nodes on Outposts" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 19: Node-level Container Insights metrics for EKS worker nodes&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;&lt;strong&gt;Pod level&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;&amp;nbsp;&lt;/p&gt; 
&lt;table border="1px" width="100%" cellpadding="10px"&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Metric&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Unit&lt;/strong&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;1&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;pod_cpu_utilization&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;% CPU used by pods&lt;/td&gt; 
   &lt;td&gt;Percent&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;2&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;pod_cpu_utilization_over_pod_limit&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;CPU usage relative to pod limit&lt;/td&gt; 
   &lt;td&gt;Percent&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;3&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;pod_memory_utilization&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;% memory used by pods&lt;/td&gt; 
   &lt;td&gt;Percent&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;4&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;pod_memory_utilization_over_pod_limit&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Memory usage relative to pod limit&lt;/td&gt; 
   &lt;td&gt;Percent&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;5&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;pod_network_rx_bytes&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Bytes received per second&lt;/td&gt; 
   &lt;td&gt;Bytes/sec&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;6&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;pod_network_tx_bytes&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Bytes transmitted per second&lt;/td&gt; 
   &lt;td&gt;Bytes/sec&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;7&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;pod_number_of_container_restarts&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Container restart count (stability indicator)&lt;/td&gt; 
   &lt;td&gt;Count&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-20.jpg" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-20.jpg" alt="CloudWatch Container Insights graph of pod-level metrics for EKS workloads on Outposts" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 20: Pod-level Container Insights metrics for EKS workloads&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;&lt;strong&gt;Service level&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;&amp;nbsp;&lt;/p&gt; 
&lt;table border="1px" width="100%" cellpadding="10px"&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Metric&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Unit&lt;/strong&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;1&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;service_number_of_running_pods&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Running pods per service&lt;/td&gt; 
   &lt;td&gt;Count&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;2&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;namespace_number_of_running_pods&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Running pods per namespace&lt;/td&gt; 
   &lt;td&gt;Count&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-21.jpg" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-21.jpg" alt="CloudWatch Container Insights graph of service-level running pod counts for EKS on Outposts" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 21: Service-level Container Insights metrics for EKS on Outposts&lt;/p&gt;
&lt;/div&gt; 
&lt;h3 id="step-5-build-a-unified-dashboard"&gt;Step 5: Build a unified dashboard&lt;/h3&gt; 
&lt;p&gt;Bring everything together in a single CloudWatch dashboard.&lt;/p&gt; 
&lt;ol type="1"&gt; 
 &lt;li&gt;Go to CloudWatch Console → &lt;strong&gt;Dashboards&lt;/strong&gt; → &lt;strong&gt;Create dashboard&lt;/strong&gt;.&lt;/li&gt; 
 &lt;li&gt;Name it &lt;code&gt;Outposts-EKS-Monitoring&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;Add widgets in this order:&lt;/li&gt; 
&lt;/ol&gt; 
&lt;p&gt;&lt;strong&gt;Row 1 — Outposts infrastructure&lt;/strong&gt;&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;code&gt;InstanceFamilyCapacityUtilization&lt;/code&gt; (line chart)&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;EBSVolumeTypeCapacityUtilization&lt;/code&gt; (line chart)&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;UsedInstanceType_Count&lt;/code&gt; (number widget)&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;strong&gt;Row 2 — Node health&lt;/strong&gt;&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;code&gt;node_cpu_utilization&lt;/code&gt; (line chart)&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;node_memory_utilization&lt;/code&gt; (line chart)&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;node_filesystem_utilization&lt;/code&gt; (line chart)&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;strong&gt;Row 3 — Pod/container workloads&lt;/strong&gt;&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;code&gt;pod_cpu_utilization&lt;/code&gt; (line chart)&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;pod_memory_utilization&lt;/code&gt; (line chart)&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;pod_number_of_container_restarts&lt;/code&gt; (number widget)&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3 id="why-this-matters-on-outposts"&gt;Why this matters on Outposts&lt;/h3&gt; 
&lt;p&gt;In the Region, if your containers need more resources, the infrastructure scales automatically. On Outposts, you have a fixed pool of compute, memory, and storage.&lt;/p&gt; 
&lt;p&gt;Without monitoring:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;Pods fail to schedule when node capacity is exhausted.&lt;/li&gt; 
 &lt;li&gt;Workloads get OOMKilled without warning.&lt;/li&gt; 
 &lt;li&gt;Disk pressure causes pod evictions.&lt;/li&gt; 
 &lt;li&gt;You have no visibility into how close you are to capacity limits.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;By combining Container Insights metrics with Outposts infrastructure metrics in a single dashboard, you get a complete picture, from application-level container health down to physical infrastructure utilization. With it, you can plan capacity proactively before issues affect your workloads.&lt;/p&gt; 
&lt;h3 id="useful-references"&gt;Useful references&lt;/h3&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/eks-on-outposts.html" target="_blank" rel="noopener"&gt;Amazon EKS on AWS Outposts documentation&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-metrics-EKS.html" target="_blank" rel="noopener"&gt;CloudWatch Container Insights metrics for EKS&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href="https://aws.amazon.com/blogs/mt/monitoring-best-practices-for-aws-outposts/" target="_blank" rel="noopener"&gt;Monitoring best practices for AWS Outposts&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href="https://aws.amazon.com/blogs/containers/deploying-containerized-application-on-aws-outposts-with-amazon-eks/" target="_blank" rel="noopener"&gt;Deploying containerized apps on Outposts with EKS&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3OutpostsCapacity.html" target="_blank" rel="noopener"&gt;Managing S3 on Outposts capacity with CloudWatch&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt; 
&lt;p&gt;Monitoring AWS Outposts requires visibility across four dimensions that don’t exist in pure-cloud deployments: Region connectivity health, local storage capacity, compute performance on fixed hardware, and container orchestration across hybrid boundaries. The gap between standard cloud monitoring and what Outposts demands is where incidents hide.&lt;/p&gt; 
&lt;p&gt;In this post, we walked through building that visibility layer using Systems Manager as the management foundation, Amazon CloudWatch for metrics and alarms, and Amazon EventBridge for automated incident response through OpsCenter. Together, these services give you a unified monitoring architecture that spans your data center and the parent Region.&lt;/p&gt; 
&lt;h2 id="next-steps"&gt;Next steps&lt;/h2&gt; 
&lt;p&gt;To get started with the monitoring approach described in this post:&lt;/p&gt; 
&lt;ol type="1"&gt; 
 &lt;li&gt;&lt;strong&gt;Deploy the Systems Manager agent&lt;/strong&gt; to all Outpost instances and verify Region connectivity through the Fleet Manager console.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Set up CloudWatch alarms&lt;/strong&gt; for the critical Outpost metrics. Start with ConnectedStatus, OutpostFreeBytes, and CapacityExceptions before expanding to application-level metrics.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Configure the Amazon EventBridge-to-OpsCenter integration&lt;/strong&gt; shown in this post to automate incident creation for Outposts health events.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Build a CloudWatch dashboard&lt;/strong&gt; that combines network, storage, and compute metrics into a single operational view for your Outpost.&lt;/li&gt; 
&lt;/ol&gt; 
&lt;p&gt;For more information, see the following resources:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href="https://docs.aws.amazon.com/outposts/latest/userguide/outposts-monitoring.html" target="_blank" rel="noopener"&gt;AWS Outposts monitoring best practices&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-managedinstances.html" target="_blank" rel="noopener"&gt;AWS Systems Manager hybrid activations&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href="https://docs.aws.amazon.com/outposts/latest/userguide/outposts-cloudwatch-metrics.html" target="_blank" rel="noopener"&gt;Amazon CloudWatch metrics for Outposts&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-EKS-quickstart.html" target="_blank" rel="noopener"&gt;Container Insights for Amazon EKS&lt;/a&gt;&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p style="clear: both"&gt; &lt;/p&gt;
&lt;hr style="width: 100%"&gt; 
&lt;h2&gt;About the authors&lt;/h2&gt; 
&lt;footer&gt; 
 &lt;div class="blog-author-box" style="padding-top: 2.0em"&gt; 
  &lt;div class="blog-author-image" style="margin-right: 1.0em"&gt;
   &lt;img loading="lazy" class="alignnone size-full" src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-22.jpg" alt="Aishwariya Khiani" width="100" height="133"&gt;
  &lt;/div&gt; 
  &lt;h3 class="lb-h4"&gt;Aishwariya Khiani&lt;/h3&gt; 
  &lt;p style="overflow: hidden"&gt;Aishwariya is a Technical Account Manager at Amazon Web Services with over 9 years of experience across cloud infrastructure, security, and operations. She brings deep expertise in cloud security and Generative AI, working with customers to architect secure, scalable environments and identify meaningful applications of AI that address complex business needs. Aishwariya is committed to helping organizations strengthen their cloud posture, accelerate innovation, and maximize the value of their AWS investments.&lt;/p&gt; 
 &lt;/div&gt; 
 &lt;div class="blog-author-box" style="padding-top: 2.0em"&gt; 
  &lt;div class="blog-author-image" style="margin-right: 1.0em"&gt;
   &lt;img loading="lazy" class="alignnone size-full" src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-23.jpg" alt="Arun Kumar N C" width="100" height="133"&gt;
  &lt;/div&gt; 
  &lt;h3 class="lb-h4"&gt;Arun Kumar N C&lt;/h3&gt; 
  &lt;p style="overflow: hidden"&gt;As an AWS Technical Account Manager specializing in Cloud networking and Generative AI, Arun excels at building strategic customer relationships and providing expert guidance. He helps customers develop scalable, secure, and cost-effective cloud solutions, offering proactive support and tailored advice to optimize AWS environments and drive successful cloud adoption.&lt;/p&gt; 
 &lt;/div&gt; 
 &lt;div class="blog-author-box" style="padding-top: 2.0em"&gt; 
  &lt;div class="blog-author-image" style="margin-right: 1.0em"&gt;
   &lt;img loading="lazy" class="alignnone size-full" src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2334-24.jpg" alt="Anjali Sharma" width="100" height="133"&gt;
  &lt;/div&gt; 
  &lt;h3 class="lb-h4"&gt;Anjali Sharma&lt;/h3&gt; 
  &lt;p style="overflow: hidden"&gt;Anjali is a Senior Technical Account Manager (TAM) at AWS with more than 10 years of IT experience. Her career includes roles as a Cloud Consultant and as an Operations Engineer at AWS Managed Services. In her current role, she partners with global enterprise customers to build secure, resilient, and sustainable solutions on AWS. She is passionate about troubleshooting complex issues and raising operational excellence for her customers, turning findings into prioritized, practical remediation that teams can act on.&lt;/p&gt; 
 &lt;/div&gt; 
&lt;/footer&gt;</content:encoded>
					
		
		
			</item>
		<item>
		<title>Observing AWS Lambda durable functions with the Durable Execution Telemetry Exporter</title>
		<link>https://aws.amazon.com/blogs/compute/observing-aws-lambda-durable-functions-with-the-durable-execution-telemetry-exporter/</link>
		
		<dc:creator><![CDATA[Pooya Paridel]]></dc:creator>
		<pubDate>Wed, 28 Oct 2026 19:36:12 +0000</pubDate>
				<category><![CDATA[Announcements]]></category>
		<category><![CDATA[AWS Lambda]]></category>
		<category><![CDATA[Intermediate (200)]]></category>
		<guid isPermaLink="false">1eb96e4908aff142fc631c6cce7725f59ea8eb07</guid>

					<description>Durable functions span many Lambda invocations, so per-invocation logs answer the wrong question. The Durable Execution Telemetry Exporter is an SDK plugin that emits one complete record per execution to any of 13 destinations with a one-line change, and a companion MCP server lets an AI agent query that data in plain language.</description>
										<content:encoded>&lt;p&gt;A durable function is an AWS Lambda function that might run for minutes, days, or even up to a year. You build these functions with the &lt;a href="https://docs.aws.amazon.com/durable-execution/" target="_blank" rel="noopener"&gt;Durable Execution SDK&lt;/a&gt;, which provides operations such as steps, waits, and parallel. A single durable execution might be spread across many Lambda invocations, with waits and retries in between. So observing a durable execution, made of many invocations, needs different tools. The question that you want answered is rarely “what did this invocation do?” It’s “how far did my durable execution get, which step failed, how many times did it retry, and how long did the whole thing take?”&lt;/p&gt; 
&lt;p&gt;After you run thousands of executions, the questions widen from one execution to all of them. Some questions are operational. Which step fails most often, and with which error? Which step causes the most retries? Did a step get slower after last week’s deployment? Other questions are about the business the workflow runs. Which customers did last night’s payment failures affect? How long does each manual approval step take? Of the orders that started, how many reached the payment step, and where did the rest stop? Answering these questions needs per execution telemetry data that includes relevant data such as status, timing, steps, and the input and output fields that you choose to emit.&lt;/p&gt; 
&lt;p&gt;Traditional Lambda observability works well for a single invocation. Lambda writes a log stream per invocation, so a durable execution that suspends four times writes to four separate log streams, interleaved with every other concurrent execution. Amazon CloudWatch metrics tell you the function’s error rate, but not which of your workflow’s steps is responsible. Distributed tracing, such as AWS X-Ray or OpenTelemetry, shows the timing of one execution. It isn’t built to answer questions across many executions, such as which step failed most often this week. For that, you need one queryable record per execution.&lt;/p&gt; 
&lt;p&gt;Today we’re introducing the &lt;a href="https://docs.aws.amazon.com/durable-execution/sdk-reference/observability/telemetry/" target="_blank" rel="noopener"&gt;Durable Execution Telemetry Exporter&lt;/a&gt;, an observability plugin for AWS Lambda durable functions. We’re also introducing the Durable Execution Telemetry MCP server, a Model Context Protocol (MCP) server that lets an AI coding agent query the telemetry data. The exporter is open source for TypeScript, Python, Java, and Go, in each language’s Durable Execution SDK repository. AWS provides the MCP server as open source in the &lt;a href="https://github.com/aws/aws-durable-execution-sdk-js/blob/main/packages/aws-durable-execution-sdk-js-telemetry-mcp/README.md" target="_blank" rel="noopener"&gt;aws-durable-execution-sdk-js&lt;/a&gt; repository.&lt;/p&gt; 
&lt;p&gt;With a one-line configuration change, you get a record of each execution, with every step, wait, callback, and invoke, including timing, retry attempts, status, and errors. The exporter delivers it to a destination you choose. There’s no custom instrumentation to write and no separate agent to run.&lt;/p&gt; 
&lt;h2 id="how-the-durable-execution-telemetry-exporter-works"&gt;How the durable execution telemetry exporter works&lt;/h2&gt; 
&lt;p&gt;The Durable Execution Telemetry Exporter is a plugin for the durable execution SDK. It runs inside your Lambda function, in the same process as your handler, and subscribes to the SDK’s instrumentation lifecycle. It doesn’t run in your request path.&lt;/p&gt; 
&lt;p&gt;On every invocation of a durable execution, the plugin builds a cumulative snapshot of that execution, rather than a delta or per-invocation view. Because the durable execution SDK replays your handler from the beginning on each resume and the SDK passes the checkpointed state to the plugin, the plugin can reconstruct the whole execution so far from any invocation. That snapshot is a single JSON document called a &lt;code&gt;DurableExecutionTelemetryRecord&lt;/code&gt;:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-json"&gt;{
  "recordType": "DurableExecutionTelemetry",
  "schemaVersion": "1.0",
  "executionArn": "arn:aws:lambda:us-east-1:111122223333:function:order-processor:$LATEST/durable-execution/abc123/inv456",
  "executionName": "abc123",
  "functionName": "order-processor",
  "status": "SUCCEEDED",
  "startTime": "2026-06-16T17:00:22.100Z",
  "endTime": "2026-06-16T17:00:27.514Z",
  "durationMs": 5414,
  "input": { "orderId": "order-12345", "customerId": "cust-789" },
  "output": { "orderId": "order-12345", "status": "completed", "charged": 99.99 },
  "operations": [
    { "name": "validate-order",  "type": "STEP", "status": "SUCCEEDED", "durationMs": 250 },
    { "name": "check-inventory", "type": "STEP", "status": "SUCCEEDED", "durationMs": 350 },
    { "name": "cool-down",       "type": "WAIT", "status": "SUCCEEDED", "durationMs": 5000 },
    { "name": "charge-payment",  "type": "STEP", "status": "SUCCEEDED", "durationMs": 80 }
  ]
}&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Each record is complete on its own. One row in a table is one durable execution, which means the questions you ask (slowest step, most-retried step, executions that failed after the payment step) become ordinary queries instead of requiring you to correlate logs across streams.&lt;/p&gt; 
&lt;h2 id="getting-started"&gt;Getting started&lt;/h2&gt; 
&lt;p&gt;Install the plugin alongside the durable execution SDK:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;npm install @aws/durable-execution-sdk-js-telemetry-exporter&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Then pass it to &lt;code&gt;withDurableExecution&lt;/code&gt;:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-javascript"&gt;import { DurableContext, withDurableExecution } from "@aws/durable-execution-sdk-js";
import { durableExecutionTelemetry } from "@aws/durable-execution-sdk-js-telemetry-exporter";

const handler = async (event: OrderEvent, context: DurableContext) =&amp;gt; {
  const order = await context.step("validate-order", async () =&amp;gt;
    validateOrder(event.orderId),
  );

  const inventory = await context.step("check-inventory", async () =&amp;gt;
    reserveInventory(order),
  );

  await context.wait({ seconds: 30 });

  return await context.step("charge-payment", async () =&amp;gt;
    chargeCustomer(order, inventory),
  );
};

export const lambdaHandler = withDurableExecution(handler, {
  plugins: [durableExecutionTelemetry({})],
});&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;That is the entire integration. With no configuration, the default &lt;code&gt;LambdaLogExporter&lt;/code&gt; writes records as JSON to your function’s own CloudWatch log group. You don’t need to create any infrastructure or grant additional AWS Identity and Access Management (IAM) permissions, because your function already writes its own logs. You can query the result immediately with Amazon CloudWatch Logs Insights:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-plaintext"&gt;fields executionName, status, durationMs
| filter recordType = "DurableExecutionTelemetry" and status = "FAILED"
| sort durationMs desc&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h2 id="choosing-where-records-go"&gt;Choosing where records go&lt;/h2&gt; 
&lt;p&gt;The plugin includes 13 destination exporters so you can send records where they are useful:&lt;/p&gt; 
&lt;table border="1px" width="100%" cellpadding="10px"&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;&lt;strong&gt;Destination&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Exporter&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Good for&lt;/strong&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Function’s own log group&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;LambdaLogExporter&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Getting started, zero setup&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Any CloudWatch log group&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;CloudWatchLogsExporter&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Centralizing records across functions&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Amazon Simple Storage Service (Amazon S3)&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;S3Exporter&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Amazon Athena SQL, long-term retention&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Amazon DynamoDB&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;DynamoDBExporter&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Fast lookup by execution, live dashboards&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Amazon Aurora&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;AuroraExporter&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Joining workflow data with business data&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Amazon Redshift&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;RedshiftExporter&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Large-scale cross-function analytics&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Amazon OpenSearch Service&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;OpenSearchExporter&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Full-text search, dashboards&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Amazon EventBridge&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;EventBridgeExporter&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Alerting and remediation on failure&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Amazon Data Firehose&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;FirehoseExporter&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Fan-out to S3, Splunk, or third parties&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Amazon Simple Queue Service (Amazon SQS)&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;SQSExporter&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Decoupled downstream processing&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Any OTLP endpoint&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;OTelExporter&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Third-party observability platforms&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Any HTTPS endpoint&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;HttpExporter&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Custom backends and webhooks&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Filesystem or Amazon Elastic File System (Amazon EFS)&lt;/td&gt; 
   &lt;td&gt;&lt;code&gt;FileExporter&lt;/code&gt;&lt;/td&gt; 
   &lt;td&gt;Local development, EFS persistence&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;p&gt;The plugin sends records to all configured exporters in parallel. This allows you to route data to different stores based on their characteristics, such as using a fast store for real-time lookups and a less expensive, high-capacity store for long-term storage:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-javascript"&gt;import {
  durableExecutionTelemetry,
  S3Exporter,
  DynamoDBExporter,
  EventBridgeExporter,
} from "@aws/durable-execution-sdk-js-telemetry-exporter";

const telemetry = durableExecutionTelemetry({
  emitMode: "on-complete",
  samplingRate: 1.0,
  exporters: [
    new S3Exporter({ bucket: string }), // Use valid bucket name you own
    new DynamoDBExporter({ tableName: "durable-execution-telemetry-live" }),
    new EventBridgeExporter({}),
  ],
});&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;With the S3 exporter, the plugin writes records under Hive-style partitions (&lt;code&gt;year=YYYY/month=MM/day=DD/&lt;/code&gt;) that an AWS Glue crawler discovers automatically, so Athena queries work without additional modeling:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-sql"&gt;SELECT op.name, COUNT(*) AS failures, AVG(op.durationms) AS avg_ms
FROM durable_execution_telemetry
CROSS JOIN UNNEST(operations) AS t(op)
WHERE status = 'FAILED' AND year = '2026' AND month = '06'
GROUP BY op.name
ORDER BY failures DESC;&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h2 id="controlling-frequency-and-content"&gt;Controlling frequency and content&lt;/h2&gt; 
&lt;p&gt;Three settings govern what a production deployment costs and exposes.&lt;/p&gt; 
&lt;p&gt;&lt;code&gt;emitMode&lt;/code&gt; determines when the plugin sends a record. The default, &lt;code&gt;on-complete&lt;/code&gt;, emits once when an execution reaches &lt;code&gt;SUCCEEDED&lt;/code&gt; or &lt;code&gt;FAILED&lt;/code&gt;. Use &lt;code&gt;on-failure&lt;/code&gt; for the lowest overhead when you only care about errors, or &lt;code&gt;on-change&lt;/code&gt; when you want to watch executions progress in near real time.&lt;/p&gt; 
&lt;p&gt;&lt;code&gt;samplingRate&lt;/code&gt; reduces frequency. The plugin derives the sampling decision from a hash of the execution ARN. The execution ARN is stable across replays, so the decision is deterministic: a sampled-in execution emits all of its records, and a sampled-out execution emits none. You never receive a half-recorded workflow.&lt;/p&gt; 
&lt;p&gt;&lt;code&gt;content&lt;/code&gt; controls what leaves your function. By default, the plugin includes execution input and output as-is, which is convenient in development and often unacceptable in production. Pass a transform to redact:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-javascript"&gt;const telemetry = durableExecutionTelemetry({
  samplingRate: 0.1,
  content: {
    input: (event) =&amp;gt; ({ orderId: event.orderId }),
    output: (result) =&amp;gt; ({ status: result.status }),
  },
});&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Each destination supports different payload sizes: CloudWatch Logs events at 256 KB, DynamoDB items at 400 KB. Each exporter has a &lt;code&gt;maxRecordSizeBytes&lt;/code&gt;, and when a record exceeds it the plugin truncates for one destination without affecting other destinations: operation results first, then whole operations oldest-first, then execution input and output last. The plugin never drops identity and timeline fields, and it marks a trimmed record &lt;code&gt;truncated: true&lt;/code&gt;, so a truncated record is always distinguishable from a complete one. We recommend using &lt;code&gt;content&lt;/code&gt; transforms to bound payloads deliberately rather than relying on truncation.&lt;/p&gt; 
&lt;h2 id="querying-execution-history-from-an-ai-agent"&gt;Querying execution history from an AI agent&lt;/h2&gt; 
&lt;p&gt;Answering “why did last night’s batch fail” requires knowing which data store you configured, which query dialect it uses, and what the record schema looks like. DynamoDB PartiQL, Athena’s Trino SQL, Aurora PostgreSQL, Amazon Redshift, OpenSearch, and CloudWatch Logs Insights all differ.&lt;/p&gt; 
&lt;p&gt;The Durable Execution Telemetry MCP server removes that requirement. It’s a local stdio server that exposes your configured destination to any MCP-capable agent, including Kiro, Claude Code, and Cursor. Add it with one command:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-plaintext"&gt;kiro-cli mcp add \
  --name durable-telemetry \
  --command npx \
  --args "-y,@aws/durable-execution-sdk-js-telemetry-mcp" \
  --env DURABLE_TELEMETRY_DESTINATION_TYPE=dynamodb \
  --env DURABLE_TELEMETRY_DYNAMODB_TABLE_NAME=durable-execution-telemetry-live \
  --env DURABLE_TELEMETRY_REGION=us-east-1 \
  --scope workspace&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Configuration is environment-only and credentials come from the standard AWS SDK provider chain, so there’s no state file and no secret. The server exposes five tools:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;code&gt;test_destination&lt;/code&gt; runs read-only connectivity checks. If a required variable is unset, it names the exact variable and returns without making any AWS call.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;describe_schema&lt;/code&gt; returns the record schema, query dialect, and row cap for whichever destination is configured. Agents should call this before writing a query.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;list_executions&lt;/code&gt; filters by status, function name, and time range with no query language involved. This handles most questions.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;get_execution&lt;/code&gt; fetches one record by execution ARN.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;query&lt;/code&gt; handles questions the filters cannot express.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;You ask a question and the agent picks the tools:&lt;/p&gt; 
&lt;blockquote&gt;
 &lt;p&gt;&lt;em&gt;Which steps in order-processor failed most often in the last 24 hours, and what was the average retry count?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;On the SQL destinations, write each query as a &lt;code&gt;SELECT&lt;/code&gt; statement, or as a &lt;code&gt;WITH&lt;/code&gt; statement that ends in a &lt;code&gt;SELECT&lt;/code&gt;. These are the only forms the server runs. It checks a query before it makes any AWS call, so a statement that would change data never reaches your destination. On the CloudWatch Logs destinations, the Logs Insights query language has no statements that write data. So every query through the server is read-only.&lt;/p&gt; 
&lt;h2 id="best-practices-and-considerations"&gt;Best practices and considerations&lt;/h2&gt; 
&lt;p&gt;&lt;strong&gt;Choose &lt;code&gt;operationDetail&lt;/code&gt; deliberately.&lt;/strong&gt; The default, &lt;code&gt;top-level&lt;/code&gt;, records only top-level operations and produces the same set of operations no matter when a record is emitted. &lt;code&gt;full-tree&lt;/code&gt; includes children of contexts such as map items and parallel branches, but by default the durable execution backend prunes finished contexts’ children from the state passed to later invocations. To keep the full tree across a suspend and resume, also set &lt;code&gt;pluginsConfig.childOperationsDepth&lt;/code&gt; on &lt;code&gt;withDurableExecution&lt;/code&gt;. That preservation has a cost: it forces a replay pass over each preserved context on resume, so enable only the depth you need.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Choose operation names that your destination can query.&lt;/strong&gt; The plugin uses names verbatim as keys and identifiers and never sanitizes them. A &lt;code&gt;.&lt;/code&gt; in a name is a field-path separator in CloudWatch Logs Insights and OpenSearch. Letters, digits, &lt;code&gt;-&lt;/code&gt;, and &lt;code&gt;_&lt;/code&gt; are portable everywhere.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Understand what the plugin cannot see.&lt;/strong&gt; The Durable Execution Telemetry Exporter runs inside your function, so it can only emit records when your function is invoked. Terminal states that originate in the Lambda service without an invocation never reach the plugin: &lt;code&gt;STOPPED&lt;/code&gt; from a manual stop, and &lt;code&gt;TIMED_OUT&lt;/code&gt; when the execution timeout is exceeded. For complete lifecycle coverage, subscribe to Lambda durable execution lifecycle events on the default Amazon EventBridge bus and update your destination from a small handler:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-json"&gt;{
  "source": ["aws.lambda"],
  "detail-type": ["Lambda Durable Execution State Change"],
  "detail": { "status": ["STOPPED", "TIMED_OUT"] }
}&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;&lt;strong&gt;Account for the cost of the destination.&lt;/strong&gt; The plugin adds at most one export each time it emits a record, because it sends only the latest of any updates that pile up. Each record is a complete snapshot, and the latest supersedes all earlier ones. If updates arrive faster than an exporter can handle, the plugin drops the intermediate snapshots. The charges that matter are the ones your destination incurs: CloudWatch Logs ingestion, DynamoDB writes, Aurora capacity, and so on. Combine &lt;code&gt;samplingRate&lt;/code&gt; and &lt;code&gt;emitMode&lt;/code&gt; to control them.&lt;/p&gt; 
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt; 
&lt;p&gt;The Durable Execution Telemetry Exporter gives AWS Lambda durable functions an observability model that matches how they run: one complete record per execution, sent to a destination that fits your team. The Durable Execution Telemetry MCP server lets an AI agent answer questions against that data directly.&lt;/p&gt; 
&lt;p&gt;To get started with durable functions, see the AWS Lambda Developer Guide. For the plugin’s full exporter reference, configuration options, and an AWS Cloud Development Kit (AWS CDK) stack that deploys every destination for testing, see the package &lt;a href="https://github.com/aws/aws-durable-execution-sdk-js/blob/main/packages/aws-durable-execution-sdk-js-telemetry-exporter/README.md" target="_blank" rel="noopener"&gt;README&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;&amp;nbsp;&lt;/p&gt; 
&lt;p style="clear: both"&gt; &lt;/p&gt;
&lt;hr style="width: 100%"&gt; 
&lt;h2&gt;About the author&lt;/h2&gt; 
&lt;footer&gt; 
 &lt;div class="blog-author-box" style="padding-top: 2.0em"&gt; 
  &lt;div class="blog-author-image" style="margin-right: 1.0em"&gt;
   &lt;img loading="lazy" class="alignnone size-full" src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/27/ComputeBlog-2775-1.jpg" alt="Pooya Paridel" width="100" height="133"&gt;
  &lt;/div&gt; 
  &lt;h3 class="lb-h4"&gt;Pooya Paridel&lt;/h3&gt; 
  &lt;p style="overflow: hidden"&gt;Pooya, Senior Software Development Engineer at AWS, has over 25 years of software development experience, including more than 7 years at AWS specializing in AWS Step Functions and Lambda Durable Functions. Before shaping the serverless developer experience for Amazon Web Services, he spent years designing high-impact software across entirely different domains, including real-time financial trading engines, stock exchange platforms, Internet of Things (IoT) systems, and CRM applications for real estate.&lt;/p&gt; 
 &lt;/div&gt; 
&lt;/footer&gt;</content:encoded>
					
		
		
			</item>
		<item>
		<title>Building document-investigation agents with Amazon Bedrock AgentCore and Amazon S3 Files</title>
		<link>https://aws.amazon.com/blogs/compute/building-document-investigation-agents-with-amazon-bedrock-agentcore-and-amazon-s3-files/</link>
		
		<dc:creator><![CDATA[Ben Freiberg]]></dc:creator>
		<pubDate>Tue, 27 Oct 2026 17:16:54 +0000</pubDate>
				<category><![CDATA[Advanced (300)]]></category>
		<category><![CDATA[Amazon Bedrock AgentCore]]></category>
		<category><![CDATA[Amazon Simple Storage Service (S3)]]></category>
		<category><![CDATA[Technical How-to]]></category>
		<guid isPermaLink="false">73595baed628127d0d455c8b4b35ed5867a43a3f</guid>

					<description>Learn how an AWS Lambda function and an Amazon Bedrock AgentCore agent investigate a folder of related documents together through a shared Amazon S3 Files file system, using ordinary file operations instead of object download and upload code.</description>
										<content:encoded>&lt;p&gt;When you investigate a set of documents, you might not know in advance which files you will need. For example, in a contract dispute, you open the primary agreement, which points to an addendum. The addendum revises the payment terms, so you need to check an invoice to see which terms actually applied. The set of required files grows as you read. An AI agent can work like a human analyst. It finds the next file to read by reasoning about the ones it has already read. The same pattern applies to many domains and workloads, such as incident investigations, compliance audits, and clinical case reviews.&lt;/p&gt; 
&lt;p&gt;This kind of investigation needs on-demand access to a whole folder of related files instead of a single predetermined input. The usual approach connects stages with object downloads and uploads. One function pulls objects from &lt;a href="https://aws.amazon.com/s3/" target="_blank" rel="noopener"&gt;Amazon Simple Storage Service (Amazon S3)&lt;/a&gt;, processes them in &lt;code&gt;/tmp&lt;/code&gt;, and writes results back. The next stage repeats the cycle. Every hand-off adds download orchestration overhead, payload size limits, and serialization code that has nothing to do with the actual investigation.&lt;/p&gt; 
&lt;p&gt;&lt;a href="https://aws.amazon.com/s3/features/files/" target="_blank" rel="noopener"&gt;Amazon S3 Files&lt;/a&gt; presents an S3 bucket as a shared file system over Network File System (NFS), with read-after-write consistency, file locking, and POSIX permissions. An AWS Lambda function can mount it directly. &lt;a href="https://aws.amazon.com/bedrock/agentcore/" target="_blank" rel="noopener"&gt;Amazon Bedrock AgentCore&lt;/a&gt; runtime can also mount an S3 Files access point into every agent session at a path you choose, through its bring-your-own file system support. This post shows how to use the two together. An &lt;a href="https://aws.amazon.com/lambda/" target="_blank" rel="noopener"&gt;AWS Lambda&lt;/a&gt; function pre-stages a set of documents onto the shared file system, and an AgentCore agent mounts the same file system to investigate them. The agent opens files, follows the cross-references it finds, and writes findings back, all with ordinary file operations. Neither side needs S3 API calls to hand documents to the other.&lt;/p&gt; 
&lt;h2 id="solution-overview"&gt;Solution overview&lt;/h2&gt; 
&lt;p&gt;The design has two stages that share one Amazon S3 Files file system.&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/26/ComputeBlog-2669-1.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/26/ComputeBlog-2669-1.png" alt="AWS Lambda pre-stage function and Bedrock AgentCore agent sharing one Amazon S3 Files file system backed by an S3 bucket" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 1: A Lambda pre-stage function and an AgentCore agent share one Amazon S3 Files file system, backed by an S3 bucket as the source of truth&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;Stage 1 is a Lambda function. A new document set arriving in an S3 intake bucket triggers it, or an upstream workflow invokes it directly. The function normalizes an incoming document set into one case folder on the mounted file system and writes a &lt;code&gt;manifest.json&lt;/code&gt; that lists the documents. It uses standard file writes, with no object upload code.&lt;/p&gt; 
&lt;p&gt;Stage 2 is an agent on Amazon Bedrock AgentCore runtime, a capability of Amazon Bedrock AgentCore. It mounts the same file system through bring-your-own file system. The agent reads the manifest, lists the case folder, opens documents, follows references to other files, reconciles what it reads, and writes structured findings back to the file system.&lt;/p&gt; 
&lt;p&gt;An S3 bucket backs the file system and remains the source of truth. Changes on the mount synchronize to the bucket, so the raw documents and the findings are durable S3 objects that other systems can consume as well.&lt;/p&gt; 
&lt;h2 id="walking-through-the-design"&gt;Walking through the design&lt;/h2&gt; 
&lt;p&gt;The &lt;a href="https://serverlessland.com/patterns/lambda-s3-files-cdk" target="_blank" rel="noopener"&gt;sample implementation&lt;/a&gt; is a single &lt;a href="https://aws.amazon.com/cloudformation/" target="_blank" rel="noopener"&gt;AWS CloudFormation&lt;/a&gt; template, defining the file system, mount targets, and access point directly against the &lt;code&gt;AWS::S3Files::*&lt;/code&gt; resource types. The template creates an &lt;a href="https://aws.amazon.com/vpc/" target="_blank" rel="noopener"&gt;Amazon Virtual Private Cloud (Amazon VPC)&lt;/a&gt; with private subnets, an S3 bucket, and the S3 Files file system. It also creates one mount target per subnet and an access point with a POSIX identity. The following snippets leave out the VPC, subnet, and &lt;a href="https://aws.amazon.com/iam/" target="_blank" rel="noopener"&gt;AWS Identity and Access Management (IAM)&lt;/a&gt; role resources:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-yaml"&gt;# S3 Files needs a service role to sync with the bucket, and a VPC with private subnets
# for the mount targets (both omitted here for brevity).
FileSystem:
  Type: AWS::S3Files::FileSystem
  Properties:
    Bucket: !GetAtt CaseBucket.Arn
    RoleArn: !GetAtt FileSystemServiceRole.Arn
    AcceptBucketWarning: true

MountTargetA:
  Type: AWS::S3Files::MountTarget
  Properties:
    FileSystemId: !GetAtt FileSystem.FileSystemId
    SubnetId: !Ref PrivateSubnetA
    SecurityGroups: [!Ref FileSystemSecurityGroup]

MountTargetB:
  Type: AWS::S3Files::MountTarget
  Properties:
    FileSystemId: !GetAtt FileSystem.FileSystemId
    SubnetId: !Ref PrivateSubnetB
    SecurityGroups: [!Ref FileSystemSecurityGroup]

AccessPoint:
  Type: AWS::S3Files::AccessPoint
  Properties:
    FileSystemId: !GetAtt FileSystem.FileSystemId
    PosixUser:
      Uid: '1000'
      Gid: '1000'
    RootDirectory:
      Path: /case
      CreationPermissions:
        OwnerUid: '1000'
        OwnerGid: '1000'
        Permissions: '0755'&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;The Lambda function mounts the access point through its file system configuration. The mount path must be under &lt;code&gt;/mnt/&lt;/code&gt; with one subdirectory level, and the function &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/configuration-filesystem-s3files.html#configuration-filesystem-s3files-permissions" target="_blank" rel="noopener"&gt;needs at least 512 MB of memory&lt;/a&gt;. &lt;code&gt;VpcConfig&lt;/code&gt; places the function in the same subnets as the mount targets, and its &lt;code&gt;FileSystemConfigs&lt;/code&gt; property attaches the access point directly. &lt;code&gt;DependsOn&lt;/code&gt; makes sure both mount targets exist before CloudFormation creates the function.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-yaml"&gt;PreStageFunction:
  Type: AWS::Lambda::Function
  Properties:
    Runtime: python3.13
    Handler: index.handler
    MemorySize: 512
    Role: !GetAtt PreStageFunctionRole.Arn
    VpcConfig:
      SubnetIds: [!Ref PrivateSubnetA, !Ref PrivateSubnetB]
      SecurityGroupIds: [!Ref FileSystemSecurityGroup]
    FileSystemConfigs:
      - Arn: !GetAtt AccessPoint.AccessPointArn
        LocalMountPath: /mnt/case
    Code:
      S3Bucket: !Ref DeploymentBucket
      S3Key: pre-stage.zip
  DependsOn:
    - MountTargetA
    - MountTargetB&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;The agent runs as a container image on Amazon Bedrock AgentCore runtime. It is an &lt;code&gt;AWS::BedrockAgentCore::Runtime&lt;/code&gt; resource with the same access point attached through &lt;code&gt;FilesystemConfigurations.S3FilesAccessPoint&lt;/code&gt;. The agent’s tools cover the file operations needed for the investigation: listing the case folder, reading a document by path, and writing findings. The model decides which tool to call at each step.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-yaml"&gt;InvestigationAgent:
  Type: AWS::BedrockAgentCore::Runtime
  Properties:
    AgentRuntimeName: DocumentInvestigationAgent
    RoleArn: !GetAtt AgentRuntimeRole.Arn
    AgentRuntimeArtifact:
      ContainerConfiguration:
        ContainerUri: !Sub '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/investigation-agent:latest'
    NetworkConfiguration:
      NetworkMode: VPC
      NetworkModeConfig:
        VpcConfig:
          Subnets: [!Ref PrivateSubnetA, !Ref PrivateSubnetB]
          SecurityGroups: [!Ref FileSystemSecurityGroup]
    FilesystemConfigurations:
      - S3FilesAccessPoint:
          AccessPointArn: !GetAtt AccessPoint.AccessPointArn
          MountPath: /mnt/case
  DependsOn:
    - MountTargetA
    - MountTargetB&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;One of the agent’s tools looks like this:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-python"&gt;@tool
def read_document(case_id: str, relative_path: str) -&amp;gt; str:
    """Open one document the agent decides it needs next, including files it
    discovered only by reading another document."""
    target = (pathlib.Path(MOUNT_PATH) / case_id / relative_path).resolve()
    return target.read_text(encoding="utf-8", errors="replace")&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Each side has least-privilege IAM permissions: &lt;code&gt;s3files:ClientMount&lt;/code&gt; and &lt;code&gt;s3files:ClientWrite&lt;/code&gt; scoped to the access point Amazon Resource Name (ARN) with an &lt;code&gt;s3files:AccessPointArn&lt;/code&gt; condition, &lt;code&gt;s3:GetObject&lt;/code&gt; for direct reads, and, for the agent, &lt;code&gt;bedrock:InvokeModel&lt;/code&gt;. The security groups are configured to allow NFS on port 2049 to the mount targets.&lt;/p&gt; 
&lt;h2 id="keeping-shared-reads-and-writes-consistent"&gt;Keeping shared reads and writes consistent&lt;/h2&gt; 
&lt;p&gt;S3 Files maintains consistency across shared mounts through three principles.&lt;/p&gt; 
&lt;ol type="1"&gt; 
 &lt;li&gt;&lt;strong&gt;Reads on the mount are immediate&lt;/strong&gt;. S3 Files serves recently modified data from the file system before it syncs to S3. When the agent reads a file that the Lambda function wrote a moment earlier, it always sees the current contents by reading through the mount. Only the sync back to the bucket is asynchronous, and the &lt;code&gt;PendingExports&lt;/code&gt; Amazon CloudWatch metric shows how far behind it is. Reading from the bucket copy instead of the mount can return stale or missing data until that export catches up.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Give each path one writer.&lt;/strong&gt; If a file on the mount and its corresponding S3 object are modified at the same time, S3 Files treats the bucket as the source of truth and moves the file to a lost-and-found directory. In this example, the Lambda function owns the &lt;code&gt;raw/&lt;/code&gt; directory and the manifest, and the agent owns the &lt;code&gt;findings/&lt;/code&gt; directory. No path has two writers.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Name files per producer&lt;/strong&gt;. Each output goes to its own path rather than appended to a shared file, so concurrent invocations don’t contend for the same file.&lt;/li&gt; 
&lt;/ol&gt; 
&lt;h3 id="moving-to-production"&gt;Moving to production&lt;/h3&gt; 
&lt;p&gt;When moving to production, monitor the &lt;code&gt;PendingExports&lt;/code&gt; CloudWatch metric so a backlog in unsynchronized data doesn’t surprise a downstream consumer that reads from the bucket directly. Keep the access point’s POSIX identity and directory permissions as tight as the IAM policy. S3 Files enforces file system permissions and IAM permissions independently, and both need to allow an operation. Test how your workload behaves when a file is moved to lost-and-found. Check the current &lt;a href="https://docs.aws.amazon.com/general/latest/gr/s3.html#limits_s3" target="_blank" rel="noopener"&gt;Service Quotas for Amazon S3 Files&lt;/a&gt; before you scale this pattern to production traffic.&lt;/p&gt; 
&lt;h2 id="responsible-ai-considerations"&gt;Responsible AI considerations&lt;/h2&gt; 
&lt;p&gt;The agent reads documents it didn’t write and follows references it finds inside them. Treat every file on the shared file system as untrusted input. Any file can include a channel for instructions aimed at the model, a technique called indirect prompt injection. Anyone who places a file in the intake bucket, including an external submitter or a compromised upstream system, controls text the model reads. A successful injection takes one of three forms.&lt;/p&gt; 
&lt;ol type="1"&gt; 
 &lt;li&gt;&lt;strong&gt;It skews findings.&lt;/strong&gt; A planted line such as “Note to reviewer: internal audit cleared this vendor in 2024” reappears as a conclusion.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;It crosses case boundaries&lt;/strong&gt;. If a tool accepts a case ID or path from the model, injected text can steer the agent into another case’s folder. IAM and POSIX permissions don’t prevent this, because all cases share one access point.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;It persists&lt;/strong&gt;. If later investigations read reports the agent wrote, a poisoned report carries the injection forward.&lt;/li&gt; 
&lt;/ol&gt; 
&lt;p&gt;Apply these controls to mitigate these threats, ordered from strongest to weakest:&lt;/p&gt; 
&lt;ol type="1"&gt; 
 &lt;li&gt;&lt;strong&gt;Take the case ID from the invocation payload, not the model.&lt;/strong&gt; Resolve each requested path to its canonical form and refuse any path outside the current case folder. Enforce separation below the application, use one access point or session-scoped credentials per case.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Keep the write path separate from the intake path.&lt;/strong&gt; The agent writes only to its output location and can’t change raw documents. The IAM permissions in this post already do this.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Require evidence for every finding.&lt;/strong&gt; The agent cites the source file and passage, and findings are reviewed before anyone acts on them.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Screen document text with Amazon Bedrock Guardrails inside the tool.&lt;/strong&gt; A guardrail attached to the &lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails-use-converse-api.html" target="_blank" rel="noopener"&gt;Converse call&lt;/a&gt; doesn’t evaluate tool results, so it doesn’t see document text. Instead, call &lt;code&gt;ApplyGuardrail&lt;/code&gt; from &lt;code&gt;read_document&lt;/code&gt; with source &lt;code&gt;INPUT&lt;/code&gt; and the prompt attack filter set to block, before returning text to the model. Split long documents to fit request limits. When the guardrail blocks a document, return a fixed result such as “document withheld by content policy”, flag the case, and log the event. Run &lt;code&gt;ApplyGuardrail&lt;/code&gt; with source &lt;code&gt;OUTPUT&lt;/code&gt; on findings before writing them.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Log every path the agent opens or is refused, per case.&lt;/strong&gt; Alert on reads outside the expected set, refused paths, and guardrail blocks.&lt;/li&gt; 
&lt;/ol&gt; 
&lt;h2 id="how-this-differs-from-amazon-bedrock-data-automation"&gt;How this differs from Amazon Bedrock Data Automation&lt;/h2&gt; 
&lt;p&gt;&lt;a href="https://aws.amazon.com/bedrock/bda/" target="_blank" rel="noopener"&gt;Amazon Bedrock Data Automation&lt;/a&gt; extracts structured output from documents, images, audio, and video with a managed pipeline. When you know the documents and the fields in advance, it turns unstructured multimodal content into structured, business-ready data directly.&lt;/p&gt; 
&lt;p&gt;A custom agent suits open-ended investigations, where one document points to another and the agent decides which file to open next based on what it just read. Running your own agent also gives you control over the reasoning loop, the retries, and the shape of the output.&lt;/p&gt; 
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt; 
&lt;p&gt;This post shows how to build an intelligent document-investigation workflow on serverless compute. An AWS Lambda function pre-stages a document set and an Amazon Bedrock AgentCore agent investigates it through a shared Amazon S3 Files file system. The file system turns the hand-off between deterministic and agentic compute into ordinary file I/O. Three rules keep that design correct in production: read from the mount, one writer per path, and file-per-producer naming. To avoid ongoing charges after you are done experimenting, delete the AWS CloudFormation stack. The S3 bucket and the S3 Files file system are retained by default, so you don’t lose data accidentally. Delete them separately after you no longer need them.&lt;/p&gt; 
&lt;p&gt;To go further, deploy the reference implementation from &lt;a href="https://serverlessland.com/patterns/lambda-s3-files-cdk" target="_blank" rel="noopener"&gt;Serverless Land&lt;/a&gt;, review the &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-files.html" target="_blank" rel="noopener"&gt;Amazon S3 Files documentation&lt;/a&gt; and the &lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-filesystem-configurations.html" target="_blank" rel="noopener"&gt;AgentCore file system configuration guide&lt;/a&gt;, and adapt the agent’s tools to the documents your own teams investigate.&lt;/p&gt; 
&lt;p&gt;&amp;nbsp;&lt;/p&gt; 
&lt;p style="clear: both"&gt;&lt;/p&gt; 
&lt;hr style="width: 100%"&gt; 
&lt;h2&gt;About the authors&lt;/h2&gt; 
&lt;footer&gt; 
 &lt;div class="blog-author-box" style="padding-top: 2.0em"&gt; 
  &lt;div class="blog-author-image" style="margin-right: 1.0em"&gt;
   &lt;img loading="lazy" class="alignnone size-full" src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/26/ComputeBlog-2669-2.jpg" alt="Ben Freiberg" width="100" height="133"&gt;
  &lt;/div&gt; 
  &lt;h3 class="lb-h4"&gt;Ben Freiberg&lt;/h3&gt; 
  &lt;p style="overflow: hidden"&gt;Ben is a Senior Solutions Architect at AWS.&lt;/p&gt; 
 &lt;/div&gt; 
 &lt;div class="blog-author-box" style="padding-top: 2.0em"&gt; 
  &lt;div class="blog-author-image" style="margin-right: 1.0em"&gt;
   &lt;img loading="lazy" class="alignnone size-full" src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/26/ComputeBlog-2669-3.jpg" alt="Nithin Chandran Rajashankar" width="100" height="133"&gt;
  &lt;/div&gt; 
  &lt;h3 class="lb-h4"&gt;Nithin Chandran Rajashankar&lt;/h3&gt; 
  &lt;p style="overflow: hidden"&gt;Nithin is a Technical Account Manager at AWS.&lt;/p&gt; 
 &lt;/div&gt; 
&lt;/footer&gt;</content:encoded>
					
		
		
			</item>
		<item>
		<title>OS patching and upgrades with Amazon EC2 root volume replacement</title>
		<link>https://aws.amazon.com/blogs/compute/os-patching-and-upgrades-with-amazon-ec2-root-volume-replacement/</link>
		
		<dc:creator><![CDATA[Akshaya Shah]]></dc:creator>
		<pubDate>Thu, 22 Oct 2026 17:30:32 +0000</pubDate>
				<category><![CDATA[Advanced (300)]]></category>
		<category><![CDATA[Amazon EC2]]></category>
		<category><![CDATA[Technical How-to]]></category>
		<guid isPermaLink="false">7b511d1e9f4333152fc426c542c04bb3310ee7e4</guid>

					<description>Amazon EC2 Replace Root Volume with the direct Amazon EBS volume option lets you prepare and validate a replacement root volume in advance, then swap it onto a running production instance with a single reboot. Learn how to upgrade the OS and apply patches while the instance keeps its production identity, including instances in Auto Scaling groups.</description>
										<content:encoded>&lt;p&gt;Customers running stateful workloads on Amazon Elastic Compute Cloud (&lt;a href="https://aws.amazon.com/pm/ec2/" target="_blank" rel="noopener"&gt;Amazon EC2&lt;/a&gt;) need to patch operating systems, upgrade OS versions, remediate vulnerabilities quickly, and patch applications in user space. These workloads are connected to resources such as &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html" target="_blank" rel="noopener"&gt;Elastic IP addresses&lt;/a&gt;, secondary network interfaces, attached data volumes, AWS Identity and Access Management (&lt;a href="https://aws.amazon.com/iam/" target="_blank" rel="noopener"&gt;IAM&lt;/a&gt;) instance profiles, and DNS records. For OS upgrades or patches that require downtime, a common approach is to replace the instance with a new one launched from a newer Amazon Machine Image (AMI). That approach means moving each of these resources to the new instance. With Amazon EC2 Replace Root Volume (&lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/replace-root.html" target="_blank" rel="noopener"&gt;RRV&lt;/a&gt;) using Amazon Elastic Block Store (&lt;a href="https://aws.amazon.com/ebs/" target="_blank" rel="noopener"&gt;Amazon EBS&lt;/a&gt;), you can prepare and validate a replacement root volume in advance. You then swap it onto a running production instance with a single API call. The interruption is limited to the reboot that RRV performs and the time your application takes to restart.&lt;/p&gt; 
&lt;p&gt;In this post, we show how to use the existing EBS volume option of root volume replacement on a Linux instance to upgrade the operating system generation and apply patches, while the instance keeps its production identity. We also cover instances in &lt;a href="https://aws.amazon.com/ec2/autoscaling/" target="_blank" rel="noopener"&gt;Amazon EC2 Auto Scaling&lt;/a&gt; groups.&lt;/p&gt; 
&lt;h2 id="constraints-and-considerations"&gt;Constraints and considerations&lt;/h2&gt; 
&lt;p&gt;RRV has the following requirements and considerations:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;The replacement volume must be in the same Availability Zone as the instance.&lt;/li&gt; 
 &lt;li&gt;The replacement volume must be in the &lt;code&gt;available&lt;/code&gt; state and must not be attached to any instance at the time of the request.&lt;/li&gt; 
 &lt;li&gt;If the original root volume is encrypted, the replacement volume must also be encrypted. You can move from an unencrypted volume to an encrypted one, but not from encrypted to unencrypted.&lt;/li&gt; 
 &lt;li&gt;For &lt;a href="https://aws.amazon.com/marketplace/" target="_blank" rel="noopener"&gt;AWS Marketplace&lt;/a&gt; instances, the product codes and billing codes on the replacement volume must match those on the instance.&lt;/li&gt; 
 &lt;li&gt;The target instance must be in the &lt;code&gt;running&lt;/code&gt; state.&lt;/li&gt; 
 &lt;li&gt;The instance is automatically rebooted during the process. Memory contents and running processes do not survive the reboot.&lt;/li&gt; 
 &lt;li&gt;The delete-on-termination attribute of the original root volume doesn’t transfer to the replacement volume.&lt;/li&gt; 
 &lt;li&gt;At this time, root volume replacement supports virtualized instance types and EC2 Mac bare metal instances. Other bare metal instance types aren’t currently supported. Check the Amazon EC2 documentation for the latest list of supported instance types.&lt;/li&gt; 
 &lt;li&gt;To avoid a failed boot, make sure the replacement volume has the Elastic Network Adapter (&lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enhanced-networking-ena.html" target="_blank" rel="noopener"&gt;ENA&lt;/a&gt;) and NVMe drivers that Nitro-based instances require. Use the same CPU architecture and boot mode (UEFI or legacy BIOS) as the target instance.&lt;/li&gt; 
 &lt;li&gt;To avoid an SSH host-key change, copy the existing host keys to the new volume before the swap.&lt;/li&gt; 
 &lt;li&gt;Review your cloud-init configuration, since a volume from a fresh AMI snapshot can re-run user data on its first boot.&lt;/li&gt; 
 &lt;li&gt;As a best practice, keep application-specific data and configuration on a separate (non-root) volume, so it is not impacted when the root volume is replaced.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2 id="benefits-of-root-volume-replacement-compared-to-instance-replacement"&gt;Benefits of root volume replacement compared to instance replacement&lt;/h2&gt; 
&lt;p&gt;Benefits of root volume replacement include:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Preparation of the replacement volume:&lt;/strong&gt; You build and validate the replacement volume on a separate instance, so the production instance is untouched until the swap.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Reduce the downtime:&lt;/strong&gt; Reduce the downtime to an in-place reboot instead of replacing the instance and reassociating its attached resources.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Test before commitment:&lt;/strong&gt; You validate the replacement volume in non-production first. If validation fails, you discard it without ever touching production.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Resource preservation:&lt;/strong&gt; The swap retains &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-eni.html" target="_blank" rel="noopener"&gt;network interfaces&lt;/a&gt; (ENIs), Elastic IP addresses, EBS data volumes, &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/InstanceStorage.html" target="_blank" rel="noopener"&gt;instance store&lt;/a&gt; data, &lt;a href="https://aws.amazon.com/iam/" target="_blank" rel="noopener"&gt;IAM&lt;/a&gt; instance profiles, &lt;a href="https://docs.aws.amazon.com/vpc/latest/userguide/vpc-security-groups.html" target="_blank" rel="noopener"&gt;security groups&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/placement-groups.html" target="_blank" rel="noopener"&gt;placement groups&lt;/a&gt;, and &lt;a href="https://docs.aws.amazon.com/vpc/latest/userguide/AmazonDNS-concepts.html" target="_blank" rel="noopener"&gt;DNS names&lt;/a&gt;. As a result, you avoid the re-association, re-attachment, and reconfiguration steps that instance replacement requires.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Rollback path:&lt;/strong&gt; If you keep the original root volume, you can swap back to it.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt; 
&lt;p&gt;It’s a two-phase process: in the preparation phase you build the new root volume, and in the replacement phase you call the root volume replacement API, which swaps the volume and reboots the instance.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Step 1 – Preparation phase&lt;/strong&gt;: On a separate preparation instance, you create a new volume from a newer OS AMI, patch and configure it in a chroot, and test a copy on a non-production instance.&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/14/ComputeBlog-2749-1.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/14/ComputeBlog-2749-1.png" alt="Preparation phase: on a separate preparation instance, a new root volume is created from a newer OS AMI, patched and configured in a chroot, then validated on a non-production instance." width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 1: Preparation phase. You build and validate the replacement root volume on a separate instance before touching production.&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;&lt;strong&gt;Step 2 – Replacement phase&lt;/strong&gt;: The &lt;code&gt;create-replace-root-volume-task&lt;/code&gt; call starts a task that, during one reboot, detaches the original root volume and attaches the prepared one. Network interfaces, data volumes, and Elastic IP addresses stay in place, and the instance returns at the same IP address after the application restarts.&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/14/ComputeBlog-2749-2.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/14/ComputeBlog-2749-2.png" alt="Replacement phase: the replace root volume task detaches the original root volume and attaches the prepared one during a single reboot, while network interfaces, data volumes, and Elastic IP addresses stay in place." width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 2: Replacement phase. A single API call swaps the prepared volume onto the running instance, which returns at the same IP address.&lt;/p&gt;
&lt;/div&gt; 
&lt;h2 id="what-is-preserved-during-the-reboot"&gt;What is preserved during the reboot&lt;/h2&gt; 
&lt;p&gt;The reboot clears memory and running processes but preserves the instance’s identity and attached resources:&lt;/p&gt; 
&lt;table border="1px" width="100%" cellpadding="10px"&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;&lt;strong&gt;Resource&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Preserved&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Notes&lt;/strong&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Instance ID&lt;/td&gt; 
   &lt;td&gt;Yes&lt;/td&gt; 
   &lt;td&gt;Same instance. No termination occurs&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Private IP address&lt;/td&gt; 
   &lt;td&gt;Yes&lt;/td&gt; 
   &lt;td&gt;Retained. The instance keeps its private IP address across the replacement&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Public IP / Elastic IP address&lt;/td&gt; 
   &lt;td&gt;Yes&lt;/td&gt; 
   &lt;td&gt;Remains associated with the instance&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Network interfaces (ENIs)&lt;/td&gt; 
   &lt;td&gt;Yes&lt;/td&gt; 
   &lt;td&gt;All ENIs retain their IP addresses, identifiers, and attachment IDs&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;EBS data volumes&lt;/td&gt; 
   &lt;td&gt;Yes&lt;/td&gt; 
   &lt;td&gt;Non-root volumes remain attached&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Instance store volumes&lt;/td&gt; 
   &lt;td&gt;Usually&lt;/td&gt; 
   &lt;td&gt;Volumes stay attached and their data normally survives the reboot, but this isn’t guaranteed. A failed reboot or a problem with the underlying host can cause instance store data to be lost. Keep data you need on EBS volumes.&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;IAM instance profile&lt;/td&gt; 
   &lt;td&gt;Yes&lt;/td&gt; 
   &lt;td&gt;Role and policies (including tag-based policies) remain enforced&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Security groups&lt;/td&gt; 
   &lt;td&gt;Yes&lt;/td&gt; 
   &lt;td&gt;All security group associations are retained&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;DNS names&lt;/td&gt; 
   &lt;td&gt;Yes&lt;/td&gt; 
   &lt;td&gt;Public and private DNS names are unchanged&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Placement group&lt;/td&gt; 
   &lt;td&gt;Yes&lt;/td&gt; 
   &lt;td&gt;Instance remains in the same placement&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Tags&lt;/td&gt; 
   &lt;td&gt;Yes&lt;/td&gt; 
   &lt;td&gt;Instance tags are unchanged&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Memory (RAM) contents&lt;/td&gt; 
   &lt;td&gt;No&lt;/td&gt; 
   &lt;td&gt;Volatile memory is wiped during the reboot&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Running processes&lt;/td&gt; 
   &lt;td&gt;No&lt;/td&gt; 
   &lt;td&gt;Applications must restart as part of the boot sequence&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;h2 id="solution-walkthrough"&gt;Solution walkthrough&lt;/h2&gt; 
&lt;p&gt;The walkthrough has four steps:&lt;/p&gt; 
&lt;ol type="1"&gt; 
 &lt;li&gt;Create the replacement volume.&lt;/li&gt; 
 &lt;li&gt;Prepare and install patches on the volume.&lt;/li&gt; 
 &lt;li&gt;Test the prepared volume.&lt;/li&gt; 
 &lt;li&gt;Swap it onto the running instance.&lt;/li&gt; 
&lt;/ol&gt; 
&lt;p&gt;Replace placeholder values (such as the instance ID, volume ID, and Availability Zone).&lt;/p&gt; 
&lt;h3 id="prerequisites"&gt;Prerequisites&lt;/h3&gt; 
&lt;p&gt;Before you begin, make sure that you have:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;AWS Command Line Interface (AWS CLI) v2.36.0 or later that supports the &lt;code&gt;--volume-id&lt;/code&gt; parameter on &lt;code&gt;create-replace-root-volume-task&lt;/code&gt;, configured with credentials that have permissions for Amazon EC2 and Amazon EBS operations (for encrypted volumes, including the AWS Key Management Service (&lt;a href="https://aws.amazon.com/kms/" target="_blank" rel="noopener"&gt;AWS KMS&lt;/a&gt;) permissions to detach the original volume and to attach and decrypt the replacement).&lt;/li&gt; 
 &lt;li&gt;A running Linux target instance with an Amazon EBS root volume that you want to replace.&lt;/li&gt; 
 &lt;li&gt;A preparation instance in the target’s Availability Zone, launched from a different AMI than the replacement volume’s base so their root filesystems are less likely to share a UUID. If they do share one on XFS, mount the volume with &lt;code&gt;-o nouuid&lt;/code&gt;.&lt;/li&gt; 
 &lt;li&gt;A non-production test instance of the same instance type, launched from the target instance’s AMI so that it has the same boot mode.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3 id="step-1-create-the-replacement-root-volume"&gt;Step 1: Create the replacement root volume&lt;/h3&gt; 
&lt;p&gt;Create the replacement volume in the target instance’s Availability Zone, typically from the root snapshot of a newer OS AMI. If the original root volume is encrypted, encrypt the new one, and make it at least as large as the current root volume. A volume restored from a snapshot loads its blocks from Amazon Simple Storage Service (&lt;a href="https://aws.amazon.com/s3/" target="_blank" rel="noopener"&gt;Amazon S3&lt;/a&gt;) on first read, so its first boot can be slower than a normal reboot. Setting the &lt;code&gt;--volume-initialization-rate&lt;/code&gt; parameter, or enabling fast snapshot restore on the snapshot, reduces this. Both are billed separately.&lt;/p&gt; 
&lt;p&gt;First, confirm that the base AMI supports the instance’s boot mode and find the AMI’s root snapshot. The instance reports &lt;code&gt;uefi&lt;/code&gt; or &lt;code&gt;legacy-bios&lt;/code&gt;. The AMI reports &lt;code&gt;uefi&lt;/code&gt;, &lt;code&gt;legacy-bios&lt;/code&gt;, or &lt;code&gt;uefi-preferred&lt;/code&gt; (which supports both). An AMI with no boot mode uses the instance type’s default.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws ec2 describe-instances \
    --instance-ids &amp;lt;target-instance-id&amp;gt; \
    --query 'Reservations[0].Instances[0].CurrentInstanceBootMode'

aws ec2 describe-images \
    --image-ids &amp;lt;base-ami-id&amp;gt; \
    --query 'Images[0].{BootMode:BootMode,RootDevice:RootDeviceName,Snapshot:BlockDeviceMappings[0].Ebs.SnapshotId}'&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Use the snapshot ID this returns as &lt;code&gt;&amp;lt;base-snapshot-id&amp;gt;&lt;/code&gt; in the next command.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws ec2 create-volume \
    --availability-zone &amp;lt;az&amp;gt; \
    --snapshot-id &amp;lt;base-snapshot-id&amp;gt; \
    --volume-type gp3 \
    --size &amp;lt;size-in-GiB&amp;gt; \
    --encrypted \
    --kms-key-id &amp;lt;kms-key-id&amp;gt; \
    --volume-initialization-rate &amp;lt;MiB-per-second&amp;gt;&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;&lt;strong&gt;Expected outcome&lt;/strong&gt;: An available EBS volume with a bootable OS, ready to attach to the preparation instance.&lt;/p&gt; 
&lt;h3 id="step-2-prepare-and-install-patches-on-the-volume"&gt;Step 2: Prepare and install patches on the volume&lt;/h3&gt; 
&lt;p&gt;Attach the volume to the preparation instance as a secondary disk:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws ec2 attach-volume \
    --volume-id &amp;lt;new-root-volume-id&amp;gt; \
    --instance-id &amp;lt;prep-instance-id&amp;gt; \
    --device /dev/sdf&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Mount the root partition and bind-mount &lt;code&gt;/proc&lt;/code&gt;, &lt;code&gt;/sys&lt;/code&gt;, &lt;code&gt;/dev&lt;/code&gt;, and &lt;code&gt;/dev/pts&lt;/code&gt; so that package managers inside the chroot install into the new volume. Use &lt;code&gt;lsblk&lt;/code&gt; to find the device. On Nitro-based instances it appears as an NVMe device (for example, &lt;code&gt;/dev/nvme1n1&lt;/code&gt;), not &lt;code&gt;/dev/sdf&lt;/code&gt;. Copy &lt;code&gt;/etc/resolv.conf&lt;/code&gt; so DNS works inside the chroot.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;lsblk
sudo mkdir -p /mnt/newroot
sudo mount &amp;lt;root-partition&amp;gt; /mnt/newroot
sudo mount --bind /proc /mnt/newroot/proc
sudo mount --bind /sys /mnt/newroot/sys
sudo mount --bind /dev /mnt/newroot/dev
sudo mount --bind /dev/pts /mnt/newroot/dev/pts
sudo cp --remove-destination /etc/resolv.conf /mnt/newroot/etc/resolv.conf&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Inside the chroot, apply OS security patches, install or upgrade application software, and apply configuration. Because the volume is detached from production, you can take as long as you need.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;sudo chroot /mnt/newroot /bin/bash
# Inside the chroot, for example:
# - apply OS security updates with your package manager
# - install or upgrade application packages
# - write application and service configuration
# - enable services to start on boot
# - if you upgrade the kernel, rebuild the initramfs and update the GRUB configuration
# - on SELinux-enabled distributions, schedule a relabel (touch /.autorelabel)
# - validate configuration (for example, a service's own config test)
exit&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Before detaching, create mount points for the target’s data volumes and add &lt;code&gt;/etc/fstab&lt;/code&gt; entries on the new volume. Use &lt;code&gt;UUID=&lt;/code&gt; or &lt;code&gt;LABEL=&lt;/code&gt; entries rather than device names, which can change between boots on Nitro-based instances.&lt;/p&gt; 
&lt;p&gt;Then unmount and detach the volume:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;sudo umount /mnt/newroot/dev/pts /mnt/newroot/dev /mnt/newroot/sys /mnt/newroot/proc
sudo umount /mnt/newroot

aws ec2 detach-volume --volume-id &amp;lt;new-root-volume-id&amp;gt;&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;&lt;strong&gt;Expected outcome&lt;/strong&gt;: An available, patched EBS volume that has not been attached to the production instance.&lt;/p&gt; 
&lt;h3 id="step-3-test-the-prepared-volume"&gt;Step 3: Test the prepared volume&lt;/h3&gt; 
&lt;p&gt;Snapshot the prepared volume, create a test volume from the snapshot in the test instance’s Availability Zone, and replace the test instance’s root volume with it. Confirm that the instance boots, the application starts, and the data volumes mount.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws ec2 create-snapshot \
    --volume-id &amp;lt;new-root-volume-id&amp;gt; \
    --description "Prepared root volume"

aws ec2 create-volume \
    --availability-zone &amp;lt;test-az&amp;gt; \
    --snapshot-id &amp;lt;prepared-snapshot-id&amp;gt; \
    --volume-type gp3 \
    --encrypted \
    --kms-key-id &amp;lt;kms-key-id&amp;gt;

aws ec2 create-replace-root-volume-task \
    --instance-id &amp;lt;test-instance-id&amp;gt; \
    --volume-id &amp;lt;test-volume-id&amp;gt; \
    --delete-replaced-root-volume&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;&lt;strong&gt;Expected outcome&lt;/strong&gt;: The test instance boots and the application passes your checks. If it doesn’t, fix the prepared volume and repeat this step.&lt;/p&gt; 
&lt;h3 id="step-4-run-the-root-volume-replacement"&gt;Step 4: Run the root volume replacement&lt;/h3&gt; 
&lt;p&gt;Before you run the replacement, record the current root volume ID and snapshot it as a fallback. Amazon EC2 keeps the original root volume by default. This example also sets &lt;code&gt;--no-delete-replaced-root-volume&lt;/code&gt; explicitly. Use &lt;code&gt;--delete-replaced-root-volume&lt;/code&gt; only if you don’t need a rollback path.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws ec2 describe-instances \
    --instance-ids &amp;lt;target-instance-id&amp;gt; \
    --query 'Reservations[0].Instances[0].[RootDeviceName,BlockDeviceMappings]'

aws ec2 create-snapshot \
    --volume-id &amp;lt;original-root-volume-id&amp;gt; \
    --description "Root volume before replacement"&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;# Then run the replacement:

aws ec2 create-replace-root-volume-task \
    --instance-id &amp;lt;target-instance-id&amp;gt; \
    --volume-id &amp;lt;new-root-volume-id&amp;gt; \
    --no-delete-replaced-root-volume&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Monitor the task. It moves through &lt;code&gt;pending&lt;/code&gt;, &lt;code&gt;in-progress&lt;/code&gt; (when the instance reboots), and &lt;code&gt;succeeded&lt;/code&gt;.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws ec2 describe-replace-root-volume-tasks \
    --replace-root-volume-task-ids &amp;lt;task-id&amp;gt; \
    --query 'ReplaceRootVolumeTasks[0].TaskState'&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;&lt;strong&gt;Expected outcome:&lt;/strong&gt; The task reports &lt;code&gt;succeeded&lt;/code&gt;, and the instance comes back on the patched root volume with its instance ID, IP addresses, network interfaces, data volumes, and IAM instance profile retained. Disruption is roughly one reboot plus your application’s start time.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;If the task doesn’t succeed:&lt;/strong&gt;&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;code&gt;failed&lt;/code&gt;: The instance was rebooted with its original root volume attached. Fix the volume (repeat Step 3), then retry.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;failed-detached&lt;/code&gt;: The instance doesn’t have a root volume attached. Contact AWS Support before you take further action on the instance.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;A task can report &lt;code&gt;succeeded&lt;/code&gt; even if the instance fails to boot on the new volume, for example because of a boot mode or driver mismatch. Confirm that the instance passes its status checks after every replacement. If it doesn’t, check the console output or the EC2 serial console, then roll back.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws ec2 describe-instance-status \
    --instance-ids &amp;lt;target-instance-id&amp;gt; \
    --include-all-instances

aws ec2 get-console-output \
    --instance-id &amp;lt;target-instance-id&amp;gt; \
    --latest&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Finally, set delete-on-termination on the new root volume to match the original:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws ec2 modify-instance-attribute \
    --instance-id &amp;lt;target-instance-id&amp;gt; \
    --block-device-mappings '[{"DeviceName":"&amp;lt;root-device-name&amp;gt;","Ebs":{"DeleteOnTermination":&amp;lt;true-or-false&amp;gt;}}]'&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h2 id="rolling-back"&gt;Rolling back&lt;/h2&gt; 
&lt;p&gt;To roll back, run another replacement with the original root volume. If you deleted it, pass the snapshot from Step 4 with &lt;code&gt;--snapshot-id&lt;/code&gt; instead of &lt;code&gt;--volume-id&lt;/code&gt; (the two are mutually exclusive). Root volume replacement accepts snapshots of the instance’s previous root volumes.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws ec2 create-replace-root-volume-task \
    --instance-id &amp;lt;target-instance-id&amp;gt; \
    --volume-id &amp;lt;original-root-volume-id&amp;gt; \
    --no-delete-replaced-root-volume&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Then validate the instance as you did after the swap and set delete-on-termination again. Changes written to the new root volume after the swap aren’t carried back, so keep data that must survive a rollback on a data volume.&lt;/p&gt; 
&lt;p&gt;If the instance is in an Auto Scaling group, roll back before you exit Standby.&lt;/p&gt; 
&lt;h2 id="using-root-volume-replacement-with-auto-scaling-groups"&gt;Using root volume replacement with Auto Scaling groups&lt;/h2&gt; 
&lt;p&gt;Instances in an Amazon EC2 Auto Scaling group need different handling, because the group’s health checks and scaling can terminate or replace an instance mid-swap. Choose the approach that matches what you’re updating.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;One instance at a time:&lt;/strong&gt; Put the instance in Standby first, reducing the desired capacity so the group doesn’t launch a replacement. Standby temporarily takes the instance out of service. Then create, validate, and run the root volume replacement, update the launch template so future instances use the new OS, and return the instance to service. For the Standby steps, see &lt;a href="https://docs.aws.amazon.com/autoscaling/ec2/userguide/as-enter-exit-standby.html" target="_blank" rel="noopener"&gt;Temporarily remove instances from your Auto Scaling group&lt;/a&gt; in the Amazon EC2 Auto Scaling User Guide.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;A whole fleet:&lt;/strong&gt; To update every instance in a group from a new AMI, use the &lt;code&gt;ReplaceRootVolume&lt;/code&gt; strategy within instance refresh, where the Auto Scaling group replaces each instance’s root volume in stages while preserving network interfaces, data volumes, and instance store data. It applies the same AMI to every instance, so it suits fleet-wide OS updates rather than a volume prepared for one stateful instance. For details, see &lt;a href="https://docs.aws.amazon.com/autoscaling/ec2/userguide/replace-root-volume.html" target="_blank" rel="noopener"&gt;Replace root volumes during instance refresh&lt;/a&gt; in the Amazon EC2 Auto Scaling User Guide.&lt;/p&gt; 
&lt;h2 id="clean-up"&gt;Clean up&lt;/h2&gt; 
&lt;p&gt;To avoid ongoing charges, delete the resources that you no longer need.&lt;/p&gt; 
&lt;p&gt;The original root volume and its fallback snapshot, when you no longer need them for rollback:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws ec2 delete-volume --volume-id &amp;lt;old-root-volume-id&amp;gt;

aws ec2 delete-snapshot --snapshot-id &amp;lt;original-root-snapshot-id&amp;gt;&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;The preparation instance:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws ec2 terminate-instances --instance-ids &amp;lt;prep-instance-id&amp;gt;&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;The test instance, the test volume, and the Step 3 snapshot:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws ec2 terminate-instances --instance-ids &amp;lt;test-instance-id&amp;gt;

aws ec2 delete-volume --volume-id &amp;lt;test-volume-id&amp;gt;

aws ec2 delete-snapshot --snapshot-id &amp;lt;prepared-snapshot-id&amp;gt;&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;If an Auto Scaling group uses an AMI registered from the snapshot, deregister the AMI before you delete the snapshot. If you launched a target instance only to try out this workflow, terminate it as well.&lt;/p&gt; 
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt; 
&lt;p&gt;Amazon EC2 Replace Root Volume with the direct EBS volume option separates volume preparation from the production interruption. When you need to upgrade an operating system or apply a critical patch, you prepare and validate the change on a separate instance, then swap it in with a single API call. The instance keeps its IP addresses, ENIs, data volume attachments, and DNS names across the swap, so you avoid re-association and re-mounting, and the interruption is limited to the single reboot that RRV performs. Before adopting this approach in production, validate it against your own workload, including boot time and any personalized data on the root volume. To get started, see &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/replace-root.html" target="_blank" rel="noopener"&gt;Replace the root volume for an Amazon EC2 instance without stopping it in the Amazon EC2 User Guide&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</content:encoded>
					
		
		
			</item>
		<item>
		<title>Building an AEO scoring pipeline with AWS Lambda durable functions</title>
		<link>https://aws.amazon.com/blogs/compute/building-an-aeo-scoring-pipeline-with-aws-lambda-durable-functions/</link>
		
		<dc:creator><![CDATA[Nick Beall]]></dc:creator>
		<pubDate>Tue, 20 Oct 2026 17:45:29 +0000</pubDate>
				<category><![CDATA[Advanced (300)]]></category>
		<category><![CDATA[AWS Lambda]]></category>
		<category><![CDATA[Technical How-to]]></category>
		<guid isPermaLink="false">d1fe6af4052e093f7bb310e78083e88967f4b5f3</guid>

					<description>Learn how to build a five-step Agent Engine Optimization (AEO) scoring pipeline on AWS Lambda durable functions. Each checkpointed step suspends without incurring costs between stages and retries without re-spending on prior work, so you can score any page against five AEO signals and deploy the solution with an AWS SAM template.</description>
										<content:encoded>&lt;p&gt;When an AI agent crawls your documentation looking for answers, it doesn’t browse like a human. It scores structure, extracts entities, checks factual consistency, and moves on, often in under a second. If your content doesn’t surface clearly in those evaluations, it won’t appear in AI-generated answers regardless of its current search ranking. This problem is called &lt;a href="https://addyosmani.com/blog/agentic-engine-optimization/" target="_blank" rel="noopener"&gt;Agent Engine Optimization&lt;/a&gt; (AEO), and solving it requires running multiple evaluation steps that are expensive, stateful, and failure-prone.&lt;/p&gt; 
&lt;p&gt;In this post, you build a five-step AEO scoring pipeline using &lt;a href="https://aws.amazon.com/lambda/lambda-durable-functions/" target="_blank" rel="noopener"&gt;AWS Lambda durable functions&lt;/a&gt;. Each step (fetch, score, analyze, publish, record) runs as a checkpointed operation that suspends without incurring additional costs between stages, retries without re-spending on prior work, and reads like ordinary Python. You score content against five AEO signals, see a real audit example, and walk away with a deployable &lt;a href="https://aws.amazon.com/serverless/sam/" target="_blank" rel="noopener"&gt;AWS Serverless Application Model (AWS SAM)&lt;/a&gt; template.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;A note on fetching:&lt;/strong&gt; The pipeline uses a plain HTTP GET, mimicking how non-rendering AI crawlers (GPTBot, ClaudeBot, PerplexityBot) see pages today. Sites that rely on client-side JavaScript may score lower because most AI agents do not execute JavaScript.&lt;/p&gt; 
&lt;h2 id="solution-overview"&gt;Solution overview&lt;/h2&gt; 
&lt;p&gt;The pipeline runs as a single Lambda durable function that chains five checkpointed steps. Scoring is fully deterministic (pure Python, no large language model (LLM)), so the same page consistently produces the same score. &lt;a href="https://aws.amazon.com/bedrock/" target="_blank" rel="noopener"&gt;Amazon Bedrock&lt;/a&gt; generates prose analysis explaining the results. For production deployments that surface generated content to end users, consider adding &lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails.html" target="_blank" rel="noopener"&gt;Amazon Bedrock Guardrails&lt;/a&gt; for responsible AI controls. Because the function suspends between steps without incurring additional costs, a failure at step 3 resumes from step 3. The deterministic scores from step 2 are already checkpointed.&lt;/p&gt; 
&lt;p&gt;The following architecture diagram shows the five pipeline stages:&lt;/p&gt; 
&lt;ol type="1"&gt; 
 &lt;li&gt;&lt;strong&gt;Fetch&lt;/strong&gt; – Retrieve the target page through an HTTP GET and extract structured signals (headings, token count, &lt;code&gt;robots.txt&lt;/code&gt; rules, &lt;code&gt;llms.txt&lt;/code&gt;, &lt;code&gt;AGENTS.md&lt;/code&gt;).&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Score&lt;/strong&gt; – Apply the deterministic rubric: threshold-based checks produce a reproducible 0–100 score with no LLM involvement.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Analyze&lt;/strong&gt; – Send the scores and raw signals to Amazon Bedrock, which generates prose findings and fix recommendations (temperature 0 for consistency).&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Publish&lt;/strong&gt; – Render the audit report as HTML and JSON, write to &lt;a href="https://aws.amazon.com/s3/" target="_blank" rel="noopener"&gt;Amazon Simple Storage Service (Amazon S3)&lt;/a&gt;.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Record&lt;/strong&gt; – Persist the score and metadata to &lt;a href="https://aws.amazon.com/dynamodb/" target="_blank" rel="noopener"&gt;Amazon DynamoDB&lt;/a&gt; for trend tracking.&lt;/li&gt; 
&lt;/ol&gt; 
&lt;div style="width: 411px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/16/2739-1.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/16/2739-1.png" alt="Architecture diagram of the AEO scoring pipeline showing five checkpointed Lambda durable function steps in sequence: fetch, score, analyze with Amazon Bedrock, publish to Amazon S3, and record to Amazon DynamoDB." width="401"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 1: The five checkpointed stages of the AEO scoring pipeline, from fetch through record.&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;This gives you retry safety, cost predictability, and simpler debugging. The pipeline runs fully automated by default, with an optional callback gate for workflows requiring human approval.&lt;/p&gt; 
&lt;h2 id="why-lambda-durable-functions"&gt;Why Lambda durable functions&lt;/h2&gt; 
&lt;p&gt;An AEO audit is five operations that depend on each other, any of which can fail mid-flight. Without checkpointing, a retry means re-running every step from the beginning, including Bedrock calls that already returned valid results.&lt;/p&gt; 
&lt;p&gt;Lambda durable functions solve this with checkpointed steps. Each step’s output is persisted before the next begins. When a Bedrock call gets throttled at step 3, only step 3 retries. The pipeline doesn’t re-run steps 1 and 2 or re-spend on their inference tokens.&lt;/p&gt; 
&lt;p&gt;Between steps, the function suspends with no environment held open, so you pay nothing while waiting. The pipeline reads as a single Python file, top to bottom. Each step’s checkpoint is independently inspectable, so debugging a failed run means looking at one step’s result rather than replaying the full execution log.&lt;/p&gt; 
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;An AWS account with Amazon Bedrock model access enabled.&lt;/li&gt; 
 &lt;li&gt;AWS SAM CLI v1.100+ installed and configured.&lt;/li&gt; 
 &lt;li&gt;Python 3.12+.&lt;/li&gt; 
 &lt;li&gt;&lt;a href="https://aws.amazon.com/iam/" target="_blank" rel="noopener"&gt;AWS Identity and Access Management (IAM)&lt;/a&gt; permissions to deploy &lt;a href="https://aws.amazon.com/cloudformation/" target="_blank" rel="noopener"&gt;AWS CloudFormation&lt;/a&gt; stacks (Lambda, DynamoDB, Amazon S3, and Amazon Bedrock invoke)&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;A SAM template in the &lt;a href="https://github.com/aws-samples/sample-aeo-scoring-pipeline" target="_blank" rel="noopener"&gt;GitHub repository&lt;/a&gt; provisions the DynamoDB table, S3 bucket, Lambda durable function, and required IAM roles. You deploy the full stack with &lt;code&gt;sam build &amp;amp;&amp;amp; sam deploy --guided&lt;/code&gt;.&lt;/p&gt; 
&lt;p&gt;Estimated time: 20–30 minutes. Each audit run uses a single Bedrock inference call plus brief Lambda durable function and DynamoDB usage. See the &lt;a href="https://calculator.aws/" target="_blank" rel="noopener"&gt;AWS Pricing Calculator&lt;/a&gt; for estimates based on your Region and usage volume.&lt;/p&gt; 
&lt;h2 id="the-five-aeo-signals"&gt;The five AEO signals&lt;/h2&gt; 
&lt;p&gt;Scoring evaluates content against five signals drawn from Addy Osmani’s &lt;a href="https://addyosmani.com/blog/agentic-engine-optimization" target="_blank" rel="noopener"&gt;Agent Engine Optimization framework&lt;/a&gt;. Each signal maps to a capability an AI agent needs when deciding whether to use your content. Scoring is deterministic: every point maps to a measurable threshold (file exists, token count under ceiling, heading hierarchy valid). No LLM is involved in producing the number.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;1. Discoverability (0–25)&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;This signal checks whether the URL returns server-rendered HTML, whether an &lt;code&gt;llms.txt&lt;/code&gt; file exists at the domain root, and whether AI crawlers receive a successful response. A page returning HTTP 200 with parseable content passes. A page returning 403 or 429 to AI user agents fails.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;2. Parsability (0–25)&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;This signal scores heading hierarchy (H1 through H6), presence of code blocks and tables, and whether the page has semantic landmarks. Because agents parse structurally rather than linearly, it’s essential for sites to be well organized and logical. Osmani suggests serving Markdown &lt;strong&gt;and&lt;/strong&gt; HTML, leading each section with the outcome, and using tables for parameter references, among other tips that make your site easier to parse.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;3. Token efficiency (0–25)&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;It measures total token count against a 30,000-token ceiling and a 15,000-token quick-start target. Pages bloated with navigation elements or repeated boilerplate score lower.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;4. Capability signaling (0–15)&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;This signal checks for &lt;code&gt;AGENTS.md&lt;/code&gt; or &lt;code&gt;skill.md&lt;/code&gt; files describing available actions, required inputs, authentication, and rate limits. Without these, agents discover capabilities through trial and error.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;5. Access control (0–10)&lt;/strong&gt;&lt;/p&gt; 
&lt;p&gt;It checks &lt;code&gt;robots.txt&lt;/code&gt; for AI-specific rules (GPTBot, ClaudeBot, PerplexityBot). Pages with explicit Allow or Disallow rules for AI user agents score higher than pages with no AI-specific rules, where access is open by default. Either choice is fine. The signal rewards making the decision on purpose.&lt;/p&gt; 
&lt;p&gt;Deterministic scores feed into the analyze step, where Bedrock generates prose explanations and actionable fix recommendations.&lt;/p&gt; 
&lt;h2 id="example-auditing-a-real-page"&gt;Example: auditing a real page&lt;/h2&gt; 
&lt;p&gt;To see the pipeline in action, here are the results from a technical documentation page: a conceptual overview for a cloud computing service.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Target:&lt;/strong&gt; A technical documentation page (conceptual overview, 958 words)&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Overall score: 58/100&lt;/strong&gt;&lt;/p&gt; 
&lt;table border="1px" width="100%" cellpadding="10px"&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;&lt;strong&gt;Signal&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Score&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Key finding&lt;/strong&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Discoverability&lt;/td&gt; 
   &lt;td&gt;17/25&lt;/td&gt; 
   &lt;td&gt;Server-rendered, &lt;code&gt;llms.txt&lt;/code&gt; exists (but bloated at 295 KB / ~74K tokens compared to the recommended 5K token limit). No &lt;code&gt;AGENTS.md&lt;/code&gt;.&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Parsability&lt;/td&gt; 
   &lt;td&gt;14/25&lt;/td&gt; 
   &lt;td&gt;Invalid heading hierarchy (H1 to H6 to H2). No fenced code blocks or tables despite being technical documentation. 63.9% HTML noise ratio.&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Token efficiency&lt;/td&gt; 
   &lt;td&gt;25/25&lt;/td&gt; 
   &lt;td&gt;1,245 tokens. Well under both the 15K quickstart target and 30K ceiling.&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Capability signaling&lt;/td&gt; 
   &lt;td&gt;0/15&lt;/td&gt; 
   &lt;td&gt;No &lt;code&gt;skill.md&lt;/code&gt;. Agents cannot discover what actions this documentation enables.&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Access control&lt;/td&gt; 
   &lt;td&gt;2/10&lt;/td&gt; 
   &lt;td&gt;No AI-specific rules in &lt;code&gt;robots.txt&lt;/code&gt;. Access is accidental rather than intentional.&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;p&gt;&lt;strong&gt;Top three fixes:&lt;/strong&gt;&lt;/p&gt; 
&lt;ol type="1"&gt; 
 &lt;li&gt;Create a &lt;code&gt;skill.md&lt;/code&gt; declaring what agents can do with this service (available actions, required inputs, constraints).&lt;/li&gt; 
 &lt;li&gt;Fix the heading hierarchy to follow valid nesting (H1, H2, H3) and add fenced code blocks with language tags.&lt;/li&gt; 
 &lt;li&gt;Add an &lt;code&gt;AGENTS.md&lt;/code&gt; at the domain root and explicit AI crawler rules to &lt;code&gt;robots.txt&lt;/code&gt;.&lt;/li&gt; 
&lt;/ol&gt; 
&lt;p&gt;The scoring is deterministic, and every point maps to a measurable condition. Amazon Bedrock then runs LLM inference on the results to generate the prose findings.&lt;/p&gt; 
&lt;h2 id="under-the-hood-steps-and-callbacks"&gt;Under the hood: Steps and callbacks&lt;/h2&gt; 
&lt;p&gt;Every step in the preceding audit, from fetch through record, runs as a checkpointed step. The callback is optional and sits after the analyze step, if you want a human to review the report before it’s published.&lt;/p&gt; 
&lt;p&gt;Lambda durable functions expose two core primitives: &lt;strong&gt;steps&lt;/strong&gt; and &lt;strong&gt;callbacks&lt;/strong&gt;. This pipeline runs fully automated by default (five steps, no human gate), but you can opt into a callback-based approval gate when the use case calls for it.&lt;/p&gt; 
&lt;h3 id="steps"&gt;Steps&lt;/h3&gt; 
&lt;p&gt;A step is a unit of work. The runtime checkpoints its return value before the next step begins. You declare one with the &lt;code&gt;@step&lt;/code&gt; decorator:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-python"&gt;@durable_step
def score_content(step_context: StepContext, page_content: str) -&amp;gt; dict:
    response = bedrock.invoke_model(
        modelId=os.environ["BEDROCK_MODEL_ID"],
        body=json.dumps({"prompt": build_scoring_prompt(page_content)})
    )
    return json.loads(response["body"].read())&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;If this step succeeds, its return value is persisted. On retry, completed steps are skipped and their cached results passed forward. Two rules:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Keep return values small.&lt;/strong&gt; Return structured results, not raw API responses.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;One side effect per step.&lt;/strong&gt; A step that calls Bedrock and also writes to DynamoDB is harder to reason about on retry. Make one external call per step.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3 id="callbacks"&gt;Callbacks&lt;/h3&gt; 
&lt;p&gt;By default, the pipeline runs all five steps without stopping. To add a human review gate, turn on the callback. The function suspends without incurring additional costs until an external signal arrives. In practice, you wire this to a Slack bot or approval dashboard rather than a CLI command. Resumption happens through the &lt;code&gt;SendDurableExecutionCallbackSuccess&lt;/code&gt; AWS API call with the callback ID. Because this is an authenticated API call, only principals with the appropriate IAM permissions can signal completion.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-python"&gt;# In the handler (called on DurableContext, not inside a step):
callback = context.create_callback(name="review_report")
send_to_reviewer(callback.callback_id, report)

# Execution suspends here until the external system calls
# SendDurableExecutionCallbackSuccess with the callback ID.
result = callback.result()&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;The function suspends at &lt;code&gt;callback.result()&lt;/code&gt; without incurring additional costs. The external system calls &lt;code&gt;SendDurableExecutionCallbackSuccess&lt;/code&gt; with the callback ID and the approval payload. Timeouts raise &lt;code&gt;TimeoutError&lt;/code&gt; for fallback routing.&lt;/p&gt; 
&lt;h3 id="when-to-add-a-callback"&gt;When to add a callback&lt;/h3&gt; 
&lt;table border="1px" width="100%" cellpadding="10px"&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;&lt;strong&gt;Run fully automated when…&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Add a callback when…&lt;/strong&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Scheduled audits or continuous integration and continuous delivery (CI/CD) regression monitoring&lt;/td&gt; 
   &lt;td&gt;High-stakes pages needing human sign-off&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Reports feed directly into dashboards or alerts&lt;/td&gt; 
   &lt;td&gt;External workflow integration (Slack, Jira, webhook)&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Fixes are suggestions, not auto-applied actions&lt;/td&gt; 
   &lt;td&gt;Downstream actions are gated (auto-filing tickets)&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;p&gt;By default, the pipeline skips the callback entirely. To turn it on, set &lt;code&gt;APPROVAL_GATE=true&lt;/code&gt; in the function’s environment variables.&lt;/p&gt; 
&lt;h2 id="clean-up"&gt;Clean up&lt;/h2&gt; 
&lt;p&gt;To avoid ongoing charges, delete the stack when you’re done experimenting:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;sam delete --stack-name aeo-scoring-pipeline&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;This removes the Lambda durable function, DynamoDB table, S3 bucket (if empty), and the associated IAM roles. If your S3 bucket contains audit reports you want to keep, download them first or remove the &lt;code&gt;DeletionPolicy: Delete&lt;/code&gt; setting from the template before deploying.&lt;/p&gt; 
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt; 
&lt;p&gt;You now have a five-step AEO scoring pipeline in a single Lambda function that checkpoints between steps without incurring additional costs. Some steps involve LLM inference you don’t want to pay for twice. Durable checkpoints help make sure you do not.&lt;/p&gt; 
&lt;p&gt;To get started:&lt;/p&gt; 
&lt;ol type="1"&gt; 
 &lt;li&gt;Clone the repository: &lt;a href="https://github.com/aws-samples/sample-aeo-scoring-pipeline" target="_blank" rel="noopener"&gt;github.com/aws-samples/sample-aeo-scoring-pipeline&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;Deploy with &lt;code&gt;sam build &amp;amp;&amp;amp; sam deploy --guided&lt;/code&gt;&lt;/li&gt; 
 &lt;li&gt;Run your first audit: &lt;code&gt;aws lambda invoke --function-name AeoScoringPipeline --payload '{"url": "https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html"}'&lt;/code&gt;&lt;/li&gt; 
&lt;/ol&gt; 
&lt;p&gt;Next steps: schedule audits using Amazon EventBridge, add Slack alerts when scores drop, or extend the rubric with domain-specific signals.&lt;/p&gt; 
&lt;p&gt;For more on Lambda durable functions, see the &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html" target="_blank" rel="noopener"&gt;AWS Lambda durable functions Developer Guide&lt;/a&gt;. For the AEO framework, see Addy Osmani’s original post on agent-optimized content.&lt;/p&gt;</content:encoded>
					
		
		
			</item>
		<item>
		<title>Your serverless attendee’s guide to AWS re:Invent 2026</title>
		<link>https://aws.amazon.com/blogs/compute/your-serverless-attendees-guide-to-aws-reinvent-2026/</link>
		
		<dc:creator><![CDATA[Nicolas Tarzia]]></dc:creator>
		<pubDate>Wed, 14 Oct 2026 16:55:24 +0000</pubDate>
				<category><![CDATA[AWS re:Invent]]></category>
		<category><![CDATA[Serverless]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">bfca6f7649a90a6261c5159aa7228e2d8c2fdba9</guid>

					<description>AWS re:Invent 2026 offers an extensive selection of serverless and application integration content, including new AWS Lambda execution models, AI agents as a new kind of serverless consumer, and maturing event-driven patterns. This guide helps you navigate the serverless sessions and find the content most relevant to you.</description>
										<content:encoded>&lt;p&gt;AWS re:Invent 2026 offers an extensive selection of serverless and application integration content. This year’s lineup includes new &lt;a href="https://aws.amazon.com/lambda/" target="_blank" rel="noopener"&gt;AWS Lambda&lt;/a&gt; execution models: durable functions, Lambda Managed Instances, and Lambda MicroVMs. It also covers AI agents as a new kind of serverless consumer and maturing patterns for production event-driven applications.&lt;/p&gt; 
&lt;p&gt;Don’t have a ticket yet? &lt;a href="https://reinvent.awsevents.com/" target="_blank" rel="noopener"&gt;Register for re:Invent 2026&lt;/a&gt; and join us in Las Vegas from November 30 to December 4.&lt;/p&gt; 
&lt;p&gt;For detailed descriptions and schedule, visit the &lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog" target="_blank" rel="noopener"&gt;AWS re:Invent Session Catalog&lt;/a&gt;. Sessions are held across several venues, so allow extra time to travel between properties.&lt;/p&gt; 
&lt;p&gt;We’ve curated this guide to help you navigate the serverless sessions and find the content most relevant to you.&lt;/p&gt; 
&lt;h2 id="session-types"&gt;Session types&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Breakout Sessions&lt;/strong&gt; are lecture-style presentations covering architecture, best practices, and deep dives into AWS services.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Workshops&lt;/strong&gt; are 2-hour hands-on sessions where you work through tasks in AWS accounts using AWS services. Laptops are required.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Chalk Talks&lt;/strong&gt; are highly interactive 60-minute sessions with smaller audiences, focused on technical deep dives with whiteboards for architectural discussions.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Builders’ Sessions&lt;/strong&gt; are 60-minute small-group sessions led by an AWS expert who guides you through a technical problem using AWS services.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Code Talks&lt;/strong&gt; are 60-minute live coding sessions where AWS experts show how to build solutions using AWS services.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Lightning Talks&lt;/strong&gt; are 20-minute sessions focused on a single idea.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2 id="whats-new-in-aws-serverless"&gt;What’s new in AWS Serverless&lt;/h2&gt; 
&lt;p&gt;Start here to get oriented on what has changed in serverless heading into re:Invent 2026.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=SVS207" target="_blank" rel="noopener"&gt;SVS207 | Modernizing your compute stack with Lambda’s new execution models&lt;/a&gt;&lt;/strong&gt; – Breakout Session&lt;/p&gt; 
&lt;p&gt;Choose a Lambda execution model for each workload class, run mixed deployments, and compare monitoring across models. Bring your workload portfolio.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=SVS305" target="_blank" rel="noopener"&gt;SVS305 | What’s new in AWS Serverless&lt;/a&gt;&lt;/strong&gt; – Workshop&lt;/p&gt; 
&lt;p&gt;Build with the newest serverless releases and work through the trade-offs that matter in real systems.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=SVS339" target="_blank" rel="noopener"&gt;SVS339 | What’s new with Amazon API Gateway&lt;/a&gt;&lt;/strong&gt; – Breakout Session&lt;/p&gt; 
&lt;p&gt;See what’s new in &lt;a href="https://aws.amazon.com/api-gateway/" target="_blank" rel="noopener"&gt;Amazon API Gateway&lt;/a&gt;, including direct service integrations that replace Lambda glue code. Learn how to design APIs for both developers and AI agents, including Model Context Protocol (MCP) servers.&lt;/p&gt; 
&lt;h2 id="getting-started-with-serverless"&gt;Getting started with serverless&lt;/h2&gt; 
&lt;p&gt;Are you new to serverless or taking your first steps? These sessions cover fundamentals and hands-on introductions.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=SVS202" target="_blank" rel="noopener"&gt;SVS202 | Building your first event-driven application&lt;/a&gt;&lt;/strong&gt; – Builders’ Session&lt;/p&gt; 
&lt;p&gt;Build a retail order system on &lt;a href="https://aws.amazon.com/eventbridge/" target="_blank" rel="noopener"&gt;Amazon EventBridge&lt;/a&gt;, Lambda, and &lt;a href="https://aws.amazon.com/dynamodb/" target="_blank" rel="noopener"&gt;Amazon DynamoDB&lt;/a&gt; where each step runs independently and one failure doesn’t cascade. No event-driven experience required.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=SVS301" target="_blank" rel="noopener"&gt;SVS301 | AWS Serverless developer experience&lt;/a&gt;&lt;/strong&gt; – Workshop&lt;/p&gt; 
&lt;p&gt;Build a realistic serverless solution while covering event-driven principles, observability, open-source tools, and deployment automation, in Python, TypeScript, Java, or .NET.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=SVS302" target="_blank" rel="noopener"&gt;SVS302 | Building serverless applications with Terraform&lt;/a&gt;&lt;/strong&gt; – Workshop&lt;/p&gt; 
&lt;p&gt;Define, deploy, and maintain serverless architectures with Terraform, including reusable modules, state management, and deployments across environments.&lt;/p&gt; 
&lt;h2 id="new-lambda-execution-models"&gt;New Lambda execution models&lt;/h2&gt; 
&lt;p&gt;Three Lambda execution models cover different workload shapes: durable functions, Lambda Managed Instances, and Lambda MicroVMs.&lt;/p&gt; 
&lt;h3 id="lambda-durable-functions"&gt;Lambda durable functions&lt;/h3&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=API314" target="_blank" rel="noopener"&gt;API314 | A closer look at AWS Lambda durable functions&lt;/a&gt;&lt;/strong&gt; – Chalk Talk&lt;/p&gt; 
&lt;p&gt;Learn how checkpointing and replay-based recovery work, see patterns such as sagas, fan-out/fan-in, and human-in-the-loop waits, and get a framework for choosing between durable functions and &lt;a href="https://aws.amazon.com/step-functions/" target="_blank" rel="noopener"&gt;AWS Step Functions&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=API316" target="_blank" rel="noopener"&gt;API316 | Coding an AI agent from scratch with AWS Lambda durable functions&lt;/a&gt;&lt;/strong&gt; – Code Talk&lt;/p&gt; 
&lt;p&gt;Build an AI agent from scratch with durable functions, including a tool-use loop, retries with exponential backoff, and human approval that doesn’t bill for idle time.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=SVS325" target="_blank" rel="noopener"&gt;SVS325 | Distributed transactions with Step Functions and durable functions&lt;/a&gt;&lt;/strong&gt; – Builders’ Session&lt;/p&gt; 
&lt;p&gt;Build a payment processing flow with the saga pattern, using Step Functions and durable functions for compensation when part of a transaction fails.&lt;/p&gt; 
&lt;h3 id="lambda-managed-instances"&gt;Lambda Managed Instances&lt;/h3&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=SVS332" target="_blank" rel="noopener"&gt;SVS332 | Lambda Managed Instances: Always-on serverless compute&lt;/a&gt;&lt;/strong&gt; – Chalk Talk&lt;/p&gt; 
&lt;p&gt;Lambda Managed Instances offer Amazon Elastic Compute Cloud (Amazon EC2) economics with multi-concurrency while Lambda manages instance lifecycle, patching, and scaling. Model your break-even point, and bring your Lambda bill.&lt;/p&gt; 
&lt;h3 id="lambda-microvms"&gt;Lambda MicroVMs&lt;/h3&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=SVS307" target="_blank" rel="noopener"&gt;SVS307 | Running untrusted code in sandboxes with AWS Lambda MicroVMs&lt;/a&gt;&lt;/strong&gt; – Builders’ Session&lt;/p&gt; 
&lt;p&gt;Build sandboxes that run untrusted code, such as AI-generated code and third-party plugins, with resource limits, permission boundaries, and tested failure modes.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=SVS337" target="_blank" rel="noopener"&gt;SVS337 | AWS Lambda MicroVMs: Strong isolation for agents and beyond&lt;/a&gt;&lt;/strong&gt; – Breakout Session&lt;/p&gt; 
&lt;p&gt;Learn how Lambda MicroVMs work: VM-level isolation per agent, tenant, or task, with state that persists across invocations and sandboxes that suspend when idle and resume on demand.&lt;/p&gt; 
&lt;h2 id="serverless-and-ai-agents"&gt;Serverless and AI agents&lt;/h2&gt; 
&lt;p&gt;A major theme this year is building, orchestrating, and operating AI agents on serverless infrastructure.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=SVS338" target="_blank" rel="noopener"&gt;SVS338 | Serverless developers in the agentic era: What changes, what doesn’t&lt;/a&gt;&lt;/strong&gt; – Breakout Session&lt;/p&gt; 
&lt;p&gt;See what changes when AI agents call your functions as tools, and what stays the same. Topics include orchestration for non-deterministic workflows and cost governance when one reasoning chain calls 200 functions.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=SVS306" target="_blank" rel="noopener"&gt;SVS306 | Building agentic AI architectures with AWS Serverless&lt;/a&gt;&lt;/strong&gt; – Builders’ Session&lt;/p&gt; 
&lt;p&gt;Build a multi-agent system that uses Lambda for tool execution, &lt;a href="https://aws.amazon.com/bedrock/" target="_blank" rel="noopener"&gt;Amazon Bedrock&lt;/a&gt; for reasoning, and Amazon EventBridge for communication between agents.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=SVS324" target="_blank" rel="noopener"&gt;SVS324 | Building agentic apps with serverless: Lambda as your agent’s toolbox&lt;/a&gt;&lt;/strong&gt; – Chalk Talk&lt;/p&gt; 
&lt;p&gt;Design Lambda functions as agent tools, with single-responsibility tools, clear input and output schemas, MCP-compatible interfaces, and multi-tenant isolation.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=SVS342" target="_blank" rel="noopener"&gt;SVS342 | Coding the tool layer for AI agents on serverless&lt;/a&gt;&lt;/strong&gt; – Code Talk&lt;/p&gt; 
&lt;p&gt;Retrofit a serverless API into an agent tool, live. The build covers an MCP server with versioned tools, discovery through the Gateway capability of &lt;a href="https://aws.amazon.com/bedrock/agentcore/" target="_blank" rel="noopener"&gt;Amazon Bedrock AgentCore&lt;/a&gt;, a Step Functions workflow exposed as one tool, and scoped agent identity.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=API312" target="_blank" rel="noopener"&gt;API312 | Building event-driven, multi-agent architectures on serverless&lt;/a&gt;&lt;/strong&gt; – Chalk Talk&lt;/p&gt; 
&lt;p&gt;Map agent coordination patterns on Amazon EventBridge, such as peer-to-peer messaging, supervisor-worker hierarchies, and broadcast, and the failure modes they introduce, including circular delegation.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=COM325" target="_blank" rel="noopener"&gt;COM325 | The agent orchestration spectrum: agents, Step Functions, or Lambda?&lt;/a&gt;&lt;/strong&gt; – Code Talk&lt;/p&gt; 
&lt;p&gt;Live-code the same AI workload with AgentCore, Step Functions, and durable functions, and compare latency, cost, and debuggability on a production content platform.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=SVS328" target="_blank" rel="noopener"&gt;SVS328 | Guardrails for AI-generated serverless infrastructure&lt;/a&gt;&lt;/strong&gt; – Chalk Talk&lt;/p&gt; 
&lt;p&gt;Coding agents can generate over-permissioned &lt;a href="https://aws.amazon.com/iam/" target="_blank" rel="noopener"&gt;AWS Identity and Access Management (IAM)&lt;/a&gt; policies and skip encryption. Learn which guardrails to automate and which need human review.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=API402" target="_blank" rel="noopener"&gt;API402 | Building event-driven architectures in the age of AI agents&lt;/a&gt;&lt;/strong&gt; – Breakout Session&lt;/p&gt; 
&lt;p&gt;See how familiar patterns such as queues, events, and retries evolve when your consumers are autonomous agents instead of microservices.&lt;/p&gt; 
&lt;h2 id="building-event-driven-architectures"&gt;Building event-driven architectures&lt;/h2&gt; 
&lt;p&gt;Event-driven architectures remain the backbone of serverless applications. These sessions cover patterns from foundational to advanced.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=API302" target="_blank" rel="noopener"&gt;API302 | Serverlesspresso: Build an event-driven app from the ground up&lt;/a&gt;&lt;/strong&gt; – Workshop&lt;/p&gt; 
&lt;p&gt;Build a serverless coffee-ordering app with Lambda, Amazon EventBridge, and durable functions, which checkpoint progress and recover from failures without custom state management.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=API305" target="_blank" rel="noopener"&gt;API305 | Building enterprise-scale event buses with Amazon EventBridge&lt;/a&gt;&lt;/strong&gt; – Builders’ Session&lt;/p&gt; 
&lt;p&gt;Configure an event bus with routing policies, schema discovery, and access controls so platform teams govern events while application teams ship independently.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=API311" target="_blank" rel="noopener"&gt;API311 | How event-driven architectures go wrong and how to fix them&lt;/a&gt;&lt;/strong&gt; – Chalk Talk&lt;/p&gt; 
&lt;p&gt;Dissect costly anti-patterns such as unbounded fan-out, missing dead-letter queues, chatty event schemas, and orchestration gaps that silently drop work, and fix them.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=API317" target="_blank" rel="noopener"&gt;API317 | Coding event-driven retry patterns that prevent outages&lt;/a&gt;&lt;/strong&gt; – Code Talk&lt;/p&gt; 
&lt;p&gt;Live-code exponential backoff with jitter, circuit breakers, poison-pill isolation, and replay from archive for Amazon EventBridge and Step Functions.&lt;/p&gt; 
&lt;h2 id="orchestration-step-functions-and-durable-functions"&gt;Orchestration: Step Functions and durable functions&lt;/h2&gt; 
&lt;p&gt;Both Step Functions and Lambda durable functions handle retries, long-running execution, and failure recovery. These sessions help you choose.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=API318" target="_blank" rel="noopener"&gt;API318 | Composing the right orchestration for serverless workflows&lt;/a&gt;&lt;/strong&gt; – Lightning Talk&lt;/p&gt; 
&lt;p&gt;A decision framework for human approvals, long-running AI agent workflows, and multi-service sagas, plus a hybrid pattern that uses durable functions inside Step Functions.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=ARC329" target="_blank" rel="noopener"&gt;ARC329 | The coordination decision: when to orchestrate and when to let go&lt;/a&gt;&lt;/strong&gt; – Breakout Session&lt;/p&gt; 
&lt;p&gt;Decide per flow whether to orchestrate or let services react to events, using a logistics platform that runs both patterns on Step Functions and Amazon EventBridge.&lt;/p&gt; 
&lt;h2 id="building-apis-and-serverless-web-applications"&gt;Building APIs and serverless web applications&lt;/h2&gt; 
&lt;p&gt;Serverless is increasingly used to build full-stack web applications, not only API backends.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=SVS348" target="_blank" rel="noopener"&gt;SVS348 | Serverless compute built for the web&lt;/a&gt;&lt;/strong&gt; – Breakout Session&lt;/p&gt; 
&lt;p&gt;Build full-stack web applications entirely on serverless services, with patterns for HTTP routing, server-side rendering, static assets, and real-time features.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=SVS327" target="_blank" rel="noopener"&gt;SVS327 | Build interactive web apps with AWS Lambda&lt;/a&gt;&lt;/strong&gt; – Chalk Talk&lt;/p&gt; 
&lt;p&gt;Run web frameworks such as Express, Hono, and &lt;code&gt;Next.js&lt;/code&gt; on Lambda with runtime adapters, including migration paths for containerized web apps.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=API304" target="_blank" rel="noopener"&gt;API304 | API Gateway unleashed&lt;/a&gt;&lt;/strong&gt; – Workshop&lt;/p&gt; 
&lt;p&gt;Create, deploy, and manage APIs with API Gateway, including message transformation, request validation, security, Infrastructure as Code, and WebSocket backends.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=API306" target="_blank" rel="noopener"&gt;API306 | Build secure APIs faster with Amazon API Gateway and Kiro CLI&lt;/a&gt;&lt;/strong&gt; – Builders’ Session&lt;/p&gt; 
&lt;p&gt;Implement and compare API Gateway authorization with &lt;a href="https://aws.amazon.com/cognito/" target="_blank" rel="noopener"&gt;Amazon Cognito&lt;/a&gt; user pools, &lt;a href="https://aws.amazon.com/verified-permissions/" target="_blank" rel="noopener"&gt;Amazon Verified Permissions&lt;/a&gt;, Lambda custom authorizers, and IAM authorizers. Then go from spec to deployed API with Kiro CLI, OpenAPI, and MCP servers.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=API309" target="_blank" rel="noopener"&gt;API309 | Amazon API Gateway: Migration strategies and agent-ready APIs&lt;/a&gt;&lt;/strong&gt; – Chalk Talk&lt;/p&gt; 
&lt;p&gt;Learn migration strategies from legacy API platforms, then design APIs that AI agents can discover, authenticate against, and call, including MCP-compatible tool definitions.&lt;/p&gt; 
&lt;h2 id="serverless-developer-experience"&gt;Serverless developer experience&lt;/h2&gt; 
&lt;p&gt;AI-assisted development is changing how serverless applications are built, tested, and deployed.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=SVS303" target="_blank" rel="noopener"&gt;SVS303 | AI-driven serverless development with Kiro&lt;/a&gt;&lt;/strong&gt; – Workshop&lt;/p&gt; 
&lt;p&gt;Use Kiro to build a serverless application with authentication, tests, observability, and an optional continuous integration and continuous delivery (CI/CD) pipeline.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=SVS343" target="_blank" rel="noopener"&gt;SVS343 | A day in the life of a serverless builder&lt;/a&gt;&lt;/strong&gt; – Code Talk&lt;/p&gt; 
&lt;p&gt;Follow one serverless application from first line of code to production, live: an AI coding agent generates the scaffolding, and you debug a failing request with OpenTelemetry.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=SVS329" target="_blank" rel="noopener"&gt;SVS329 | Testing serverless and event-driven applications&lt;/a&gt;&lt;/strong&gt; – Chalk Talk&lt;/p&gt; 
&lt;p&gt;Whiteboard testing strategies for serverless and event-driven apps, from unit and contract tests to chaos techniques such as duplicate and out-of-order delivery.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=SVS322" target="_blank" rel="noopener"&gt;SVS322 | Build self-healing serverless applications with AWS DevOps Agent&lt;/a&gt;&lt;/strong&gt; – Builders’ Session&lt;/p&gt; 
&lt;p&gt;Inject failures such as Lambda throttling, timeout cascades, and dead-letter queue buildup, then configure AWS DevOps Agent to find root causes and apply fixes with approval gates.&lt;/p&gt; 
&lt;h2 id="performance-cost-and-operations-at-scale"&gt;Performance, cost, and operations at scale&lt;/h2&gt; 
&lt;p&gt;Tune your Lambda functions, optimize costs, and learn what changes when you operate at enterprise scale.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=SVS341" target="_blank" rel="noopener"&gt;SVS341 | Lambda performance tuning and cost optimization&lt;/a&gt;&lt;/strong&gt; – Chalk Talk&lt;/p&gt; 
&lt;p&gt;Go beyond memory tuning with SnapStart and provisioned concurrency, event source mapping tuning, and guidance on when Lambda Managed Instances beat per-invocation pricing.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=SVS335" target="_blank" rel="noopener"&gt;SVS335 | Operating serverless at scale: What changes at 1,000+ functions&lt;/a&gt;&lt;/strong&gt; – Chalk Talk&lt;/p&gt; 
&lt;p&gt;Learn what changes between 10 and 1,000 functions: safe deployments, account structure and concurrency management, observability without cardinality overload, and platform patterns.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=ARC325" target="_blank" rel="noopener"&gt;ARC325 | Serverless at 1M RPS: Lambda, DynamoDB, and SQS scaling lessons&lt;/a&gt;&lt;/strong&gt; – Chalk Talk&lt;/p&gt; 
&lt;p&gt;Push Lambda, DynamoDB, and &lt;a href="https://aws.amazon.com/sqs/" target="_blank" rel="noopener"&gt;Amazon Simple Queue Service (Amazon SQS)&lt;/a&gt; to one million requests per second and see what breaks. The session shares real numbers on cold start budgets, retry amplification, and backpressure.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=SVS334" target="_blank" rel="noopener"&gt;SVS334 | Serverless observability: OpenTelemetry and vended logs&lt;/a&gt;&lt;/strong&gt; – Chalk Talk&lt;/p&gt; 
&lt;p&gt;Set up OpenTelemetry and API Gateway vended logs for tracing across Step Functions, Amazon EventBridge, and SQS, plus observability for agentic workloads such as token use.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=SVS320" target="_blank" rel="noopener"&gt;SVS320 | Same code, any compute: Portable architecture on AWS&lt;/a&gt;&lt;/strong&gt; – Builders’ Session&lt;/p&gt; 
&lt;p&gt;Apply Hexagonal Architecture and 12-factor patterns so compute is a deployment decision, not an architectural one, using the AWS Lambda Web Adapter and runtime-neutral handlers.&lt;/p&gt; 
&lt;h2 id="serverless-data-processing"&gt;Serverless data processing&lt;/h2&gt; 
&lt;p&gt;Process data at scale without provisioning clusters or managing batch infrastructure.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=SVS309" target="_blank" rel="noopener"&gt;SVS309 | Building serverless distributed data processing workloads&lt;/a&gt;&lt;/strong&gt; – Builders’ Session&lt;/p&gt; 
&lt;p&gt;Build a pipeline with Step Functions Distributed Map, Lambda, and &lt;a href="https://aws.amazon.com/s3/" target="_blank" rel="noopener"&gt;Amazon Simple Storage Service (Amazon S3)&lt;/a&gt; that processes thousands of objects in parallel and handles partial failures.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=SVS321" target="_blank" rel="noopener"&gt;SVS321 | Serverless streaming data processing with AWS Lambda and Apache Kafka&lt;/a&gt;&lt;/strong&gt; – Builders’ Session&lt;/p&gt; 
&lt;p&gt;Build a real-time location tracking app that ingests events from &lt;a href="https://aws.amazon.com/msk/" target="_blank" rel="noopener"&gt;Amazon Managed Streaming for Apache Kafka (Amazon MSK)&lt;/a&gt;, processes them with Lambda, and updates a dashboard through &lt;a href="https://aws.amazon.com/appsync/" target="_blank" rel="noopener"&gt;AWS AppSync&lt;/a&gt;.&lt;/p&gt; 
&lt;h2 id="community-sessions"&gt;Community sessions&lt;/h2&gt; 
&lt;p&gt;Sessions led by AWS community members and customers sharing production experience with the preceding execution models and patterns.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=COM303" target="_blank" rel="noopener"&gt;COM303 | Lambda for every scale and workload shape&lt;/a&gt;&lt;/strong&gt; – Breakout Session&lt;/p&gt; 
&lt;p&gt;Honeycomb shares how it runs its query backend across all three Lambda execution models. Honeycomb reports that Managed Instances absorb steady-state traffic at roughly 7.5x lower cost than Functions, while MicroVMs take spikes and Functions catch bursts.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=COM326" target="_blank" rel="noopener"&gt;COM326 | Observable agents with Lambda durable functions and OpenTelemetry&lt;/a&gt;&lt;/strong&gt; – Code Talk&lt;/p&gt; 
&lt;p&gt;Build a multi-agent purchasing coordinator on durable functions and instrument it with OpenTelemetry for one coherent trace across all invocations, plus &lt;a href="https://aws.amazon.com/cloudwatch/" target="_blank" rel="noopener"&gt;Amazon CloudWatch&lt;/a&gt; insights for fleet-wide queries.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;&lt;a href="https://registration.awsevents.com/flow/awsevents/reinvent2026/eventcatalog/page/eventcatalog?search=COM304" target="_blank" rel="noopener"&gt;COM304 | Hidden trade-offs in distributed architectures&lt;/a&gt;&lt;/strong&gt; – Breakout Session&lt;/p&gt; 
&lt;p&gt;Investigate unexpected system behavior in a real-world case study built on Lambda, DynamoDB, DynamoDB Streams, and Step Functions, and learn the trade-offs behind it.&lt;/p&gt; 
&lt;h2 id="additional-resources"&gt;Additional resources&lt;/h2&gt; 
&lt;p&gt;Many sessions run more than once, so if a session is full, check the catalog for another time.&lt;/p&gt; 
&lt;p&gt;If you cannot join in person, we upload breakout sessions to the &lt;a href="https://www.youtube.com/c/AWSEventsChannel" target="_blank" rel="noopener"&gt;AWS Events YouTube channel&lt;/a&gt; after the event.&lt;/p&gt; 
&lt;p&gt;For more serverless learning resources, visit &lt;a href="https://serverlessland.com" target="_blank" rel="noopener"&gt;Serverless Land&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;We look forward to seeing you at re:Invent 2026!&lt;/p&gt;</content:encoded>
					
		
		
			</item>
		<item>
		<title>Exploring AWS Lambda Web Functions for building web applications</title>
		<link>https://aws.amazon.com/blogs/compute/exploring-aws-lambda-web-functions-for-building-web-applications/</link>
		
		<dc:creator><![CDATA[Julian Wood]]></dc:creator>
		<pubDate>Tue, 13 Oct 2026 17:59:52 +0000</pubDate>
				<category><![CDATA[Announcements]]></category>
		<category><![CDATA[AWS Lambda]]></category>
		<category><![CDATA[Intermediate (200)]]></category>
		<guid isPermaLink="false">fbffcc9550dea957bd17c89c6ea501ec07bdbe6d</guid>

					<description>Run a standard Node.js web server on AWS Lambda with Lambda Web Functions, a new type of Lambda function. Deploy it with one command or AWS CloudFormation and get a public HTTPS endpoint with no adapter layer and no servers to manage. See how one execution environment handles many concurrent requests and how active-CPU billing keeps the cost of waiting low.</description>
										<content:encoded>&lt;p&gt;You can now run a standard &lt;code&gt;Node.js&lt;/code&gt; web server on &lt;a href="https://aws.amazon.com/lambda" target="_blank" rel="noopener"&gt;AWS Lambda&lt;/a&gt; with Lambda Web Functions, a new type of Lambda function. Deploy it with one command or &lt;a href="https://aws.amazon.com/cloudformation/" target="_blank" rel="noopener"&gt;AWS CloudFormation&lt;/a&gt; and get a public HTTPS endpoint with no adapter layer and no servers or load balancers to manage.&lt;/p&gt; 
&lt;p&gt;Lambda Web Functions suit server-side rendered web apps, REST and GraphQL APIs, streaming endpoints, and microservices. Building on the &lt;a href="https://aws.amazon.com/blogs/aws/announcing-aws-lambda-web-functions-for-fast-consistent-web-app-performance-anywhere" target="_blank" rel="noopener"&gt;launch announcement&lt;/a&gt;, this post uses a sample application to show how one execution environment handles many requests at once and how the same app serves a global audience. See how active-CPU billing keeps the cost of waiting low while your code waits, with memory and requests billed separately.&lt;/p&gt; 
&lt;h2 id="overview"&gt;Overview&lt;/h2&gt; 
&lt;p&gt;Lambda launched in 2014 with a minimal model: upload your code, and the service handles everything else. For over a decade that code ran as an event handler, invoked once per event such as a batch of queue messages or an object landing in &lt;a href="https://aws.amazon.com/s3/" target="_blank" rel="noopener"&gt;Amazon Simple Storage Service (Amazon S3)&lt;/a&gt;. We now call this an &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/lambda-functions-chapter.html" target="_blank" rel="noopener"&gt;Event Function&lt;/a&gt; and it remains the right choice for event-driven work.&lt;/p&gt; 
&lt;p&gt;Web Functions are a second type of Lambda function, running on the same &lt;a href="https://firecracker-microvm.github.io/" target="_blank" rel="noopener"&gt;Firecracker&lt;/a&gt;-based isolation as Event Functions. Instead of a handler that receives an event, your code runs as a standard HTTP server that listens on a port, which is what lets a web framework, or in this case a plain &lt;code&gt;Node.js&lt;/code&gt; server, run unmodified.&lt;/p&gt; 
&lt;p&gt;A Web Function is made of three resources:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Web Function&lt;/strong&gt; is the top-level resource with a name and configuration.&lt;/li&gt; 
 &lt;li&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/web-functions-revisions.html" target="_blank" rel="noopener"&gt;Revision&lt;/a&gt; is an immutable snapshot of your code and configuration which Lambda creates each time you deploy code or change revision configuration, so you can roll back by routing traffic to an earlier revision.&lt;/li&gt; 
 &lt;li&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/web-functions-endpoints.html" target="_blank" rel="noopener"&gt;Endpoint&lt;/a&gt; is a network entry point with a unique HTTPS domain, an authentication type, and the rules that route traffic to your revisions.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;At launch, Web Functions run Node.js 24 on Arm64, with 2 vCPUs and 2 GB of memory per execution environment. Web Functions support Amazon Virtual Private Cloud (VPC) connectivity, allowing your function to access resources that exist within a VPC.&lt;/p&gt; 
&lt;h2 id="walkthrough"&gt;Walkthrough&lt;/h2&gt; 
&lt;p&gt;&lt;code&gt;Node.js&lt;/code&gt; frameworks that start an HTTP server, such as Express, Fastify, and Hono, run without adapters. &lt;code&gt;Next.js&lt;/code&gt; in standalone mode needs a small &lt;code&gt;index.js&lt;/code&gt; that sets its host and port. This post uses a plain &lt;code&gt;Node.js&lt;/code&gt; server to stay dependency-free.&lt;/p&gt; 
&lt;p&gt;The full source is available in the &lt;a href="https://serverlessland.com/patterns/lambda-web-sse-dashboard-nodejs-awscli" target="_blank" rel="noopener"&gt;Serverless Patterns collection&lt;/a&gt; along with &lt;a href="http://serverlessland.com/patterns?services=lambda-web-functions" target="_blank" rel="noopener"&gt;other Web Functions patterns&lt;/a&gt;.&lt;/p&gt; 
&lt;h3 id="prerequisites"&gt;Prerequisites&lt;/h3&gt; 
&lt;p&gt;You need an AWS account with the &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html" target="_blank" rel="noopener"&gt;AWS Command Line Interface (AWS CLI)&lt;/a&gt; installed and configured and &lt;a href="https://nodejs.org/" target="_blank" rel="noopener"&gt;&lt;code&gt;Node.js&lt;/code&gt;&lt;/a&gt; installed locally.&lt;/p&gt; 
&lt;p&gt;The &lt;a href="https://serverlessland.com/patterns/lambda-web-sse-dashboard-nodejs-awscli" target="_blank" rel="noopener"&gt;pattern instructions&lt;/a&gt; show how to clone the repo and change to the pattern directory or download the pattern .zip file to run the example.&lt;/p&gt; 
&lt;h3 id="the-app"&gt;The app&lt;/h3&gt; 
&lt;p&gt;The dashboard is a single &lt;code&gt;Node.js&lt;/code&gt; HTTP server that streams live server metrics to the browser over &lt;a href="https://html.spec.whatwg.org/multipage/server-sent-events.html" target="_blank" rel="noopener"&gt;server-sent events&lt;/a&gt; (SSE).&lt;/p&gt; 
&lt;p&gt;The runtime provides the address to listen on in the &lt;code&gt;AWS_LAMBDA_HTTP_ENDPOINT&lt;/code&gt; environment variable, in &lt;code&gt;host:port&lt;/code&gt; form. The server reads it and starts listening, exactly as it would anywhere else:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-javascript"&gt;const [host, port] = (process.env.AWS_LAMBDA_HTTP_ENDPOINT || "0.0.0.0:3000").split(":");
server.listen(Number(port), host);&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;The runtime is &lt;code&gt;nodejs24.x&lt;/code&gt;, and it loads &lt;code&gt;index.js&lt;/code&gt; at the package root by default. To use a different entry file, set &lt;code&gt;AWS_LAMBDA_NODEJS_ENTRYPOINT&lt;/code&gt; to its path.&lt;/p&gt; 
&lt;h3 id="run-locally"&gt;Run locally&lt;/h3&gt; 
&lt;p&gt;You can run the server locally with &lt;code&gt;npm start&lt;/code&gt;.&lt;/p&gt; 
&lt;p&gt;Browse to &lt;code&gt;http://localhost:3000/&lt;/code&gt; to view the dashboard streaming from the local server.&lt;/p&gt; 
&lt;h3 id="deploy"&gt;Deploy&lt;/h3&gt; 
&lt;ol type="1"&gt; 
 &lt;li&gt;Deploy using the single command: 
  &lt;div class="hide-language"&gt; 
   &lt;pre&gt;&lt;code class="language-bash"&gt;aws lambda-web deploy --name lambda-web-sse-dashboard --code .&lt;/code&gt;&lt;/pre&gt; 
  &lt;/div&gt; &lt;p&gt;For this example, you can also use &lt;code&gt;npm run deploy&lt;/code&gt; defined in the &lt;code&gt;package.json&lt;/code&gt; file.&lt;/p&gt;&lt;/li&gt; 
&lt;/ol&gt; 
&lt;p&gt;The AWS CLI bundles your code, creates the function and an endpoint named &lt;code&gt;dev&lt;/code&gt; with a live HTTPS URL. It also creates an execution role and a versioned S3 bucket, if one does not exist, that all CLI-deployed Web Functions in the Region share.&lt;/p&gt; 
&lt;ol start="2" type="1"&gt; 
 &lt;li&gt;Press &lt;strong&gt;Enter&lt;/strong&gt; to create the resources.&lt;/li&gt; 
&lt;/ol&gt; 
&lt;p&gt;The AWS CLI output shows the URL in the format: &lt;code&gt;https://&amp;lt;id&amp;gt;.&amp;lt;shard&amp;gt;.lambda-web.&amp;lt;region&amp;gt;.on.aws&lt;/code&gt;&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/30/ComputeBlog-2664-1.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/30/ComputeBlog-2664-1.png" alt="AWS CLI terminal output from the aws lambda-web deploy command showing the created function and live HTTPS endpoint URL" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 1: AWS CLI showing the aws lambda-web deploy command.&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;Browse to the URL and the dashboard loads, already streaming. This endpoint is public and the sample has no authentication, so use it for evaluation and delete it when you finish.&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/30/ComputeBlog-2664-2.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/30/ComputeBlog-2664-2.png" alt="Streaming dashboard in the browser showing live function information, including environment uptime and open connection count" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 2: The app streaming dashboard showing function information.&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;The dashboard shows how long the execution environment has been alive and how many streaming connections it is holding open. It shows how much CPU it has used with a button to generate real CPU load on demand. The function runs in the US East (N. Virginia) Region (us-east-1). From my laptop in the United Kingdom, latency is 90 ms.&lt;/p&gt; 
&lt;p&gt;The dashboard updates every two seconds over a single HTTP streaming response. A Web Function environment is a long-lived process, so it keeps the connection open and keeps pushing data to the browser. The long-lived process can also run background tasks outside the main request path, such as emitting telemetry events.&lt;/p&gt; 
&lt;p&gt;An Event Function environment serves one request at a time. It can stream a response during an invocation, but each open stream occupies a whole environment. Lambda freezes the environment between invocations, so background work stops.&lt;/p&gt; 
&lt;h3 id="active-cpu-billing"&gt;Active-CPU billing&lt;/h3&gt; 
&lt;p&gt;If the environment stays alive for minutes at a time, what are you paying for? You pay for requests, consumed memory, and the CPU time the environment consumes. For this example, compare connection uptime with CPU time. The environment keeps running but uses only a fraction of a second of CPU.&lt;/p&gt; 
&lt;p&gt;Choose &lt;strong&gt;Generate CPU load&lt;/strong&gt;, and the app runs a cryptographic hashing loop for about 1.5 seconds. CPU time climbs on the chart, then falls back to near zero when the work stops. When a request waits on a database, downstream API, or AI inference, your code uses little CPU, so the wait costs less than it would under wall-clock billing.&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/30/ComputeBlog-2664-3.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/30/ComputeBlog-2664-3.png" alt="Dashboard CPU chart showing a spike in CPU time after choosing Generate CPU load, then falling back toward zero" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 3: CPU chart mid-spike after choosing Generate CPU load.&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;For pricing details, read the &lt;a href="https://aws.amazon.com/lambda/pricing/" target="_blank" rel="noopener"&gt;AWS Lambda pricing page&lt;/a&gt;.&lt;/p&gt; 
&lt;h2 id="concurrency-and-scale-out"&gt;Concurrency and scale-out&lt;/h2&gt; 
&lt;p&gt;With Web Functions, each execution environment handles many requests at once, not one at a time. As environments approach their concurrency limit, Lambda adds more environments and removes them again when traffic falls.&lt;/p&gt; 
&lt;p&gt;You can control how a Web Function scales. &lt;code&gt;maxConcurrencyPerEnvironment&lt;/code&gt; sets the maximum number of requests each execution environment handles at once, up to 128, with a default of 64. On the endpoint, &lt;code&gt;maxEnvironments&lt;/code&gt; caps the number of execution environments and &lt;code&gt;rateLimit&lt;/code&gt; caps requests per second. You can use these two settings to protect downstream dependencies such as databases and external APIs. Both apply in each Region the endpoint serves and &lt;code&gt;maxEnvironments&lt;/code&gt; applies to each revision. Requests above a limit receive HTTP 429 and are not queued.&lt;/p&gt; 
&lt;p&gt;Generate load on the app. Send 300 streaming requests to the &lt;code&gt;/api/events&lt;/code&gt; endpoint, with up to 200 open at once, rather than a burst of quick responses.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;curl -sN --parallel --parallel-immediate --parallel-max 200 --max-time 90 "https://&amp;lt;ENDPOINT&amp;gt;/api/events?[1-300]"&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/30/ComputeBlog-2664-4.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/30/ComputeBlog-2664-4.png" alt="Dashboard showing many concurrent SSE connections held open by a single execution environment during the load test" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 4: Concurrency showing increased connections in a single execution environment.&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;The dashboard updates to reflect the active SSE connections and peak for the currently connected execution environment.&lt;/p&gt; 
&lt;p&gt;The runtime also writes a per-environment summary record to &lt;a href="https://aws.amazon.com/cloudwatch/" target="_blank" rel="noopener"&gt;Amazon CloudWatch&lt;/a&gt; Logs every minute with the instance ID, request count, peak concurrency, and CPU time. A CloudWatch Logs Insights query aggregates them across the fleet:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;QID=$(aws logs start-query \
    --log-group-name /aws/lambda/web/lambda-web-sse-dashboard \
    --start-time $(($(date +%s)-300)) --end-time $(date +%s) \
    --query-string 'filter type="platform.invokeSummary" | stats count_distinct(record.instanceId) as environments, sum(record.metrics.requests) as totalRequests, max(record.metrics.concurrentRequests) as peakConcurrency, sum(record.metrics.cpuTimeMs)/1000 as totalCpuSeconds' \
    --query queryId --output text) &amp;amp;&amp;amp; sleep 6 &amp;amp;&amp;amp; aws logs get-query-results --query-id "$QID"&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;From a sample run of 300 streaming requests with up to 200 open at once, the logs showed the following:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;Execution environments used: 5.&lt;/li&gt; 
 &lt;li&gt;Total requests handled: 484.&lt;/li&gt; 
 &lt;li&gt;Peak concurrency on a single environment: 59.&lt;/li&gt; 
 &lt;li&gt;Total CPU consumed across the whole fleet: 4.75 seconds.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;One environment peaked at 59 connections, near the default limit of 64. Lambda adds environments before existing ones reach their limit, so this load used five. Event Functions serve one request per environment, so 200 open streams would need up to 200 environments. Across 484 requests, the whole fleet used about 4.8 seconds of CPU.&lt;/p&gt; 
&lt;p&gt;Each environment reports only its own connections, because Lambda routes each request independently with no session affinity.&lt;/p&gt; 
&lt;h2 id="going-multi-region"&gt;Going multi-Region&lt;/h2&gt; 
&lt;p&gt;The same app can serve each caller from the Region with the lowest latency. Because an endpoint’s type and Regions are fixed when you create it, going global means adding a new endpoint:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws lambda-web deploy --name lambda-web-sse-dashboard --code . --endpoint-name global --endpoint-type MultiRegion --regions us-east-1,eu-west-2&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/30/ComputeBlog-2664-5.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/30/ComputeBlog-2664-5.png" alt="AWS CLI terminal output creating a multi-Region global endpoint and confirming replication to a second Region" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 5: AWS CLI creating a global endpoint.&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;Lambda replicates your code and revision configuration, including environment variables, to each Region, and centralizes logs in the home Region. In this case, Lambda replicates to Europe (London) Region (eu-west-2). It provides a single global domain URL and uses &lt;a href="https://aws.amazon.com/route53/" target="_blank" rel="noopener"&gt;Amazon Route 53&lt;/a&gt; latency-based routing to send each request to the lowest-latency Region.&lt;/p&gt; 
&lt;p&gt;Browse to the new global URL which is now in the format: &lt;code&gt;https://&amp;lt;domain&amp;gt;.lambda-web.global.on.aws&lt;/code&gt;&lt;/p&gt; 
&lt;div style="width: 552px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/30/ComputeBlog-2664-6.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/30/ComputeBlog-2664-6.png" alt="App dashboard served from the closest Region through the global endpoint, showing lower latency for the local caller" width="542"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 6: The app dashboard showing routing to the local Region.&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;From my laptop in the United Kingdom, the request routes to eu-west-2 (London) in 16 ms, where the single-Region endpoint in us-east-1 replied in 90 ms. These are single measurements from one location, not a benchmark. Each request goes to the Region with the lowest latency for the caller through the same URL. Lambda manages the DNS routing, so there are no load balancers or Route 53 records to configure.&lt;/p&gt; 
&lt;h2 id="authentication-and-running-behind-amazon-cloudfront"&gt;Authentication and running behind Amazon CloudFront&lt;/h2&gt; 
&lt;p&gt;Each endpoint has an authentication type that you can change without redeploying code.&lt;/p&gt; 
&lt;p&gt;With &lt;strong&gt;ApplicationManaged&lt;/strong&gt;, the endpoint is public, and your code handles authentication (OAuth, JWT, a session cookie, or &lt;a href="https://aws.amazon.com/cognito/" target="_blank" rel="noopener"&gt;Amazon Cognito&lt;/a&gt;). Administrators can prevent public endpoints across an organization with a service control policy that uses the &lt;code&gt;lambda:Request/WebFunctionAuthType&lt;/code&gt; condition key.&lt;/p&gt; 
&lt;p&gt;With &lt;strong&gt;IamAuth&lt;/strong&gt;, Lambda validates each request with AWS Signature Version 4 (SigV4) for single-Region endpoints and SigV4a for multi-Region endpoints. Only callers with the &lt;code&gt;lambda:InvokeWebFunctionEndpoint&lt;/code&gt; permission reach your app, which suits service-to-service APIs. Endpoints are always reachable over the public internet, and &lt;code&gt;IamAuth&lt;/code&gt; controls who can invoke them.&lt;/p&gt; 
&lt;p&gt;Endpoints use a Lambda-provided domain. For a custom domain, edge caching, and &lt;a href="https://aws.amazon.com/waf/" target="_blank" rel="noopener"&gt;AWS WAF&lt;/a&gt;, place &lt;a href="https://aws.amazon.com/cloudfront/" target="_blank" rel="noopener"&gt;Amazon CloudFront&lt;/a&gt; in front of the endpoint. Use &lt;code&gt;IamAuth&lt;/code&gt; with origin access control so the Lambda domain cannot &lt;a href="https://aws.amazon.com/cloudfront/" target="_blank" rel="noopener"&gt;bypass&lt;/a&gt; CloudFront which still passes your application’s own &lt;code&gt;Authorization&lt;/code&gt; header through to your code.&lt;/p&gt; 
&lt;h2 id="build-it-with-an-agent"&gt;Build it with an agent&lt;/h2&gt; 
&lt;p&gt;Because deployment is a single &lt;code&gt;aws lambda-web deploy&lt;/code&gt; command and the code is an ordinary HTTP server, you can scaffold, build, and deploy an app from a prompt using AWS skills for coding agents. The &lt;a href="https://aws.amazon.com/products/developer-tools/agent-toolkit-for-aws/" target="_blank" rel="noopener"&gt;Agent Toolkit for AWS&lt;/a&gt; includes Web Functions.&lt;/p&gt; 
&lt;h2 id="clean-up"&gt;Clean up&lt;/h2&gt; 
&lt;p&gt;To remove the default resources that the &lt;code&gt;aws lambda-web deploy&lt;/code&gt; command created, see the &lt;a href="https://serverlessland.com/patterns/lambda-web-sse-dashboard-js-cli" target="_blank" rel="noopener"&gt;cleanup instructions&lt;/a&gt; in the repo.&lt;/p&gt; 
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt; 
&lt;p&gt;AWS Lambda Web Functions bring the serverless operating model to web applications without adapter layers. You write a standard &lt;code&gt;Node.js&lt;/code&gt; HTTP server, deploy it with one command or CloudFormation, and get a scalable, pay-per-use HTTPS endpoint with global routing built in. Deploy the sample application from the &lt;a href="https://serverlessland.com/patterns/lambda-web-sse-dashboard-nodejs-awscli" target="_blank" rel="noopener"&gt;Serverless Patterns collection&lt;/a&gt; along with &lt;a href="http://serverlessland.com/patterns?services=lambda-web-functions" target="_blank" rel="noopener"&gt;other Web Functions patterns&lt;/a&gt;. Read the Lambda Web Functions documentation to go deeper and the Lambda roadmap.&lt;/p&gt; 
&lt;p&gt;For more serverless learning resources, visit &lt;a href="https://serverlessland.com/" target="_blank" rel="noopener"&gt;Serverless Land&lt;/a&gt;.&lt;/p&gt;</content:encoded>
					
		
		
			</item>
		<item>
		<title>Reducing cross-AZ latency with the AWS Lambda metadata endpoint</title>
		<link>https://aws.amazon.com/blogs/compute/reducing-cross-az-latency-with-the-aws-lambda-metadata-endpoint/</link>
		
		<dc:creator><![CDATA[Daniel Abib]]></dc:creator>
		<pubDate>Fri, 09 Oct 2026 19:41:24 +0000</pubDate>
				<category><![CDATA[Announcements]]></category>
		<category><![CDATA[AWS Lambda]]></category>
		<category><![CDATA[Foundational (100)]]></category>
		<guid isPermaLink="false">b3855d4617c0476bbb55078e6877f3f2942af317</guid>

					<description>AWS Lambda now exposes Availability Zone metadata through an endpoint in the execution environment, so your function can discover its AZ ID with an HTTP request. Use it to prefer same-AZ endpoints for services like ElastiCache, Amazon RDS, and MemoryDB, reduce cross-AZ latency and data transfer costs, and build AZ-aware resilience patterns.</description>
										<content:encoded>&lt;p&gt;Customers use &lt;a href="https://aws.amazon.com/lambda/" target="_blank" rel="noopener"&gt;AWS Lambda&lt;/a&gt; to build applications that connect to stateful, latency-sensitive backends such as &lt;a href="https://aws.amazon.com/elasticache/" target="_blank" rel="noopener"&gt;Amazon ElastiCache&lt;/a&gt;, &lt;a href="https://aws.amazon.com/rds/" target="_blank" rel="noopener"&gt;Amazon Relational Database Service (Amazon RDS)&lt;/a&gt;, and other services that expose per-Availability Zone (AZ) endpoints. For high availability, Lambda automatically provisions your execution environments across multiple Availability Zones in a Region. That resilience is transparent to your code. It also means that, until now, a function had no way of knowing &lt;em&gt;which&lt;/em&gt; Availability Zone it was running in. When a function in one AZ connects to a resource in another AZ, the request crosses the AZ boundary, adding network latency and, in some cases, &lt;a href="https://aws.amazon.com/ec2/pricing/on-demand/#Data_Transfer" target="_blank" rel="noopener"&gt;cross-AZ data transfer costs&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;Lambda now exposes Availability Zone metadata through a &lt;strong&gt;metadata endpoint&lt;/strong&gt; in the execution environment. Your function can now discover its AZ ID (for example, &lt;code&gt;use1-az1&lt;/code&gt;) with an HTTP request. You can use that information to prefer same-AZ endpoints for downstream services, reduce cross-AZ latency, and implement AZ-aware resilience patterns such as AZ-specific fault injection testing. The feature is available at no additional cost in all commercial AWS Regions where Lambda is available. It works across all runtimes, including custom runtimes and container images, and is compatible with &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html" target="_blank" rel="noopener"&gt;SnapStart&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/provisioned-concurrency.html" target="_blank" rel="noopener"&gt;provisioned concurrency&lt;/a&gt;, and functions in a &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/configuration-vpc.html" target="_blank" rel="noopener"&gt;virtual private cloud (VPC)&lt;/a&gt;. For more information about these compatibility details, see &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/configuration-metadata-endpoint.html" target="_blank" rel="noopener"&gt;Using the Lambda metadata endpoint&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;In this post, you will learn how the Lambda metadata endpoint works, how to retrieve the AZ ID using &lt;a href="https://docs.aws.amazon.com/powertools/" target="_blank" rel="noopener"&gt;Powertools for AWS Lambda&lt;/a&gt; or by calling the endpoint directly, and how to apply the AZ ID to route to same-AZ resources for lower latency.&lt;/p&gt; 
&lt;h2 id="why-availability-zone-awareness-matters"&gt;Why Availability Zone awareness matters&lt;/h2&gt; 
&lt;p&gt;Consider a latency-sensitive read path: an API-backed Lambda function that reads from an ElastiCache cluster with a node in each of three Availability Zones. Lambda places your execution environments across those same AZs for resilience, but the placement is independent of where each cache node lives. Roughly two out of three invocations end up talking to a cache node in a &lt;em&gt;different&lt;/em&gt; AZ than the one the function is running in.&lt;/p&gt; 
&lt;p&gt;A same-AZ round trip typically completes in &lt;a href="https://aws.amazon.com/blogs/architecture/improving-performance-and-reducing-cost-using-availability-zone-affinity/" target="_blank" rel="noopener"&gt;single-digit milliseconds&lt;/a&gt;. A cross-AZ round trip adds latency on top of that, and on a hot read path executed thousands of times per second, those milliseconds compound into higher p99 latency and additional cross-AZ data transfer charges. Before this feature, avoiding cross-AZ traffic from Lambda required custom workarounds. These included embedding AZ hints in environment variables per function version, or inferring locality from IP ranges, none of which were reliable.&lt;/p&gt; 
&lt;p&gt;The same pattern appears across many of the VPC-based, AZ-scoped services your functions connect to. With Amazon RDS and &lt;a href="https://aws.amazon.com/rds/aurora/" target="_blank" rel="noopener"&gt;&lt;strong&gt;Amazon Aurora&lt;/strong&gt;&lt;/a&gt;, the writer instance lives in a single AZ, and each read replica lives in an AZ of its own. A read-heavy function that spreads its queries across replicas will, more often than not, reach a replica in a different AZ. Once your function knows its own AZ ID, you can direct reads to the replica that shares it. This keeps the hot query path in-AZ while still failing over to another replica when no same-AZ one is available. For more information, see &lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/Aurora.Overview.Endpoints.html" target="_blank" rel="noopener"&gt;Configuring Aurora read replica load balancing&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;&lt;a href="https://aws.amazon.com/memorydb/" target="_blank" rel="noopener"&gt;&lt;strong&gt;Amazon MemoryDB&lt;/strong&gt;&lt;/a&gt; extends the same idea to a durable primary/replica topology: writes go to the shard’s primary in one AZ, while reads can be served from replicas spread across the others. Consider a high-volume, read-mostly path that tolerates eventual consistency, such as looking up reference data or serving cached lookups. Steering reads to the replica in the function’s AZ keeps the hottest part of the workload in-AZ, while writes continue to route to the primary wherever it lives. Because replicas lag the primary by a small, asynchronous delay, send any read that must reflect its own write directly to the primary rather than to a same-AZ replica.&lt;/p&gt; 
&lt;p&gt;Container platforms exhibit the same behavior when Lambda calls into them. If your function invokes a service running on &lt;a href="https://aws.amazon.com/eks/" target="_blank" rel="noopener"&gt;&lt;strong&gt;Amazon Elastic Kubernetes Service (Amazon EKS)&lt;/strong&gt;&lt;/a&gt; or &lt;a href="https://aws.amazon.com/ecs/" target="_blank" rel="noopener"&gt;&lt;strong&gt;Amazon Elastic Container Service (Amazon ECS)&lt;/strong&gt;&lt;/a&gt;, the pods or tasks behind that service are distributed across AZs, and by default a request can land on any of them. You can combine the function’s AZ ID with topology-aware routing to keep east-west traffic within the AZ. Examples include Kubernetes &lt;a href="https://kubernetes.io/docs/concepts/services-networking/topology-aware-routing/" target="_blank" rel="noopener"&gt;Topology Aware Routing&lt;/a&gt; or an internal load balancer with cross-zone balancing tuned. The same reasoning applies to a function calling a private service fronted by an internal &lt;a href="https://aws.amazon.com/elasticloadbalancing/application-load-balancer/" target="_blank" rel="noopener"&gt;&lt;strong&gt;Application Load Balancer&lt;/strong&gt;&lt;/a&gt; or discovered through &lt;a href="https://aws.amazon.com/cloud-map/" target="_blank" rel="noopener"&gt;&lt;strong&gt;AWS Cloud Map&lt;/strong&gt;&lt;/a&gt;: knowing the caller’s AZ turns “any healthy target” into “the nearest healthy target.”&lt;/p&gt; 
&lt;p&gt;The metadata endpoint removes that guesswork. Your function asks the execution environment where it is running, gets back a stable AZ ID, and routes accordingly.&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/09/ComputeBlog-2700-1.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/09/ComputeBlog-2700-1.png" alt="Diagram showing a Lambda function reading from same-AZ resources and routing writes to a centralized primary using the AZ ID from the metadata endpoint" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 1: AZ-aware reads and centralized writes with the AWS Lambda metadata endpoint&lt;/p&gt;
&lt;/div&gt; 
&lt;h2 id="how-the-metadata-endpoint-works"&gt;How the metadata endpoint works&lt;/h2&gt; 
&lt;p&gt;The metadata endpoint is a loopback HTTP API available inside the Lambda execution environment, accessible to both runtimes and extensions. Lambda automatically sets two environment variables in every execution environment:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;code&gt;AWS_LAMBDA_METADATA_API&lt;/code&gt; – The metadata server address in the format &lt;code&gt;{ipv4_address}:{port}&lt;/code&gt; (for example, &lt;code&gt;169.254.100.1:9001&lt;/code&gt;). For more information about how this address and port are assigned, see &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/configuration-metadata-endpoint.html" target="_blank" rel="noopener"&gt;Using the Lambda metadata endpoint&lt;/a&gt;.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;AWS_LAMBDA_METADATA_TOKEN&lt;/code&gt; – A unique authentication token for the current execution environment, generated automatically at initialization. You include it in every metadata API request.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;You retrieve metadata with an authenticated &lt;code&gt;GET&lt;/code&gt; request:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;GET http://${AWS_LAMBDA_METADATA_API}/2026-01-15/metadata/execution-environment&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;The response is a small JSON document:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-json"&gt;{
  "AvailabilityZoneID": "use1-az1"
}&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;The &lt;code&gt;Authorization&lt;/code&gt; header must contain a Bearer token (&lt;code&gt;Authorization: Bearer &amp;lt;token&amp;gt;&lt;/code&gt;). This token-based authentication provides defense in depth against Server-Side Request Forgery (SSRF) vulnerabilities. Each execution environment receives its own randomly generated token, so a leaked or guessed URL alone is not enough to read metadata.&lt;/p&gt; 
&lt;p&gt;The response is immutable within an execution environment and returns a &lt;code&gt;Cache-Control: private, max-age=43200, immutable&lt;/code&gt; header. We recommend that you cache the response and respect the TTL rather than calling the endpoint on every invocation. For &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html" target="_blank" rel="noopener"&gt;SnapStart&lt;/a&gt; functions, the TTL is reduced during initialization so that clients refresh the metadata after restore, since a restored execution environment might come up in a different AZ. For more information, see &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/configuration-metadata-endpoint.html" target="_blank" rel="noopener"&gt;Lambda SnapStart metadata behavior&lt;/a&gt;.&lt;/p&gt; 
&lt;h2 id="retrieving-the-az-id-with-powertools-for-aws-lambda"&gt;Retrieving the AZ ID with Powertools for AWS Lambda&lt;/h2&gt; 
&lt;p&gt;The most direct way to consume the endpoint is with the &lt;a href="https://docs.aws.amazon.com/powertools/" target="_blank" rel="noopener"&gt;Powertools for AWS Lambda&lt;/a&gt; metadata utility, available for Python, TypeScript, Java, and .NET. The utility caches the response after the first call and handles SnapStart cache invalidation automatically, so you don’t need to manage tokens, HTTP requests, or TTLs yourself. The following examples show how to use Powertools in each language.&lt;/p&gt; 
&lt;h3 id="python"&gt;Python&lt;/h3&gt; 
&lt;p&gt;Install the Powertools package:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;pip install "aws-lambda-powertools"&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Use the metadata utility in your handler:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-python"&gt;from aws_lambda_powertools.utilities.metadata import LambdaMetadata, get_lambda_metadata

def handler(event, context):
    metadata = get_lambda_metadata()
    az_id = metadata.availability_zone_id  # e.g., "use1-az1"

    return {"az_id": az_id}&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h3 id="typescript"&gt;TypeScript&lt;/h3&gt; 
&lt;p&gt;Install the Powertools package:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;npm install @aws-lambda-powertools/commons&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Use the metadata utility in your handler:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-typescript"&gt;import { getMetadata } from '@aws-lambda-powertools/commons/utils/metadata';

const metadata = await getMetadata();

export const handler = async () =&amp;gt; {
  const { AvailabilityZoneID: azId } = metadata;
  return azId;
};&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h3 id="java"&gt;Java&lt;/h3&gt; 
&lt;p&gt;Add the Powertools dependency to your &lt;code&gt;pom.xml&lt;/code&gt;:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-xml"&gt;&amp;lt;dependencies&amp;gt;
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;software.amazon.lambda&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;powertools-lambda-metadata&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;2.10.0&amp;lt;/version&amp;gt;
    &amp;lt;/dependency&amp;gt;
&amp;lt;/dependencies&amp;gt;&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Use the metadata client in your handler:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-java"&gt;import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import software.amazon.lambda.powertools.metadata.LambdaMetadata;
import software.amazon.lambda.powertools.metadata.LambdaMetadataClient;

public class App implements RequestHandler&amp;lt;Object, String&amp;gt; {

    @Override
    public String handleRequest(Object input, Context context) {
        LambdaMetadata metadata = LambdaMetadataClient.get();
        String azId = metadata.getAvailabilityZoneId(); // e.g., "use1-az1"

        return "{\"azId\": \"" + azId + "\"}";
    }
}&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h3 id="net"&gt;.NET&lt;/h3&gt; 
&lt;p&gt;Install the Powertools package:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;dotnet add package AWS.Lambda.Powertools.Metadata&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Use the metadata class in your handler:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-cs"&gt;using Amazon.Lambda.Core;
using AWS.Lambda.Powertools.Metadata;

public class Function
{
    public string Handler(object input, ILambdaContext context)
    {
        var azId = LambdaMetadata.AvailabilityZoneId;
        return $"Running in AZ: {azId}";
    }
}&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h2 id="calling-the-metadata-endpoint-directly"&gt;Calling the metadata endpoint directly&lt;/h2&gt; 
&lt;p&gt;If you use a custom runtime, a container image, or prefer not to add a dependency, you can call the endpoint directly using the environment variables Lambda sets for you. The following example uses &lt;code&gt;curl&lt;/code&gt; and &lt;code&gt;jq&lt;/code&gt; to read the AZ ID:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;# Variables are automatically set by Lambda
METADATA_ENDPOINT="http://${AWS_LAMBDA_METADATA_API}/2026-01-15/metadata/execution-environment"

# Make the request
RESPONSE=$(curl -s -w "\n%{http_code}" -H "Authorization: Bearer ${AWS_LAMBDA_METADATA_TOKEN}" "$METADATA_ENDPOINT")

HTTP_CODE=$(echo "$RESPONSE" | tail -1)

if [ "$HTTP_CODE" != "200" ]; then
  echo "Metadata request failed with status $HTTP_CODE" &amp;gt;&amp;amp;2
  exit 1
fi

# Parse the AZ ID
AZ_ID=$(echo "$RESPONSE" | sed '$d' | jq -r '.AvailabilityZoneID')

echo "Function is running in AZ ID: $AZ_ID"&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Notice the configuration:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;code&gt;AWS_LAMBDA_METADATA_API&lt;/code&gt;: Lambda sets this to the metadata server address, so you never hardcode the host or port.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;Authorization: Bearer ${AWS_LAMBDA_METADATA_TOKEN}&lt;/code&gt;: The token is required on every request. A missing or invalid token returns &lt;code&gt;401 Unauthorized&lt;/code&gt;.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;GET&lt;/code&gt; &lt;strong&gt;only&lt;/strong&gt;: The endpoint accepts &lt;code&gt;GET&lt;/code&gt; requests. Any other method returns &lt;code&gt;405 Method Not Allowed&lt;/code&gt;.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;When you call the endpoint directly, retrieve the AZ ID once during initialization (outside the handler) and cache it for the life of the execution environment, rather than calling on every invocation. If your function uses SnapStart, refresh the value after restore, because the restored environment might run in a different AZ.&lt;/p&gt; 
&lt;h2 id="understanding-availability-zone-ids"&gt;Understanding Availability Zone IDs&lt;/h2&gt; 
&lt;p&gt;The endpoint returns an AZ &lt;em&gt;ID&lt;/em&gt; (for example, &lt;code&gt;use1-az1&lt;/code&gt;), not an AZ &lt;em&gt;name&lt;/em&gt; (for example, &lt;code&gt;us-east-1a&lt;/code&gt;). Before you use it, it helps to read the ID itself. An AZ ID follows the pattern &lt;code&gt;&amp;lt;region-code&amp;gt;-az&amp;lt;number&amp;gt;&lt;/code&gt;:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;code&gt;use1&lt;/code&gt; is the shortened Region code, in this case US East 1 (&lt;code&gt;us-east-1&lt;/code&gt;). Other Regions follow the same convention, such as &lt;code&gt;usw2&lt;/code&gt; for US West (Oregon) and &lt;code&gt;euw1&lt;/code&gt; for Europe (Ireland).&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;az1&lt;/code&gt; identifies the individual Availability Zone within that Region. So &lt;code&gt;use1-az1&lt;/code&gt; reads as “Availability Zone az1 in us-east-1.”&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;This distinction matters. AZ IDs always refer to the same physical location across all AWS accounts, while AZ names might map to different physical infrastructure in each account in certain Regions. In other words, the &lt;code&gt;us-east-1a&lt;/code&gt; name in your account and the &lt;code&gt;us-east-1a&lt;/code&gt; name in another account can point to two different physical Availability Zones, but &lt;code&gt;use1-az1&lt;/code&gt; is the same physical zone in every account. There is no fixed mapping between a name like &lt;code&gt;us-east-1a&lt;/code&gt; and an ID like &lt;code&gt;use1-az1&lt;/code&gt;. AWS assigns names independently per account to balance resources across zones. That’s exactly why the endpoint returns the ID: comparing AZ IDs gives you a consistent, account-independent result about whether your function and a downstream resource share a physical Availability Zone. For more information, see &lt;a href="https://docs.aws.amazon.com/global-infrastructure/latest/regions/az-ids.html" target="_blank" rel="noopener"&gt;AZ IDs for cross-account consistency&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;If you need the AZ name (for example, for logging or for an API that expects a name), convert the AZ ID using the &lt;a href="https://aws.amazon.com/ec2/" target="_blank" rel="noopener"&gt;Amazon Elastic Compute Cloud (Amazon EC2)&lt;/a&gt; &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeAvailabilityZones.html" target="_blank" rel="noopener"&gt;DescribeAvailabilityZones&lt;/a&gt; API. To call it, add the &lt;code&gt;ec2:DescribeAvailabilityZones&lt;/code&gt; permission to your function’s execution role:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-json"&gt;{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "ec2:DescribeAvailabilityZones",
            "Resource": "*"
        }
    ]
}&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h2 id="routing-to-same-az-resources"&gt;Routing to same-AZ resources&lt;/h2&gt; 
&lt;p&gt;Retrieving the AZ ID is only useful if you act on it. The following Python example shows the common pattern illustrated in Figure 1: look up the AZ ID once at initialization, select the connection endpoint that lives in the same AZ, and fall back gracefully when there is no same-AZ match.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-python"&gt;from aws_lambda_powertools.utilities.metadata import LambdaMetadata, get_lambda_metadata

# Map each cache node to the AZ ID it lives in.
# Populate this from configuration (for example, environment variables or Parameter Store).
CACHE_NODES_BY_AZ = {
    "use1-az1": "cache-node-1.example.use1-az1.cache.amazonaws.com",
    "use1-az2": "cache-node-2.example.use1-az2.cache.amazonaws.com",
    "use1-az3": "cache-node-3.example.use1-az3.cache.amazonaws.com",
}

# Read the AZ ID once during initialization (cached across warm invocations).
AZ_ID = get_lambda_metadata().availability_zone_id

# Prefer the same-AZ node; fall back to any node if there isn't one.
CACHE_ENDPOINT = CACHE_NODES_BY_AZ.get(AZ_ID) or next(iter(CACHE_NODES_BY_AZ.values()))


def handler(event, context):
    # Use CACHE_ENDPOINT for your read path. When AZ_ID matches the node's AZ,
    # the request stays within the Availability Zone.
    return {"az_id": AZ_ID, "cache_endpoint": CACHE_ENDPOINT}&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Notice the design choices:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Resolve at initialization&lt;/strong&gt;: &lt;code&gt;AZ_ID&lt;/code&gt; and &lt;code&gt;CACHE_ENDPOINT&lt;/code&gt; are computed once per execution environment, not per invocation, so the metadata lookup and endpoint selection don’t add latency to the request path.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Always provide a fallback&lt;/strong&gt;: If there is no node in your function’s AZ (for example, the service isn’t deployed in every AZ the function runs in), fall back to any available endpoint. Correctness must not depend on a same-AZ match being present.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Compare AZ IDs, not names&lt;/strong&gt;: Because the endpoint returns AZ IDs, and services like ElastiCache and RDS expose the AZ of their nodes, you can compare the two directly for a reliable same-AZ decision.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;Beyond latency-aware routing, the same AZ ID unlocks resilience testing. You can, for example, inject faults only in functions running in a specific AZ to validate that your application degrades gracefully during a simulated AZ impairment, without affecting traffic served from other AZs.&lt;/p&gt; 
&lt;h2 id="best-practices"&gt;Best practices&lt;/h2&gt; 
&lt;p&gt;Based on the endpoint’s behavior, keep these recommendations in mind:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Cache the metadata&lt;/strong&gt;: The response is immutable for the life of an execution environment. Read it once at initialization and reuse it. If you call the endpoint directly, respect the &lt;code&gt;Cache-Control&lt;/code&gt; TTL rather than requesting on every invocation.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Handle SnapStart correctly&lt;/strong&gt;: A restored SnapStart environment might resume in a different AZ than the one it was snapshotted in. Refresh the AZ ID after restore. Powertools handles this invalidation for you automatically.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Ignore unknown fields&lt;/strong&gt;: Additional fields might be added to the response in the future. Parse defensively and don’t fail if new fields appear.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Degrade gracefully&lt;/strong&gt;: Treat same-AZ routing as an optimization, not a requirement. Always keep a working fallback path so your function stays correct when no same-AZ resource is available.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Keep the token server-side&lt;/strong&gt;: The &lt;code&gt;AWS_LAMBDA_METADATA_TOKEN&lt;/code&gt; is scoped to a single execution environment. Never log it or forward it outside the function.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt; 
&lt;p&gt;In this post, you learned how the Lambda metadata endpoint helps your functions discover the Availability Zone they run in. With a single authenticated HTTP request, or one call through Powertools for AWS Lambda, your function can retrieve a stable AZ ID and use it to route to same-AZ resources, cutting cross-AZ latency and data transfer on hot paths, and to build AZ-aware resilience patterns like targeted fault injection. The feature works across all runtimes, integrates with SnapStart, provisioned concurrency, and VPC-enabled functions, and is available at no additional cost in all commercial AWS Regions where Lambda is available.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;The key takeaway&lt;/strong&gt;: if your Lambda function reads from or writes to AZ-scoped resources such as ElastiCache or RDS on a latency-sensitive path, resolve the AZ ID at initialization, prefer the same-AZ endpoint, and always keep a fallback. You get lower, more predictable latency with no change to how Lambda manages high availability for you.&lt;/p&gt; 
&lt;p&gt;To get started, see &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/configuration-metadata-endpoint.html" target="_blank" rel="noopener"&gt;Using the Lambda metadata endpoint&lt;/a&gt; in the AWS Lambda Developer Guide.&lt;/p&gt; 
&lt;h2 id="additional-resources"&gt;Additional resources&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/configuration-metadata-endpoint.html" target="_blank" rel="noopener"&gt;Using the Lambda metadata endpoint&lt;/a&gt;.&lt;/li&gt; 
 &lt;li&gt;&lt;a href="https://docs.aws.amazon.com/powertools/" target="_blank" rel="noopener"&gt;Powertools for AWS Lambda&lt;/a&gt;.&lt;/li&gt; 
 &lt;li&gt;&lt;a href="https://docs.aws.amazon.com/global-infrastructure/latest/regions/az-ids.html" target="_blank" rel="noopener"&gt;AZ IDs for cross-account consistency&lt;/a&gt;.&lt;/li&gt; 
 &lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeAvailabilityZones.html" target="_blank" rel="noopener"&gt;Amazon EC2 DescribeAvailabilityZones API&lt;/a&gt;.&lt;/li&gt; 
 &lt;li&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html" target="_blank" rel="noopener"&gt;AWS Lambda SnapStart&lt;/a&gt;.&lt;/li&gt; 
&lt;/ul&gt;</content:encoded>
					
		
		
			</item>
		<item>
		<title>Scaling RL rollouts with Firecracker on Amazon EC2 metal</title>
		<link>https://aws.amazon.com/blogs/compute/scaling-rl-rollouts-with-firecracker-on-amazon-ec2-metal/</link>
		
		<dc:creator><![CDATA[Karsten Ploesser]]></dc:creator>
		<pubDate>Fri, 09 Oct 2026 14:38:27 +0000</pubDate>
				<category><![CDATA[Amazon EC2]]></category>
		<category><![CDATA[Expert (400)]]></category>
		<category><![CDATA[Technical How-to]]></category>
		<guid isPermaLink="false">a589ff67c2281ee753222c33e5c809109d6c898b</guid>

					<description>Reinforcement learning at scale runs thousands of isolated rollout sandboxes in parallel, and packing more of them onto each host lowers your cost per training step. This post shows how to tune Firecracker microVM density on Amazon EC2 metal, and introduces labsweep, a harness for mapping your own latency and density curve.</description>
										<content:encoded>&lt;p&gt;Modern reinforcement learning (RL) systems rely on thousands of rollout environments running in parallel. For large language model (LLM) training using Verifiable Rewards (RLVR) each rollout environment runs in a tightly isolated sandbox so state never leaks between environments.&lt;/p&gt; 
&lt;p&gt;The faster you can recycle sandboxes, the more training steps you can run per hour. That means higher rollout density per host which directly lowers your cost per step.&lt;/p&gt; 
&lt;p&gt;But density is a tuning knob with two failure modes. Push it too high and you hit a tail latency cliff. Play it too safe and you overprovision, leaving money on the table. The sweet spot depends on your instance type, workload profile, and how your training algorithm amplifies stragglers.&lt;/p&gt; 
&lt;p&gt;This post shows how to find that setting. We walk through the tunables that control density on Amazon EC2 metal. We then introduce &lt;code&gt;labsweep&lt;/code&gt;, a measurement harness for mapping your latency and density curve. Throughout the post, we draw on lessons learned from production deployments with customers. The post is written for readers familiar with Kernel-based Virtual Machine (KVM), Firecracker, and container orchestration.&lt;/p&gt; 
&lt;h2 id="background-ec2-metal-nitro-and-firecracker"&gt;Background: EC2 metal, Nitro, and Firecracker&lt;/h2&gt; 
&lt;p&gt;The AWS Nitro System offloads networking, storage, and security to dedicated hardware. Amazon EC2 instances expose a stable CPU topology you can inspect and pin workloads against. On Amazon EC2 metal, applications run directly on the underlying hardware.&lt;/p&gt; 
&lt;p&gt;Firecracker is a lightweight virtual machine monitor (VMM) designed for high density workloads. Each microVM boots quickly, runs its own Linux kernel, and has a small memory footprint.&lt;/p&gt; 
&lt;p&gt;Running Firecracker on Amazon EC2 metal combines direct access to underlying hardware with lightweight virtualization to support high density sandboxing. The key question is how far you can increase density before tail latency hurts the RL training loop.&lt;/p&gt; 
&lt;h2 id="solution-overview"&gt;Solution overview&lt;/h2&gt; 
&lt;p&gt;The following diagram shows the reference architecture of a production RL sandbox node. This architecture serves as the foundation for the rest of the post. An Amazon EC2 metal instance runs a host agent that manages Firecracker microVMs, CPU pinning, non-uniform memory access (NUMA)-aware memory placement, and the warm pool used for dispatch.&lt;/p&gt; 
&lt;figure&gt; 
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/25/ComputeBlog-2671-1.jpg" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/25/ComputeBlog-2671-1.jpg" alt="Reference architecture of a production RL sandbox node showing host agent orchestration of Firecracker microVMs, resource preparation, warm pool management, workload dispatch, and telemetry collection on Amazon EC2 metal" width="800"&gt;&lt;/a&gt;
 &lt;figcaption aria-hidden="true"&gt;
  Reference architecture of a production RL sandbox node showing host agent orchestration of Firecracker microVMs, resource preparation, warm pool management, workload dispatch, and telemetry collection on Amazon EC2 metal
 &lt;/figcaption&gt;
&lt;/figure&gt; 
&lt;p&gt;The host agent runs as a DaemonSet on each Amazon EC2 metal node in the Kubernetes cluster. At startup, it discovers the CPU topology, creates per-microVM &lt;code&gt;cgroup&lt;/code&gt; hierarchies, and orchestrates Firecracker jailer processes throughout the microVM lifecycle.&lt;/p&gt; 
&lt;p&gt;To reduce dispatch latency, the system maintains a warm pool of pre-booted microVMs. The host agent applies CPU pinning, NUMA-aware memory placement, and memory sizing on a per-microVM basis. &lt;code&gt;labsweep&lt;/code&gt; identifies the combination of these settings that best balances dispatch latency, density, and tail latency for a given workload.&lt;/p&gt; 
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;Amazon EC2 metal instance (for example, we tested m8i.metal-48xl, m8a.metal-48xl, and m8g.metal-48xl).&lt;/li&gt; 
 &lt;li&gt;Linux kernel 6.2+ (required for &lt;code&gt;cgroup&lt;/code&gt; partition isolated mode).&lt;/li&gt; 
 &lt;li&gt;Firecracker 1.7+ and the Firecracker jailer.&lt;/li&gt; 
 &lt;li&gt;Go 1.22+ (to build &lt;code&gt;labsweep&lt;/code&gt;).&lt;/li&gt; 
 &lt;li&gt;AWS CDK v2 with Python 3.11+ (to deploy the accompanying stack).&lt;/li&gt; 
 &lt;li&gt;Guest rootfs image (a builder script is included in the accompanying repository).&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;Scope note: this post focuses on CPU and memory placement for Firecracker microVMs. Other system variables including storage architecture (Amazon Elastic Block Store (Amazon EBS), local SSD) and network latency to the LLM endpoint were held constant to isolate the effects of CPU and memory placement.&lt;/p&gt; 
&lt;h2 id="density-tunables-on-ec2-metal"&gt;Density tunables on EC2 metal&lt;/h2&gt; 
&lt;p&gt;Your density ceiling depends on tunables whose availability varies by instance type. Not every knob exists on every instance type, and where a knob does exist its underlying mechanism can differ. The following table shows which tunables are available across the three metal instance types this post considers: m8i, m8a, and m8g. You can derive availability and mechanism from each instance type’s published CPU topology. The measured latency and throughput results later in the post currently cover m8i and m8a, with m8g results to follow.&lt;/p&gt; 
&lt;table border="1px" cellpadding="10px" width="100%"&gt; 
 &lt;tbody&gt;
  &lt;tr&gt; 
   &lt;td&gt;&lt;strong&gt;Tunable&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;m8i.metal-48xl&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;m8a.metal-48xl&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;m8g.metal-48xl&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;What it does&lt;/strong&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Core pinning (&lt;code&gt;cpuset.cpus&lt;/code&gt;)&lt;/td&gt; 
   &lt;td&gt;✓&lt;/td&gt; 
   &lt;td&gt;✓&lt;/td&gt; 
   &lt;td&gt;✓&lt;/td&gt; 
   &lt;td&gt;Dedicates a physical core to each microVM. Eliminates scheduler-induced tail latency&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;NUMA node confinement (&lt;code&gt;cpuset.mems&lt;/code&gt;)&lt;/td&gt; 
   &lt;td&gt;✓&lt;/td&gt; 
   &lt;td&gt;✓&lt;/td&gt; 
   &lt;td&gt;✓ (2 NUMA nodes on the 48xl)&lt;/td&gt; 
   &lt;td&gt;Keeps memory allocations local. The remote-node latency penalty varies by instance type. Check the NUMA distance matrix for your instance before pinning&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;SMT state (smt/control)&lt;/td&gt; 
   &lt;td&gt;✓ (on/off)&lt;/td&gt; 
   &lt;td&gt;N/A (no SMT)&lt;/td&gt; 
   &lt;td&gt;N/A (no SMT)&lt;/td&gt; 
   &lt;td&gt;Doubles vCPUs when on. Workload-dependent: helps I/O-bound sandboxes, hurts compute-bound loops&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;L3 cache domain pinning&lt;/td&gt; 
   &lt;td&gt;✓ (place workloads within NUMA-aligned cache domains)&lt;/td&gt; 
   &lt;td&gt;✓ (24 domains, 8 cores each)&lt;/td&gt; 
   &lt;td&gt;✓ (single shared L3 per socket. Pin on NUMA/socket boundary)&lt;/td&gt; 
   &lt;td&gt;Reduces cache contention for working sets above 4 MiB per microVM&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;&lt;code&gt;cgroup&lt;/code&gt; partition (isolated)&lt;/td&gt; 
   &lt;td&gt;✓&lt;/td&gt; 
   &lt;td&gt;✓&lt;/td&gt; 
   &lt;td&gt;✓&lt;/td&gt; 
   &lt;td&gt;Removes kernel workqueue interference from pinned cores. Requires kernel 6.2+&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Guest memory size&lt;/td&gt; 
   &lt;td&gt;✓&lt;/td&gt; 
   &lt;td&gt;✓&lt;/td&gt; 
   &lt;td&gt;✓&lt;/td&gt; 
   &lt;td&gt;Primary cost driver. Determines how much of your memory-to-core budget each guest consumes; M-series gives 4 GiB per vCPU&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt;
&lt;/table&gt; 
&lt;p&gt;Key observation: &lt;strong&gt;different instance types expose different optimization opportunities.&lt;/strong&gt; Among the instances evaluated, simultaneous multithreading (SMT) is available on m8i but not on m8a or m8g. Cache-local placement also differs by instance type: some present many discrete L3 domains, some a shared L3 that is effectively partitioned along NUMA boundaries, and some a single mesh-shared L3 per socket where the meaningful locality boundary is the NUMA/socket rather than a cache-domain count. Each instance type’s L3 layout is described in its own row of the table above and in its published CPU topology. As a result, the set of tunables and their impact on density vary by instance type. This is why measuring your own configuration matters more than following generic engineering best practice lists.&lt;/p&gt; 
&lt;p&gt;To make this concrete, here is what configuring one tunable looks like in practice: a &lt;code&gt;cpuset&lt;/code&gt; pin that dedicates a single physical core to one microVM.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;# Create an isolated cgroup for one microVM on core 12
mkdir -p /sys/fs/cgroup/microvm/vm-012
echo "12" &amp;gt; /sys/fs/cgroup/microvm/vm-012/cpuset.cpus
echo "0" &amp;gt; /sys/fs/cgroup/microvm/vm-012/cpuset.mems
# Launch the jailer into this cgroup
firecracker-jailer --id vm-012 \
  --exec-file /usr/bin/firecracker \
  --parent-cgroup microvm/vm-012 \
  --uid 1000 --gid 1000&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h2 id="from-tunables-to-measurement-labsweep"&gt;From tunables to measurement: labsweep&lt;/h2&gt; 
&lt;p&gt;These tunables interact in ways that depend on your workload and instance type. You cannot predict their combined effect from the specification sheet alone. You must measure the resulting system behavior.&lt;/p&gt; 
&lt;p&gt;&lt;code&gt;labsweep&lt;/code&gt; is the test harness we built to do exactly that. It is a Go tool that:&lt;/p&gt; 
&lt;ol type="1"&gt; 
 &lt;li&gt;Discovers your host topology through sysfs (cores, NUMA nodes, L3 domains).&lt;/li&gt; 
 &lt;li&gt;Plans a matrix of configurations and densities.&lt;/li&gt; 
 &lt;li&gt;Launches jailed Firecracker microVMs at each density with bounded concurrency.&lt;/li&gt; 
 &lt;li&gt;Runs the workload in every guest concurrently and records per-microVM latency.&lt;/li&gt; 
 &lt;li&gt;Outputs raw samples, percentile aggregates, and variance data with full host provenance.&lt;/li&gt; 
&lt;/ol&gt; 
&lt;p&gt;Methodology note: each experiment is performed at fixed microVM density. Dynamic churn is outside the scope of this evaluation.&lt;/p&gt; 
&lt;p&gt;The following command launches a typical &lt;code&gt;labsweep&lt;/code&gt; run on an m8a.metal-48xl:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;labsweep -configs A,B \
  -densities 90,120,150,186 \
  -repeats 5 \
  -resident-kib 131072 \
  -steps 14 \
  -write-kib 4096&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Each run produces percentile latencies for every configuration, variance across repeated trials, and raw samples for recomputing any statistics. Results include full provenance (instance type, CPU model, kernel version, and Firecracker versions) making runs reproducible and comparable over time. If a microVM fails to respond, the harness reports failed samples instead of silently omitting them. This prevents failures from biasing the reported results.&lt;/p&gt; 
&lt;p&gt;The accompanying repository includes everything needed to reproduce these experiments: the &lt;code&gt;labsweep&lt;/code&gt; harness, guest agent, rootfs builder, and the CDK application that deploys the complete stack on an Amazon EC2 metal instance (&lt;a href="https://github.com/aws-samples/sample-firecracker-microvm-density-lab" target="_blank" rel="noopener"&gt;github.com/aws-samples/sample-firecracker-microvm-density-lab&lt;/a&gt;).&lt;/p&gt; 
&lt;h2 id="results-on-representative-workloads"&gt;Results on representative workloads&lt;/h2&gt; 
&lt;p&gt;Using &lt;code&gt;labsweep&lt;/code&gt; we benchmarked workloads representative of the execution patterns in production RL systems: short-lived verification tasks (run a test suite, check the result), build-heavy tasks (compile and link), full 14-turn replayed RL episodes, and a synthetic compute loop as a control. Across all evaluated instance types, we collected more than 100,000 samples across 500+ configurations.&lt;/p&gt; 
&lt;h3 id="the-1.0x-ratio-rule"&gt;The 1.0x ratio rule&lt;/h3&gt; 
&lt;p&gt;Tail latency remains flat as density increases until the workload reaches one microVM per vCPU. Beyond that threshold, p99 latency rises sharply over the next 15% increase in density before reaching a new plateau while median latency remains essentially unchanged. Expressing density as microVMs per vCPU rather than as an absolute microVM count makes this threshold portable across instance types. The latency cliff occurs at the same 1.0x density threshold regardless of instance size. Only the maximum number of microVMs scales with available vCPUs. The complete per-density measurements supporting this figure are provided in the appendix.&lt;/p&gt; 
&lt;figure&gt; 
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/25/ComputeBlog-2671-2.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/25/ComputeBlog-2671-2.png" alt="Rollout latency versus density (microVMs per vCPU): the p99 latency cliff occurs at approximately 1.0x density while median latency remains stable." width="800"&gt;&lt;/a&gt;
 &lt;figcaption aria-hidden="true"&gt;
  Rollout latency versus density (microVMs per vCPU): the p99 latency cliff occurs at approximately 1.0x density while median latency remains stable.
 &lt;/figcaption&gt;
&lt;/figure&gt; 
&lt;h3 id="core-pinning-reduces-the-tail-latency-for-most-real-workloads"&gt;Core pinning reduces the tail latency for most real workloads&lt;/h3&gt; 
&lt;p&gt;On the synthetic compute loop, core pinning made no measurable difference at equal density. On real sandbox workloads however, core pinning measurably tightened the tail: it reduced the p99/p50 ratio toward roughly 1.1x. The p99/p50 ratio measures tail spread by dividing the 99th-percentile latency by the median. Lower values indicate a tighter, more predictable latency distribution. The advantage grows with density, so pinning matters most where you are pushing the host hardest.&lt;/p&gt; 
&lt;p&gt;Why does this matter when choosing the right density? If you run Group Relative Policy Optimization (GRPO), every gradient step waits for the slowest rollout in the group. At a group size G=64, a p99 event affects ~47% of gradient steps. The effect becomes more pronounced as deployment density increases.&lt;/p&gt; 
&lt;table border="1px" cellpadding="10px" width="100%"&gt; 
 &lt;tbody&gt;
  &lt;tr&gt; 
   &lt;td&gt;&lt;strong&gt;Density / cores&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;G=8&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;G=16&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;G=64&lt;/strong&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;0.94x&lt;/td&gt; 
   &lt;td&gt;1.01x&lt;/td&gt; 
   &lt;td&gt;1.01x&lt;/td&gt; 
   &lt;td&gt;1.04x&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;1.04x&lt;/td&gt; 
   &lt;td&gt;1.01x&lt;/td&gt; 
   &lt;td&gt;1.03x&lt;/td&gt; 
   &lt;td&gt;1.13x&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;1.15x&lt;/td&gt; 
   &lt;td&gt;1.01x&lt;/td&gt; 
   &lt;td&gt;1.04x&lt;/td&gt; 
   &lt;td&gt;1.32x&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt;
&lt;/table&gt; 
&lt;p&gt;Past the 1.0x ceiling the amplification climbs steadily, and by the time you are well above it a p99 event can dominate the group’s completion time. Median-focused dashboards do not surface this because the median stays flat. Core pinning keeps the p99/p50 ratio low across density, holding tail latency amplification far closer to flat than an unpinned configuration even at a group size of 64. Oversubscription can appear to provide spare capacity until tail latency amplification dominates training time. Set the density to the highest value where the amplification factor remains flat.&lt;/p&gt; 
&lt;h3 id="smt-depends-on-your-workload"&gt;SMT depends on your workload&lt;/h3&gt; 
&lt;p&gt;The optimal SMT setting depends on the workload:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;I/O-bound workloads:&lt;/strong&gt; SMT-on provides higher throughput. At high density it delivers 1.49x throughput because the vCPU count stays above the 1.0x ratio.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Compute-bound workloads:&lt;/strong&gt; SMT-off produces more predictable tail latency, with a markedly tighter p99 spread than SMT-on.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;Most RL sandbox workloads are I/O-bound, spending much of their time waiting on file operations, process creation, or git operations. For these workloads, keep SMT enabled. With SMT enabled, you can place more microVMs before reaching the 1.0x ratio, for higher density without crossing the latency cliff.&lt;/p&gt; 
&lt;h3 id="configuration-matters-as-much-as-hardware"&gt;Configuration matters as much as hardware&lt;/h3&gt; 
&lt;p&gt;Hardware selection is only one factor affecting performance. Configuration choices produce measurable differences. To isolate the effect of configuration, we compare identical workloads on the same m8i instance with SMT enabled and disabled. The results show that changing a single configuration parameter measurably affects peak throughput per host.&lt;/p&gt; 
&lt;p&gt;The table below shows how enabling and disabling SMT affects peak throughput across a representative set of RL workloads, expressed as the SMT-on to SMT-off throughput ratio. The workloads were selected to represent the major execution patterns encountered in RL systems. Collectively, they cover short-lived verification tasks, interactive sessions, and full RL episodes.&lt;/p&gt; 
&lt;table border="1px" cellpadding="10px" width="100%"&gt; 
 &lt;tbody&gt;
  &lt;tr&gt; 
   &lt;td&gt;&lt;strong&gt;Workload&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Throughput gain from SMT&lt;/strong&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Verification task&lt;/td&gt; 
   &lt;td&gt;1.14x&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Build task&lt;/td&gt; 
   &lt;td&gt;1.13x&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Replayed RL episode&lt;/td&gt; 
   &lt;td&gt;1.17x&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt;
&lt;/table&gt; 
&lt;p&gt;The optimal SMT configuration depends on the density at which the workload is intended to run. With SMT enabled, the host exposes more vCPUs, which supports higher microVM densities before reaching the 1.0x microVM per vCPU threshold. This increases throughput at higher densities by delaying the onset of the tail latency cliff. At densities at or below one microVM per vCPU, SMT disabled delivers slightly better per-task performance and tighter tail latency. These results demonstrate that no single SMT configuration is universally optimal. The best choice depends on the target operating density. You should therefore determine the optimal configuration through measurement rather than assuming it in advance.&lt;/p&gt; 
&lt;h3 id="when-memory-becomes-the-limiting-resource"&gt;When memory becomes the limiting resource&lt;/h3&gt; 
&lt;p&gt;We ran all experiments on M-series metal instances, which provide 4 GiB of memory per vCPU. At this memory-to-vCPU ratio, every workload we tested remained vCPU-bound. We exhausted vCPUs before memory. If your workloads require a higher memory-to-vCPU ratio, the bottleneck shifts from vCPUs to memory. In that case, a memory-optimized instance family may be the better choice. It provides more memory per vCPU but fewer vCPUs per host. As a result, the maximum sandbox density is lower. Consider this trade-off when selecting an instance family.&lt;/p&gt; 
&lt;h2 id="reproduce-these-results-on-your-own-workloads"&gt;Reproduce these results on your own workloads&lt;/h2&gt; 
&lt;p&gt;You do not need to take these numbers on faith. With &lt;code&gt;labsweep&lt;/code&gt;, you can reproduce them on your own workloads. Clone the accompanying repository and deploy the CDK stack on the instance type you plan to run in production. Build a rootfs from your real workload. Sweep across densities below and above your expected level so you can see where expected performance drops off (the &lt;code&gt;-densities&lt;/code&gt; flag in the preceding example is a reasonable start). Repeat each configuration a few times using the &lt;code&gt;-repeats&lt;/code&gt; flag so you can see the variance, then read the p99/p50 ratio and the amplification table for your group size. Tune your system based on the curve you measure for your own workloads. That is more reliable than tuning to synthetic benchmarks.&lt;/p&gt; 
&lt;h2 id="clean-up"&gt;Clean up&lt;/h2&gt; 
&lt;p&gt;If you deployed the accompanying CDK stack for &lt;code&gt;labsweep&lt;/code&gt;, tear down these resources when you are done:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;Delete the CDK stack (&lt;code&gt;cdk destroy&lt;/code&gt;).&lt;/li&gt; 
 &lt;li&gt;Terminate any running Amazon EC2 metal instances.&lt;/li&gt; 
 &lt;li&gt;Remove the guest rootfs images from Amazon Simple Storage Service (Amazon S3) (if uploaded).&lt;/li&gt; 
 &lt;li&gt;Delete the Amazon CloudWatch log groups created by the harness.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt; 
&lt;p&gt;Sandbox density on Amazon EC2 metal is determined by a small set of tunables whose optimal values depend on both the workload and the underlying instance type. Because those values vary across workloads, there is no single density setting or configuration that is optimal for every deployment. Instance type specifications give you a starting point but only measurement can identify the right operating point for your workload. &lt;code&gt;labsweep&lt;/code&gt; is designed to make that measurement straightforward so you can optimize against your own production workloads.&lt;/p&gt; 
&lt;h2 id="blog-resources"&gt;Blog resources&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href="https://github.com/aws-samples/sample-firecracker-microvm-density-lab" target="_blank" rel="noopener"&gt;Accompanying repository&lt;/a&gt;.&lt;/li&gt; 
 &lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html" target="_blank" rel="noopener"&gt;Amazon EC2 bare metal instances&lt;/a&gt;.&lt;/li&gt; 
 &lt;li&gt;&lt;a href="https://github.com/firecracker-microvm/firecracker/blob/main/docs/getting-started.md" target="_blank" rel="noopener"&gt;Firecracker documentation&lt;/a&gt;.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2 id="appendix"&gt;Appendix&lt;/h2&gt; 
&lt;p&gt;Full per-density measurements behind the tail-latency chart in “The 1.0x ratio rule.” Conditions: m8i, SMT off, 96 physical cores, config A (unpinned). Amplification columns give the GRPO group-completion factor (group max over rollout p50) at group sizes G=8, G=16, and G=64.&lt;/p&gt; 
&lt;table border="1px" cellpadding="10px" width="100%"&gt; 
 &lt;tbody&gt;
  &lt;tr&gt; 
   &lt;td&gt;&lt;strong&gt;Density&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Density / cores&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Rollout p50&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Rollout p99&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;G=8 amp&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;G=16 amp&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;G=64 amp&lt;/strong&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;45&lt;/td&gt; 
   &lt;td&gt;0.47x&lt;/td&gt; 
   &lt;td&gt;7,768 us&lt;/td&gt; 
   &lt;td&gt;7,857 us&lt;/td&gt; 
   &lt;td&gt;1.01&lt;/td&gt; 
   &lt;td&gt;1.01&lt;/td&gt; 
   &lt;td&gt;1.01&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;90&lt;/td&gt; 
   &lt;td&gt;0.94x&lt;/td&gt; 
   &lt;td&gt;7,740 us&lt;/td&gt; 
   &lt;td&gt;8,035 us&lt;/td&gt; 
   &lt;td&gt;1.01&lt;/td&gt; 
   &lt;td&gt;1.01&lt;/td&gt; 
   &lt;td&gt;1.04&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;100&lt;/td&gt; 
   &lt;td&gt;1.04x&lt;/td&gt; 
   &lt;td&gt;7,740 us&lt;/td&gt; 
   &lt;td&gt;8,601 us&lt;/td&gt; 
   &lt;td&gt;1.01&lt;/td&gt; 
   &lt;td&gt;1.03&lt;/td&gt; 
   &lt;td&gt;1.13&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;110&lt;/td&gt; 
   &lt;td&gt;1.15x&lt;/td&gt; 
   &lt;td&gt;7,737 us&lt;/td&gt; 
   &lt;td&gt;9,909 us&lt;/td&gt; 
   &lt;td&gt;1.01&lt;/td&gt; 
   &lt;td&gt;1.04&lt;/td&gt; 
   &lt;td&gt;1.32&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;135&lt;/td&gt; 
   &lt;td&gt;1.44x&lt;/td&gt; 
   &lt;td&gt;7,743 us&lt;/td&gt; 
   &lt;td&gt;15,601 us&lt;/td&gt; 
   &lt;td&gt;1.03&lt;/td&gt; 
   &lt;td&gt;1.20&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;2.01&lt;/strong&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;186&lt;/td&gt; 
   &lt;td&gt;1.94x&lt;/td&gt; 
   &lt;td&gt;7,744 us&lt;/td&gt; 
   &lt;td&gt;15,697 us&lt;/td&gt; 
   &lt;td&gt;1.22&lt;/td&gt; 
   &lt;td&gt;1.56&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;2.03&lt;/strong&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt;
&lt;/table&gt; 
&lt;p&gt;&lt;/p&gt;</content:encoded>
					
		
		
			</item>
		<item>
		<title>Get started with AWS Lambda SnapStart for container images</title>
		<link>https://aws.amazon.com/blogs/compute/get-started-with-aws-lambda-snapstart-for-container-images/</link>
		
		<dc:creator><![CDATA[Sachin Saini]]></dc:creator>
		<pubDate>Tue, 06 Oct 2026 16:59:51 +0000</pubDate>
				<category><![CDATA[Advanced (300)]]></category>
		<category><![CDATA[Announcements]]></category>
		<category><![CDATA[AWS Lambda]]></category>
		<guid isPermaLink="false">721ab9615b9ff41b0fbbe6243d9fe49d1dcf0f41</guid>

					<description>AWS Lambda SnapStart now supports container image functions, reducing startup times from several seconds to as low as sub-second. Learn how SnapStart for container images works, how to enable it on new or existing functions, and best practices for latency-sensitive workloads.</description>
										<content:encoded>&lt;p&gt;&lt;a href="https://aws.amazon.com/lambda/" target="_blank" rel="noopener"&gt;AWS Lambda&lt;/a&gt; recently &lt;a href="https://aws.amazon.com/about-aws/whats-new/2026/07/aws-lambda-snapstart-container/" target="_blank" rel="noopener"&gt;launched SnapStart for container image functions&lt;/a&gt;, reducing startup times from several seconds to as low as sub-second. Customers deploy Lambda functions with container images to align with their organization’s container-based deployment standards, or to package larger dependencies up to 10 GB. However, larger container images can experience startup times of several seconds as Lambda downloads image layers and initializes the runtime and application code. &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html" target="_blank" rel="noopener"&gt;SnapStart&lt;/a&gt; addresses this by taking a snapshot of the initialized execution environment during function deployment, caching it, and resuming from it on invocation, instead of initializing from scratch.&lt;/p&gt; 
&lt;p&gt;In November 2022, Lambda launched &lt;a href="https://aws.amazon.com/blogs/aws/new-accelerate-your-lambda-functions-with-lambda-snapstart/" target="_blank" rel="noopener"&gt;SnapStart for Java&lt;/a&gt;, reducing startup latency by up to 10x. In November 2024, &lt;a href="https://aws.amazon.com/blogs/aws/aws-lambda-snapstart-for-python-and-net-functions-is-now-generally-available/" target="_blank" rel="noopener"&gt;SnapStart expanded to Python and .NET&lt;/a&gt; managed runtimes, reducing cold start latency to as low as sub-second. These launches helped developers achieve faster startup time, but only for &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/configuration-function-zip.html" target="_blank" rel="noopener"&gt;.zip file archives&lt;/a&gt;. By extending SnapStart support for container image functions, customers can improve startup times for latency-sensitive workloads such as ML inference and interactive APIs.&lt;/p&gt; 
&lt;p&gt;This post covers how SnapStart for container images works, how to enable it, and best practices and considerations for your workloads.&lt;/p&gt; 
&lt;h2 id="how-snapstart-for-container-images-works"&gt;How SnapStart for container images works&lt;/h2&gt; 
&lt;p&gt;When you deploy a Lambda function, you choose one of two deployment models: a .zip file archive or a container image. With managed runtimes we already support SnapStart for Python, .NET, and Java functions, and now we have extended this capability to container images. When you invoke the deployed function for the first time, or when a burst of traffic arrives, Lambda checks if there is an available execution environment. If none are available, Lambda creates a new one.&lt;/p&gt; 
&lt;p&gt;For container image functions, this means downloading and extracting image layers, bootstrapping the runtime, and running your initialization code. This process can take several seconds, which users experience as a cold start.&lt;/p&gt; 
&lt;p&gt;When you enable SnapStart and publish a function version, Lambda proactively creates an execution environment, initializes your function, and then takes a &lt;a href="https://github.com/firecracker-microvm/firecracker/blob/main/docs/snapshotting/snapshot-support.md" target="_blank" rel="noopener"&gt;Firecracker microVM snapshot&lt;/a&gt; of the full memory and disk state. This snapshot is encrypted and cached for low latency access and remains cached until you delete the corresponding function version.&lt;/p&gt; 
&lt;p&gt;On invocation, Lambda resumes from the cached snapshot rather than initializing from scratch. With SnapStart, initialization happens once at deployment time rather than on every invocation, replacing the initialization phase with a faster restore phase that speeds up startup time to as low as sub-second.&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/02/Lambda-Snapstart-Container-Images-v5.0.drawio.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/10/02/Lambda-Snapstart-Container-Images-v5.0.drawio.png" alt="Diagram of the SnapStart for container images lifecycle, from image push to snapshot restore at invocation" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 1: SnapStart for container images lifecycle, from image push to snapshot restore at invocation&lt;/p&gt;
&lt;/div&gt; 
&lt;h3 id="supported-base-images"&gt;Supported base images&lt;/h3&gt; 
&lt;p&gt;For managed runtimes, you provide your code, and Lambda handles the runtime environment. For container image functions, you package your own runtime environment using Lambda-vended base images or your own custom base images. SnapStart for container images supports the following Lambda base images at launch. To learn about supported base images per runtime, see the &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html#snapstart-runtimes" target="_blank" rel="noopener"&gt;Lambda SnapStart developer guide.&lt;/a&gt;&lt;/p&gt; 
&lt;table border="1px" width="100%" cellpadding="10px"&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;&lt;strong&gt;Runtime&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Base Image&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Architecture&lt;/strong&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Java 11 and later&lt;/td&gt; 
   &lt;td&gt;public.ecr.aws/lambda/java:11, :17, :21, :25&lt;/td&gt; 
   &lt;td&gt;x86_64, arm64&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Python 3.12 and later&lt;/td&gt; 
   &lt;td&gt;public.ecr.aws/lambda/python:3.12, :3.13, :3.14&lt;/td&gt; 
   &lt;td&gt;x86_64, arm64&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;.NET 8 and later&lt;/td&gt; 
   &lt;td&gt;public.ecr.aws/lambda/dotnet:8, :9, :10&lt;/td&gt; 
   &lt;td&gt;x86_64, arm64&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;p&gt;Regardless of which base image you use, there is an important consideration to understand before enabling SnapStart. When Lambda restores a function from a snapshot, any state captured during initialization is shared across all execution environments restored from that snapshot. This includes random number generators, unique IDs, cached credentials, and database connections. Your function needs to restore a unique state after each resume to avoid reusing the same random seed or an expired database connection across invocations. For more details on these considerations, see &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/snapstart-uniqueness.html" target="_blank" rel="noopener"&gt;SnapStart uniqueness documentation.&lt;/a&gt;&lt;/p&gt; 
&lt;p&gt;To help you restore uniqueness for your application, Lambda provides &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/snapstart-runtime-hooks.html" target="_blank" rel="noopener"&gt;runtime hooks&lt;/a&gt; for managed runtimes that let you run your own code at specific points in the snapshot-and-restore cycle. With SnapStart for container images, we are extending these same hooks to container image functions.&lt;/p&gt; 
&lt;p&gt;If your function uses one of the preceding Lambda-managed base images, Lambda offers runtime hooks for you to run your code (for example, to restore database connections). Lambda supports these runtime hooks for Java through &lt;a href="https://crac.org/" target="_blank" rel="noopener"&gt;CRaC&lt;/a&gt;, for Python through &lt;a href="https://pypi.org/project/snapshot-restore-py/" target="_blank" rel="noopener"&gt;snapshot_restore_py&lt;/a&gt;, and for .NET through &lt;a href="https://www.nuget.org/packages/SnapshotRestore.Registry" target="_blank" rel="noopener"&gt;SnapshotRestore&lt;/a&gt;. To register your own before-snapshot and after-restore hooks for these runtimes, see SnapStart runtime hooks &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/snapstart-runtime-hooks.html" target="_blank" rel="noopener"&gt;documentation.&lt;/a&gt;&lt;/p&gt; 
&lt;p&gt;If your function uses a base image without native SnapStart support (for example, a &lt;code&gt;Node.js&lt;/code&gt; or Ruby base image), a custom &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html" target="_blank" rel="noopener"&gt;Runtime Interface Client&lt;/a&gt;, or a custom runtime built on &lt;a href="https://docs.aws.amazon.com/linux/al2023/ug/lambda.html" target="_blank" rel="noopener"&gt;provided.al2023&lt;/a&gt;, review the &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/snapstart-runtime-hooks-custom.html" target="_blank" rel="noopener"&gt;documentation&lt;/a&gt; on implementing SnapStart hooks for container image functions and choose one of the following options.&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Option 1: Implement SnapStart runtime hooks.&lt;/strong&gt; If you need to run custom logic when your function is snapshotted or restored, implement the /restore/next API in your container image as described in &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/snapstart-runtime-hooks-custom.html#snapstart-custom-implement" target="_blank" rel="noopener"&gt;SnapStart runtime hooks&lt;/a&gt; documentation.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Option 2: Opt in without hooks.&lt;/strong&gt; If you do not need before-snapshot or after-restore hooks, add the following label to your Dockerfile (LABEL com.amazonaws.lambda.feature.snapstart=”Allow”)&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;For a reference implementation of SnapStart runtime hooks integration in a custom runtime, refer to the &lt;a href="https://github.com/aws/aws-lambda-rust-runtime" target="_blank" rel="noopener"&gt;Lambda Rust Runtime repository&lt;/a&gt;, including its examples for both &lt;a href="https://github.com/aws/aws-lambda-rust-runtime/tree/main/examples/basic-snapstart" target="_blank" rel="noopener"&gt;event-driven&lt;/a&gt; and &lt;a href="https://github.com/aws/aws-lambda-rust-runtime/tree/main/examples/http-snapstart" target="_blank" rel="noopener"&gt;HTTP functions&lt;/a&gt; to see how SnapStart and runtime hooks are implemented.&lt;/p&gt; 
&lt;h2 id="getting-started"&gt;Getting started&lt;/h2&gt; 
&lt;p&gt;To get started, you can use the &lt;a href="https://console.aws.amazon.com/lambda" target="_blank" rel="noopener"&gt;AWS Management Console&lt;/a&gt;, &lt;a href="https://aws.amazon.com/cli/" target="_blank" rel="noopener"&gt;AWS Command Line Interface (AWS CLI)&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/sdk-general-information-section.html" target="_blank" rel="noopener"&gt;AWS Software Development Kits (AWS SDKs)&lt;/a&gt;, &lt;a href="https://aws.amazon.com/cloudformation/" target="_blank" rel="noopener"&gt;AWS CloudFormation,&lt;/a&gt; &lt;a href="https://aws.amazon.com/serverless/sam/" target="_blank" rel="noopener"&gt;AWS Serverless Application Model (AWS SAM)&lt;/a&gt;, or &lt;a href="https://aws.amazon.com/cdk/" target="_blank" rel="noopener"&gt;AWS Cloud Development Kit (AWS CDK)&lt;/a&gt; to activate, update, and delete SnapStart for container images. You can also use the &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/agent-setup-guide.html" target="_blank" rel="noopener"&gt;Agent Toolkit for AWS&lt;/a&gt; to enable SnapStart as part of your agent-based workflows.&lt;/p&gt; 
&lt;p&gt;To use SnapStart with a container image function, your function must be deployed with &lt;a href="https://docs.aws.amazon.com/lambda/latest/api/API_CreateFunction.html" target="_blank" rel="noopener"&gt;PackageType Image&lt;/a&gt;, and the image must be pushed to an &lt;a href="https://aws.amazon.com/ecr/" target="_blank" rel="noopener"&gt;Amazon Elastic Container Registry (Amazon ECR)&lt;/a&gt; repository in the same AWS Region as your function. The examples in this section use a supported Lambda base image and us-east-1 as the AWS Region. Either set your default region or add –region to each command.&lt;/p&gt; 
&lt;h3 id="activating-snapstart-on-an-existing-function"&gt;Activating SnapStart on an existing function&lt;/h3&gt; 
&lt;p&gt;If you already have a container image function using a supported base image, activate SnapStart by updating the function configuration and publishing a version:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws lambda update-function-configuration \
    --function-name my-function \
    --snap-start ApplyOn=PublishedVersions

aws lambda publish-version \
    --function-name my-function&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h3 id="creating-a-new-function-with-snapstart"&gt;Creating a new function with SnapStart&lt;/h3&gt; 
&lt;p&gt;Create an Amazon ECR repository:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws ecr create-repository --repository-name my-function-repo&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Start with a Dockerfile using a supported base image. Here is an example for Python:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-dockerfile"&gt;FROM public.ecr.aws/lambda/python:3.12
COPY requirements.txt ${LAMBDA_TASK_ROOT}
RUN pip install -r requirements.txt
COPY lambda_function.py ${LAMBDA_TASK_ROOT}
CMD ["lambda_function.handler"]&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Build, push to Amazon ECR, and create the function with SnapStart in a single flow:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;# Build the container image locally. --platform pins the CPU architecture
# (must match --architectures on create-function). --provenance=false is
# required because BuildKit otherwise wraps the image in an OCI image index
# (manifest list) to attach a provenance attestation, and Lambda only accepts
# a single image manifest.
docker buildx build --platform linux/amd64 --provenance=false -t my-function-repo:latest .

aws ecr get-login-password | \
docker login --username AWS --password-stdin 111122223333.dkr.ecr.us-east-1.amazonaws.com
docker tag my-function-repo:latest 111122223333.dkr.ecr.us-east-1.amazonaws.com/my-function-repo:latest
docker push 111122223333.dkr.ecr.us-east-1.amazonaws.com/my-function-repo:latest

aws lambda create-function \
    --function-name my-function \
    --package-type Image \
    --code ImageUri=111122223333.dkr.ecr.us-east-1.amazonaws.com/my-function-repo:latest \
    --role arn:aws:iam::111122223333:role/lambda-execution-role \
    --architectures x86_64 \
    --snap-start ApplyOn=PublishedVersions

# Once the function is active, publish the version
aws lambda publish-version \
    --function-name my-function&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h3 id="verifying-snapstart-is-active"&gt;Verifying SnapStart is active&lt;/h3&gt; 
&lt;p&gt;After publishing, check the function version configuration:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws lambda get-function-configuration \
    --function-name my-function:1&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;When SnapStart is active, the response shows:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-json"&gt;{
    "SnapStart": {
        "ApplyOn": "PublishedVersions",
        "OptimizationStatus": "On"
    },
    "State": "Active"
}&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Once the state is Active, invoke the published version:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws lambda invoke \
    --function-name my-function:1 \
    --cli-binary-format raw-in-base64-out \
    --payload '{"key": "value"}' \
    response.json&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Note that SnapStart applies only to published versions, not $LATEST. You must invoke a specific version number to use SnapStart.&lt;/p&gt; 
&lt;h2 id="best-practices-and-considerations"&gt;Best practices and considerations&lt;/h2&gt; 
&lt;p&gt;As SnapStart resumes your function from a point-in-time snapshot, here are some best practices to consider for resources initialized at snapshot time that may become stale when your function resumes, such as network connections, credentials, and unique IDs.&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Performance tuning:&lt;/strong&gt; Preload dependencies and initialize resources in your init code rather than the handler. This moves heavy setup into the snapshot, where it’s captured once and reused across restores. For guidance on optimizing function startup latency, see the &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/snapstart-best-practices.html#snapstart-tuning" target="_blank" rel="noopener"&gt;performance tuning section&lt;/a&gt; of the Lambda developer guide.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Network connections:&lt;/strong&gt; Since snapshots can persist over an extended period, connections established during initialization may no longer be valid after restore. Network connections established through an AWS SDK resume automatically. For connections your code manages directly, such as database connections, use after-restore hooks to re-establish them as described in the &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/snapstart-best-practices.html#snapstart-networking" target="_blank" rel="noopener"&gt;networking best practices&lt;/a&gt; section of the Lambda developer guide.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Uniqueness:&lt;/strong&gt; Avoid generating unique IDs, secrets, or random values during initialization, because these are shared across all execution environments restored from the same snapshot. Instead, generate them in the function handler or use after-restore hooks. Software that always gets random numbers from the operating system (for example, from /dev/random or /dev/urandom) does not need any updates to maintain randomness. Lambda always reseeds /dev/random and /dev/urandom when restoring a snapshot, so random numbers are not repeated even when multiple execution environments resume from the same snapshot. For more details on managing unique state across restores, see the &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/snapstart-uniqueness.html" target="_blank" rel="noopener"&gt;handling uniqueness documentation&lt;/a&gt; for Lambda SnapStart.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Ephemeral data:&lt;/strong&gt; Cached credentials, timestamps, or other time-sensitive data captured during initialization may be stale by the time your function resumes from a snapshot. Use after-restore hooks to verify freshness and refresh any expired state before processing requests.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Monitoring:&lt;/strong&gt; &lt;a href="https://aws.amazon.com/cloudwatch/" target="_blank" rel="noopener"&gt;Amazon CloudWatch&lt;/a&gt; logs include a RESTORE_REPORT line showing the time spent restoring the snapshot. The REPORT line includes Restore Duration, Billed Restore Duration, Duration, and Billed Duration. Note that InitDuration does not appear for SnapStart invocations because the function resumes from a snapshot rather than initializing. You can also use &lt;a href="https://docs.aws.amazon.com/xray/latest/devguide/aws-xray.html" target="_blank" rel="noopener"&gt;AWS X-Ray&lt;/a&gt; active tracing to capture real-time telemetry for extensions through the &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/telemetry-api.html" target="_blank" rel="noopener"&gt;Telemetry API&lt;/a&gt;, and measure end-to-end latency with &lt;a href="https://aws.amazon.com/api-gateway/" target="_blank" rel="noopener"&gt;Amazon API Gateway&lt;/a&gt; and &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/urls-monitoring.html" target="_blank" rel="noopener"&gt;Lambda function URL&lt;/a&gt; metrics. To learn more about available monitoring options, visit the &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/snapstart-monitoring.html" target="_blank" rel="noopener"&gt;Lambda documentation&lt;/a&gt; on monitoring for SnapStart.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/provisioned-concurrency.html" target="_blank" rel="noopener"&gt;Provisioned concurrency&lt;/a&gt;, &lt;a href="https://aws.amazon.com/efs/" target="_blank" rel="noopener"&gt;Amazon Elastic File System (Amazon EFS)&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-files.html" target="_blank" rel="noopener"&gt;Amazon Simple Storage Service (Amazon S3) Files&lt;/a&gt; and ephemeral storage greater than 512 MB are not supported with SnapStart. Maximum container image size remains 10 GB. If you need any of the currently unsupported features, please reach out to us on the &lt;a href="https://github.com/aws/aws-lambda-roadmap" target="_blank" rel="noopener"&gt;Lambda Roadmap GitHub page&lt;/a&gt;.&lt;/p&gt; 
&lt;h2 id="pricing-and-availability"&gt;Pricing and availability&lt;/h2&gt; 
&lt;p&gt;SnapStart for container images uses the &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html#snapstart-pricing" target="_blank" rel="noopener"&gt;same pricing dimensions&lt;/a&gt; as SnapStart for Python 3.12+ and .NET 8+. You pay for the cost of caching a snapshot per function version that you publish with SnapStart enabled, and the cost of restore each time a function is restored from a snapshot. To reduce your caching costs, &lt;a href="https://docs.aws.amazon.com/cli/latest/reference/lambda/delete-function.html" target="_blank" rel="noopener"&gt;delete unused function versions&lt;/a&gt;. Refer to the &lt;a href="https://aws.amazon.com/lambda/pricing/" target="_blank" rel="noopener"&gt;Lambda pricing&lt;/a&gt; page for more details.&lt;/p&gt; 
&lt;p&gt;Lambda SnapStart for container images is available in all commercial AWS Regions except Asia Pacific (New Zealand) and Asia Pacific (Taipei). For the latest list of supported Regions, see the &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html#:~:text=unpublished%20version%20(%24LATEST).-,Supported%20Regions,-Lambda%20SnapStart%20is" target="_blank" rel="noopener"&gt;Lambda SnapStart supported regions&lt;/a&gt;.&lt;/p&gt; 
&lt;h2 id="cleanup"&gt;Cleanup&lt;/h2&gt; 
&lt;p&gt;To avoid ongoing charges for the resources created in this walkthrough, delete them when you are done. Deleting a Lambda function version removes the associated cached snapshot and stops any related snapshot caching charges.&lt;/p&gt; 
&lt;p&gt;Delete the Lambda function. This removes all published versions and their cached snapshots:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws lambda delete-function \
    --function-name my-function&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Delete the container image and the Amazon ECR repository:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws ecr delete-repository \
    --repository-name my-function-repo \
    --force&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;If you created an IAM execution role only for this walkthrough, delete it as well. For details, see &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_manage_delete.html" target="_blank" rel="noopener"&gt;deleting an IAM role&lt;/a&gt;.&lt;/p&gt; 
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt; 
&lt;p&gt;In this post, we described how Lambda SnapStart for container images reduces cold start latency by snapshotting the initialized execution environment and resuming from it on subsequent invocations. We covered how SnapStart works, how to get started based on your base image type, best practices and considerations, and pricing and availability. We look forward to hearing from you about the future capabilities you need for SnapStart, on our &lt;a href="https://github.com/aws/aws-lambda-roadmap" target="_blank" rel="noopener"&gt;Lambda Roadmap GitHub page&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;Try SnapStart on your container image functions today. To learn more, visit the &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html" target="_blank" rel="noopener"&gt;Lambda SnapStart documentation&lt;/a&gt;. For more serverless learning resources, visit &lt;a href="https://serverlessland.com/" target="_blank" rel="noopener"&gt;Serverless Land&lt;/a&gt;.&lt;/p&gt;</content:encoded>
					
		
		
			</item>
		<item>
		<title>Introducing EC2 AMI Tag Sharing: Share EC2 tags across AWS accounts</title>
		<link>https://aws.amazon.com/blogs/compute/introducing-ec2-ami-tag-sharing-share-ec2-tags-across-aws-accounts/</link>
		
		<dc:creator><![CDATA[Gena Gizzi]]></dc:creator>
		<pubDate>Mon, 05 Oct 2026 19:05:04 +0000</pubDate>
				<category><![CDATA[Amazon EC2]]></category>
		<category><![CDATA[Announcements]]></category>
		<category><![CDATA[Intermediate (200)]]></category>
		<guid isPermaLink="false">2b1593eb54076916c167c72387fbe3a55c1c6f2b</guid>

					<description>EC2 Tag Sharing lets AMI owners share tags with any account that has access to the image, using the ec2:SharedTag/ prefix. Updates propagate automatically with no custom replication workflows. This post walks through how it works, a golden AMI use case, and considerations for ABAC policies and account governance.</description>
										<content:encoded>&lt;p&gt;Tags are an important and versatile tool on AWS. FinOps teams track costs with them, security teams enforce compliance, and governance teams gate access through attribute-based access control (ABAC).&lt;/p&gt; 
&lt;p&gt;Tags become especially important as infrastructure management grows more complex across multiple accounts in an organization. Because compute is a common shared resource, many organizations tag their AMIs to track approval status, OS versions, and team. However, when you share an AMI with another AWS account, the tags you attached to it stay behind. The other account sees the image, but tag metadata used to describe it could not be shared.&lt;/p&gt; 
&lt;p&gt;Until today, the only way to solve this was to build a custom workflow to copy tags into every account the AMI is shared with. Typically created with services such as &lt;a href="https://aws.amazon.com/sns/" target="_blank" rel="noopener"&gt;Amazon Simple Notification Service (Amazon SNS)&lt;/a&gt; and &lt;a href="https://aws.amazon.com/pm/lambda/" target="_blank" rel="noopener"&gt;AWS Lambda&lt;/a&gt;, this caused operational burden.&lt;/p&gt; 
&lt;p&gt;Today, we’re introducing EC2 Tag Sharing, a new feature that AMI owners can use to share tags with any account that has access to the image. Whether an AMI is shared with an account, across an organization, or made public, a shared tag is automatically shared alongside the image by adding the &lt;code&gt;ec2:SharedTag/&lt;/code&gt; prefix to the tag key. Updates also propagate automatically without any need for custom replication workflows. In this post, we walk through how tag sharing works, demonstrate a common use case, and cover considerations and best practices.&lt;/p&gt; 
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt; 
&lt;p&gt;Any tag whose key starts with &lt;code&gt;ec2:SharedTag/&lt;/code&gt; is visible to all AWS accounts the AMI is shared with, and also when the AMI is shared publicly. Tags without the prefix remain private to the account that created them, exactly as they do today.&lt;/p&gt; 
&lt;p&gt;Only the resource owner can create, modify, or delete tags with the &lt;code&gt;ec2:SharedTag/&lt;/code&gt; prefix. Accounts you share the AMI with can view these tags but cannot change them. They can continue to add their own private tags to a shared AMI.&lt;/p&gt; 
&lt;p&gt;Shared tags count against the resource owner’s 50-tag-per-resource quota for both shared and private tags. They do not count against the quota of accounts you share the image with. When you copy an AMI that has shared tags, &lt;a href="https://aws.amazon.com/ec2/" target="_blank" rel="noopener"&gt;Amazon Elastic Compute Cloud (Amazon EC2)&lt;/a&gt; copies the shared tags to the new image when the &lt;code&gt;--copy-image-tags&lt;/code&gt; parameter is included. At launch, tag sharing is supported specifically for AMI resources.&lt;/p&gt; 
&lt;h3 id="creating-a-shared-tag-cli"&gt;Creating a shared tag (CLI)&lt;/h3&gt; 
&lt;p&gt;To share a tag, create it with the &lt;code&gt;ec2:SharedTag/&lt;/code&gt; prefix on the key name. For example, to share a tag indicating the AMI’s approval status:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws ec2 create-tags \
    --resources ami-0abcdef1234567890 \
    --tags Key=ec2:SharedTag/status,Value=approved&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;You can add multiple shared tags alongside your private tags. In the following example, status and os-version are shared with other accounts. The team tag remains private to the owner.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws ec2 create-tags \
    --resources ami-0abcdef1234567890 \
    --tags \
    Key=ec2:SharedTag/status,Value=approved \
    Key=ec2:SharedTag/os-version,Value=al2023-2026.09 \
    Key=team,Value=platform-engineering&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;You can also apply shared tags when you create an AMI from the start, using the &lt;code&gt;--tag-specifications&lt;/code&gt; parameter. For example:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws ec2 create-image \
    --instance-id i-1234567890abcdef0 \
    --name "My server" \
    --tag-specifications "ResourceType=image,Tags=[{Key=ec2:SharedTag/publicTag,Value=text}]"&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h3 id="listing-all-resources-with-shared-tags-cli"&gt;Listing all resources with shared tags (CLI)&lt;/h3&gt; 
&lt;p&gt;To see which of your AMIs have shared tags, you can run the following CLI command:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws ec2 describe-tags \
    --filters "Name=key,Values=ec2:SharedTag/*"&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;And get an output such as:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-json"&gt;{
    "Tags": [
        {
            "Key": "ec2:SharedTag/status",
            "ResourceId": "ami-0abcdef1234567890",
            "ResourceType": "image",
            "Value": "approved"
        },
        {
            "Key": "ec2:SharedTag/os-version",
            "ResourceId": "ami-0abcdef1234567890",
            "ResourceType": "image",
            "Value": "al2023-2026.09"
        }
    ]
}&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;You can also receive a similar output using the &lt;code&gt;describe-images&lt;/code&gt; command as shown in the following:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws ec2 describe-images --filters "Name=tag-key,Values=ec2:SharedTag/*"&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h3 id="stopping-tag-sharing"&gt;Stopping tag sharing&lt;/h3&gt; 
&lt;p&gt;To stop sharing a specific tag, delete the tag with the &lt;code&gt;ec2:SharedTag/&lt;/code&gt; prefix:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;# Remove the shared tag
aws ec2 delete-tags \
    --resources ami-0abcdef1234567890 \
    --tags Key=ec2:SharedTag/status&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;If you want to keep the tag private, recreate it without the prefix:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;# Optionally, recreate as a private tag
aws ec2 create-tags \
    --resources ami-0abcdef1234567890 \
    --tags Key=status,Value=approved&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h3 id="viewing-shared-tags-as-a-recipient"&gt;Viewing shared tags as a recipient&lt;/h3&gt; 
&lt;p&gt;When an AMI is shared with your account, you can see the shared tags alongside any tags you’ve added yourself. Figure 1 shows an example of an AMI shared from the original account with both private and shared tags. Figure 2 shows that AMI in the recipient account. The &lt;code&gt;ec2:SharedTag/&lt;/code&gt; prefix in the key name makes it clear which tags came from the owner.&lt;/p&gt; 
&lt;div style="width: 479px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/25/ComputeBlog-2768-1.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/25/ComputeBlog-2768-1.png" alt="Amazon EC2 console in the owner account showing an AMI with both private tags and ec2:SharedTag/ prefixed shared tags" width="469"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 1: AMI tags in the originating account, showing both private and shared tags&lt;/p&gt;
&lt;/div&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/25/ComputeBlog-2768-2.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/25/ComputeBlog-2768-2.png" alt="Amazon EC2 console in the recipient account showing only the shared tags on the same AMI, with the private tags absent" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 2: The same AMI in the recipient account, where only the shared tags are visible&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;As you can see in the preceding figures, the shared tags are visible across both accounts. However, the private tags created in the original account are only visible in the original account.&lt;/p&gt; 
&lt;h3 id="a-common-use-case-golden-amis"&gt;A common use case: Golden AMIs&lt;/h3&gt; 
&lt;p&gt;Many organizations maintain a central build factory account that produces hardened, security-approved AMIs. These golden images can be shared with hundreds or thousands of workload accounts across an organization. Tags like &lt;code&gt;status=approved&lt;/code&gt; or &lt;code&gt;patch-date=2026-09-18&lt;/code&gt; are commonly used by recipient accounts to enforce policies that only allow launches from approved images.&lt;/p&gt; 
&lt;p&gt;Before tag sharing, the build factory had to replicate tags to every account the AMI is shared with after each AMI publish. A typical workflow looked like this:&lt;/p&gt; 
&lt;ol type="1"&gt; 
 &lt;li&gt;The build factory creates a new AMI and tags it.&lt;/li&gt; 
 &lt;li&gt;An SNS notification triggers a Lambda function in each account.&lt;/li&gt; 
 &lt;li&gt;Each Lambda function reads the tag values from the Amazon SNS message and calls &lt;code&gt;CreateTags&lt;/code&gt; on the shared AMI in its own account.&lt;/li&gt; 
&lt;/ol&gt; 
&lt;p&gt;Because this runs for every AMI, in every Region, across every account, the number of &lt;code&gt;CreateTags&lt;/code&gt; API calls can grow rapidly in concentrated bursts. At that scale, teams risk throttling, failed Lambda invocations, and tag drift when calls silently fail.&lt;/p&gt; 
&lt;p&gt;With tag sharing, the build factory tags the AMI with the &lt;code&gt;ec2:SharedTag/&lt;/code&gt; prefix. Every account the AMI is shared with sees these tags, without the need for additional pipelines to replicate the tags. When the build factory updates a tag (for example, marking an older image as deprecated), the change is visible across all accounts without any additional API calls.&lt;/p&gt; 
&lt;h2 id="considerations"&gt;Considerations&lt;/h2&gt; 
&lt;p&gt;Shared tags are visible to every account with access. We recommend that you do not include personally identifying, confidential, or sensitive information in these tags.&lt;/p&gt; 
&lt;p&gt;If consuming accounts have ABAC policies that evaluate tags, those policies will also apply to the shared AMI. For example, if a recipient account has a policy that allows &lt;code&gt;ec2:RunInstances&lt;/code&gt; only when the AMI has the tag &lt;code&gt;status=approved&lt;/code&gt;, and you share that tag by using &lt;code&gt;ec2:SharedTag/status=approved&lt;/code&gt;, the policy will deny it.&lt;/p&gt; 
&lt;p&gt;When you adopt the shared tags model, any action that depends on those tags is controlled by the AMI owner, not by the recipient account. This includes tag-gated instance launches, AWS Identity and Access Management (IAM) and ABAC policy evaluations, and any downstream automation that reads tag values. Because only the owner can create, modify, or delete shared tags, the recipient account cannot change the values its own policies depend on. Before you rely on a shared tag in a policy or workflow, make sure you trust the owner account to set and maintain that value.&lt;/p&gt; 
&lt;p&gt;As a best practice, apply account-level governance so that you only consume AMIs from providers you trust. With &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-allowed-amis.html" target="_blank" rel="noopener"&gt;Allowed AMIs&lt;/a&gt;, you can define criteria for which AMIs are allowed in your account, for example a list of trusted AMI provider account IDs. Only AMIs that meet the criteria are discoverable and available to launch in your account. To preview the impact before enforcing, start in audit mode.&lt;/p&gt; 
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt; 
&lt;p&gt;EC2 Tag Sharing removes the need to build and maintain cross-account tag replication workflows. For organizations that share AMIs, this means less undifferentiated heavy lifting. To get started, add a tag with the &lt;code&gt;ec2:SharedTag/&lt;/code&gt; prefix to a shared AMI in the &lt;a href="https://console.aws.amazon.com/ec2/" target="_blank" rel="noopener"&gt;Amazon EC2 console&lt;/a&gt;. To learn more, see &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Using_Tags.html" target="_blank" rel="noopener"&gt;Tag your Amazon EC2 resources&lt;/a&gt; in the Amazon EC2 User Guide.&lt;/p&gt;</content:encoded>
					
		
		
			</item>
		<item>
		<title>Implementing customer managed keys for AWS Lambda durable functions with Terraform</title>
		<link>https://aws.amazon.com/blogs/compute/implementing-customer-managed-keys-for-aws-lambda-durable-functions-with-terraform/</link>
		
		<dc:creator><![CDATA[Rajdeep Banerjee]]></dc:creator>
		<pubDate>Tue, 29 Sep 2026 17:14:00 +0000</pubDate>
				<category><![CDATA[Advanced (300)]]></category>
		<category><![CDATA[AWS Key Management Service]]></category>
		<category><![CDATA[AWS Lambda]]></category>
		<category><![CDATA[Technical How-to]]></category>
		<guid isPermaLink="false">db91eabc9cfca26ee3fbbed72ac7160e425845ca</guid>

					<description>Lambda durable functions checkpoint execution state to durable storage, and for regulated payment workloads that data is sensitive. This post shows how to configure a customer managed key in AWS KMS to encrypt durable execution data, define a least-privilege key policy, and verify encryption through AWS CloudTrail, all deployed with Terraform.</description>
										<content:encoded>&lt;p&gt;If you run regulated workloads, you must control how persisted data is encrypted and who can access it. You need to manage encryption key rotation schedules, restrict decryption to authorized principals, and produce audit evidence that proves encryption controls are operating as designed.&lt;/p&gt; 
&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html" target="_blank" rel="noopener"&gt;AWS Lambda durable functions&lt;/a&gt; build resilient, multi-step workflows that survive failures through automatic checkpointing. The checkpoint mechanism persists execution state, including step results, payloads, and callback responses, to durable storage. For payment processing workloads, this persisted data is sensitive. AWS Lambda durable functions support &lt;a href="https://docs.aws.amazon.com/kms/latest/cryptographic-details/basic-concepts.html" target="_blank" rel="noopener"&gt;customer managed keys&lt;/a&gt; from &lt;a href="https://aws.amazon.com/kms/" target="_blank" rel="noopener"&gt;AWS Key Management Service (AWS KMS)&lt;/a&gt;. A customer managed key gives you three controls: you set the key rotation schedule, you restrict decryption access through the key policy, and you generate per-function audit trails in &lt;a href="https://aws.amazon.com/cloudtrail/" target="_blank" rel="noopener"&gt;AWS CloudTrail&lt;/a&gt;. A durable execution uses the same encryption key it started with for its entire lifetime. Changing or removing the key affects only executions that start after the change.&lt;/p&gt; 
&lt;p&gt;Updating the customer managed key policy to remove decrypt permissions, or disabling the key, stops the Lambda service from accessing previously checkpointed state. Customer managed key deletion is a permanent action, and all durable executions encrypted with that key become unrecoverable because the Lambda service has no mechanism to restore the data. Before scheduling key deletion, use the AWS KMS waiting period (7 to 30 days) and monitor AWS CloudTrail for &lt;code&gt;Decrypt&lt;/code&gt; calls to confirm that the key is no longer in active use.&lt;/p&gt; 
&lt;p&gt;In this post, you learn to configure a customer managed key to encrypt durable execution data in an event-driven payment processing workflow. You create a &lt;a href="https://docs.aws.amazon.com/kms/latest/developerguide/create-symmetric-cmk.html" target="_blank" rel="noopener"&gt;symmetric encryption key in AWS KMS&lt;/a&gt; and define a key policy that grants the Lambda service, the function’s execution role, the function author, and durable execution operators only the AWS KMS actions each principal requires. You then configure the function to use the key for durable execution encryption and verify encryption operations through AWS CloudTrail logs. By the end, you have a deployable reference architecture you can adapt for regulated workloads running on Lambda durable functions.&lt;/p&gt; 
&lt;p&gt;To learn more about how AWS Lambda encrypts durable execution data, see &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/durable-encryption.html" target="_blank" rel="noopener"&gt;Encrypting AWS Lambda durable execution data&lt;/a&gt; in the AWS Lambda Developer Guide.&lt;/p&gt; 
&lt;h2 id="solution-overview"&gt;Solution overview&lt;/h2&gt; 
&lt;p&gt;The sample application implements an event-driven payment processing pipeline using &lt;a href="https://aws.amazon.com/dynamodb/" target="_blank" rel="noopener"&gt;Amazon DynamoDB&lt;/a&gt;, &lt;a href="https://aws.amazon.com/eventbridge/" target="_blank" rel="noopener"&gt;Amazon EventBridge&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-pipes.html" target="_blank" rel="noopener"&gt;Amazon EventBridge Pipes&lt;/a&gt;, &lt;a href="https://aws.amazon.com/lambda/" target="_blank" rel="noopener"&gt;AWS Lambda&lt;/a&gt;, and &lt;a href="https://aws.amazon.com/sqs/" target="_blank" rel="noopener"&gt;Amazon SQS&lt;/a&gt;. The pipeline receives authorized payment transactions, validates and enriches them. A Lambda durable function applies business rules to the enriched transactions. The approved transactions are sent to a downstream settlement system for posting.&lt;/p&gt; 
&lt;p&gt;The following section covers the key architectural steps.&lt;/p&gt; 
&lt;h3 id="architecture-steps"&gt;Architecture steps&lt;/h3&gt; 
&lt;ol type="1"&gt; 
 &lt;li&gt;The upstream authorization system writes authorized payment records to a DynamoDB table.&lt;/li&gt; 
 &lt;li&gt;&lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.html" target="_blank" rel="noopener"&gt;DynamoDB Streams&lt;/a&gt; captures each new record as an ordered change event.&lt;/li&gt; 
 &lt;li&gt;&lt;a href="https://aws.amazon.com/eventbridge/pipes/" target="_blank" rel="noopener"&gt;Amazon EventBridge Pipes&lt;/a&gt; polls the record from the DynamoDB stream. The pipe triggers a Lambda function as part of &lt;a href="https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-pipes-logs-execution-steps.html" target="_blank" rel="noopener"&gt;enrichment&lt;/a&gt; step for duplicate checking.&lt;/li&gt; 
 &lt;li&gt;The deduplication Lambda uses a DynamoDB table with &lt;a href="https://aws.amazon.com/blogs/database/building-distributed-locks-with-the-dynamodb-lock-client/" target="_blank" rel="noopener"&gt;conditional writes&lt;/a&gt; to identify duplicate inbound transactions based on transaction properties and time window.&lt;/li&gt; 
 &lt;li&gt;When the deduplication is successful, the pipe publishes an event to the Amazon EventBridge custom event bus.&lt;/li&gt; 
 &lt;li&gt;An Amazon EventBridge rule invokes a Lambda function for matching events. The function adds business context such as account type, bank routing details, and merchant category codes. The function publishes a new enriched event to the custom event bus.&lt;/li&gt; 
 &lt;li&gt;Another Amazon EventBridge rule matches the enriched events to a Lambda durable function. The durable function applies business rules to the incoming event. When the event passes all business rules, the function publishes a new event to the event bus.&lt;/li&gt; 
 &lt;li&gt;An Amazon EventBridge rule routes the approved event to an Amazon SQS queue preserving ordering for settlement and buffering against downstream throughput limits.&lt;/li&gt; 
 &lt;li&gt;The Posting Lambda function reads from the Amazon SQS and invokes the downstream posting subsystem to post the transaction. Finally, the function publishes a completion event to the event bus completing the transaction lifecycle.&lt;/li&gt; 
&lt;/ol&gt; 
&lt;p&gt;With customer managed keys configured on DynamoDB, Amazon EventBridge, SQS, and the AWS Lambda durable function, every piece of persisted data in this pipeline is encrypted with keys you own and control. The walkthrough that follows shows you how to deploy this configuration with Terraform.&lt;/p&gt; 
&lt;p&gt;Figure 1 shows the reference architecture for this solution.&lt;/p&gt; 
&lt;h3 id="reference-architecture"&gt;Reference architecture&lt;/h3&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/28/ComputeBlog-2578-1.jpg" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/28/ComputeBlog-2578-1.jpg" alt="Reference architecture for payment processing using Lambda durable functions" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 1: Payment processing using Lambda durable functions&lt;/p&gt;
&lt;/div&gt; 
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;/h2&gt; 
&lt;p&gt;To deploy this solution, you need the following prerequisites:&lt;/p&gt; 
&lt;ol type="1"&gt; 
 &lt;li&gt;&lt;strong&gt;AWS account and CLI&lt;/strong&gt;: An active AWS account with the &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html" target="_blank" rel="noopener"&gt;AWS CLI&lt;/a&gt; installed and configured with appropriate credentials.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Terraform&lt;/strong&gt;: &lt;a href="https://developer.hashicorp.com/terraform/install" target="_blank" rel="noopener"&gt;Terraform&lt;/a&gt; installed (version 1.0 or later) for infrastructure provisioning.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Python environment&lt;/strong&gt;: &lt;a href="https://www.python.org/downloads/release/python-3110/" target="_blank" rel="noopener"&gt;Python 3.11&lt;/a&gt; or later, with &lt;a href="https://docs.pytest.org/en/stable/" target="_blank" rel="noopener"&gt;pytest&lt;/a&gt; for running unit tests. The &lt;code&gt;aws-durable-execution-sdk-python&lt;/code&gt; package requires Python 3.11 or later.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;&lt;a href="https://aws.amazon.com/iam/" target="_blank" rel="noopener"&gt;AWS Identity and Access Management (IAM)&lt;/a&gt; permissions&lt;/strong&gt;: The IAM permissions to create the resources. Follow the &lt;a href="https://github.com/aws-samples/sample-payment-processing-with-lambda-durable-functions" target="_blank" rel="noopener"&gt;sample repository&lt;/a&gt; for the sample policy.&lt;/li&gt; 
 &lt;li&gt;Basic understanding and familiarity with &lt;a href="https://aws.amazon.com/serverless/" target="_blank" rel="noopener"&gt;AWS Serverless services&lt;/a&gt;.&lt;/li&gt; 
&lt;/ol&gt; 
&lt;h2 id="solution-walkthrough"&gt;Solution walkthrough&lt;/h2&gt; 
&lt;p&gt;The following is a step-by-step guide to deploy and test the payment processing solution.&lt;/p&gt; 
&lt;h3 id="step-1-clone-the-repository"&gt;Step 1: Clone the repository&lt;/h3&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;git clone https://github.com/aws-samples/sample-payment-processing-with-lambda-durable-functions.git
cd sample-payment-processing-with-lambda-durable-functions/source&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h3 id="step-2-run-unit-tests"&gt;Step 2: Run unit tests&lt;/h3&gt; 
&lt;p&gt;Validate the payment processing logic locally before deploying:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;cd lambda-src/business_rules
pip3 install -r requirements-test.txt
pytest test_app.py -v&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;This runs unit tests that cover transaction validation, business rule checks (foreign transaction detection, currency conversion, merchant type), event schema validation, and misconfiguration handling. The tests use the &lt;a href="https://docs.aws.amazon.com/durable-execution/testing/" target="_blank" rel="noopener"&gt;AWS Durable Execution Testing SDK&lt;/a&gt; to run the handler locally without deploying AWS resources.&lt;/p&gt; 
&lt;p&gt;Figure 2 shows an example of test results running locally.&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/28/ComputeBlog-2578-2.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/28/ComputeBlog-2578-2.png" alt="Test run results of the business rules" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 2: Test run results of the business rules&lt;/p&gt;
&lt;/div&gt; 
&lt;h3 id="step-3-inspect-the-lambda-durable-functions-construct"&gt;Step 3: Inspect the Lambda durable functions construct&lt;/h3&gt; 
&lt;p&gt;Open the payments-business-rules Lambda function in &lt;code&gt;source/lambda-src/business_rules/business-rules-app.py&lt;/code&gt; for a sample Lambda durable function. Refer to Figure 3 for the code walkthrough.&lt;/p&gt; 
&lt;h4 id="key-features-used"&gt;Key features used&lt;/h4&gt; 
&lt;ol type="1"&gt; 
 &lt;li&gt;&lt;code&gt;@durable_execution&lt;/code&gt; decorator: Transforms a standard Lambda handler into a durable function handler. The durable execution SDK manages checkpointing automatically. No infrastructure changes are required.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;context.step("validate-transaction")&lt;/code&gt;: Validates that the transaction has a non-empty &lt;code&gt;issuingCountryCode&lt;/code&gt;. The durable execution checkpoints the result (&lt;code&gt;True&lt;/code&gt; or &lt;code&gt;False&lt;/code&gt;) to durable storage. The durable execution restores checkpoint results instead of re-executing steps during the replay phase. This phase occurs whenever the function is re-invoked after an interruption such as a wait period completing, a failure, or a suspension. This checkpointed result is part of the durable execution data encrypted by your customer managed key.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;context.step("publish-posting-failure")&lt;/code&gt;: Publishes the full Amazon EventBridge envelope to &lt;a href="https://aws.amazon.com/sns/" target="_blank" rel="noopener"&gt;Amazon SNS&lt;/a&gt; when validation fails. This step only runs on the failure path. The runtime checkpoints the Amazon SNS publish response to durable storage.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;context.parallel("run-business-rules")&lt;/code&gt;: Runs three independent rule checks concurrently: foreign transaction detection, currency conversion, and merchant type validation. Each branch checkpoints independently. If one branch fails, the others are not replayed on resume. Each branch result is persisted to durable storage and encrypted by the customer managed key.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;ctx.step("trigger-foreign-transaction-rule")&lt;/code&gt; (inside parallel): Compares &lt;code&gt;billingAmount&lt;/code&gt; against &lt;code&gt;transactionAmount&lt;/code&gt;. If they differ, it emits a &lt;code&gt;ForeignTransactionFound&lt;/code&gt; event to Amazon EventBridge. This step is checkpointed independently within the parallel group.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;ctx.step("trigger-conversion-rate-rule")&lt;/code&gt; (inside parallel): Checks whether &lt;code&gt;conversionRate&lt;/code&gt; equals &lt;code&gt;1&lt;/code&gt;. If so, it emits a &lt;code&gt;CurrencyConversionTransactionFound&lt;/code&gt; event to Amazon EventBridge. This step is checkpointed independently within the parallel group.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;ctx.step("trigger-merchant-rule")&lt;/code&gt; (inside parallel): Checks whether &lt;code&gt;merchantType&lt;/code&gt; equals &lt;code&gt;AAFF&lt;/code&gt;. If so, it emits a &lt;code&gt;WarningMerchantTypeTransactionFound&lt;/code&gt; event to Amazon EventBridge. This step is checkpointed independently within the parallel group.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;context.step("post-transaction-processed")&lt;/code&gt;: Emits the final &lt;code&gt;TransactionPostingApproved&lt;/code&gt; event to Amazon EventBridge. This step is only reached when validation passes and all business rules complete. The runtime checkpoints the Amazon EventBridge response. On replay, if this step already succeeded, the event is not re-published, which guarantees exactly-once approval semantics.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;context.logger&lt;/code&gt;: Provides replay-aware logging throughout the handler. During replay of previously completed steps, log statements are suppressed to prevent duplicate log entries in &lt;a href="https://aws.amazon.com/cloudwatch/" target="_blank" rel="noopener"&gt;Amazon CloudWatch&lt;/a&gt;.&lt;/li&gt; 
&lt;/ol&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/28/ComputeBlog-2578-3.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/28/ComputeBlog-2578-3.png" alt="Lambda durable functions code walkthrough" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 3: Sample Lambda durable functions code&lt;/p&gt;
&lt;/div&gt; 
&lt;h3 id="step-4-deploy-infrastructure-with-terraform"&gt;Step 4: Deploy infrastructure with Terraform&lt;/h3&gt; 
&lt;p&gt;Terraform currently doesn’t support attaching a customer managed key directly to the durable function. You create the symmetric key in Terraform and then associate the key with the durable function on the AWS Management Console. Refer to &lt;code&gt;source/durable_kms.tf&lt;/code&gt; for the key configuration.&lt;/p&gt; 
&lt;p&gt;Initialize and deploy the AWS resources that make up the solution:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;cd ../../
terraform init
terraform plan -var="region=us-east-2"&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Review the plan output, then apply:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;terraform apply -var="region=us-east-2" --auto-approve&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;&lt;em&gt;Note: Replace &lt;code&gt;us-east-2&lt;/code&gt; with your preferred AWS Region.&lt;/em&gt;&lt;/p&gt; 
&lt;p&gt;On successful completion, Terraform outputs the AWS KMS key alias, key ARN, and DynamoDB Streams ARN used by the event-driven pipeline:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-plaintext"&gt;Apply complete! Resources: N added, 0 changed, 0 destroyed.

Outputs:

durable_kms_key_alias = "durable-function-encryption"
durable_kms_key_arn = "arn:aws:kms:us-east-2:xxxxxxxxxxxx:key/4e87d4c2-1190-4db4-8b97-46657f83ee00"
stream_arn = "arn:aws:dynamodb:us-east-2:xxxxxxxxxxxx:table/visa/stream/2026-03-16T14:25:47.847"&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h3 id="step-5-verify-lambda-durable-functions-configuration"&gt;Step 5: Verify Lambda durable functions configuration&lt;/h3&gt; 
&lt;p&gt;In the AWS Lambda console, navigate to the &lt;code&gt;payments-business-rules&lt;/code&gt; function. Confirm that the function &lt;strong&gt;Type&lt;/strong&gt; displays &lt;strong&gt;Durable&lt;/strong&gt;, which indicates that the checkpoint-and-replay mechanism is active. Figure 4 shows the expected function configuration.&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/28/ComputeBlog-2578-4.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/28/ComputeBlog-2578-4.png" alt="The durable function in the AWS Lambda console" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 4: The Lambda durable function in the AWS Lambda console&lt;/p&gt;
&lt;/div&gt; 
&lt;h3 id="step-6-add-the-aws-kms-key-to-the-lambda-durable-function"&gt;Step 6: Add the AWS KMS key to the Lambda durable function&lt;/h3&gt; 
&lt;ol type="1"&gt; 
 &lt;li&gt;The durable function is not encrypted with a customer managed key. Figure 5 shows the function’s encryption configuration as empty. &lt;p&gt;&lt;/p&gt;
  &lt;div style="width: 810px" class="wp-caption alignnone"&gt;
   &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/28/ComputeBlog-2578-5.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/28/ComputeBlog-2578-5.png" alt="The Lambda durable function missing an AWS KMS key in the AWS Lambda console" width="800"&gt;&lt;/a&gt;
   &lt;p class="wp-caption-text"&gt;Figure 5: The Lambda durable function missing a customer managed key in the AWS Lambda console&lt;/p&gt;
  &lt;/div&gt;&lt;/li&gt; 
 &lt;li&gt;Choose &lt;strong&gt;Edit&lt;/strong&gt;, then turn on &lt;strong&gt;Customize encryption settings&lt;/strong&gt; as shown in Figure 6. &lt;p&gt;&lt;/p&gt;
  &lt;div style="width: 810px" class="wp-caption alignnone"&gt;
   &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/28/ComputeBlog-2578-6.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/28/ComputeBlog-2578-6.png" alt="The Lambda durable function encryption settings in the AWS Lambda console" width="800"&gt;&lt;/a&gt;
   &lt;p class="wp-caption-text"&gt;Figure 6: The Lambda durable function check encryption in the AWS Lambda console&lt;/p&gt;
  &lt;/div&gt;&lt;/li&gt; 
 &lt;li&gt;Select the AWS KMS key ARN created for the durable function. The key ARN is available in the Terraform output from Step 4. Figure 7 shows the key selection. &lt;p&gt;&lt;/p&gt;
  &lt;div style="width: 810px" class="wp-caption alignnone"&gt;
   &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/28/ComputeBlog-2578-7.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/28/ComputeBlog-2578-7.png" alt="Selecting the AWS KMS key for the durable function in the AWS Lambda console" width="800"&gt;&lt;/a&gt;
   &lt;p class="wp-caption-text"&gt;Figure 7: Select the AWS KMS key ARN for the durable function in the AWS Lambda console&lt;/p&gt;
  &lt;/div&gt;&lt;/li&gt; 
 &lt;li&gt;Choose &lt;strong&gt;Save&lt;/strong&gt; and confirm that the durable function is now encrypted with a customer managed key, as shown in Figure 8. &lt;p&gt;&lt;/p&gt;
  &lt;div style="width: 810px" class="wp-caption alignnone"&gt;
   &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/28/ComputeBlog-2578-8.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/28/ComputeBlog-2578-8.png" alt="The Lambda durable function with the AWS KMS key in the AWS Lambda console" width="800"&gt;&lt;/a&gt;
   &lt;p class="wp-caption-text"&gt;Figure 8: AWS Lambda durable function with the customer managed key in the AWS Lambda console&lt;/p&gt;
  &lt;/div&gt;&lt;/li&gt; 
&lt;/ol&gt; 
&lt;h3 id="step-7-execute-a-test-payment"&gt;Step 7: Execute a test payment&lt;/h3&gt; 
&lt;p&gt;Invoke the &lt;code&gt;payments-visa-mock&lt;/code&gt; Lambda function to simulate an end-to-end authorization flow. The mock function reads sample Visa authorization messages from a CSV file and writes them to DynamoDB, which triggers the event-driven pipeline. Figure 9 shows a sample test invocation.&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/28/ComputeBlog-2578-9.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/28/ComputeBlog-2578-9.png" alt="Invoking the payments-visa-mock function to trigger the workflow" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 9: Invoke the payments-visa-mock function to trigger workflow&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;Figure 10 shows a sample response after invocation.&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/28/ComputeBlog-2578-10.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/28/ComputeBlog-2578-10.png" alt="Test results from the payments-visa-mock function" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 10: Test results from the payments-visa-mock function to trigger workflow&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;The mock Lambda invocation creates records that follow the process described in the preceding architecture steps.&lt;/p&gt; 
&lt;h3 id="step-8-verify-results"&gt;Step 8: Verify results&lt;/h3&gt; 
&lt;p&gt;Open Amazon CloudWatch Logs and inspect the log group &lt;code&gt;/aws/lambda/payments-business_rules&lt;/code&gt;. This log group belongs to the Lambda durable function for this use case. Figure 11 shows the CloudWatch log group on the console.&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/28/ComputeBlog-2578-11.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/28/ComputeBlog-2578-11.png" alt="Search in CloudWatch Logs for the durable function log group" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 11: Search in CloudWatch&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;You see the complete business rules lifecycle for each transaction, as shown in Figure 12. The highlighted sections show all the business rules performed by the durable function. Each step is checkpointed by the runtime and encrypted by the customer managed key.&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/29/computeblog-2578-fig-12.png" target="_blank" rel="noopener"&gt;&lt;img loading="lazy" src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/29/computeblog-2578-fig-12.png" alt="Search Results in lambda durable functions console" width="800" height="1143"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 12: Search Results in lambda durable functions console&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;You can also check the other log groups to trace the full pipeline:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;code&gt;/aws/lambda/payments-enrich&lt;/code&gt;: Transaction enrichment logs.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;/aws/lambda/payments-posting&lt;/code&gt;: Settlement posting logs.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3 id="step-9-verify-the-customer-managed-key-configuration"&gt;Step 9: Verify the customer managed key configuration&lt;/h3&gt; 
&lt;p&gt;You can verify the key configuration by using the AWS CLI:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws lambda get-function-configuration \
    --function-name payments-business-rules \
    --query "DurableConfig" \
    --region us-east-2&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Expected response:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-json"&gt;{
    "KMSKeyArn": "arn:aws:kms:us-east-2:xxxxxxxxxxxx:key/4e87d4c2-1190-4db4-8b97-46657f83ee00",
    "RetentionPeriodInDays": 7,
    "ExecutionTimeout": 180
}&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;You can search in AWS CloudTrail to track the AWS KMS calls. When you configure or update the customer managed key on a durable function, Lambda validates the key policy with dry-run &lt;code&gt;GenerateDataKey&lt;/code&gt; and &lt;code&gt;Decrypt&lt;/code&gt; calls. These appear in CloudTrail with a &lt;code&gt;DryRunOperationException&lt;/code&gt; error code, which confirms that the key policy permissions are correct and does not indicate an actual error. For more details, see &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/durable-encryption.html" target="_blank" rel="noopener"&gt;Encrypting AWS Lambda durable execution data&lt;/a&gt;.&lt;/p&gt; 
&lt;h2 id="clean-up"&gt;Clean up&lt;/h2&gt; 
&lt;p&gt;To avoid ongoing charges, destroy all deployed resources using the following command:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;terraform destroy -var="region=us-east-2" --auto-approve&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Expected output:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-plaintext"&gt;Destroy complete! Resources: N destroyed.&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt; 
&lt;p&gt;In this post, you configured a customer managed key to encrypt durable execution data in a Lambda durable function. With a customer managed key, you control the key rotation schedule, restrict decryption access through the key policy, and generate per-function audit trails in AWS CloudTrail. You can revoke access to durable execution data at any time by updating the key policy, giving you full control over who can read execution state. In-flight executions stop at the next checkpoint call and new executions must be started after restoring access. For details, see &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/durable-encryption.html#durable-encryption-key-unavailable" target="_blank" rel="noopener"&gt;When the customer managed key is unavailable&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;For payment processors and financial institutions, encrypting durable execution data with a customer managed key satisfies compliance obligations for data-at-rest encryption, key governance, and access auditability across multi-step transaction workflows.&lt;/p&gt; 
&lt;p&gt;To get started, clone the &lt;a href="https://github.com/aws-samples/sample-payment-processing-with-lambda-durable-functions" target="_blank" rel="noopener"&gt;sample repository&lt;/a&gt; and follow the preceding walkthrough. To learn more about Lambda durable functions, see the &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html" target="_blank" rel="noopener"&gt;AWS Lambda Developer Guide&lt;/a&gt;.&lt;/p&gt; 
&lt;h2 id="related-resources"&gt;Related resources&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/durable-encryption.html" target="_blank" rel="noopener"&gt;AWS Lambda durable functions encryption documentation&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html" target="_blank" rel="noopener"&gt;AWS Lambda durable functions Developer Guide&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href="https://docs.aws.amazon.com/eventbridge/" target="_blank" rel="noopener"&gt;Amazon EventBridge Documentation&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href="https://docs.aws.amazon.com/step-functions/" target="_blank" rel="noopener"&gt;AWS Step Functions Comparison Guide&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.html" target="_blank" rel="noopener"&gt;Amazon DynamoDB Streams Documentation&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href="https://aws.amazon.com/solutions/guidance/payment-systems-using-event-driven-architecture-on-aws/" target="_blank" rel="noopener"&gt;AWS Guidance for Payment Systems using Event-Driven Architecture&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;&lt;a href="https://workshops.aws/" target="_blank" rel="noopener"&gt;AWS Serverless Workshops&lt;/a&gt; – Search for Lambda and serverless services workshops.&lt;/li&gt; 
&lt;/ul&gt;</content:encoded>
					
		
		
			</item>
		<item>
		<title>Simplify AMI discovery with Amazon EC2 and SSM Parameter Store</title>
		<link>https://aws.amazon.com/blogs/compute/simplify-ami-discovery-with-amazon-ec2-and-ssm-parameter-store/</link>
		
		<dc:creator><![CDATA[Ashwani Tyagi]]></dc:creator>
		<pubDate>Tue, 29 Sep 2026 16:14:17 +0000</pubDate>
				<category><![CDATA[Amazon EC2]]></category>
		<category><![CDATA[Intermediate (200)]]></category>
		<category><![CDATA[Technical How-to]]></category>
		<guid isPermaLink="false">a24666aa6abc73d7f0d54d34b2ea4d898192c856</guid>

					<description>Managing Amazon EC2 AMIs at scale means constantly mapping AMI IDs to their AWS Systems Manager parameter paths by hand. A recent enhancement to the DescribeImages API returns the associated SSM parameter directly. This post shows how to use it across the AWS CLI, AWS CloudFormation, Terraform, and Auto Scaling launch templates.</description>
										<content:encoded>&lt;p&gt;If you manage &lt;a href="https://aws.amazon.com/ec2/" target="_blank" rel="noopener"&gt;Amazon Elastic Compute Cloud (Amazon EC2)&lt;/a&gt; infrastructure at scale, you have likely encountered the following situation. You release an infrastructure change with the correct Region, the correct instance type, and a launch template that has operated reliably for months. The deployment nevertheless comes up on an &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html" target="_blank" rel="noopener"&gt;Amazon Machine Image (AMI)&lt;/a&gt; that is several patch cycles out of date, because the AMI ID hardcoded in the template had become stale weeks earlier. The condition goes unnoticed until a security scan flags the instance, at which point you must reconcile AMI IDs across Regions rather than close out the week.&lt;/p&gt; 
&lt;p&gt;That scenario is rarely a one-time event. It is one example of a broader pattern that quietly taxes teams running Amazon EC2 at scale: stale AMI IDs, manual parameter lookups, inconsistent Region mappings, and pipelines that silently fail to update. The following section examines four variations of this pattern in detail.&lt;/p&gt; 
&lt;p&gt;The common thread across all of these is the same. Locating the correct image is not the hard part. The difficulty lies in wiring that image into your infrastructure as code (IaC) in a manner that remains current. You identify the appropriate AMI on the console, then search &lt;a href="https://aws.amazon.com/systems-manager/features/#Parameter_Store" target="_blank" rel="noopener"&gt;AWS Systems Manager (SSM) Parameter Store&lt;/a&gt; paths to obtain the dynamic reference that maps to it. The workflow spans two tools and two mental models, with a gap in between where errors accumulate. Because the authoritative link between an AMI and its SSM parameter lived outside the API, teams had to reconstruct it by hand, and hands make mistakes.&lt;/p&gt; 
&lt;p&gt;A recent enhancement to the Amazon EC2 DescribeImages API closes that gap. When you call DescribeImages on a public AMI, the response now contains a PublicSsmParameterName field: the SSM parameter that resolves to the latest AMI in that lineage. A single API call replaces manual correlation.&lt;/p&gt; 
&lt;p&gt;In this post, we examine the operational friction that makes AMI management harder than it should be and show how this enhancement addresses it. We walk through practical examples using the &lt;a href="https://aws.amazon.com/cli/" target="_blank" rel="noopener"&gt;AWS Command Line Interface (AWS CLI)&lt;/a&gt;, &lt;a href="https://aws.amazon.com/cloudformation/" target="_blank" rel="noopener"&gt;AWS CloudFormation&lt;/a&gt;, &lt;a href="https://www.terraform.io/" target="_blank" rel="noopener"&gt;Terraform&lt;/a&gt;, and &lt;a href="https://aws.amazon.com/ec2/autoscaling/" target="_blank" rel="noopener"&gt;Amazon EC2 Auto Scaling&lt;/a&gt; launch templates. We conclude with best practices for golden AMI pipelines, including operational considerations to review before adopting the feature in production.&lt;/p&gt; 
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;/h2&gt; 
&lt;p&gt;To follow the examples in this post, you will need the following:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;An AWS account.&lt;/li&gt; 
 &lt;li&gt;The AWS CLI v2 installed and configured with appropriate permissions (ec2:DescribeImages, ssm:GetParameters).&lt;/li&gt; 
 &lt;li&gt;Basic familiarity with AMIs, SSM Parameter Store, and at least one IaC tool (CloudFormation or Terraform).&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2 id="understanding-the-operational-challenges"&gt;Understanding the operational challenges&lt;/h2&gt; 
&lt;p&gt;Before addressing the solution, it is worth examining the problem in detail, because the problem seldom manifests as a single, dramatic failure. It is instead a gradual accumulation of minor frictions that, in aggregate, impose a measurable cost on teams responsible for compute.&lt;/p&gt; 
&lt;p&gt;AMI IDs are Region-specific, version-specific, and change frequently. The workflow of finding an AMI, locating its SSM parameter, and referencing it in templates spans multiple tools, and the boundaries between steps are where errors accumulate.&lt;/p&gt; 
&lt;h3 id="challenge-1-silent-image-aging"&gt;Challenge 1: Silent image aging&lt;/h3&gt; 
&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; An engineer copies an AMI ID into a Terraform module as an interim measure. Several months later, that identifier is embedded across four environments. New instances launch on an image that predates numerous patches. There is no error and no alert, only drift that remains invisible until an audit or a review brings it to light.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Impact:&lt;/strong&gt; Hardcoded AMI IDs do not fail conspicuously. They fail quietly, by launching a prior image at a later date. The distance between “this was correct when written” and “this remains correct” widens continuously, and no owner is assigned to monitor it.&lt;/p&gt; 
&lt;h3 id="challenge-2-the-multi-region-maintenance-burden"&gt;Challenge 2: The multi-region maintenance burden&lt;/h3&gt; 
&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; An application operates across three Regions. The same logical image (for example, the latest &lt;a href="https://aws.amazon.com/linux/amazon-linux-2023/" target="_blank" rel="noopener"&gt;Amazon Linux 2023&lt;/a&gt;) carries a different AMI ID in each Region. Templates therefore accrue region-to-AMI mapping blocks, lookup logic, or both. Each additional Region introduces another entry to maintain, and each AMI refresh requires updating all of them.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Impact:&lt;/strong&gt; The team ends up maintaining a translation table that AWS already maintains on its behalf. The mapping logic becomes load-bearing infrastructure in its own right, and a single stale entry in one Region produces inconsistent fleets that are difficult to diagnose.&lt;/p&gt; 
&lt;h3 id="challenge-3-barriers-to-onboarding"&gt;Challenge 3: Barriers to onboarding&lt;/h3&gt; 
&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; A new engineer joins the team and poses a reasonable question: which SSM parameter corresponds to a given AMI? The answer resides in an internal knowledge-base page that was accurate eighteen months earlier. The engineer copies a path that appears correct, deploys, and inadvertently references the wrong lineage.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Impact:&lt;/strong&gt; When the relationship between an AMI and its parameter is not discoverable from the API, it must be documented manually. Manually maintained mappings degrade over time. Each new team member re-learns the same institutional knowledge, and each instance of degradation introduces an opportunity to reference an incorrect value.&lt;/p&gt; 
&lt;h3 id="challenge-4-uncertainty-about-update-success"&gt;Challenge 4: Uncertainty about update success&lt;/h3&gt; 
&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; A golden AMI pipeline completes a build and updates a parameter. The command returns a success response, and the team assumes the new image is in effect. However, for certain parameter data types, a success response does not always indicate that the value was accepted. This specific behavior is examined in the best-practices section, as it is particularly relevant to golden AMI pipelines.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Impact:&lt;/strong&gt; Confidence without confirmation carries substantial risk. A pipeline that presumes success can propagate a stale image across a fleet before the discrepancy is identified.&lt;/p&gt; 
&lt;p&gt;Considered individually, none of these situations constitutes a crisis. Considered collectively, they explain why “launch the latest image” is never, in fact, a single step. The common root cause is consistent across all four: the authoritative link between an AMI and its SSM parameter existed outside the API, requiring teams to reconstruct it manually, a process inherently prone to error.&lt;/p&gt; 
&lt;h2 id="whats-new-describeimages-returns-the-associated-ssm-parameter"&gt;What’s new: DescribeImages returns the associated SSM parameter&lt;/h2&gt; 
&lt;p&gt;The new feature addresses precisely this boundary.&lt;/p&gt; 
&lt;p&gt;As of July 16, 2026, the Amazon EC2 DescribeImages API response includes a new field, PublicSsmParameterName, for public AMIs that have an associated SSM parameter. This capability is available at no additional cost in supported AWS Regions, including AWS GovCloud (US) Regions and the China Regions.&lt;/p&gt; 
&lt;p&gt;In place of the previous three-step correlation exercise, the workflow reduces to a single call:&lt;/p&gt; 
&lt;table border="1px" width="100%" cellpadding="10px"&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;&lt;strong&gt;Before&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;After&lt;/strong&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Find AMI → manually search SSM paths → confirm the correct match&lt;/td&gt; 
   &lt;td&gt;Find AMI → PublicSsmParameterName returns the SSM path immediately&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Two separate API calls or console workflows&lt;/td&gt; 
   &lt;td&gt;A single DescribeImages call provides the complete mapping&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Prone to mapping an incorrect parameter to an AMI&lt;/td&gt; 
   &lt;td&gt;Authoritative mapping obtained directly from the API&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;p&gt;The change introduces neither a new service nor a new pricing dimension. It relocates information that previously lived in knowledge bases into the API response.&lt;/p&gt; 
&lt;p&gt;In addition, you can now use the public-ssm-parameter-name filter in DescribeImages to identify all AMIs associated with a specific SSM parameter, making the relationship queryable in either direction.&lt;/p&gt; 
&lt;h2 id="how-it-works-api-response-walkthrough"&gt;How it works: API response walkthrough&lt;/h2&gt; 
&lt;p&gt;Call DescribeImages on a public AMI with an associated SSM parameter. The response includes PublicSsmParameterName:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-json"&gt;{
  "Images": [
    {
      "ImageId": "ami-0abcdef1234567890",
      "Name": "al2023-ami-2023.7.20260601.0-kernel-6.1-arm64",
      "Description": "Amazon Linux 2023 AMI 2023.7.20260601.0 arm64 HVM kernel-6.1",
      "Architecture": "arm64",
      "PlatformDetails": "Linux/UNIX",
      "State": "available",
      "Public": true,
      "OwnerId": "111122223333",
      "ImageType": "machine",
      "RootDeviceType": "ebs",
      "VirtualizationType": "hvm",
      "EnaSupport": true,
      "PublicSsmParameterName": "aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-arm64"
    }
  ]
}&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;The &lt;code&gt;PublicSsmParameterName&lt;/code&gt; value (in this case, &lt;code&gt;aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-arm64&lt;/code&gt;) identifies the SSM parameter associated with this AMI lineage.&lt;/p&gt; 
&lt;blockquote&gt;
 &lt;p&gt;&lt;em&gt;&lt;strong&gt;Tip:&lt;/strong&gt; The field is returned under the aws/service/ namespace without a leading slash. When using this value in SSM API calls, resolve:ssm: references, or CloudFormation dynamic references, prepend a forward slash. For example, use &lt;code&gt;/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-arm64&lt;/code&gt;. The SSM parameter is intended to resolve to the latest AMI in the lineage, which can help you keep infrastructure current.&lt;/em&gt;&lt;/p&gt; 
 &lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; Not every public AMI has an associated parameter. The field is present only for lineages for which AWS publishes parameters. The field is also populated only for public AMIs. If you query one of your own private AMIs and observe an empty field, this is expected behavior rather than a defect.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;h2 id="practical-examples"&gt;Practical examples&lt;/h2&gt; 
&lt;p&gt;The following four examples show how to use the new PublicSsmParameterName field across common IaC tools.&lt;/p&gt; 
&lt;h3 id="example-1-discover-the-ssm-parameter-for-an-ami-using-the-aws-cli"&gt;Example 1: Discover the SSM parameter for an AMI using the AWS CLI&lt;/h3&gt; 
&lt;p&gt;Suppose you have identified an AMI on the console and wish to determine its SSM parameter path for use in your templates:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws ec2 describe-images \
  --image-ids ami-0abcdef1234567890 \
  --query "Images[0].PublicSsmParameterName" \
  --output text&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Output:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-plaintext"&gt;aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-arm64&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;You can also perform the inverse operation and determine which AMI a given SSM parameter currently references:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;# Linux example
aws ssm get-parameter \
  --name "/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-arm64" \
  --query "Parameter.Value" \
  --output text

# Windows example
aws ssm get-parameter \
  --name "/aws/service/ami-windows-latest/Windows_Server-2022-English-Full-Base" \
  --query "Parameter.Value" \
  --output text&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;blockquote&gt;
 &lt;p&gt;&lt;em&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Public SSM parameters are available for both Linux (/aws/service/ami-amazon-linux-latest) and Windows (/aws/service/ami-windows-latest) AMIs. You can list all available parameters under these paths using aws ssm get-parameters-by-path –path .&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;Alternatively, you can use the new filter to identify AMIs by their SSM parameter name:&lt;/p&gt; 
&lt;blockquote&gt;
 &lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; The public-ssm-parameter-name filter returns all AMIs that have ever been associated with the specified parameter, including previous versions. Use sorting or additional filters (such as –query with CreationDate) to identify the most recent AMI.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws ec2 describe-images \
  --filters "Name=public-ssm-parameter-name,Values=/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-arm64" \
  --query "Images[].{ImageId:ImageId,Name:Name,CreationDate:CreationDate}" \
  --output table&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h3 id="example-2-cloudformation-with-dynamic-ssm-references"&gt;Example 2: CloudFormation with dynamic SSM references&lt;/h3&gt; 
&lt;p&gt;Once the SSM parameter path is known from DescribeImages, you can use CloudFormation dynamic references to resolve to the latest AMI at deployment time:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-yaml"&gt;AWSTemplateFormatVersion: '2010-09-09'
Description: EC2 instance using SSM parameter for latest Amazon Linux 2023 AMI

Parameters:
  InstanceType:
    Type: String
    Default: t4g.micro

Resources:
  MyInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !Ref InstanceType
      ImageId: '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-arm64}}'
      Tags:
        - Key: Name
          Value: MyLatestAL2023Instance&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Alternatively, you can use the AWS::SSM::Parameter::Value parameter type to permit users to override the SSM path at stack creation time:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-yaml"&gt;AWSTemplateFormatVersion: '2010-09-09'
Description: EC2 instance with configurable SSM-based AMI lookup

Parameters:
  AmiSsmParameter:
    Type: 'AWS::SSM::Parameter::Value&amp;lt;AWS::EC2::Image::Id&amp;gt;'
    Default: '/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-arm64'
    Description: SSM parameter path for the AMI (discovered via DescribeImages)
  InstanceType:
    Type: String
    Default: t4g.micro

Resources:
  MyInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !Ref InstanceType
      ImageId: !Ref AmiSsmParameter
      Tags:
        - Key: Name
          Value: DynamicAMIInstance&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;CloudFormation resolves the AMI ID at deployment time, so the template never contains a hardcoded AMI ID, and any stack update adopts the latest AMI automatically. Two considerations warrant attention before relying on this approach. First, running instances are not affected. A stack update is required to roll out a newer AMI. Second, CloudFormation does not support drift detection on dynamic references, so if the underlying SSM parameter value changes between deployments, CloudFormation will not report it as drift. For ssm dynamic references in which a version has not been pinned, AWS recommends performing a stack update whenever the parameter changes, so that the stack retrieves the current value.&lt;/p&gt; 
&lt;h3 id="example-3-terraform-with-ssm-parameter-data-source"&gt;Example 3: Terraform with SSM parameter data source&lt;/h3&gt; 
&lt;p&gt;Use the aws_ssm_parameter data source to resolve the SSM path to the latest AMI ID:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-hcl"&gt;# Use the SSM parameter path discovered from DescribeImages
data "aws_ssm_parameter" "latest_al2023" {
  name = "/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-arm64"
}

resource "aws_instance" "web" {
  ami           = data.aws_ssm_parameter.latest_al2023.value
  instance_type = "t4g.micro"

  tags = {
    Name = "LatestAL2023-Instance"
  }
}&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;blockquote&gt;
 &lt;p&gt;&lt;em&gt;&lt;strong&gt;Important:&lt;/strong&gt; In Terraform, ami is a replacement-forcing argument on aws_instance. When the SSM parameter changes, Terraform proposes to destroy and recreate the instance. For stateful workloads, add lifecycle { ignore_changes = [ami] } or use launch templates with Auto Scaling (Example 4) instead.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;h3 id="example-4-auto-scaling-launch-templates-with-ssm-parameters"&gt;Example 4: Auto Scaling launch templates with SSM parameters&lt;/h3&gt; 
&lt;p&gt;For Auto Scaling groups, you can reference the SSM parameter directly in the launch template using the resolve:ssm: prefix:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;# Create a launch template that uses the SSM parameter
aws ec2 create-launch-template \
  --launch-template-name al2023-auto-scaling \
  --launch-template-data '{
  "ImageId": "resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-arm64",
  "InstanceType": "t4g.micro"
}'&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;When EC2 Auto Scaling launches a new instance, it resolves the SSM parameter at launch time to obtain the current AMI ID. You can verify the AMI ID to which a launch template resolves:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws ec2 describe-launch-template-versions \
  --launch-template-name al2023-auto-scaling \
  --versions '$Latest' \
  --resolve-alias&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;The response shows the resolved ImageId:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-json"&gt;{
  "LaunchTemplateVersions": [
    {
      "LaunchTemplateId": "lt-089c023a30example",
      "LaunchTemplateName": "al2023-auto-scaling",
      "VersionNumber": 1,
      "LaunchTemplateData": {
        "ImageId": "ami-0ac394d6a3example",
        "InstanceType": "t4g.micro"
      }
    }
  ]
}&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;The parameter is stored in the launch template. When the Auto Scaling group scales out or replaces an instance, it uses the launch template to resolve the SSM parameter and determine the AMI to launch. This is the most direct of the four patterns: the parameter serves as the single source of truth, and the Auto Scaling group’s normal instance lifecycle effects the rollout.&lt;/p&gt; 
&lt;h2 id="before-and-after-workflow-comparison"&gt;Before-and-after workflow comparison&lt;/h2&gt; 
&lt;p&gt;The following table summarizes how this feature improves common workflows, and relates each entry to the challenges described earlier.&lt;/p&gt; 
&lt;table border="1px" width="100%" cellpadding="10px"&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;&lt;strong&gt;Workflow&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Before&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;After&lt;/strong&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Discover the SSM path for a known AMI&lt;/td&gt; 
   &lt;td&gt;Search SSM parameter namespaces manually. Test multiple paths. Confirm a correct match&lt;/td&gt; 
   &lt;td&gt;A single DescribeImages call returns PublicSsmParameterName&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Validate that an SSM parameter maps to the expected AMI&lt;/td&gt; 
   &lt;td&gt;Call GetParameter, then call DescribeImages on the returned ID to verify&lt;/td&gt; 
   &lt;td&gt;Use the public-ssm-parameter-name filter to view all associated AMIs directly&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Set up IaC templates&lt;/td&gt; 
   &lt;td&gt;Find AMI → search for SSM path → copy path to template → verify correctness over time&lt;/td&gt; 
   &lt;td&gt;Find AMI → read PublicSsmParameterName from the response → use directly in the template&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Onboard new team members&lt;/td&gt; 
   &lt;td&gt;Document AMI-to-parameter mappings in knowledge bases, which become stale&lt;/td&gt; 
   &lt;td&gt;New members self-discover using standard API calls&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Audit AMI usage across teams&lt;/td&gt; 
   &lt;td&gt;Cross-reference AMI IDs with SSM parameters in separate calls&lt;/td&gt; 
   &lt;td&gt;A single API call provides the complete picture&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;h2 id="best-practices-using-ssm-parameters-for-golden-ami-pipelines"&gt;Best practices: Using SSM parameters for golden AMI pipelines&lt;/h2&gt; 
&lt;p&gt;The following recommendations describe how to derive the greatest benefit from this feature, with operational considerations identified where they are material.&lt;/p&gt; 
&lt;h3 id="discontinue-hardcoding-ami-ids"&gt;1. Discontinue hardcoding AMI IDs&lt;/h3&gt; 
&lt;p&gt;With PublicSsmParameterName removing the discovery barrier, switch all templates to SSM parameter references. Use {{resolve:ssm:}} in CloudFormation, the aws_ssm_parameter data source in Terraform (note the replacement behavior in Example 3), or the resolve:ssm: prefix in launch templates.&lt;/p&gt; 
&lt;h3 id="create-custom-ssm-parameters-for-your-golden-amis"&gt;2. Create custom SSM parameters for your golden AMIs&lt;/h3&gt; 
&lt;p&gt;For internally built golden AMIs, create your own SSM parameters using the aws:ec2:image data type:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws ssm put-parameter \
  --name "/my-org/golden-ami/amazon-linux-hardened" \
  --type "String" \
  --data-type "aws:ec2:image" \
  --value "ami-0abcdef1234567890"&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;When the pipeline produces a new golden AMI, update the parameter:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws ssm put-parameter \
  --name "/my-org/golden-ami/amazon-linux-hardened" \
  --type "String" \
  --data-type "aws:ec2:image" \
  --value "ami-0fedcba9876543210" \
  --overwrite&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Stacks, launch templates, or Terraform configurations that reference this parameter can adopt the new AMI on their next deployment, with no template edits required in most cases.&lt;/p&gt; 
&lt;blockquote&gt;
 &lt;p&gt;&lt;em&gt;&lt;strong&gt;Operational consideration:&lt;/strong&gt; Because PutParameter validates aws:ec2:image values asynchronously, an HTTP 200 does not confirm the value was accepted. Subscribe to Parameter Store change events in &lt;a href="https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-what-is.html" target="_blank" rel="noopener"&gt;Amazon EventBridge&lt;/a&gt; and confirm the operation succeeded before considering the rollout complete.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;h3 id="use-parameter-versions-and-labels-for-controlled-rollouts"&gt;3. Use parameter versions and labels for controlled rollouts&lt;/h3&gt; 
&lt;p&gt;SSM Parameter Store supports versioning and labels, which provide control over rollouts:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;# Label the current production version
aws ssm label-parameter-version \
  --name "/my-org/golden-ami/amazon-linux-hardened" \
  --parameter-version 5 \
  --labels "prod"&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Production launch templates reference the labeled version:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-yaml"&gt;ImageId: resolve:ssm:/my-org/golden-ami/amazon-linux-hardened:prod&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;With this approach, you can update the parameter with a new AMI without immediately affecting production. Promotion to production is accomplished by moving the prod label, a deliberate, auditable action rather than an automatic side effect.&lt;/p&gt; 
&lt;h3 id="combine-with-amazon-ec2-image-builder-for-end-to-end-automation"&gt;4. Combine with Amazon EC2 Image Builder for end-to-end automation&lt;/h3&gt; 
&lt;p&gt;Use &lt;a href="https://docs.aws.amazon.com/imagebuilder/latest/userguide/what-is-image-builder.html" target="_blank" rel="noopener"&gt;Amazon EC2 Image Builder&lt;/a&gt; to automate AMI creation, then configure the distribution settings to update your SSM parameter automatically when a new AMI is built. Combined with the new discovery feature, this establishes a closed loop:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;Image Builder creates a new AMI on a schedule.&lt;/li&gt; 
 &lt;li&gt;Distribution settings update the SSM parameter to point to the new AMI.&lt;/li&gt; 
 &lt;li&gt;Auto Scaling and IaC resolve the parameter to the latest AMI at launch time.&lt;/li&gt; 
 &lt;li&gt;With DescribeImages, any authorized party can determine which SSM parameter an AMI maps to.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3 id="scope-iam-permissions-appropriately"&gt;5. Scope IAM permissions appropriately&lt;/h3&gt; 
&lt;p&gt;Two permission requirements apply.&lt;/p&gt; 
&lt;p&gt;To launch instances by using SSM-referenced AMIs, the launching principal requires ssm:GetParameters on the relevant parameter paths:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-json"&gt;{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "ssm:GetParameters",
      "Resource": "arn:aws:ssm:*:*:parameter/aws/service/ami-amazon-linux-latest/*"
    }
  ]
}&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Scope the Resource element to the paths actually in use. If you reference Windows parameters (/aws/service/ami-windows-latest/&lt;em&gt;) or your own golden AMI paths (/my-org/golden-ami/&lt;/em&gt;), include those ARNs as well. Otherwise, launches will fail with an AccessDenied error.&lt;/p&gt; 
&lt;p&gt;To create a custom aws:ec2:image parameter, the pipeline principal also requires ssm:PutParameter and ec2:DescribeImages:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-json"&gt;{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "ssm:PutParameter",
      "Resource": "arn:aws:ssm:*:*:parameter/my-org/golden-ami/*"
    },
    {
      "Effect": "Allow",
      "Action": "ec2:DescribeImages",
      "Resource": "*"
    }
  ]
}&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;For broader guidance on keeping infrastructure current and automating operational processes, see the &lt;a href="https://docs.aws.amazon.com/wellarchitected/latest/operational-excellence-pillar/welcome.html" target="_blank" rel="noopener"&gt;Operational Excellence Pillar&lt;/a&gt; of the AWS Well-Architected Framework.&lt;/p&gt; 
&lt;h2 id="clean-up"&gt;Clean up&lt;/h2&gt; 
&lt;p&gt;The examples in this post use read-only API calls (DescribeImages, GetParameter) and do not create billable resources. If you created a launch template while following Example 4, you can delete it as follows:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws ec2 delete-launch-template --launch-template-name al2023-auto-scaling&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt; 
&lt;p&gt;The difficulty of AMI management was never attributable to any single failure. It arose from the steady accumulation of stale identifiers, region-mapping tables, stale documentation, and pipelines that presumed success, all of which are minor frictions that together produced significant operational effort and risk. The common thread was that the authoritative link between an AMI and its SSM parameter existed outside the API, requiring teams to reconstruct it manually.&lt;/p&gt; 
&lt;p&gt;The new PublicSsmParameterName field in the Amazon EC2 DescribeImages API relocates that link into the response, where it appropriately belongs. With a single API call, you can determine the SSM parameter for any public AMI. You can then reference it directly in CloudFormation templates, Terraform configurations, or Auto Scaling launch templates for automatic AMI updates.&lt;/p&gt; 
&lt;p&gt;To begin, call DescribeImages on any public AMI and examine the &lt;code&gt;PublicSsmParameterName&lt;/code&gt; field. For further detail, see &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/finding-an-ami-parameter-store.html" target="_blank" rel="noopener"&gt;Reference the latest AMIs using Systems Manager public parameters&lt;/a&gt; in the Amazon EC2 User Guide.&lt;/p&gt; 
&lt;p&gt;For additional learning resources on AMI management and IaC on AWS, explore &lt;a href="https://aws.amazon.com/ec2/" target="_blank" rel="noopener"&gt;Amazon EC2&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html" target="_blank" rel="noopener"&gt;AWS Systems Manager Parameter Store&lt;/a&gt;, and &lt;a href="https://aws.amazon.com/image-builder/" target="_blank" rel="noopener"&gt;Amazon EC2 Image Builder&lt;/a&gt;.&lt;/p&gt;</content:encoded>
					
		
		
			</item>
		<item>
		<title>Frozen package management for air-gapped RHEL-family AMIs</title>
		<link>https://aws.amazon.com/blogs/compute/frozen-package-management-for-air-gapped-rhel-family-amis/</link>
		
		<dc:creator><![CDATA[Anand Krishna Varanasi]]></dc:creator>
		<pubDate>Tue, 29 Sep 2026 15:55:07 +0000</pubDate>
				<category><![CDATA[Advanced (300)]]></category>
		<category><![CDATA[Amazon EC2]]></category>
		<category><![CDATA[Technical How-to]]></category>
		<guid isPermaLink="false">34d380583160feea2d919a68f65541555032776f</guid>

					<description>Learn a serverless, two-account pattern for running regulated, air-gapped RHEL-family fleets on AWS. It separates connected package ingestion from the air-gapped workload, adds explicit human approval for package changes, and keeps EC2 Image Builder AMIs and Patch Manager on one frozen Amazon S3 repository snapshot.</description>
										<content:encoded>&lt;p&gt;If you run a regulated, air-gapped compute fleet on RHEL-family instances, you have probably felt three requirements pulling against each other. Your organization must configure the network to remove internet access from the instances. Your team must review and approve new packages or version upgrades before you adopt them. Your team removes public repository definitions, restricts network paths, and configures instances to use only the internal repository your team has approved. Teams in chip design, finance, healthcare, defense, and the public sector often face this combination while still needing operating system updates.&lt;/p&gt; 
&lt;p&gt;This post describes a two-account pattern that separates the connected package-ingestion path from the air-gapped fleet. You create an authorized initial baseline and approve later changes to form a versioned package snapshot in &lt;a href="https://aws.amazon.com/s3/" target="_blank" rel="noopener"&gt;Amazon Simple Storage Service (Amazon S3)&lt;/a&gt;. &lt;a href="https://aws.amazon.com/image-builder/" target="_blank" rel="noopener"&gt;EC2 Image Builder&lt;/a&gt; uses the frozen snapshot to build &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html" target="_blank" rel="noopener"&gt;Amazon Machine Images (AMIs)&lt;/a&gt;. Your team configures &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/patch-manager.html" target="_blank" rel="noopener"&gt;AWS Systems Manager Patch Manager&lt;/a&gt; to patch the instances your organization runs from the same internal package source.&lt;/p&gt; 
&lt;p&gt;The accompanying reference implementation demonstrates the pattern for RPM-based RHEL-family systems (AlmaLinux for example). It is a reference, not a substitute for distribution of licensing, vulnerability analysis, testing, or an organization’s change-management process.&lt;/p&gt; 
&lt;h2 id="the-challenge-getting-packages-into-an-air-gapped-approval-gated-fleet"&gt;The challenge: Getting packages into an air-gapped approval-gated fleet&lt;/h2&gt; 
&lt;p&gt;Common delivery models each assume something an air-gapped fleet might not provide:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Red Hat Update Infrastructure (RHUI)&lt;/strong&gt; expects each instance to reach the service. A fleet with no internet egress needs a different content path.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Red Hat Satellite&lt;/strong&gt; supports disconnected content management, but it is a separate product and operational footprint. Teams that need a custom package-level approval workflow must integrate that workflow with their content-management process.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;The Red Hat CDN&lt;/strong&gt; requires a connected, entitled content-management path. Centralizing that path changes the network architecture, not the customer’s Red Hat subscription obligations.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;The objective is not to replace these products universally. It is to show a serverless AWS pattern for teams that need an authorized repository baseline, explicit approval for later package changes, and a fleet with no public package source.&lt;/p&gt; 
&lt;h2 id="how-the-pattern-works"&gt;How the pattern works&lt;/h2&gt; 
&lt;p&gt;The pattern combines three controls:&lt;/p&gt; 
&lt;ol type="1"&gt; 
 &lt;li&gt;&lt;strong&gt;A frozen package repository on Amazon S3:&lt;/strong&gt; The pattern stores a deployment-authorized baseline and subsequent approved package changes in versioned, per-OS repository prefixes. The repository manifest records the package inventory for each state.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;EC2 Image Builder Orchestration builds AMIs from that repository:&lt;/strong&gt; The build helps remove upstream repository definitions and configures the internal frozen mirror to be used for all package operations.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;The launched fleet has no internet egress:&lt;/strong&gt; The &lt;code&gt;dnf&lt;/code&gt; operations are configured to resolve the internal mirror. Patch Manager uses the same repository source, so image builds and in-place patching draw from one frozen snapshot.&lt;/li&gt; 
&lt;/ol&gt; 
&lt;h2 id="choosing-the-upstream-source"&gt;Choosing the upstream source&lt;/h2&gt; 
&lt;p&gt;Choose one package lineage end to end. The parent AMI, repository content, and trusted signing keys must belong to that same lineage.&lt;/p&gt; 
&lt;p&gt;The reference implementation defaults to AlmaLinux vault content plus EPEL and an AlmaLinux parent AMI. The AlmaLinux OS Foundation states that AlmaLinux aims for binary and application binary interface (ABI) compatibility with RHEL. This is an AlmaLinux compatibility goal, not a Red Hat certification, and it does not make repository mixing a supported practice.&lt;/p&gt; 
&lt;p&gt;For genuine RHEL systems, use a Red Hat parent AMI, entitled Red Hat repositories, and Red Hat signing keys. A connected content-management host can retrieve content for the isolated environment. This centralizes the network path but does not reduce or change the customer’s Red Hat subscription obligations. Confirm those obligations against the applicable Red Hat agreement.&lt;/p&gt; 
&lt;p&gt;Do not pair AlmaLinux repositories with genuine RHEL hosts, or Red Hat repositories with AlmaLinux hosts. Mixed-vendor package lineages can create support, stability, and maintainability problems even when the RPMs appear mechanically compatible.&lt;/p&gt; 
&lt;h2 id="architecture-and-workflow"&gt;Architecture and workflow&lt;/h2&gt; 
&lt;p&gt;The account boundary provides a primary security boundary for this architecture. The following diagram shows the connected Distribution account, the read-only Workload account, and an example cross-Region layout.&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/25/ComputeBlog-2688-1.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/25/ComputeBlog-2688-1.png" alt="Two-account architecture showing the connected Distribution account with the control plane and internet path, and the air-gapped read-only Workload account, spanning two Regions" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 1: Two-account, cross-Region architecture separating the connected Distribution account from the air-gapped Workload account&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;The &lt;strong&gt;Distribution account&lt;/strong&gt; owns the writable control plane and the only internet path. It runs &lt;a href="https://aws.amazon.com/eventbridge/" target="_blank" rel="noopener"&gt;Amazon EventBridge&lt;/a&gt;, three &lt;a href="https://aws.amazon.com/lambda/lambda-functions/" target="_blank" rel="noopener"&gt;AWS Lambda functions&lt;/a&gt;, &lt;a href="https://aws.amazon.com/dynamodb/" target="_blank" rel="noopener"&gt;Amazon DynamoDB&lt;/a&gt;, &lt;a href="https://aws.amazon.com/sns/" target="_blank" rel="noopener"&gt;Amazon Simple Notification Service (Amazon SNS)&lt;/a&gt;, and the &lt;a href="https://aws.amazon.com/fargate/" target="_blank" rel="noopener"&gt;AWS Fargate&lt;/a&gt; sync task. It also owns the frozen S3 repository and its &lt;a href="https://aws.amazon.com/kms/" target="_blank" rel="noopener"&gt;AWS Key Management Service (AWS KMS) key&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;The &lt;strong&gt;Workload account&lt;/strong&gt; is air-gapped and read-only with respect to the repository. It runs the internal HTTPS mirror, EC2 Image Builder, Patch Manager, and the compute fleet. Its mirror task role can read and decrypt frozen content but cannot write it.&lt;/p&gt; 
&lt;p&gt;The sample repository places the Distribution control plane in US East (N. Virginia), the frozen store in US West (Oregon), and the Workload resources in US West (Oregon) to demonstrate API-only cross-account and cross-Region operation. This Region split is not required. In most deployments, place the Distribution control plane and frozen store in the same Region unless data residency, disaster recovery, or an existing regional footprint justifies the additional latency, transfer cost, and KMS policy complexity.&lt;/p&gt; 
&lt;p&gt;The two accounts do not need &lt;a href="https://aws.amazon.com/vpc/" target="_blank" rel="noopener"&gt;Amazon Virtual Private Cloud (VPC)&lt;/a&gt; peering or a transit gateway. Cross-account access uses S3, KMS, and IAM policies. The VPC address ranges can overlap because no &lt;code&gt;VPC-to-VPC&lt;/code&gt; route is required.&lt;/p&gt; 
&lt;h2 id="package-baseline-and-scheduled-upgrade-workflow"&gt;Package baseline and scheduled upgrade workflow&lt;/h2&gt; 
&lt;p&gt;Before the scheduled workflow begins, your organization must authorize and run a full sync to establish the initial repository baseline. This bootstrap does not provide package-by-package approval. If your organization requires individual approval for every initial RPM, your team should generate and review the baseline manifest before promotion instead of relying solely on deployment authorization.&lt;/p&gt; 
&lt;p&gt;After the baseline, the detector runs on a customer-defined schedule. The reference implementation defaults to monthly. The following diagram shows the bootstrap distinction and the selective approval flow.&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/25/ComputeBlog-2688-2.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/25/ComputeBlog-2688-2.png" alt="Workflow diagram distinguishing the initial baseline bootstrap sync from the recurring detect, request approval, review, record, selective sync, and manifest update steps" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 2: Package baseline bootstrap and the scheduled selective approval workflow&lt;/p&gt;
&lt;/div&gt; 
&lt;ol type="1"&gt; 
 &lt;li&gt;&lt;strong&gt;Detect.&lt;/strong&gt; Amazon EventBridge invokes the detector Lambda function on the configured schedule. The detector compares upstream repository metadata with &lt;code&gt;manifest.json&lt;/code&gt;, which records the current frozen inventory. It classifies a newer version as an upgrade and an absent package as new.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Request approval.&lt;/strong&gt; The detector writes candidates to S3, creates a KMS-protected review token carrying the request ID and expiry, and is designed to send a review link through SNS. The detector can use &lt;code&gt;kms:Encrypt&lt;/code&gt; but not &lt;code&gt;kms:Decrypt&lt;/code&gt;.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Review.&lt;/strong&gt; A human opens the review page through an &lt;a href="https://aws.amazon.com/api-gateway/" target="_blank" rel="noopener"&gt;Amazon API Gateway&lt;/a&gt; HTTP API, reviews the proposed package versions, and chooses which changes to approve. The approver can use &lt;code&gt;kms:Decrypt&lt;/code&gt; but not &lt;code&gt;kms:Encrypt&lt;/code&gt;.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Record and start.&lt;/strong&gt; A conditional DynamoDB update changes a request from &lt;code&gt;pending&lt;/code&gt; to &lt;code&gt;approved&lt;/code&gt; only once. The approver then starts the Fargate sync task and passes the request ID.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Selective sync.&lt;/strong&gt; The task reads the approved package list, downloads those package versions, is designed to perform verification checks, and regenerates repository metadata.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Update the manifest.&lt;/strong&gt; When the task stops, Amazon EventBridge invokes the manifest-updater Lambda function. It archives the outgoing manifest and records the resulting repository inventory.&lt;/li&gt; 
&lt;/ol&gt; 
&lt;p&gt;The approval decision controls adoption. It does not prove that package code is safe. Advisory review, vulnerability scanning, testing, and staged rollout remain in separate controls.&lt;/p&gt; 
&lt;h2 id="evidence-from-the-approval-workflow"&gt;Evidence from the approval workflow&lt;/h2&gt; 
&lt;p&gt;The token ties a review action to a specific request and expiry. Separating &lt;code&gt;kms:Encrypt&lt;/code&gt; from &lt;code&gt;kms:Decrypt&lt;/code&gt; prevents either Lambda function from performing both token roles. The conditional DynamoDB write makes the approval transition single-use.&lt;/p&gt; 
&lt;p&gt;DynamoDB records request state, &lt;a href="https://aws.amazon.com/cloudtrail/" target="_blank" rel="noopener"&gt;AWS CloudTrail&lt;/a&gt; records control-plane API activity, and manifest history records repository inventory changes. These service records can feed the organization’s existing audit and evidence-management workflow. Object-level S3 access auditing requires CloudTrail S3 data events. KMS activity alone is not a substitute for those events.&lt;/p&gt; 
&lt;h2 id="the-frozen-package-repository-on-amazon-s3"&gt;The frozen package repository on Amazon S3&lt;/h2&gt; 
&lt;p&gt;The following diagram shows the per-OS, per-component prefix layout, and manifest objects.&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/25/ComputeBlog-2688-3.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/25/ComputeBlog-2688-3.png" alt="Amazon S3 prefix layout with one prefix per operating system version, each holding BaseOS, AppStream, and EPEL components with Packages and repodata trees plus manifest objects" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 3: Per-OS, per-component prefix layout of the frozen repository on Amazon S3&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;Each pinned operating system version receives its own prefix. Repository components such as &lt;strong&gt;BaseOS&lt;/strong&gt;, &lt;strong&gt;AppStream&lt;/strong&gt;, and &lt;strong&gt;EPEL&lt;/strong&gt; contain &lt;code&gt;Packages/&lt;/code&gt; and &lt;code&gt;repodata/&lt;/code&gt; trees. &lt;code&gt;manifest.json&lt;/code&gt; records the active inventory, and archived manifests preserve historical evidence and comparison points.&lt;/p&gt; 
&lt;p&gt;Your organization configures the bucket with versioning and SSE-KMS. Public RPM content does not require a customer-managed KMS key for confidentiality, so your organization could instead configure SSE-S3 for encryption at rest. However, SSE-S3 would remove the separate cross-account authorization control provided by the customer-managed KMS key policy. The customer managed key is used here for explicit cross-account key-policy control and revocation, and the manifests reveal the fleet’s exact software inventory. S3 Bucket Keys reduce KMS request volume. If object-level access evidence is required, enable CloudTrail S3 data events.&lt;/p&gt; 
&lt;p&gt;A rollback must restore a coherent repository state, including metadata and any required object versions. Restoring only &lt;code&gt;manifest.json&lt;/code&gt; does not roll back repository contents.&lt;/p&gt; 
&lt;h2 id="building-patching-and-running-the-fleet"&gt;Building, patching, and running the fleet&lt;/h2&gt; 
&lt;p&gt;At AMI build time, an Image Builder component installs the configured repository keys, moves existing repository definitions aside, and writes one frozen repository definition per component. It locks the package manager to the frozen repository directory, fetches metadata through the internal mirror, and fails the build if the mirror validation step fails. An optional curated package list demonstrates that the AMI can install real packages through the frozen path.&lt;/p&gt; 
&lt;p&gt;Patch Manager uses the same mirror for the running fleet. A host created from an older AMI and a newly built host are therefore patched toward the same frozen snapshot. Instances run without an &lt;a href="https://docs.aws.amazon.com/vpc/latest/userguide/vpc-nat-gateway.html" target="_blank" rel="noopener"&gt;Amazon VPC NAT gateway&lt;/a&gt;, public IP, or an &lt;a href="https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Internet_Gateway.html" target="_blank" rel="noopener"&gt;Amazon VPC internet gateway&lt;/a&gt; route in the Workload VPC, and their repository configuration contains no public fallback.&lt;/p&gt; 
&lt;p&gt;The intended verification model is defense in depth: the sync task helps verify a vendor’s signature before content enters the trusted repository, and the system verifies it again at installation through &lt;code&gt;dnf&lt;/code&gt;. The ingestion gate helps reject digest-only results and can be configured to help confirm that only valid package signatures from a trusted lineage key are accepted.&lt;/p&gt; 
&lt;h2 id="the-package-mirror"&gt;The package mirror&lt;/h2&gt; 
&lt;p&gt;Nginx fronts &lt;code&gt;aws-sigv4-proxy&lt;/code&gt;, which signs cross-account S3 GET requests using the mirror task role. To a client, the service appears as a standard HTTPS package repository behind an internal &lt;a href="https://aws.amazon.com/elasticloadbalancing/application-load-balancer/" target="_blank" rel="noopener"&gt;Application Load Balancer&lt;/a&gt; and private DNS name.&lt;/p&gt; 
&lt;p&gt;Use the latest version of &lt;code&gt;aws-sigv4-proxy&lt;/code&gt; (current latest is v1.12). This version 1.12 contains the fix for signing S3 paths (or the OS package names) with special characters such as &lt;code&gt;+&lt;/code&gt;. Earlier versions can return &lt;code&gt;SignatureDoesNotMatch&lt;/code&gt;. The reference implementation pins the reviewed v1.12 release commit immutably. Keep it current through dependency-update reviews.&lt;/p&gt; 
&lt;h2 id="security-boundaries-and-limits"&gt;Security boundaries and limits&lt;/h2&gt; 
&lt;p&gt;The design provides the following controls:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;No automatic public-repository adoption:&lt;/strong&gt; A new upstream version enters the selective path only after an explicit, recorded decision by the user.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Repository ingestion and installation checks:&lt;/strong&gt; You configure strict sync-time signature validation to help validate content before it enters the trusted store. &lt;code&gt;dnf&lt;/code&gt; verifies again during installation.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;No package-channel egress:&lt;/strong&gt; Workload instances are configured to prevent access to public package sources.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;A read-only workload boundary:&lt;/strong&gt; A Workload-account principal cannot modify the frozen repository.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;Human approval is not a malware detection. A reviewer cannot reliably identify a backdoor in a legitimately signed package merely by seeing its name, version, or changelog. Use vulnerability intelligence, scanning, pre-production tests, and staged deployment as additional controls.&lt;/p&gt; 
&lt;p&gt;The approval state, manifests, and CloudTrail records can help support evidence for control frameworks such as SOC 2 change management, ISO 27001 patch-management controls, and FDA 21 CFR Part 11 electronic records. Applicability depends on the organization’s environment, audit scope, and assessor. Confirm it with the compliance team under the AWS shared responsibility model.&lt;/p&gt; 
&lt;h2 id="cost-and-operations"&gt;Cost and operations&lt;/h2&gt; 
&lt;p&gt;Cost depends on the amount of repository content and the chosen networking and availability design. Components can include S3 storage and requests, KMS requests, Lambda invocations, DynamoDB, SNS, Fargate tasks, the internal load balancer, Distribution-account internet egress, &lt;a href="https://docs.aws.amazon.com/vpc/latest/privatelink/create-interface-endpoint.html" target="_blank" rel="noopener"&gt;Amazon VPC endpoints&lt;/a&gt;, and AMI snapshots. A three-task always-on mirror costs more than an S3 bucket alone. Estimate the target topology with current AWS pricing rather than applying a fixed monthly figure from the sample.&lt;/p&gt; 
&lt;p&gt;Run detection and review at an interval defined by patch policy and risk tolerance. The supplied default is monthly, but the Terraform input is configurable. If a package change must be reversed, restore a tested, coherent repository version and rebuild or patch affected hosts as appropriate.&lt;/p&gt; 
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;/h2&gt; 
&lt;p&gt;To set up the reference implementation, work through these in order:&lt;/p&gt; 
&lt;ol type="1"&gt; 
 &lt;li&gt;&lt;strong&gt;Two AWS accounts:&lt;/strong&gt; a connected Distribution account and an air-gapped Workload account.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Deployment tools:&lt;/strong&gt; Terraform 1.5 or later, Terragrunt, Finch or Docker, and Python with &lt;code&gt;pip&lt;/code&gt;.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;AWS Command Line Interface (AWS CLI):&lt;/strong&gt; one named profile per account.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Distribution networking:&lt;/strong&gt; private subnets with internet egress that works without public IPs, security-group egress on port 443, and DNS resolution for public names.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Workload networking:&lt;/strong&gt; VPC interface endpoints for &lt;code&gt;ssm&lt;/code&gt;, &lt;code&gt;ssmmessages&lt;/code&gt;, &lt;code&gt;ec2messages&lt;/code&gt;, &lt;code&gt;logs&lt;/code&gt;, &lt;code&gt;kms&lt;/code&gt;, and &lt;code&gt;imagebuilder&lt;/code&gt;, plus an S3 gateway endpoint.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Internal mirror identity:&lt;/strong&gt; an AWS Certificate Manager (ACM) certificate and a private hosted zone. If the parent AMI does not trust the issuing CA, configure the CA file so the build installs the trust anchor.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Package lineage:&lt;/strong&gt; a parent AMI, repositories, and signing keys from the same distribution lineage. A RHEL subscription is required when retrieving genuine entitled Red Hat content.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Optional deployment roles:&lt;/strong&gt; otherwise, the stack uses each profile’s credentials.&lt;/li&gt; 
&lt;/ol&gt; 
&lt;p&gt;The deployment creates state backend and &lt;a href="https://aws.amazon.com/ecr/" target="_blank" rel="noopener"&gt;Amazon Elastic Container Registry (ECR)&lt;/a&gt; repositories. Do not create those ECR repositories separately before applying their own Terraform units.&lt;/p&gt; 
&lt;h2 id="reference-implementation"&gt;Reference implementation&lt;/h2&gt; 
&lt;p&gt;The &lt;a href="https://github.com/aws-samples/sample-frozen-repo-image-build" target="_blank" rel="noopener"&gt;companion repository&lt;/a&gt; provides Terraform modules, Lambda handlers, two container images, a Terragrunt two-account layout, and Makefile targets for deployment and verification. The shipped &lt;code&gt;alma810&lt;/code&gt; example defaults to the AlmaLinux lineage (RHEL family).&lt;/p&gt; 
&lt;p&gt;Choose one distribution lineage before deployment:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;AlmaLinux Parent Image default:&lt;/strong&gt; use an AlmaLinux parent AMI, AlmaLinux vault repositories, EPEL, and the included AlmaLinux and EPEL signing keys. No Red Hat subscription is required.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Genuine RHEL Parent Image:&lt;/strong&gt; use a Red Hat parent AMI, an entitled Red Hat content source, and Red Hat signing keys. The customer supplies the Red Hat subscription and content-access integration.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The reference implementation only provides AlmaLinux lineage setup, not genuine RHEL. If you choose to use a genuine RHEL parent image lineage, only the reference implementation code needs to be updated to fetch the Red Hat credentials or subscription access, and the rest of the workflow remains the same.&lt;/p&gt; 
&lt;p&gt;Please follow the &lt;a href="https://github.com/aws-samples/sample-frozen-repo-image-build/blob/main/README.md" target="_blank" rel="noopener"&gt;repository README&lt;/a&gt; for detailed setup instructions:&lt;/p&gt; 
&lt;ol type="1"&gt; 
 &lt;li&gt;Fill in &lt;code&gt;environments/config.hcl&lt;/code&gt; and both account files with the two accounts, networking, mirror certificate, package lineage, and parent AMI.&lt;/li&gt; 
 &lt;li&gt;Create the Terraform state backend with &lt;code&gt;make bootstrap DIST_PROFILE=&amp;lt;dist&amp;gt; WORK_PROFILE=&amp;lt;work&amp;gt;&lt;/code&gt;.&lt;/li&gt; 
 &lt;li&gt;Review both account plans with &lt;code&gt;make plan DIST_PROFILE=&amp;lt;dist&amp;gt; WORK_PROFILE=&amp;lt;work&amp;gt;&lt;/code&gt;.&lt;/li&gt; 
 &lt;li&gt;Deploy in dependency order with &lt;code&gt;make all BASELINE_APPROVED=true DIST_PROFILE=&amp;lt;dist&amp;gt; WORK_PROFILE=&amp;lt;work&amp;gt;&lt;/code&gt;. The baseline sync can take several hours.&lt;/li&gt; 
&lt;/ol&gt; 
&lt;h2 id="validate-the-internal-package-management-workflow"&gt;Validate the internal package management workflow&lt;/h2&gt; 
&lt;p&gt;Validation begins by running the AlmaLinux EC2 Image Builder pipeline. A successful build produces private, encrypted AMIs in the configured AWS Regions. To validate the configuration, launch a test instance from the generated AMI in a no-egress Workload subnet and verify that the instance is connected to the internal frozen repository for all package management workflow.&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/25/ComputeBlog-2688-4.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/25/ComputeBlog-2688-4.png" alt="Terminal output listing only the internal frozen-baseos, frozen-appstream, and frozen-epel repositories enabled, with dnf makecache downloading metadata through the private mirror" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 4: Instance showing only the internal frozen repositories enabled, with no public repository configured&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;The output confirms that only the internal frozen AlmaLinux repositories are enabled: &lt;code&gt;frozen-baseos&lt;/code&gt;, &lt;code&gt;frozen-appstream&lt;/code&gt;, and &lt;code&gt;frozen-epel&lt;/code&gt;. The &lt;code&gt;dnf makecache&lt;/code&gt; command successfully downloads metadata for all three repositories through the private mirror. No public repository is configured or used.&lt;/p&gt; 
&lt;p&gt;Now try installing, upgrading, or installing a new package to test that package operations are served by the internal frozen repository.&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/25/ComputeBlog-2688-5.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/25/ComputeBlog-2688-5.png" alt="Terminal output showing a package install and upgrade completing successfully through the internal frozen repository mirror" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 5: Package install and upgrade served by the internal frozen repository&lt;/p&gt;
&lt;/div&gt; 
&lt;h2 id="recommended-practices"&gt;Recommended practices&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Fail closed on approval data.&lt;/strong&gt; If the approved package list cannot be retrieved, stop the sync task and avoid substituting a full sync.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Govern the initial baseline.&lt;/strong&gt; Record who authorized the bootstrap full sync, or require explicit review of its manifest before promotion.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Require vendor signatures at ingestion.&lt;/strong&gt; Do not treat a valid package digest as equivalent to a trusted signature.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Keep package lineages consistent.&lt;/strong&gt; Parent AMI, repository content, and signing keys must come from the same distribution lineage.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Use a customer-defined review cadence.&lt;/strong&gt; Monthly is only the sample default.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Use immutable dependency references with active updates.&lt;/strong&gt; Require &lt;code&gt;aws-sigv4-proxy&lt;/code&gt; v1.12 or later, pin the reviewed artifact by digest or full SHA, and automate update proposals.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Test rollback as a repository operation.&lt;/strong&gt; Restore metadata and objects together, then validate the mirror before using the restored state.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2 id="clean-up"&gt;Clean up&lt;/h2&gt; 
&lt;p&gt;The walkthrough deploys billable resources in both accounts. Please follow the &lt;a href="https://github.com/aws-samples/sample-frozen-repo-image-build/blob/main/README.md" target="_blank" rel="noopener"&gt;repository README&lt;/a&gt; for detailed setup cleanup instructions.&lt;/p&gt; 
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt; 
&lt;p&gt;This pattern separates connected package ingestion from an air-gapped fleet, provides an authorized package baseline and an explicit decision point for later package changes or upgrades, and keeps image builds and running hosts on one frozen repository snapshot. To learn more, visit the EC2 Image Builder service page, the EC2 Image Builder documentation, the Patch Manager documentation, and the Amazon S3 user guide. The reference implementation is available in &lt;a href="https://github.com/aws-samples/sample-frozen-repo-image-build" target="_blank" rel="noopener"&gt;aws-samples&lt;/a&gt;.&lt;/p&gt;</content:encoded>
					
		
		
			</item>
		<item>
		<title>Building event-driven applications at scale with Amazon EventBridge</title>
		<link>https://aws.amazon.com/blogs/compute/building-event-driven-applications-at-scale-with-amazon-eventbridge/</link>
		
		<dc:creator><![CDATA[Nahid Karimaghalou]]></dc:creator>
		<pubDate>Mon, 28 Sep 2026 22:38:57 +0000</pubDate>
				<category><![CDATA[Advanced (300)]]></category>
		<category><![CDATA[Amazon EventBridge]]></category>
		<category><![CDATA[Announcements]]></category>
		<guid isPermaLink="false">752597509722bb2a043058e1df06ec9ac2c7e4cd</guid>

					<description>Amazon EventBridge relaunched the Custom event bus so a platform team can share one governed bus across the organization while application teams publish and subscribe from their own accounts. See how retention, ordering, open formats, transformation, and direct target delivery change what one bus can carry.</description>
										<content:encoded>&lt;p&gt;Event-driven applications on &lt;a href="https://aws.amazon.com/eventbridge/" target="_blank" rel="noopener"&gt;Amazon EventBridge&lt;/a&gt; usually start small and then spread. One team creates a Custom event bus, adds a few rules, and ships. Another team needs some of those events, so a rule forwards them to a bus in a second account. A third team needs a subset of what the second team receives, so another rule forwards again. A year later the organization runs dozens of Custom event buses joined by forwarding rules, and that topology has become a thing to operate in its own right.&lt;/p&gt; 
&lt;p&gt;That shape has a price, and the smallest part of it is the bill. Every forwarding hop is a separate ingestion, so cost tracks the topology rather than the number of consumers that needed the event. The harder problem is that nobody can see the whole picture. Governance spreads across the accounts it was meant to cover. Answering who publishes to a bus, who consumes a given event type, or what breaks when a team stops publishing means visiting each account and reading its rule configuration. Tracing one event is harder still: its path crosses several buses in several accounts, each with its own metrics and logs, and no single view follows it from publication to the consumer that never received it.&lt;/p&gt; 
&lt;p&gt;Application teams also wait. Publishing to a bus in another account, or consuming from one, needs a resource policy, a role, and a forwarding rule owned by a central team. The team that wants to build opens a ticket, and the platform team becomes a queue. Both the missing visibility and the waiting grow with every team onboarded.&lt;/p&gt; 
&lt;p&gt;Amazon EventBridge recently relaunched the Custom event bus, which tackles these challenges directly. A platform team creates one bus, shares it across the organization, and keeps control of who can publish and who can subscribe. Every consumer of those events is listed on the one bus rather than inferred from configuration spread across accounts. Application teams create their own Subscribers in their own accounts. The bus stores events for a retention period you choose, preserves order within a key the publisher sets, accepts Avro and Protocol Buffers (Protobuf) alongside JSON (including CloudEvents), and delivers to targets without a function in the path to translate a call. It runs alongside the Custom event bus – classic, so adoption is incremental.&lt;/p&gt; 
&lt;p&gt;In this post, you see how a platform team stands up a shared bus and governs access to it, how application teams onboard themselves with a single Subscriber resource, and how retention, ordering, open formats, transformation, and direct target integrations change what one bus can carry.&lt;/p&gt; 
&lt;h2 id="one-bus-shared-with-the-organization"&gt;One bus, shared with the organization&lt;/h2&gt; 
&lt;p&gt;The platform team’s job on a shared bus is narrower than it was on a fleet of them. It owns the bus and sets the boundaries: which principals can publish and what their events can declare, which principals can subscribe, and, where it matters, what those principals are allowed to filter on. Application teams then manage their own configuration within those boundaries, such as filters, targets, delivery roles, retry policies, and failure destinations, none of which the platform team needs to write or review. That division is the point of the design. The platform team keeps governance of the bus and stops owning everyone else’s configuration, which is what takes it out of the provisioning path without giving up control of who is on the bus.&lt;/p&gt; 
&lt;p&gt;Creating the bus is a single call in a platform account.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;BUS_ARN=$(aws eventsv2 create-event-bus \
    --name company-events \
    --storage-configuration '{"RetentionPeriodInDays":7}' \
    --query EventBusArn --output text)&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Retention is the one setting worth deciding deliberately here rather than revisiting after an incident. It runs from 1 to 365 days and can be modified later, but a change only applies going forward. Raising it widens the window for events published from that point on, and does not make older events readable again. Seven days covers a working week of history, which is usually enough to onboard a consumer or reprocess after a bug without paying to store a year of events nobody will read.&lt;/p&gt; 
&lt;p&gt;Sharing the bus is the second decision. &lt;a href="https://aws.amazon.com/ram/" target="_blank" rel="noopener"&gt;AWS Resource Access Manager&lt;/a&gt; is the route to reach for first: it associates automatically for accounts in the same organization and reaches accounts outside it by invitation the consumer accepts. A resource policy written on the bus directly is the alternative, and can also name accounts inside or outside the organization.&lt;/p&gt; 
&lt;p&gt;Access is granted per principal, and publishing and subscribing are separate permissions. A team that produces order events gains no ability to read payment events from the same bus. One grant is not enough for a cross-account caller, as usual on AWS: the role that publishes or subscribes also needs its own IAM policy allowing those actions. The platform team decides which accounts can reach the bus, and each consuming team decides which of its own principals can use that access.&lt;/p&gt; 
&lt;p&gt;Taken together, those decisions produce the architecture in the following diagram. One bus lives in a platform account, and application teams publish to it and subscribe from their own accounts. An AWS Lambda function in Team A’s account calls &lt;code&gt;PutRawEvents&lt;/code&gt; to publish events onto the Amazon EventBridge bus in the platform account. Team B and Team C each attach their own Subscriber: Team B’s delivers to a Lambda function, Team C’s to an &lt;a href="https://aws.amazon.com/dynamodb/" target="_blank" rel="noopener"&gt;Amazon DynamoDB&lt;/a&gt; table.&lt;/p&gt; 
&lt;figure&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/28/ComputeBlog-2709-1.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/28/ComputeBlog-2709-1.png" alt="Architecture diagram of one Custom event bus in a platform account. A Lambda function in Team A’s account calls PutRawEvents to publish events onto the Amazon EventBridge bus in the platform account. Team B and Team C each attach their own Subscriber in their own accounts: Team B’s Subscriber delivers to a Lambda function, and Team C’s Subscriber delivers to an Amazon DynamoDB table." width="800"&gt;&lt;/a&gt;
&lt;/figure&gt; 
&lt;p&gt;Figure 1: Multi-account sharing&lt;/p&gt; 
&lt;p&gt;Cost follows team boundaries because charges separate ingestion from delivery. The account that publishes an event pays to put it on the bus, and the account that owns a Subscriber pays for what that Subscriber consumes. Each team’s usage appears on its own bill, which is what makes a shared bus something a platform team can charge back rather than a shared cost center nobody can decompose. Removing the forwarding hops also removes the duplicated ingestion and delivery those hops created: the same event reaching the same three consumers is ingested once instead of three times.&lt;/p&gt; 
&lt;h2 id="publishing-in-the-format-teams-already-use"&gt;Publishing in the format teams already use&lt;/h2&gt; 
&lt;p&gt;Not every producer speaks JSON. Teams that standardize event exchange across an organization often register schemas and publish compact binary payloads, because the schema is the contract between teams that deploy on their own timetables. Accepting the formats those producers already emit is simpler than changing each one to convert to JSON first.&lt;/p&gt; 
&lt;p&gt;With the new Custom event bus, application teams can publish events in Avro, Protobuf, and CloudEvents (JSON) formats. For the binary formats, a schema registry named on the request is used to deserialize the events.&lt;/p&gt; 
&lt;p&gt;There are two publish APIs, and the payload decides which one to call. &lt;code&gt;PutEvents&lt;/code&gt; takes structured JSON with the familiar &lt;code&gt;Detail&lt;/code&gt;, &lt;code&gt;Source&lt;/code&gt;, and &lt;code&gt;DetailType&lt;/code&gt; fields. &lt;code&gt;PutRawEvents&lt;/code&gt; takes a binary payload plus metadata you define, and is the one to use for Avro, Protobuf, CloudEvents, or bytes the bus should not interpret.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-python"&gt;import boto3

events = boto3.client("eventbridgev2")
events.put_raw_events(
    EventBusArn=BUS_ARN,
    SchemaRegistryConfiguration={"RegistryUri": GLUE_REGISTRY_ARN},
    Entries=[
        {
            "Data": avro_encoded_order,  # bytes, straight from your existing producer
            "SystemMetadata": {"ContentType": "application/avro"},
            "Metadata": {"eventType": "OrderPlaced"},
        }
    ],
)&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;The schema registry can be either the &lt;a href="https://docs.aws.amazon.com/glue/latest/dg/schema-registry.html" target="_blank" rel="noopener"&gt;AWS Glue Schema Registry&lt;/a&gt; or the Confluent Cloud Schema Registry.&lt;/p&gt; 
&lt;p&gt;Because the bus decodes the event before filters and transformations run, a consumer subscribing to Avro events written by another team needs no schema, no decoder, and no access to the registry. It writes the same filter it would write against JSON. Producers and consumers stay decoupled, and no deserialization code has to be repeated in each consuming team.&lt;/p&gt; 
&lt;p&gt;Publishers get one more setting on the same request: deduplication. A retry that already succeeded would otherwise leave a duplicate for every consumer to handle. It works one of two ways: the bus hashes the content of each event, or it uses a deduplication ID you supply. Content-based hashing suits producers with no natural key, since two identical events hash the same. A deduplication ID fits when you already have one, such as an order ID combined with a state transition. It keeps matching even when parts of the payload differ in ways that should not count as a new event.&lt;/p&gt; 
&lt;h2 id="self-service-onboarding-for-application-teams"&gt;Self-service onboarding for application teams&lt;/h2&gt; 
&lt;p&gt;The new Custom event bus introduces a new resource called a Subscriber. Application teams create and configure their own Subscribers in their own accounts, provided they have been granted subscribe access to the bus. A Subscriber is the one place a consumer’s behavior is defined: which events it receives, where they are delivered, how delivery is retried, and where events go when delivery does not succeed. Reviewing or changing a consumer is one thing to read and one thing to update.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;SUBSCRIBER_ARN=$(aws eventsv2 create-subscriber \
    --name orders-to-fulfilment \
    --event-bus-arn "$BUS_ARN" \
    --filter-configuration '{"Filters":[{"Scope":"METADATA","Pattern":"{\"eventType\":[\"OrderPlaced\"]}"}]}' \
    --invoke-configuration '{"TargetArn":"'"$QUEUE_ARN"'","RoleArn":"'"$ROLE_ARN"'"}' \
    --retry-policy '{"MaxRetryAttempts":10,"MaxEventAgeInSeconds":3600}' \
    --on-failure-configuration '{"Arn":"'"$DLQ_ARN"'"}' \
    --query SubscriberArn --output text)&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;A filter’s scope decides which part of the event the pattern is matched against. &lt;code&gt;DATA&lt;/code&gt; matches the payload, &lt;code&gt;METADATA&lt;/code&gt; matches the key-value pairs the publisher attached to the event, and &lt;code&gt;SYSTEM_METADATA&lt;/code&gt; matches the event’s system fields: the content type and ordering key a publisher declares, plus the fields Amazon EventBridge adds itself. Because Avro and Protobuf payloads are decoded as they are published, a &lt;code&gt;DATA&lt;/code&gt; filter reads their fields directly, the same as it would for JSON.&lt;/p&gt; 
&lt;p&gt;The retry policy says how the bus should behave when a target is failing. &lt;code&gt;MaxRetryAttempts&lt;/code&gt; sets how many times a delivery is retried, and &lt;code&gt;MaxEventAgeInSeconds&lt;/code&gt; sets how long an event stays eligible for retry, measured from when it was published. Retries stop as soon as either limit is reached, so both bound the same delivery.&lt;/p&gt; 
&lt;p&gt;When deliveries do fail, the reason shows up in the Subscriber’s own logs, which application teams can turn on themselves. They record the error from each delivery attempt alongside the exact input sent to the target, which makes a problem quick to place. Seeing what the target actually received separates a transformation that produced the wrong shape from a target that rejected a correct one.&lt;/p&gt; 
&lt;figure&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/28/ComputeBlog-2709-2.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/28/ComputeBlog-2709-2.png" alt="Screenshot of the Amazon EventBridge console showing the Create subscriber form, with fields for the subscriber name, event bus, filter configuration, target (invoke configuration), retry policy, and on-failure destination." width="800"&gt;&lt;/a&gt;
 &lt;figcaption aria-hidden="true"&gt;&lt;/figcaption&gt;Figure 2: Creating a Subscriber on console
&lt;/figure&gt; 
&lt;h3 id="history-for-consumers-that-did-not-exist-yet"&gt;History for consumers that did not exist yet&lt;/h3&gt; 
&lt;p&gt;A Subscriber sometimes needs events that were published before it existed. For example, a new analytics service needs hydrating with recent history, or a target processed a window of events incorrectly and needs that window replayed. Because the bus retains events for the period configured on it, a Subscriber can be created with a starting position in the past, so it reads history, catches up, and continues with live traffic:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws eventsv2 create-subscriber \
    --name analytics-backfill \
    --event-bus-arn "$BUS_ARN" \
    --starting-position POINT_IN_TIME \
    --point-in-time-configuration '{"PointType":"TIMESTAMP","StartingPoint":"2026-09-14T06:00:00Z"}' \
    --filter-configuration '{"Filters":[{"Scope":"METADATA","Pattern":"{\"eventType\":[\"OrderPlaced\"]}"}]}' \
    --invoke-configuration '{"TargetArn":"'"$ANALYTICS_ARN"'","RoleArn":"'"$ROLE_ARN"'"}'&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;A starting position is either &lt;code&gt;LATEST&lt;/code&gt; or &lt;code&gt;POINT_IN_TIME&lt;/code&gt;. Choosing &lt;code&gt;POINT_IN_TIME&lt;/code&gt; then needs a point-in-time configuration: a &lt;code&gt;PointType&lt;/code&gt; of &lt;code&gt;TIMESTAMP&lt;/code&gt; with a starting point, or &lt;code&gt;HORIZON&lt;/code&gt; to begin at the earliest event still retained. An optional end point stops the read at a chosen time, which is what you want when reprocessing a known-bad window rather than catching up to live traffic.&lt;/p&gt; 
&lt;p&gt;Two things to keep in mind. The starting position is fixed when the Subscriber is created, so reading a different window means a new Subscriber. Treat the starting position as part of a Subscriber’s identity rather than a dial to turn later. And retention cannot reach back beyond the retention window, so the read starts at the earliest retained event however far back the timestamp asks for.&lt;/p&gt; 
&lt;h3 id="order-where-order-matters"&gt;Order, where order matters&lt;/h3&gt; 
&lt;p&gt;In event-driven architectures, where components are built to work asynchronously, the order events arrive in usually does not matter. There are still use cases where a consumer relies on ordered delivery, and the new Custom event bus offers it as an option on individual Subscribers.&lt;/p&gt; 
&lt;p&gt;Ordering is scoped by a key the publisher sets. A publisher includes an event group ID (a customer ID, an order ID, a driver ID), and a Subscriber created with FIFO delivery type receives the events for each group in the order they were published. A FIFO Subscriber reading events published without a group ID has nothing to sequence by, so the two sides work together. Creating one takes the same call as an unordered Subscriber, with the delivery type set to FIFO:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws eventsv2 create-subscriber \
    --name inventory-ordered \
    --event-bus-arn "$BUS_ARN" \
    --type FIFO \
    --filter-configuration '{"Filters":[{"Scope":"METADATA","Pattern":"{\"eventType\":[\"OrderPlaced\"]}"}]}' \
    --invoke-configuration '{"TargetArn":"'"$FIFO_QUEUE_ARN"'","RoleArn":"'"$ROLE_ARN"'","SqsParameters":{"MessageGroupId":"{% $events.SystemMetadata.EventGroupId %}","MessageDeduplicationId":"{% $events.SystemMetadata.DeduplicationId %}"}}'&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Ordering is per group, so throughput scales with the number of groups. If an event cannot be delivered, it holds up the rest of its own group while other groups keep moving. Choosing the key therefore matters: one that maps to a business entity, such as an order or a customer, gives sequencing where it is needed and independence everywhere else. A key so broad that most events share it puts them all in a single sequence, and a key so specific that every event has its own leaves nothing to order.&lt;/p&gt; 
&lt;p&gt;Because ordering is set on each Subscriber, consumers of the same events do not need to agree on it. An inventory service can receive a group’s events in sequence while an analytics service subscribing to those same events takes them as they arrive.&lt;/p&gt; 
&lt;h2 id="reshaping-events-and-delivering-directly-to-a-target"&gt;Reshaping events, and delivering directly to a target&lt;/h2&gt; 
&lt;p&gt;A consumer’s business logic expects events in a particular shape, and the events on the bus are not always in that shape. Where the two get reconciled is an ownership decision: inside the consumer, where it becomes part of that team’s code, or on the Subscriber, ahead of it.&lt;/p&gt; 
&lt;p&gt;The first case is reformatting. A downstream system, often owned by another domain or outside the organization entirely, expects a different structure from the one the publisher emits. A JSONata transformer on the Subscriber produces that structure before delivery, so the consumer receives what it already expects. The business logic stays where it belongs, and when the published shape changes upstream, or another event type needs deriving into the same input, it is the transformer that changes rather than the consumer:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;--transformer '{
    "Type":"JSONATA",
    "JsonataConfiguration":{
        "Expression":"{% {\"orderRef\": $events.Data.detail.orderId, \"total\": $events.Data.detail.amount} %}"
    }
}'&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;The transformer type determines the shape of what gets delivered. &lt;code&gt;RAW&lt;/code&gt; delivers the event payload as is and is the default, so a Subscriber with no transformer configuration receives only the payload. &lt;code&gt;WITH_METADATA&lt;/code&gt; adds the event envelope alongside it, and &lt;code&gt;JSONATA&lt;/code&gt; reshapes it with an expression wrapped in &lt;code&gt;{% %}&lt;/code&gt;.&lt;/p&gt; 
&lt;p&gt;The transformation reshapes events only for the Subscriber that owns it and does not affect what other Subscribers of the same bus receive. That also makes it a data minimization control: a partner can receive only the fields it needs rather than a whole internal event. Defining it at the Subscriber means it holds for every event without anyone remembering to strip fields.&lt;/p&gt; 
&lt;p&gt;The second case is calling an AWS service API. A Subscriber delivers directly to targets including &lt;a href="https://aws.amazon.com/sqs/" target="_blank" rel="noopener"&gt;Amazon Simple Queue Service (Amazon SQS)&lt;/a&gt;, &lt;a href="https://aws.amazon.com/sns/" target="_blank" rel="noopener"&gt;Amazon Simple Notification Service (Amazon SNS)&lt;/a&gt;, &lt;a href="https://aws.amazon.com/lambda/" target="_blank" rel="noopener"&gt;AWS Lambda&lt;/a&gt;, and &lt;a href="https://aws.amazon.com/kinesis/data-streams/" target="_blank" rel="noopener"&gt;Amazon Kinesis Data Streams&lt;/a&gt;. For other services it has been common practice to add a proxy step whose only job is to make the call. With universal targets, the new Custom event bus can call a supported AWS service API directly, with the request body built by a JSONata expression.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-yaml"&gt;TargetArn: arn:aws:events:::aws-sdk:dynamodb:putItem
UniversalTargetParameters.Input:
{% { "TableName": "orders", "Item": { "pk": { "S": $events.Data.detail.orderId } } } %}&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Note that a universal target shapes its input through that parameter rather than through the preceding transformer, and setting a transformer on one is rejected when the Subscriber is created. The two mechanisms do the same kind of work on different targets.&lt;/p&gt; 
&lt;p&gt;That removes the proxy processing that existed only to make the call. The delivery role still needs the action the target requires and getting that wrong is the most common cause of a Subscriber that looks healthy and delivers nothing.&lt;/p&gt; 
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt; 
&lt;p&gt;Running an event-driven application across many accounts no longer means running many event buses and the forwarding between them. A platform team creates one new Custom event bus, shares it across the organization through AWS Resource Access Manager or a resource policy on the bus, and keeps one place to decide who publishes and who consumes. Application teams create and own their Subscribers without waiting for provisioning. Ingestion and delivery are charged separately, so each team’s usage appears on its own bill, and the duplicated ingestion that forwarding hops created disappears with the hops.&lt;/p&gt; 
&lt;p&gt;The capabilities that used to send individual teams elsewhere now sit on the same bus. Ordering is per Subscriber and scoped by a publisher-supplied key, so one team’s sequencing requirement no longer fragments an architecture. Retention makes it possible to onboard a consumer that needs history it was never subscribed to. Avro and Protobuf are decoded by the bus, so producers keep their binary contracts. Transformation and universal targets keep business logic where it belongs, removing the proxy steps that existed only to reshape an event or make an API call.&lt;/p&gt; 
&lt;p&gt;Because the new Custom event bus runs alongside the Custom event bus – classic, adoption is incremental. Point one new consumer at a shared bus or forward a slice of an existing bus into it and move the rest as teams are ready.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Next steps.&lt;/strong&gt; Create a bus, add a Subscriber, and publish an event, starting from the &lt;a href="https://docs.aws.amazon.com/eventbridge/" target="_blank" rel="noopener"&gt;Amazon EventBridge documentation&lt;/a&gt; for the resource model and the &lt;a href="https://aws.amazon.com/cli/" target="_blank" rel="noopener"&gt;AWS Command Line Interface (AWS CLI)&lt;/a&gt; reference. If you already run Custom event buses, the migration guidance covers routing existing events into a new Custom event bus without changing producers. From there, look at the Subscriber logging and metrics options for tracing an event from publication to delivery, and at &lt;a href="https://aws.amazon.com/ram/" target="_blank" rel="noopener"&gt;AWS Resource Access Manager&lt;/a&gt; for how sharing and permissions work across an organization. If you have questions or feedback about the new Custom event bus, leave a comment on this post. We’d like to hear how you’re using it.&lt;/p&gt;</content:encoded>
					
		
		
			</item>
		<item>
		<title>Improving Lambda function latency with scalable network bandwidth</title>
		<link>https://aws.amazon.com/blogs/compute/improving-lambda-function-latency-with-scalable-network-bandwidth/</link>
		
		<dc:creator><![CDATA[Rahul Shandilya]]></dc:creator>
		<pubDate>Mon, 28 Sep 2026 21:17:09 +0000</pubDate>
				<category><![CDATA[Announcements]]></category>
		<category><![CDATA[AWS Lambda]]></category>
		<category><![CDATA[Intermediate (200)]]></category>
		<guid isPermaLink="false">716ba562f3f1d920bd3aa3997c7f825fd79c5e7f</guid>

					<description>AWS Lambda now supports scalable network bandwidth for functions with 2,048 MB of memory or more running outside a VPC. Sustained throughput scales from 625 Mbps up to 3,000 Mbps at 10,240 MB, reducing execution times and per-invocation costs for latency-sensitive data processing workloads.</description>
										<content:encoded>&lt;p&gt;&lt;a href="https://aws.amazon.com/lambda/" target="_blank" rel="noopener"&gt;AWS Lambda&lt;/a&gt; now supports scalable network bandwidth for functions configured with 2,048 MB of memory or more, running outside of a virtual private cloud (VPC). Previously, sustained network throughput was capped at 625 Mbps regardless of your function’s memory configuration. Now, sustained throughput scales proportionally from 625 Mbps at configurations below 2,048 MB up to 3,000 Mbps at 10,240 MB, increasing the rate at which data moves to and from your execution environment.&lt;/p&gt; 
&lt;p&gt;In this post, you learn how to apply this new capability to latency-sensitive data processing workloads, helping reduce function execution times and per-invocation costs while improving the end-user experience through reduced latency. You also walk through a deployable implementation that demonstrates the performance improvements this capability unlocks.&lt;/p&gt; 
&lt;h2&gt;Latency-sensitive data processing&lt;/h2&gt; 
&lt;p&gt;Latency-sensitive data processing applications are data processing workloads that must be completed in a defined period of time. They often experience bursty, ad hoc traffic patterns while being required to download gigabytes or even terabytes of data from a data store, process it in a compute environment, and return a result to a waiting end user.&lt;/p&gt; 
&lt;p&gt;Latency-sensitive data processing is often highly parallelizable. Data can be divided into smaller pieces with each piece being individually processed before combining them together to obtain a result.&lt;/p&gt; 
&lt;p&gt;These workloads can be found in multiple industries and verticals. Examples include:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Log querying engines&lt;/strong&gt; – An end user initiates an on-demand search across terabytes of log data and expects results within seconds.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Insurance underwriting&lt;/strong&gt; – A prospective customer submits an application, triggering real-time evaluation of historical claims and risk data. The underwriting process determines what coverage and premiums to offer to the prospective customer.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Financial ETL pipelines&lt;/strong&gt; – An economic announcement triggers an unexpected burst of market data that must be ingested, transformed, and made available to downstream trading systems before the next market tick.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Genomics platforms&lt;/strong&gt; – A clinician orders a diagnostic test, requiring gigabytes of DNA or RNA sequencing data to pass through a bioinformatics pipeline and be compared against a reference genome while the patient awaits results.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;These workloads are challenging to build on traditional compute clusters. Their spiky and unpredictable nature forces you to choose between under-provisioning compute to optimize costs (and risk missing your SLA) or over-provisioning and paying for idle capacity.&lt;/p&gt; 
&lt;h2&gt;Why Lambda fits latency-sensitive data processing&lt;/h2&gt; 
&lt;p&gt;Lambda eliminates this tradeoff. Instead of pre-provisioning a compute cluster, Lambda scales compute capacity in response to incoming requests, matching processing power to unpredictable traffic patterns. Because latency-sensitive data processing is highly parallelizable, the ability of Lambda to rapidly scale out execution environments makes it a natural fit. You can fan out across thousands of concurrent functions to process data in parallel, paying only for the compute you use.&lt;/p&gt; 
&lt;p&gt;However, as data volume and performance requirements grow, network bandwidth to and from the compute environment can become the limiting factor in minimizing workload latency.&lt;/p&gt; 
&lt;p&gt;Scalable network bandwidth directly addresses this limitation by raising the per-environment network throughput ceiling, improving the rate at which data can be transferred to and from the execution environment. Each execution environment can now drive up to 3,000 Mbps of sustained throughput when configured with 10,240 MB of memory, a 4.8x increase from the previous ceiling of 625 Mbps. Combined with the ability of Lambda to scale out at a rate of 1,000 execution environments every 10 seconds, you can download more than 3 TB of data in under 10 seconds.&lt;/p&gt; 
&lt;h2&gt;New network throughput behavior for Lambda functions&lt;/h2&gt; 
&lt;p&gt;Scalable network bandwidth applies to both data ingress to and egress from an execution environment for functions outside of a VPC. For functions configured with 2 GB of memory or more, network bandwidth scales by approximately 280 Mbps increments for every 1 GB of additional memory allocated.&lt;/p&gt; 
&lt;p&gt;The following table shows the maximum sustained bandwidth available to each execution environment at each memory configuration.&lt;/p&gt; 
&lt;table border="1px" width="100%" cellpadding="10px"&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;&lt;strong&gt;Memory Configuration&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Max Sustained Bandwidth&lt;/strong&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Less than 2,048 MB&lt;/td&gt; 
   &lt;td&gt;625 Mbps&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;2,048 MB&lt;/td&gt; 
   &lt;td&gt;765 Mbps&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;3,072 MB&lt;/td&gt; 
   &lt;td&gt;1,044 Mbps&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;4,096 MB&lt;/td&gt; 
   &lt;td&gt;1,324 Mbps&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;5,120 MB&lt;/td&gt; 
   &lt;td&gt;1,603 Mbps&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;6,144 MB&lt;/td&gt; 
   &lt;td&gt;1,883 Mbps&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;7,168 MB&lt;/td&gt; 
   &lt;td&gt;2,162 Mbps&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;8,192 MB&lt;/td&gt; 
   &lt;td&gt;2,441 Mbps&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;9,216 MB&lt;/td&gt; 
   &lt;td&gt;2,721 Mbps&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;10,240 MB&lt;/td&gt; 
   &lt;td&gt;3,000 Mbps (4.8x increase)&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;p&gt;&lt;em&gt;Table 1. Lambda sustained network bandwidth by memory configuration. Bandwidth scales at ~280 Mbps per additional GB of memory above 2 GB.&lt;/em&gt;&lt;/p&gt; 
&lt;p&gt;In the following section, you learn how scalable network bandwidth improves end-user latency by building an ETL pipeline that demonstrates it. You can find the source code in the &lt;a href="https://github.com/aws-samples/sample-lambda-enhanced-bandwidth" target="_blank" rel="noopener"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt; 
&lt;h2&gt;Solution overview&lt;/h2&gt; 
&lt;p&gt;Consider a SaaS analytics platform where users submit ad hoc queries against a data store. The application must extract the relevant data, apply a filter or transformation, and return an aggregate result while the user waits. In this example, the result needs to be returned in 8 seconds or less.&lt;/p&gt; 
&lt;p&gt;The following diagram illustrates the architecture of the solution.&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/18/ComputeBlog-2609-1.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/18/ComputeBlog-2609-1.png" alt="ETL fan-out architecture: a client calls an orchestrator Lambda function, which fans out to multiple worker Lambda functions that read data in parallel from Amazon S3, with bandwidth scaling callouts for each memory tier." width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 1. ETL fan-out pattern: an orchestrator Lambda function distributes work to multiple worker Lambda functions that read from Amazon S3 in parallel, with bandwidth scaling callouts per memory tier.&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;A client initiates an ad hoc query by calling the orchestrator Lambda function through the Lambda API. The orchestrator function determines how to split the work. To process the data in parallel, the orchestrator function uses a &lt;code&gt;ThreadPoolExecutor&lt;/code&gt; to issue synchronous invoke requests to the Lambda worker function, fanning out the worker across multiple execution environments at the same time.&lt;/p&gt; 
&lt;p&gt;Each Lambda worker function is configured with 10,240 MB of memory, so it has access to up to 3,000 Mbps of sustained network throughput. After the data is processed, the aggregated result is returned to the client.&lt;/p&gt; 
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;/h2&gt; 
&lt;p&gt;Before you start the deployment process, make sure that you have completed the following steps:&lt;/p&gt; 
&lt;ol type="1"&gt; 
 &lt;li&gt;Install the AWS SAM CLI on your computer and confirm that you are running Python 3.12 or later.&lt;/li&gt; 
 &lt;li&gt;Have your AWS account credentials ready.&lt;/li&gt; 
 &lt;li&gt;Submit a request to &lt;a href="https://console.aws.amazon.com/servicequotas/home/services/lambda/quotas" target="_blank" rel="noopener"&gt;AWS Service Quotas&lt;/a&gt; to turn on scalable network bandwidth for your Lambda functions. This quota is listed under Network bandwidth per execution environment.&lt;/li&gt; 
&lt;/ol&gt; 
&lt;p&gt;Clone the source code from the GitHub repo and deploy the application within your AWS account. Creating the 10 GB test dataset and running the benchmark can incur charges to your AWS account.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;git clone https://github.com/aws-samples/sample-lambda-enhanced-bandwidth
cd sample-lambda-enhanced-bandwidth
sam build
sam deploy --guided&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;After the AWS CloudFormation stack is deployed, record the &lt;code&gt;DataBucketName&lt;/code&gt; and orchestrator function name from the stack outputs to use in subsequent commands.&lt;/p&gt; 
&lt;p&gt;To simulate data for the end user to query, the GitHub repo has a script that creates 10 GB of synthetic data and uploads it to your S3 bucket.&lt;/p&gt; 
&lt;h2 id="mode-1-processing-pre-partitioned-data"&gt;Mode 1: Processing pre-partitioned data&lt;/h2&gt; 
&lt;p&gt;In Mode 1, the 10 GB of synthetic data is pre-partitioned. Pre-partitioned data is typically produced incrementally by many sources over a period of time, which can be the case with IoT data or access logs. The following command creates 10 GB of data divided into 20 partitions that are 512 MB each.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;python scripts/generate_data.py \
    --bucket &amp;lt;DATA_BUCKET_NAME&amp;gt; \
    --total-gb 10 \
    --chunk-mb 512&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Turning on scalable network bandwidth does not, on its own, make your downloads faster. A single download request only opens one connection to Amazon S3, and one connection does not move data fast enough to fill all the bandwidth now available to your Lambda function. To actually use your full allotment of network bandwidth, the execution environment has to pull the data over several connections at once. It does this by preferring the AWS Common Runtime (CRT) transfer client, a high-performance download engine built into Boto3. When the worker calls &lt;code&gt;download_fileobj&lt;/code&gt;, the CRT client automatically breaks the 512 MB object into smaller parts and downloads them in parallel across multiple Amazon S3 requests. Those parallel downloads are what let a single Lambda worker take advantage of its full network bandwidth.&lt;/p&gt; 
&lt;p&gt;The following command runs the benchmark on the pre-partitioned data.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;python scripts/run_fanout_benchmark.py \
    --orchestrator-name &amp;lt;STACK_NAME&amp;gt;-orchestrator \
    --bucket &amp;lt;DATA_BUCKET_NAME&amp;gt; \
    --iterations 5&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h2 id="mode-2-processing-single-large-objects"&gt;Mode 2: Processing single large objects&lt;/h2&gt; 
&lt;p&gt;Mode 2 generates 10 GB of data in one large object. This arrangement is more common when data is produced or delivered as one complete unit, such as database backups or genomic datasets. The following command creates 10 GB of data in a single large object.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;python scripts/generate_data.py \
    --bucket &amp;lt;DATA_BUCKET_NAME&amp;gt; \
    --single-object-gb 10 \
    --key large-object/large-file.bin&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;In Mode 1, the CRT preference applies to Boto3 managed transfer methods such as &lt;code&gt;download_file&lt;/code&gt; and &lt;code&gt;download_fileobj&lt;/code&gt;. Mode 2 takes a different approach. Each worker reads a specific byte range of a single large object using &lt;code&gt;get_object&lt;/code&gt;. The CRT preference setting has no effect on these calls. Instead, you can control concurrency by explicitly tuning the number of Lambda workers and using a bounded &lt;code&gt;ThreadPoolExecutor&lt;/code&gt; to issue multiple byte-range requests at the same time.&lt;/p&gt; 
&lt;p&gt;When you run the following command, the orchestrator takes the single large object and divides it into consecutive byte ranges of 512 MB each. Each of the individual ranges is then processed by a Lambda worker execution environment in parallel.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;python scripts/run_fanout_benchmark.py \
    --orchestrator-name &amp;lt;STACK_NAME&amp;gt;-orchestrator \
    --bucket &amp;lt;DATA_BUCKET_NAME&amp;gt; \
    --key large-object/large-file.bin \
    --slice-size-mb 512 \
    --iterations 5&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;The benchmark reports wall-clock duration, client-observed duration, aggregate throughput across workers, worker completion counts, and target compliance. When comparing memory configurations, keep the code, dataset, AWS Region, partition count, warm-up policy, and measurement count identical. You should run the benchmark multiple times in your account because placement, cold starts, concurrency, S3 behavior, and execution-environment reuse could affect results.&lt;/p&gt; 
&lt;h2 id="results"&gt;Results&lt;/h2&gt; 
&lt;p&gt;To compare results, we ran the benchmark using a baseline configuration where the worker Lambda function is configured with only 1,024 MB of memory, well below the 2,048 MB threshold required for scalable network bandwidth to take effect. The 1,024 MB configuration limits network throughput to the previous &lt;em&gt;sustained&lt;/em&gt; ceiling of 625 Mbps.&lt;/p&gt; 
&lt;p&gt;In our baseline test run, a worker downloaded and processed a single 512 MB partition with a 6.61-second download time at a 649.8 Mbps throughput (at p50). The 649.8 Mbps throughput exceeds the 625 Mbps ceiling because Lambda is capable of bursts in network throughput over a short period of time. Across twenty measured fan-out queries, the complete 10 GB query was completed with a 7.113-second wall-clock at p50. This fits within the 8-second SLA but leaves very little headroom.&lt;/p&gt; 
&lt;p&gt;To run our scalable network bandwidth benchmark, we re-deployed our worker Lambda function with a 10,240 MB memory configuration and re-ran the application. At a 10,240 MB memory configuration, each execution environment can now access up to 3,000 Mbps in sustained throughput. Direct 512 MB downloads achieved a 1.70-second download time and 2,521.3 Mbps throughput (both at p50). The complete 10 GB query was completed with a 2.640-second wall-clock at p50. That is 2.69 times faster, or 62.9% lower median latency, than the 1,024 MB configuration.&lt;/p&gt; 
&lt;p&gt;Table 2 summarizes the direct worker and end-to-end fan-out measurements for the same 10 GB dataset and 20 × 512 MB orchestration pattern. Aggregate throughput is the total data transfer rate across all twenty execution environments spun up to run the benchmark.&lt;/p&gt; 
&lt;table border="1px" width="100%" cellpadding="10px"&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;&lt;strong&gt;Memory Configuration&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Single 512 MB partition download time and throughput (p50)&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;10 GB fan-out wall time (p50)&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Aggregate throughput p50&lt;/strong&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;1,024 MB baseline tier (sustained 625 Mbps)&lt;/td&gt; 
   &lt;td&gt;6.61s / 649.8 Mbps&lt;/td&gt; 
   &lt;td&gt;7.113s&lt;/td&gt; 
   &lt;td&gt;12.08 Gbps&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;10,240 MB scalable tier (up to 3,000 Mbps)&lt;/td&gt; 
   &lt;td&gt;1.70s / 2,521.3 Mbps&lt;/td&gt; 
   &lt;td&gt;2.640s&lt;/td&gt; 
   &lt;td&gt;32.54 Gbps&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;p&gt;&lt;em&gt;Table 2. Measured 1,024 MB baseline tier and 10,240 MB scalable bandwidth performance for a 10 GB fan-out ETL query.&lt;/em&gt;&lt;/p&gt; 
&lt;p&gt;Using scalable network bandwidth, the customer’s SLA headroom has improved by nearly 5 seconds. The Lambda function can now handle larger partitions within the same SLA window, reducing costs while still remaining comfortably within the customer’s SLA.&lt;/p&gt; 
&lt;h2 id="clean-up"&gt;Clean up&lt;/h2&gt; 
&lt;p&gt;To clean up the resources you created for the benchmark test, run the following commands:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws s3 rm s3://&amp;lt;DATA_BUCKET_NAME&amp;gt; --recursive
sam delete --stack-name &amp;lt;STACK_NAME&amp;gt;&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h2&gt;Best practices&lt;/h2&gt; 
&lt;p&gt;After scalable network bandwidth is turned on for your AWS account, the following practices help you get the most out of it.&lt;/p&gt; 
&lt;h2 id="profiling-and-planning"&gt;Profiling and planning&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Test before you tune.&lt;/strong&gt; Not every function is network-bound. Before increasing memory, profile your function to confirm that network I/O is the primary contributor to invocation duration and not CPU or application logic. Use Amazon CloudWatch Lambda Insights to inspect &lt;code&gt;rx_bytes&lt;/code&gt;, &lt;code&gt;tx_bytes&lt;/code&gt;, and duration. Functions where network I/O dominates invocation time are prime candidates for tuning.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Design for parallelism.&lt;/strong&gt; Break your data into parallelizable chunks that can be processed independently in a fan-out pattern across multiple execution environments. You can use &lt;a href="https://aws.amazon.com/s3/" target="_blank" rel="noopener"&gt;Amazon S3&lt;/a&gt; byte-range reads to split large files into independently downloadable partitions. For implementation details, see &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/downloading-an-object.html" target="_blank" rel="noopener"&gt;Downloading an object with part numbers&lt;/a&gt; in the Amazon S3 User Guide.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Run AWS Lambda Power Tuning.&lt;/strong&gt; &lt;a href="https://github.com/alexcasalboni/aws-lambda-power-tuning" target="_blank" rel="noopener"&gt;Lambda Power Tuning&lt;/a&gt; is a state machine that helps you optimize your Lambda functions for cost and performance. Use Power Tuning to sweep memory configurations from 1,024 MB to 10,240 MB and identify the optimal cost-vs-latency point for your workload.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2 id="implementation"&gt;Implementation&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Check upstream and downstream limits.&lt;/strong&gt; Check the throughput limits of your data sources. For example, a Lambda function running at 3,000 Mbps can exceed the throughput capacity of a single S3 prefix, which supports up to 5,500 GET requests per second. When this happens, you will see HTTP 503 (Slow Down) errors in your application logs. Distribute your S3 objects across multiple prefixes to parallelize reads and avoid per-prefix throttling.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Balance bandwidth and CPU.&lt;/strong&gt; Lambda allocates CPU proportionally to memory. For example, at a 1.7 GB memory configuration you are allocated 1 vCPU while a 10 GB memory configuration is allocated up to 6 vCPU. If your function processes data in parallel threads, the higher memory tiers give you both more network bandwidth and more CPU to process it. Use the &lt;a href="https://docs.python.org/3/library/concurrent.futures.html" target="_blank" rel="noopener"&gt;concurrent.futures&lt;/a&gt; module in Python or &lt;a href="https://nodejs.org/api/worker_threads.html" target="_blank" rel="noopener"&gt;worker_threads&lt;/a&gt; in &lt;code&gt;Node.js&lt;/code&gt; to process data across parallel threads and maximize both CPU and network utilization.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Turn on Amazon S3 CRT for Boto3.&lt;/strong&gt; If your function uses the Python runtime, initialize your Amazon S3 client with &lt;code&gt;preferred_transfer_client: 'crt'&lt;/code&gt; to maximize single-connection throughput. The AWS Common Runtime automatically parallelizes requests across multiple TCP connections, which matters because individual TCP connections have a throughput ceiling.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Use SnapStart for JVM workloads.&lt;/strong&gt; If you use &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html" target="_blank" rel="noopener"&gt;Lambda SnapStart&lt;/a&gt; for Java functions, scalable network bandwidth reduces &lt;code&gt;afterRestore&lt;/code&gt; hook latency. Network activity that occurs during function restore, such as pre-warming connections or pre-fetching configuration data, can complete faster.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Conclusion&lt;/h2&gt; 
&lt;p&gt;Scalable network bandwidth raises the per-environment sustained throughput ceiling of AWS Lambda from 625 Mbps to 3,000 Mbps, directly reducing end-to-end latency for data-intensive workloads. Combined with the Lambda scaling rate, you can now move terabytes of data in seconds, without provisioning or managing infrastructure.&lt;/p&gt; 
&lt;p&gt;To get started, request the Network bandwidth per execution environment quota increase through &lt;a href="https://console.aws.amazon.com/servicequotas/home/services/lambda/quotas" target="_blank" rel="noopener"&gt;AWS Service Quotas&lt;/a&gt; and deploy the sample application from the &lt;a href="https://github.com/aws-samples/sample-lambda-enhanced-bandwidth" target="_blank" rel="noopener"&gt;GitHub repository&lt;/a&gt; to see the improvement firsthand.&lt;/p&gt; 
&lt;p style="clear: both"&gt;&lt;/p&gt;</content:encoded>
					
		
		
			</item>
		<item>
		<title>Adding custom domains to AWS Lambda MicroVMs with Application Load Balancer</title>
		<link>https://aws.amazon.com/blogs/compute/adding-custom-domains-to-aws-lambda-microvms-with-application-load-balancer/</link>
		
		<dc:creator><![CDATA[Frank Scarfo]]></dc:creator>
		<pubDate>Tue, 22 Sep 2026 16:48:32 +0000</pubDate>
				<category><![CDATA[Advanced (300)]]></category>
		<category><![CDATA[AWS Lambda]]></category>
		<category><![CDATA[Technical How-to]]></category>
		<guid isPermaLink="false">eed40814f635759befd9a9e6f671e1e93dc9f934</guid>

					<description>Many teams want to expose their AWS Lambda MicroVMs under a custom domain they own, and satisfy CORS for browser clients, without changing the application. This post shows how, using an Application Load Balancer that rewrites the Host header and forwards over AWS PrivateLink, deployed with the AWS CDK.</description>
										<content:encoded>&lt;p&gt;AWS Lambda MicroVMs is a serverless compute building block that provides VM-level isolation, near-instant startup performance, and state retention. You can now give each user or job their own execution environment to securely run just-in-time code, whether user or AI-generated. You do this without managing virtualization infrastructure or choosing between isolation, speed, and state retention. Lambda MicroVMs are powered by Firecracker virtualization, the technology underpinning AWS Lambda.&lt;/p&gt; 
&lt;p&gt;When you run a workload on &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/lambda-microvms-guide.html" target="_blank" rel="noopener"&gt;AWS Lambda MicroVMs&lt;/a&gt;, each MicroVM is reachable at a service-generated endpoint that looks like &lt;code&gt;92cfc7f9-….lambda-microvm-….on.aws&lt;/code&gt;. That works, but many teams want to expose their MicroVMs under a domain they own, such as &lt;code&gt;92cfc7f9-….microvms.example.com&lt;/code&gt;. When a browser is the client, they also want to satisfy &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" target="_blank" rel="noopener"&gt;cross-origin resource sharing (CORS)&lt;/a&gt; without changing the application inside the MicroVM.&lt;/p&gt; 
&lt;p&gt;Both are achievable today, entirely from load-balancing and networking primitives. There is no &lt;a href="https://aws.amazon.com/cloudfront/" target="_blank" rel="noopener"&gt;Amazon CloudFront&lt;/a&gt; distribution and no compute in the request path. All you need is an &lt;a href="https://aws.amazon.com/elasticloadbalancing/application-load-balancer/" target="_blank" rel="noopener"&gt;Application Load Balancer (ALB)&lt;/a&gt; that terminates TLS with your &lt;a href="https://docs.aws.amazon.com/acm/latest/userguide/acm-overview.html" target="_blank" rel="noopener"&gt;AWS Certificate Manager (ACM)&lt;/a&gt; certificate, rewrites the &lt;code&gt;Host&lt;/code&gt; header, and forwards the request over &lt;a href="https://aws.amazon.com/privatelink/" target="_blank" rel="noopener"&gt;AWS PrivateLink&lt;/a&gt;. In this post you’ll deploy that pattern with the &lt;a href="https://aws.amazon.com/cdk/" target="_blank" rel="noopener"&gt;AWS Cloud Development Kit (AWS CDK)&lt;/a&gt;, map a wildcard of custom domains onto your MicroVMs, and let the ALB handle CORS for you.&lt;/p&gt; 
&lt;p&gt;The complete, deployable example is available as a pattern on &lt;a href="https://serverlessland.com/patterns/lambda-microvm-custom-domain-cdk" target="_blank" rel="noopener"&gt;Serverless Land&lt;/a&gt;. This walkthrough centers on the reusable networking pattern. The sample also includes a small demo application that &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/microvms-launching.html" target="_blank" rel="noopener"&gt;provisions&lt;/a&gt; a MicroVM and mints an &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/microvms-security.html#microvms-security-auth-tokens" target="_blank" rel="noopener"&gt;access token&lt;/a&gt;, which we reference but do not detail here.&lt;/p&gt; 
&lt;h2 id="what-youll-build"&gt;What you’ll build&lt;/h2&gt; 
&lt;p&gt;By the end you’ll have:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;A wildcard custom domain like &lt;code&gt;*.microvms.example.com&lt;/code&gt;, where each &lt;code&gt;&amp;lt;uuid&amp;gt;.microvms.example.com&lt;/code&gt; maps transparently to the corresponding MicroVM.&lt;/li&gt; 
 &lt;li&gt;An internet-facing ALB that rewrites the incoming request’s &lt;code&gt;Host&lt;/code&gt; header to the real MicroVM endpoint and forwards requests to it privately over PrivateLink.&lt;/li&gt; 
 &lt;li&gt;CORS preflight and response headers handled at the ALB, with no change to the code running in the MicroVM.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;Calling &lt;code&gt;https://&amp;lt;uuid&amp;gt;.microvms.example.com/&amp;lt;path&amp;gt;&lt;/code&gt; (with the MicroVM access headers described later) reaches the right MicroVM, with your domain intact end to end.&lt;/p&gt; 
&lt;h2 id="solution-overview"&gt;Solution overview&lt;/h2&gt; 
&lt;p&gt;The request flow looks like this:&lt;/p&gt; 
&lt;figure&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/17/ComputeBlog-2746-1.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/17/ComputeBlog-2746-1.png" alt="Request flow from a browser through the Application Load Balancer, which terminates TLS and rewrites the Host header, then forwards over AWS PrivateLink to the Lambda MicroVM service." width="661"&gt;&lt;/a&gt;
 &lt;figcaption aria-hidden="true"&gt;
  Request flow from a browser through the Application Load Balancer, which terminates TLS and rewrites the Host header, then forwards over AWS PrivateLink to the Lambda MicroVM service.
 &lt;/figcaption&gt;
&lt;/figure&gt; 
&lt;p&gt;The key component is the ALB &lt;strong&gt;host header rewrite&lt;/strong&gt;, introduced in &lt;a href="https://aws.amazon.com/blogs/networking-and-content-delivery/introducing-url-and-host-header-rewrite-with-aws-application-load-balancers/" target="_blank" rel="noopener"&gt;URL and host header rewrite for Application Load Balancers&lt;/a&gt;. A listener rule matches the incoming custom host with a &lt;strong&gt;regex condition&lt;/strong&gt;, captures the MicroVM ID from the left-most label, and a &lt;code&gt;host-header-rewrite&lt;/code&gt; &lt;strong&gt;transform&lt;/strong&gt; rewrites the &lt;code&gt;Host&lt;/code&gt; header to &lt;code&gt;&amp;lt;uuid&amp;gt;.lambda-microvm.&amp;lt;region&amp;gt;.on.aws&lt;/code&gt; before forwarding. Because the MicroVM service front-end routes on the &lt;code&gt;Host&lt;/code&gt; header, the request lands on the correct MicroVM, while the customer’s domain stays in the browser’s address bar the whole time.&lt;/p&gt; 
&lt;h3 id="why-not-cloudfront-why-not-an-alb-redirect"&gt;Why not CloudFront? Why not an ALB redirect?&lt;/h3&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;CloudFront&lt;/strong&gt; can also rewrite &lt;code&gt;Host&lt;/code&gt;/SNI toward the origin, but a single distribution has static origins. Mapping a &lt;em&gt;wildcard&lt;/em&gt; of MicroVM IDs through one distribution would require a CloudFront Function to compute the origin per request. The ALB transform performs the same rewrite for the entire wildcard with zero code.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;An ALB redirect action&lt;/strong&gt; only issues an &lt;code&gt;HTTP 301 Moved Permanently&lt;/code&gt;/&lt;code&gt;302 Found&lt;/code&gt; response. The browser would follow it, and the address bar would then show the &lt;code&gt;.on.aws&lt;/code&gt; URL, which breaks our design as it is not a real custom domain. The transform (not a redirect) is what makes the custom domain transparent.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2 id="walkthrough"&gt;Walkthrough&lt;/h2&gt; 
&lt;p&gt;The example is an AWS CDK application. Configuration lives under the &lt;code&gt;microvm-custom-domains&lt;/code&gt; key in &lt;code&gt;cdk.json&lt;/code&gt; (hosted zone, wildcard base, the endpoint base to rewrite to, the PrivateLink service name, and the CORS origin). Set those values, then deploy. The sections below explain what the stack creates and why.&lt;/p&gt; 
&lt;h3 id="prerequisites"&gt;Prerequisites&lt;/h3&gt; 
&lt;ul&gt; 
 &lt;li&gt;An AWS account.&lt;/li&gt; 
 &lt;li&gt;An existing &lt;a href="https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/AboutHZWorkingWith.html" target="_blank" rel="noopener"&gt;Amazon Route 53 public hosted zone&lt;/a&gt; for your domain (for example, &lt;code&gt;example.com&lt;/code&gt;). The stack imports it and adds a wildcard record.&lt;/li&gt; 
 &lt;li&gt;&lt;code&gt;Node.js&lt;/code&gt; v22 or higher and the &lt;a href="https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html" target="_blank" rel="noopener"&gt;AWS CDK v2&lt;/a&gt;.&lt;/li&gt; 
 &lt;li&gt;Credentials for the target account with permission to create Lambda, &lt;a href="https://aws.amazon.com/vpc/" target="_blank" rel="noopener"&gt;Amazon Virtual Private Cloud (VPC)&lt;/a&gt;, Elastic Load Balancing, &lt;a href="https://aws.amazon.com/certificate-manager/" target="_blank" rel="noopener"&gt;AWS Certificate Manager (ACM)&lt;/a&gt;, and Route 53 resources through &lt;a href="https://aws.amazon.com/cloudformation/" target="_blank" rel="noopener"&gt;AWS CloudFormation&lt;/a&gt;.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h3 id="create-the-network-and-the-privatelink-endpoint"&gt;1. Create the network and the PrivateLink endpoint&lt;/h3&gt; 
&lt;p&gt;A small VPC (two Availability Zones, which is the minimum for an internet-facing ALB) hosts the ALB and an interface VPC endpoint to the AWS managed MicroVM service. There are no NAT gateways, because nothing here needs egress, which keeps the footprint lean.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-typescript"&gt;// Interface (PrivateLink) endpoint to the AWS managed MicroVM service.
const endpoint = new ec2.InterfaceVpcEndpoint(this, 'MicroVmEndpoint', {
  vpc,
  service: new ec2.InterfaceVpcEndpointService(cfg.microvmVpceServiceName, 443),
  subnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
});&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h3 id="discover-the-endpoints-private-ip-addresses-at-deploy-time"&gt;2. Discover the endpoint’s private IP addresses at deploy time&lt;/h3&gt; 
&lt;p&gt;An ALB IP target group needs the private ENI IP addresses of the interface endpoint (one per Availability Zone). CloudFormation does not expose those IPs as a usable attribute, so the stack resolves them during deployment with an &lt;a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.custom_resources.AwsCustomResource.html" target="_blank" rel="noopener"&gt;AwsCustomResource&lt;/a&gt; that reads the endpoint’s own ENIs by ID (&lt;code&gt;DescribeNetworkInterfaces&lt;/code&gt; on &lt;code&gt;vpcEndpointNetworkInterfaceIds&lt;/code&gt;).&lt;/p&gt; 
&lt;p&gt;This is the &lt;strong&gt;only&lt;/strong&gt; compute the package deploys, it runs &lt;strong&gt;only during&lt;/strong&gt; &lt;code&gt;cdk deploy&lt;/code&gt;, and it is &lt;strong&gt;never in the request path&lt;/strong&gt;.&lt;/p&gt; 
&lt;h3 id="request-a-wildcard-tls-certificate"&gt;3. Request a wildcard TLS certificate&lt;/h3&gt; 
&lt;p&gt;ACM issues a DNS-validated wildcard certificate for &lt;code&gt;*.microvms.example.com&lt;/code&gt;, validated through the hosted zone you imported. The ALB presents this certificate for every custom domain under the wildcard.&lt;/p&gt; 
&lt;h3 id="create-the-alb-and-the-microvm-target-group"&gt;4. Create the ALB and the MicroVM target group&lt;/h3&gt; 
&lt;p&gt;The internet-facing ALB has an HTTPS:443 listener using the wildcard certificate. The target group holds the endpoint ENI IPs as IP targets, reached over HTTPS:443.&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Encrypted in transit.&lt;/strong&gt; A customer-provided AWS Certificate Manager (ACM) certificate is used to securely terminate encryption between the client and the ALB. The ALB re-originates TLS to the MicroVM service so traffic stays encrypted through the network.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;IP-based targets.&lt;/strong&gt; The target group uses IP-based targets with the local IP addresses of the VPC endpoints.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Health check matcher &lt;code&gt;200,403,404&lt;/code&gt;.&lt;/strong&gt; The load balancer’s health probes are unauthenticated, so the MicroVM endpoint answers them with &lt;code&gt;403&lt;/code&gt;. A &lt;code&gt;403&lt;/code&gt; here means “endpoint is reachable,” not “auth is broken,” so the matcher treats it as healthy.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-typescript"&gt;const targetGroup = new elbv2.ApplicationTargetGroup(this, 'MicroVmTargets', {
  vpc,
  protocol: elbv2.ApplicationProtocol.HTTPS,
  port: 443,
  targetType: elbv2.TargetType.IP,
  targets: targetIps.map((ip) =&amp;gt; new elbv2t.IpTarget(ip, 443)),
  healthCheck: {
    protocol: elbv2.Protocol.HTTPS,
    path: '/',
    healthyHttpCodes: '200,403,404',
  },
});

const listener = alb.addListener('Https', {
  port: 443,
  protocol: elbv2.ApplicationProtocol.HTTPS,
  certificates: [certificate],
  // Default action for anything that doesn't match our host regex.
  defaultAction: elbv2.ListenerAction.fixedResponse(404, {
    contentType: 'text/plain',
    messageBody: 'Unknown custom domain',
  }),
});&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h3 id="add-the-host-header-rewrite-rule"&gt;5. Add the host-header rewrite rule&lt;/h3&gt; 
&lt;p&gt;A listener rule matches &lt;code&gt;&amp;lt;uuid&amp;gt;.microvms.example.com&lt;/code&gt; with a regex condition and rewrites the &lt;code&gt;Host&lt;/code&gt; header to &lt;code&gt;&amp;lt;uuid&amp;gt;.lambda-microvm.&amp;lt;region&amp;gt;.on.aws&lt;/code&gt; with a &lt;code&gt;host-header-rewrite&lt;/code&gt; transform. The regex captures the left-most label (the MicroVM ID) and reuses it in the replacement.&lt;/p&gt; 
&lt;p&gt;At the time of writing, the CDK L2 constructs don’t yet model regex host conditions or transforms, so the example reaches the underlying &lt;code&gt;CfnListenerRule&lt;/code&gt; to set them:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-typescript"&gt;const escapedBase = customDomainBase.replace(/[.]/g, '\\.');
const matchRegex = `^(.+)\\.${escapedBase}$`;     // capture &amp;lt;uuid&amp;gt;
const replaceWith = `$1.${microvmEndpointBase}`;   // &amp;lt;uuid&amp;gt;.lambda-microvm.&amp;lt;region&amp;gt;.on.aws

const cfnRule = forwardingRule.node.defaultChild as elbv2.CfnListenerRule;

cfnRule.conditions = [{ field: 'host-header', regexValues: [matchRegex] }];

cfnRule.addPropertyOverride('Transforms', [
  {
    Type: 'host-header-rewrite',
    HostHeaderRewriteConfig: { Rewrites: [{ Regex: matchRegex, Replace: replaceWith }] },
  },
]);&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h3 id="point-route-53-at-the-alb"&gt;6. Point Route 53 at the ALB&lt;/h3&gt; 
&lt;p&gt;Wildcard A and AAAA alias records (&lt;code&gt;*.microvms.example.com&lt;/code&gt;) target the ALB, so every MicroVM custom subdomain resolves to it.&lt;/p&gt; 
&lt;h3 id="deploy"&gt;7. Deploy&lt;/h3&gt; 
&lt;p&gt;Run the following commands to install the dependencies and then deploy the application.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;npm install
npx cdk deploy&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h2 id="handling-cors-at-the-alb"&gt;Handling CORS at the ALB&lt;/h2&gt; 
&lt;p&gt;If your clients are browsers calling the MicroVM from another origin, CORS is handled entirely at the ALB, with no change to the application inside the MicroVM.&lt;/p&gt; 
&lt;p&gt;The listener uses &lt;a href="https://docs.aws.amazon.com/elasticloadbalancing/latest/application/header-modification.html#insert-header" target="_blank" rel="noopener"&gt;ALB header-modification attributes&lt;/a&gt; to insert the &lt;code&gt;Access-Control-Allow-*&lt;/code&gt; headers on &lt;strong&gt;every&lt;/strong&gt; response. A higher-priority rule answers &lt;code&gt;OPTIONS&lt;/code&gt; preflight requests at the edge with a fast &lt;code&gt;204&lt;/code&gt; response. Otherwise, preflight requests would reach the origin and be rejected without an access token.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-typescript"&gt;// Insert CORS headers on every response on this listener.
const cfnListener = listener.node.defaultChild as elbv2.CfnListener;
cfnListener.addPropertyOverride('ListenerAttributes', [
  { Key: 'routing.http.response.access_control_allow_origin.header_value',  Value: cfg.corsAllowOrigin },
  { Key: 'routing.http.response.access_control_allow_methods.header_value', Value: 'GET,POST,PUT,DELETE,OPTIONS,PATCH,HEAD' },
  { Key: 'routing.http.response.access_control_allow_headers.header_value', Value: 'x-aws-proxy-auth,x-aws-proxy-port,content-type,authorization' },
  { Key: 'routing.http.response.access_control_expose_headers.header_value', Value: 'content-type,content-length' },
  { Key: 'routing.http.response.access_control_max_age.header_value',        Value: '86400' },
]);

// Answer OPTIONS preflights at the ALB.
new elbv2.ApplicationListenerRule(this, 'CorsPreflightRule', {
  listener,
  priority: 10,
  conditions: [elbv2.ListenerCondition.httpRequestMethods(['OPTIONS'])],
  action: elbv2.ListenerAction.fixedResponse(204, { contentType: 'text/plain', messageBody: '' }),
});&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Because the ALB adds those headers to both the preflight &lt;code&gt;204&lt;/code&gt; and the forwarded MicroVM response, a browser’s cross-origin call succeeds without any application change. Set &lt;code&gt;corsAllowOrigin&lt;/code&gt; to &lt;code&gt;*&lt;/code&gt; for quick testing, and pin it to your own site for anything beyond a demo.&lt;/p&gt; 
&lt;h2 id="test-it-end-to-end"&gt;Test it end to end&lt;/h2&gt; 
&lt;p&gt;First, launch a Lambda MicroVM and mint an access token (follow &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/microvms-getting-started.html" target="_blank" rel="noopener"&gt;Create your first Lambda MicroVM&lt;/a&gt;). When it’s running, the service gives you a generated endpoint that looks like:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-text"&gt;012345678-9abc-defg.lambda-microvm.us-east-2.on.aws&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;To get the custom-domain equivalent, replace the endpoint suffix (&lt;code&gt;.lambda-microvm.&amp;lt;region&amp;gt;.on.aws&lt;/code&gt;) with your wildcard base: &lt;code&gt;.microvms.example.com&lt;/code&gt;. Everything ahead of that suffix is preserved exactly:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-text"&gt;012345678-9abc-defg.microvms.example.com&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;The ALB’s rewrite rule captures whatever precedes the suffix and re-attaches it to the real endpoint base, so the mapping holds for the entire wildcard. You never register anything per-MicroVM.&lt;/p&gt; 
&lt;p&gt;With your token in hand, call the custom domain you derived:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;curl "https://012345678-9abc-defg.microvms.example.com/&amp;lt;path&amp;gt;" \
  -H "X-aws-proxy-auth: &amp;lt;token&amp;gt;" \
  -H "X-aws-proxy-port: 8080"&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;The request travels to the ALB, which terminates TLS, rewrites the host header, and forwards over PrivateLink to the MicroVM. The response comes back under your domain.&lt;/p&gt; 
&lt;p&gt;The reference architecture also includes a single-page demo and a &lt;code&gt;POST /api/provision&lt;/code&gt; endpoint that runs or reuses a MicroVM and mints a short-lived token. With it, you can try the flow without wiring up token creation yourself. It even performs this suffix swap for you and hands back a ready-to-click custom-domain URL. See the repository for that piece.&lt;/p&gt; 
&lt;h2 id="important-considerations"&gt;Important considerations&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Authentication is still the client’s job.&lt;/strong&gt; This pattern only rewrites &lt;code&gt;Host&lt;/code&gt;. The client must still supply a valid, unexpired access token in &lt;code&gt;X-aws-proxy-auth&lt;/code&gt;. This is deliberate. MicroVM tokens are per-MicroVM and short-lived, so baking them into infrastructure would be fragile and insecure.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Region pinning.&lt;/strong&gt; PrivateLink is regional, so the ALB, the endpoint, and the MicroVM service must all be in the same Region.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Production hardening.&lt;/strong&gt; If you adapt the sample’s provisioning endpoint, put &lt;a href="https://docs.aws.amazon.com/elasticloadbalancing/latest/application/listener-authenticate-users.html" target="_blank" rel="noopener"&gt;authentication&lt;/a&gt; and &lt;a href="https://aws.amazon.com/waf/" target="_blank" rel="noopener"&gt;rate limiting&lt;/a&gt; in front of it, pin CORS to your origin, and scope IAM to the minimum. The sample’s provisioning path is intentionally open for demonstration and is not production-safe as written.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Cost.&lt;/strong&gt; You pay for the ALB and the interface endpoint (hourly plus data processing) in addition to the Lambda MicroVM usage. There is no CloudFront distribution and no per-request compute in the data path.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2 id="clean-up"&gt;Clean up&lt;/h2&gt; 
&lt;p&gt;Run the following command in the same directory where you deployed the application from.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;npx cdk destroy&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;This removes the ALB, target groups, endpoint, certificate, VPC, and Route 53 records created by the stack.&lt;/p&gt; 
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt; 
&lt;p&gt;You can front AWS Lambda MicroVMs with customer-owned wildcard custom domains using an Application Load Balancer and AWS PrivateLink. The key is the ALB’s host-header rewrite. Because the MicroVM service routes requests based on the &lt;code&gt;Host&lt;/code&gt; header, a single rewrite rule can transparently map an entire wildcard of custom domains onto your MicroVMs. CORS is handled at the edge as well. The whole setup relies only on networking primitives, with no CloudFront distribution and no compute in the request path.&lt;/p&gt; 
&lt;p&gt;To try it yourself, deploy the &lt;a href="https://serverlessland.com/patterns/lambda-microvm-custom-domain-cdk" target="_blank" rel="noopener"&gt;reference architecture&lt;/a&gt; and review the &lt;a href="https://aws.amazon.com/blogs/networking-and-content-delivery/introducing-url-and-host-header-rewrite-with-aws-application-load-balancers/" target="_blank" rel="noopener"&gt;ALB URL and host header rewrite launch post&lt;/a&gt; for more on the transform feature.&lt;/p&gt;</content:encoded>
					
		
		
			</item>
		<item>
		<title>Running self-hosted AI agent sandboxes with AWS Lambda MicroVMs</title>
		<link>https://aws.amazon.com/blogs/compute/running-self-hosted-ai-agent-sandboxes-with-aws-lambda-microvms/</link>
		
		<dc:creator><![CDATA[Brian Krygsman]]></dc:creator>
		<pubDate>Fri, 18 Sep 2026 15:10:33 +0000</pubDate>
				<category><![CDATA[Advanced (300)]]></category>
		<category><![CDATA[Announcements]]></category>
		<category><![CDATA[AWS Lambda]]></category>
		<guid isPermaLink="false">944ab8480d283c186edab190849be500bbcf4b16</guid>

					<description>Learn how to run AI agent tool calls in secure, isolated sandboxes using AWS Lambda MicroVMs. This post shows how to architect a self-hosted control plane that launches a fresh, VM-isolated MicroVM for each agent session, keeping credentials, networking, and governance entirely within your own AWS account.</description>
										<content:encoded>&lt;p&gt;Organizations are building AI agents that autonomously write code, query databases, and interact with internal systems on behalf of their teams. These agents handle use cases such as automated code review, data pipeline optimization, and infrastructure troubleshooting. When your AI agent generates a shell command, queries a database, or writes to a file system, that code needs a secure environment to run in. Without isolation, one session’s tool calls can contaminate another session’s state, inadvertently expose sensitive data across tenants, or unintentionally allow untrusted code to reach production resources. Self-hosted sandboxes solve this by keeping agent execution within your own AWS account, giving you full control over networking, secrets, and governance.&lt;/p&gt; 
&lt;p&gt;Say you’re building an internal AI agent that optimizes database queries for your engineering team. A developer asks it to find the ten slowest queries in your analytics database, rewrite them with better indexing, and test the results. That’s three tool calls in a single session. One hits a live database with real credentials. One generates code. One executes it. Now multiply that by fifty developers using the assistant at the same time. Each session needs its own credentials, its own filesystem, its own network boundary. If credentials or state cross session boundaries, you have inadvertent data exposure.&lt;/p&gt; 
&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/lambda/" target="_blank" rel="noopener"&gt;AWS Lambda MicroVMs&lt;/a&gt; is a serverless compute environment that provides general-purpose runtimes with the strong isolation of virtual machines and the rapid scaling of &lt;a href="https://aws.amazon.com/lambda/" target="_blank" rel="noopener"&gt;AWS Lambda&lt;/a&gt;. Powered by Firecracker virtualization, each MicroVM runs Amazon Linux with full OS access for up to 8 hours. You launch, suspend, resume, and terminate MicroVMs programmatically. You get the serverless benefits of managed infrastructure, responsive scaling, and pay-per-use pricing. Three capabilities make Lambda MicroVMs a strong fit for agent sandboxes:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;VM-level isolation per environment&lt;/strong&gt;: Each MicroVM runs in its own Firecracker virtual machine, providing hardware-virtualization-based isolation between sessions without the resource overhead and startup time required of full VMs. One developer cannot see a teammate’s session, even when both run at the same time.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Launch from snapshot:&lt;/strong&gt; Like &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html" target="_blank" rel="noopener"&gt;Lambda SnapStart&lt;/a&gt;, MicroVMs boot from a pre-captured memory and disk snapshot, skipping application initialization entirely. Your agent gets a near-instant ready-to-use environment.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;4x vertical scaling without re-provisioning&lt;/strong&gt;: A running MicroVM can scale CPU and memory up to 4x its initial allocation, which can range from 0.25 vCPU/0.5 GB to 4 vCPU/8 GB, without terminating or re-creating the environment. If the agent needs to run a heavy data transformation mid-session, it can get more resources without starting over.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;In this post, we show you how to architect and build a self-hosted AI agent that uses Lambda MicroVMs as secure, isolated sandboxes for tool-call execution. Lambda MicroVMs can handle the compute isolation for running tool calls, while the host for production AI agents, such as Amazon Bedrock AgentCore, manages the agent logic, model routing, and session state. A complete reference solution is available in &lt;a href="https://github.com/aws-samples/sample-lambda-microvm-claude-managed-agents" target="_blank" rel="noopener"&gt;aws-samples&lt;/a&gt;.&lt;/p&gt; 
&lt;h2 id="how-self-hosted-sandboxes-work"&gt;How self-hosted sandboxes work&lt;/h2&gt; 
&lt;p&gt;A developer asks the agent to “find the ten slowest queries in our analytics database and suggest index improvements.” The agent orchestration system starts a session then breaks the objective into tool calls and distributes them. A worker needs to pick up that session, run the queries, and return results.&lt;/p&gt; 
&lt;p&gt;Most AI agent orchestration services and frameworks use a work queue model to distribute tool-call execution. The orchestration service enqueues sessions representing tool-call work. A worker, the process that claims a session and executes its tool calls, runs inside a compute environment, posts results, and exits. In this architecture, each Lambda MicroVM is the compute environment, and the worker is the process running inside it. Claude Managed Agents self-hosted sandboxes run those workers inside your own infrastructure rather than on a shared, multi-tenant compute pool. Your database credentials stay in your virtual private cloud (VPC). Your network, introspection, and governance rules apply.&lt;/p&gt; 
&lt;p&gt;You can trigger workers in two ways:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Webhook-triggered:&lt;/strong&gt; The orchestration application sends a notification when a session is ready. Your control plane launches a worker on demand.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Always-on:&lt;/strong&gt; A long-running process continuously polls the work queue for new sessions.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;The Lambda MicroVMs lifecycle aligns with the webhook-triggered pattern, where each session produces one inbound event that launches a fresh MicroVM. Lambda MicroVMs support configurable &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/microvms-launching.html#microvms-launching-idle-policy" target="_blank" rel="noopener"&gt;idle policies&lt;/a&gt;. After a configurable idle period, a MicroVM suspends automatically, preserving disk and memory state. It resumes when inbound traffic arrives or when you call the resume API. The MicroVM runs for the duration of the session, the worker exits, and the idle policy suspends then finally terminates the VM. &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/microvms-launching.html#microvms-launching-lifecycle-hooks" target="_blank" rel="noopener"&gt;Lifecycle hooks&lt;/a&gt; allow you to run custom logic at key steps in the MicroVM lifecycle.&lt;/p&gt; 
&lt;p&gt;In contrast, the always-on pattern risks breaking the polling loop by suspending the MicroVM when idle, since there’s no inbound traffic between sessions. You could disable the configurable idle period, but then you pay for empty polling. Use the webhook-triggered approach for self-hosted sandboxes on Lambda MicroVMs.&lt;/p&gt; 
&lt;h2 id="architecture"&gt;Architecture&lt;/h2&gt; 
&lt;p&gt;The following figure shows the reference solution’s architecture, with the Anthropic agent orchestration service control plane on the left interacting with a self-hosted sandbox environment in AWS on the right.&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;a href="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/16/ComputeBlog-2668-1.png" target="_blank" rel="noopener"&gt;&lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/09/16/ComputeBlog-2668-1.png" alt="Reference architecture showing the Anthropic orchestration control plane sending a webhook through API Gateway to a launcher Lambda function that starts a MicroVM worker in your AWS account" width="800"&gt;&lt;/a&gt;
 &lt;p class="wp-caption-text"&gt;Figure 1: Reference architecture for self-hosted AI agent sandboxes on Lambda MicroVMs&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;The sample architecture is event-driven. The only inbound traffic is the webhook call. When the event arrives, the handler launches a MicroVM. Once launched, the MicroVM pulls its assigned session from the orchestration system’s work queue and runs the task. In our example, the developer’s “find slow queries” request has been queued as a session. The agent now needs to reach your infrastructure, spin up an isolated environment, and hand off the work. The following sequence shows how each component interacts to fulfill a single session.&lt;/p&gt; 
&lt;p&gt;The orchestration service queues work as &lt;strong&gt;sessions&lt;/strong&gt;. A &lt;strong&gt;MicroVM&lt;/strong&gt; launches to service each session, and the &lt;strong&gt;worker&lt;/strong&gt; is the process running inside that MicroVM that claims the session, executes tool calls, and returns results.&lt;/p&gt; 
&lt;ol type="1"&gt; 
 &lt;li&gt;Once the orchestration service marks a session as ready to run, it sends a &lt;code&gt;session.status_run_started&lt;/code&gt; webhook to an &lt;a href="https://aws.amazon.com/api-gateway/" target="_blank" rel="noopener"&gt;Amazon API Gateway&lt;/a&gt; endpoint, triggering a MicroVM launch.&lt;/li&gt; 
 &lt;li&gt;The launcher verifies the webhook signature using a signing secret from &lt;a href="https://aws.amazon.com/systems-manager/" target="_blank" rel="noopener"&gt;AWS Systems Manager Parameter Store&lt;/a&gt;, rejecting invalid or stale deliveries before spending compute.&lt;/li&gt; 
 &lt;li&gt;The launcher calls &lt;code&gt;RunMicrovm&lt;/code&gt;, passing the session ID and a secret reference through &lt;code&gt;runHookPayload&lt;/code&gt;. It deduplicates on the webhook event ID (backed by &lt;a href="https://aws.amazon.com/dynamodb/" target="_blank" rel="noopener"&gt;Amazon DynamoDB&lt;/a&gt;) so retries do not launch duplicate VMs.&lt;/li&gt; 
 &lt;li&gt;The MicroVM boots from a pre-captured Firecracker snapshot and receives the dispatch on its &lt;code&gt;/run&lt;/code&gt; lifecycle hook. The worker fetches the environment key from &lt;a href="https://aws.amazon.com/systems-manager/" target="_blank" rel="noopener"&gt;Parameter Store&lt;/a&gt; using its execution role. It pulls the matching session from the work queue, claims it, and executes tool calls in an isolated &lt;code&gt;/workspace&lt;/code&gt; directory. When finished, it posts results and exits. The idle policy suspends then terminates the VM.&lt;/li&gt; 
&lt;/ol&gt; 
&lt;p&gt;&lt;strong&gt;Deduplication.&lt;/strong&gt; The webhook event ID serves as the idempotency key. The launcher uses &lt;a href="https://docs.powertools.aws.dev/lambda/python/latest/utilities/idempotency/" target="_blank" rel="noopener"&gt;Powertools for AWS Lambda (Python)&lt;/a&gt; with a DynamoDB persistence layer to verify exactly-once processing. If the orchestration application retries a delivery with the same event ID, Powertools protects the system from launching extra MicroVMs and doing extra work.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Credential boundaries&lt;/strong&gt;. Each component accesses only the single secret it needs. The launcher reads only the webhook signing secret to verify inbound events. It passes only an ARN reference to the environment key into the MicroVM payload. The MicroVM’s execution role retrieves only that environment key at runtime. No single component holds both secrets.&lt;/p&gt; 
&lt;table border="1px" width="100%" cellpadding="10px"&gt; 
 &lt;tbody&gt; 
  &lt;tr&gt; 
   &lt;td&gt;&lt;strong&gt;Component&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;Has access to&lt;/strong&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Launcher Lambda&lt;/td&gt; 
   &lt;td&gt;Webhook signing secret (verify inbound events)&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;MicroVM worker&lt;/td&gt; 
   &lt;td&gt;Environment key (through the execution role, to poll and claim sessions)&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt; 
&lt;/table&gt; 
&lt;p&gt;&lt;strong&gt;Cost model&lt;/strong&gt;. &lt;a href="https://aws.amazon.com/lambda/pricing/#Lambda_MicroVMs_Pricing" target="_blank" rel="noopener"&gt;You pay for MicroVM run time per session&lt;/a&gt;, plus standard charges for API Gateway requests, Parameter Store API calls, and Lambda invocations for the launcher. When no sessions are active, no MicroVMs run. Cost scales with concurrent sessions and their duration, avoiding idle compute charges.&lt;/p&gt; 
&lt;h2 id="implementation"&gt;Implementation&lt;/h2&gt; 
&lt;p&gt;The following sections explore the &lt;a href="https://github.com/aws-samples/sample-lambda-microvm-claude-managed-agents" target="_blank" rel="noopener"&gt;reference architecture&lt;/a&gt; in more depth.&lt;/p&gt; 
&lt;h3 id="project-structure"&gt;Project structure&lt;/h3&gt; 
&lt;p&gt;The reference solution uses &lt;a href="https://aws.amazon.com/serverless/sam/" target="_blank" rel="noopener"&gt;AWS Serverless Application Model (AWS SAM)&lt;/a&gt; for infrastructure-as-code. Alternatively, if you use an AI coding agent such as Claude Code, Kiro, or Cursor, the &lt;a href="https://aws.amazon.com/products/developer-tools/agent-toolkit-for-aws/" target="_blank" rel="noopener"&gt;Agent Toolkit for AWS&lt;/a&gt; includes a &lt;a href="https://github.com/aws/agent-toolkit-for-aws/tree/main/skills/specialized-skills/serverless-skills/aws-lambda-microvms" target="_blank" rel="noopener"&gt;Lambda MicroVMs skill&lt;/a&gt; that gives your agent the procedures to provision, configure, and deploy MicroVM-based sandbox environments on your behalf.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-plaintext"&gt;├── template.yaml                    # SAM: launcher, API, WAF, secrets, roles
├── src/
│   ├── functions/launcher.py        # Verify signature, RunMicrovm
│   ├── microvm-image/
│   │   ├── Dockerfile               # AL2023 + Node.js worker
│   │   └── worker/worker.mjs        # Lifecycle hook server
│   └── scripts/build-image.sh       # Package + create MicroVM image&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h3 id="launcher-verify-the-webhook-before-spinning-up-compute"&gt;Launcher: verify the webhook before spinning up compute&lt;/h3&gt; 
&lt;p&gt;When the webhook arrives saying a developer’s session is ready, the launcher’s first action is signature verification. If it fails, the function returns 401 immediately. No MicroVM launches. No DynamoDB writes. You don’t pay for fraudulent or replayed requests.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-python"&gt;signing_secret = [REDACTED_PASSWORD]  # Verify webhook before spending compute
if not verify_signature(raw_body, headers, signing_secret):
    return {"statusCode": 401, "body": "invalid signature"}&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;After verification, the launcher builds a dispatch payload containing the session ID, environment ID, region, and an ARN reference to the environment key secret. It passes this to &lt;code&gt;RunMicrovm&lt;/code&gt; through &lt;code&gt;runHookPayload&lt;/code&gt;:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-python"&gt;launched = microvm_client.run_microvm(
    image_identifier="arn:aws:lambda:us-east-1:123456789012:microvm-image:worker",
    run_hook_payload=json.dumps({"session": dispatch}),
    execution_role_arn=config.execution_role_arn,
    maximum_duration_in_seconds=28800,
    ingress_network_connectors=["arn:aws:lambda:::network-connector:aws-network-connector:ALL_INGRESS"],
    egress_network_connectors=["arn:aws:lambda:::network-connector:aws-network-connector:INTERNET_EGRESS"],
)&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h3 id="microvm-worker-claim-one-session-execute-exit"&gt;MicroVM worker: claim one session, execute, exit&lt;/h3&gt; 
&lt;p&gt;The MicroVM image is built from a &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/microvms-images-snapshots.html" target="_blank" rel="noopener"&gt;Firecracker snapshot&lt;/a&gt;. The worker process starts during image creation and is captured in the snapshot, so there is no application startup at run time. The /run &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/microvms-launching.html#microvms-launching-lifecycle-hooks" target="_blank" rel="noopener"&gt;lifecycle hook&lt;/a&gt; delivers the dispatch payload:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-javascript"&gt;// POST /aws/lambda-microvms/runtime/v1/run
case "run": {
    const envelope = JSON.parse(rawBody);
    const dispatch = JSON.parse(envelope.runHookPayload);
    res.writeHead(200); // Acknowledge hook immediately
    res.end();
    const key = await fetchParameter(dispatch.session.ENVIRONMENT_KEY_PARAM_NAME);
    await pollAndHandleSession(dispatch.session.ANTHROPIC_SESSION_ID, key);
    // Session complete; terminate this MicroVM to release all resources
    await terminateMicroVm(envelope.microvmId);
}&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;The worker acknowledges the hook within its timeout, fetches the environment key, and claims the session. This is where the requested work begins. The worker connects to the analytics database, runs &lt;code&gt;EXPLAIN ANALYZE&lt;/code&gt; on the flagged queries, writes optimized alternatives to &lt;code&gt;/workspace/suggestions.sql&lt;/code&gt;, and posts the results back to the developer. All of that happens inside this single VM. When the session completes, the worker calls &lt;code&gt;terminate-microvm&lt;/code&gt; to release all compute resources.&lt;/p&gt; 
&lt;h3 id="deployment"&gt;Deployment&lt;/h3&gt; 
&lt;p&gt;For full deployment instructions, see the &lt;a href="https://github.com/aws-samples/sample-lambda-microvm-claude-managed-agents" target="_blank" rel="noopener"&gt;reference solution README&lt;/a&gt;. Before deploying, make sure you have these prerequisites.&lt;/p&gt; 
&lt;h4 id="prerequisites"&gt;Prerequisites&lt;/h4&gt; 
&lt;ul&gt; 
 &lt;li&gt;An AWS account with permissions for &lt;a href="https://aws.amazon.com/s3/" target="_blank" rel="noopener"&gt;Amazon Simple Storage Service (Amazon S3)&lt;/a&gt;, &lt;a href="https://aws.amazon.com/iam/" target="_blank" rel="noopener"&gt;AWS Identity and Access Management (IAM)&lt;/a&gt;, &lt;a href="https://aws.amazon.com/systems-manager/" target="_blank" rel="noopener"&gt;AWS Systems Manager Parameter Store&lt;/a&gt;, &lt;a href="https://aws.amazon.com/api-gateway/" target="_blank" rel="noopener"&gt;Amazon API Gateway&lt;/a&gt;, &lt;a href="https://aws.amazon.com/lambda/" target="_blank" rel="noopener"&gt;AWS Lambda&lt;/a&gt;, &lt;a href="https://aws.amazon.com/waf/" target="_blank" rel="noopener"&gt;AWS WAF&lt;/a&gt;, &lt;a href="https://aws.amazon.com/cloudwatch/" target="_blank" rel="noopener"&gt;Amazon CloudWatch Logs&lt;/a&gt;, and &lt;a href="https://aws.amazon.com/lambda/lambda-microvms/" target="_blank" rel="noopener"&gt;AWS Lambda MicroVMs&lt;/a&gt;.&lt;/li&gt; 
 &lt;li&gt;&lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html" target="_blank" rel="noopener"&gt;AWS Command Line Interface (AWS CLI) v2+&lt;/a&gt;.&lt;/li&gt; 
 &lt;li&gt;The &lt;a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html" target="_blank" rel="noopener"&gt;AWS SAM CLI&lt;/a&gt;.&lt;/li&gt; 
 &lt;li&gt;An existing &lt;a href="https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes" target="_blank" rel="noopener"&gt;Anthropic Claude Managed Agents&lt;/a&gt; agent configured with a &lt;code&gt;self_hosted&lt;/code&gt; environment (note the agent ID and environment ID).&lt;/li&gt; 
 &lt;li&gt;A webhook signing secret and environment key, both generated in the &lt;a href="https://platform.claude.com/" target="_blank" rel="noopener"&gt;Anthropic Claude Console&lt;/a&gt;.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h4 id="four-steps"&gt;Four steps&lt;/h4&gt; 
&lt;ol type="1"&gt; 
 &lt;li&gt;&lt;strong&gt;Deploy the control plane.&lt;/strong&gt; Build and deploy the SAM stack, which creates the launcher Lambda, API Gateway endpoint, WAF WebACL, DynamoDB idempotency table, Parameter Store entries, and MicroVM execution role. 
  &lt;div class="hide-language"&gt; 
   &lt;pre&gt;&lt;code class="language-bash"&gt;sam build
sam deploy --guided --capabilities CAPABILITY_NAMED_IAM&lt;/code&gt;&lt;/pre&gt; 
  &lt;/div&gt; &lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Register the webhook and populate secrets.&lt;/strong&gt; In the &lt;a href="https://platform.claude.com/" target="_blank" rel="noopener"&gt;Claude Console&lt;/a&gt;, register the stack’s &lt;code&gt;WebhookUrl&lt;/code&gt; output as a webhook endpoint subscribed to &lt;code&gt;session.status_run_started&lt;/code&gt;. Store the signing secret and environment key in the Parameter Store resources created by the stack.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Build the MicroVM image.&lt;/strong&gt; Package the Dockerfile and worker code, upload to Amazon S3, and create the image. The service runs your Dockerfile, launches the worker, and captures a Firecracker snapshot. Monitor build progress in Amazon CloudWatch under &lt;code&gt;/aws/lambda/microvms/&amp;lt;image-name&amp;gt;&lt;/code&gt;. 
  &lt;div class="hide-language"&gt; 
   &lt;pre&gt;&lt;code class="language-bash"&gt;./src/scripts/build-image.sh&lt;/code&gt;&lt;/pre&gt; 
  &lt;/div&gt; &lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Verify.&lt;/strong&gt; Create a test session and confirm a MicroVM launches and completes end-to-end. The reference solution includes a verification script that creates a session, triggers the webhook, and validates the full flow.&lt;/li&gt; 
&lt;/ol&gt; 
&lt;h2 id="using-claude-platform-on-aws-cpoa"&gt;Using Claude Platform on AWS (CPOA)&lt;/h2&gt; 
&lt;p&gt;The preceding architecture works similarly when you access Claude through &lt;a href="https://aws.amazon.com/claude-platform/" target="_blank" rel="noopener"&gt;Claude Platform on AWS&lt;/a&gt; rather than the first-party API. Three things change in the worker:&lt;/p&gt; 
&lt;ol type="1"&gt; 
 &lt;li&gt;&lt;strong&gt;Client initialization.&lt;/strong&gt; Replace the first-party client with the AWS client and supply your workspace ID: 
  &lt;div class="hide-language"&gt; 
   &lt;pre&gt;&lt;code class="language-python"&gt;from anthropic import AnthropicAWS

client = AnthropicAWS(aws_region="us-east-1")

# Workspace ID is required on every request
# Set via ANTHROPIC_AWS_WORKSPACE_ID env var or pass per-call&lt;/code&gt;&lt;/pre&gt; 
  &lt;/div&gt; &lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Authentication options.&lt;/strong&gt; CPOA supports two modes: 
  &lt;ol type="a"&gt; 
   &lt;li&gt;&lt;strong&gt;CPOA API key&lt;/strong&gt; (&lt;code&gt;aws-external-anthropic-api-key-...&lt;/code&gt;): Store it in Parameter Store the same way as the first-party environment key. These keys are short-lived (12-hour STS tokens) and must be regenerated when they expire.&lt;/li&gt; 
   &lt;li&gt;&lt;strong&gt;SigV4 (IAM)&lt;/strong&gt;: The MicroVM execution role can sign requests directly, so there is no secret to store or rotate. Set the environment key secret to a placeholder value (for example, &lt;code&gt;use-sigv4&lt;/code&gt;) and the SDK falls through to IAM credentials automatically. This is the recommended path for production.&lt;/li&gt; 
  &lt;/ol&gt; &lt;/li&gt; 
&lt;/ol&gt; 
&lt;p&gt;In both authentication modes, attach the AWS managed policy &lt;code&gt;AnthropicSelfHostedEnvironmentAccess&lt;/code&gt; to the MicroVM execution role. This policy grants the &lt;code&gt;aws-external-anthropic&lt;/code&gt; actions needed to poll the work queue, claim sessions, and post results. See &lt;a href="https://platform.claude.com/docs/en/api/claude-platform-on-aws-iam-actions" target="_blank" rel="noopener"&gt;IAM actions for Claude Platform on AWS&lt;/a&gt; for the full reference.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Prerequisite:&lt;/strong&gt; &lt;a href="https://aws.amazon.com/blogs/aws/simplify-access-to-external-services-using-aws-iam-outbound-identity-federation/" target="_blank" rel="noopener"&gt;Enable outbound web identity federation&lt;/a&gt; once per AWS account:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws iam enable-outbound-web-identity-federation&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Everything else, including webhook verification, deduplication, credential separation, and idle policy remains the same.&lt;/p&gt; 
&lt;h2 id="security"&gt;Security&lt;/h2&gt; 
&lt;p&gt;Earlier we talked about what goes wrong without isolation. Credentials exposed between sessions. Scripts unintentionally reaching production. Agents escaping their sandbox. This architecture implements defense in depth to help prevent these.&lt;/p&gt; 
&lt;p&gt;Each component accesses a single, scoped secret. The launcher passes only an ARN reference to the worker credential into the MicroVM. The MicroVM’s execution role retrieves only that credential at runtime. The analytics database connection string does not touch the launcher and does not leave your environment.&lt;/p&gt; 
&lt;p&gt;&lt;a href="https://aws.amazon.com/waf/" target="_blank" rel="noopener"&gt;AWS WAF&lt;/a&gt; applies managed rule sets (OWASP, known bad inputs, IP reputation) and per-IP rate limiting. &lt;a href="https://aws.amazon.com/api-gateway/" target="_blank" rel="noopener"&gt;Amazon API Gateway&lt;/a&gt; request validation rejects malformed bodies. The launcher performs HMAC signature verification as the true authentication boundary.&lt;/p&gt; 
&lt;p&gt;Each session runs in its own MicroVM. Sessions do not share memory, disk, or network namespaces. Firecracker provides hardware-virtualization-based isolation. The launcher IAM role reads only the signing secret. The MicroVM execution role reads only the worker credential. Both are scoped to specific Parameter Store ARNs. The &lt;a href="https://aws.amazon.com/s3/" target="_blank" rel="noopener"&gt;Amazon S3&lt;/a&gt; artifact bucket blocks public access, enables versioning, and uses server-side encryption.&lt;/p&gt; 
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt; 
&lt;p&gt;This post walked through how to give your internal AI agent a safe place to run database queries, generate code, and execute scripts on behalf of fifty developers without leaking data between sessions or reaching resources it shouldn’t.&lt;/p&gt; 
&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/lambda/" target="_blank" rel="noopener"&gt;AWS Lambda MicroVMs&lt;/a&gt; provide ephemeral, VM-isolated compute environments that align with the per-session execution model of AI agent sandboxes. Snapshot-based launch avoids application startup latency. Idle policies terminate VMs once sessions complete. Firecracker isolation verifies that sessions do not share state. You pay only for active execution time and maintain full control over credentials, networking, and governance within your AWS boundary.&lt;/p&gt; 
&lt;p&gt;You build and operate a serverless control plane. You get per-session VM isolation with no idle compute cost and no shared tenancy.&lt;/p&gt; 
&lt;p&gt;To get started, explore these resources:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;Read more about Lambda MicroVMs in the &lt;a href="https://aws.amazon.com/blogs/aws/run-isolated-sandboxes-with-full-lifecycle-control-aws-lambda-introduces-microvms/" target="_blank" rel="noopener"&gt;launch announcement post&lt;/a&gt;.&lt;/li&gt; 
 &lt;li&gt;Clone the reference solution in the &lt;a href="https://github.com/aws-samples/sample-lambda-microvm-claude-managed-agents" target="_blank" rel="noopener"&gt;aws-samples repository&lt;/a&gt;.&lt;/li&gt; 
 &lt;li&gt;Add the &lt;a href="https://github.com/aws/agent-toolkit-for-aws/tree/main/skills/specialized-skills/serverless-skills/aws-lambda-microvms" target="_blank" rel="noopener"&gt;MicroVMs skill&lt;/a&gt; to your coding agent.&lt;/li&gt; 
 &lt;li&gt;Learn more about AWS Lambda MicroVMs in the &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/lambda-microvms-guide.html" target="_blank" rel="noopener"&gt;Developer Guide&lt;/a&gt;.&lt;/li&gt; 
 &lt;li&gt;Learn about Anthropic self-hosted sandbox configuration in the &lt;a href="https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes" target="_blank" rel="noopener"&gt;self-hosted sandbox documentation&lt;/a&gt;.&lt;/li&gt; 
 &lt;li&gt;For more serverless learning resources, visit &lt;a href="https://serverlessland.com/" target="_blank" rel="noopener"&gt;Serverless Land&lt;/a&gt;.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p style="clear: both"&gt;&lt;/p&gt;</content:encoded>
					
		
		
			</item>
		<item>
		<title>Multi-modal autoscaling with Amazon EC2 Auto Scaling: adding signals for faster, more reliable scaling</title>
		<link>https://aws.amazon.com/blogs/compute/multi-modal-autoscaling-with-amazon-ec2-auto-scaling-adding-signals-for-faster-more-reliable-scaling/</link>
		
		<dc:creator><![CDATA[Shubhendu Dubey]]></dc:creator>
		<pubDate>Thu, 17 Sep 2026 18:18:38 +0000</pubDate>
				<category><![CDATA[Advanced (300)]]></category>
		<category><![CDATA[Amazon EC2]]></category>
		<category><![CDATA[Auto Scaling]]></category>
		<category><![CDATA[Technical How-to]]></category>
		<guid isPermaLink="false">f0cd20d867fe47384347b6529408872a9b3b0ef7</guid>

					<description>Multi-modal autoscaling with Amazon EC2 Auto Scaling combines infrastructure metrics like CPU with application-level signals, so a group scales on the demand its users create. In this post, we show you how to implement it, with code samples and results from a controlled test.</description>
										<content:encoded>&lt;p&gt;How do you handle unpredictable workload patterns that spike during promotional events or seasonal peaks? Multi-modal autoscaling with &lt;a href="https://aws.amazon.com/ec2/autoscaling/" target="_blank" rel="noopener"&gt;Amazon EC2 Auto Scaling&lt;/a&gt; combines infrastructure metrics like CPU with application-level signals, so a group scales on the demand its users create and not only on how busy the servers look. Those signals track the load that drives your business outcomes, such as sales or sign-ups.&lt;/p&gt; 
&lt;p&gt;CPU-based autoscaling works well for many workloads, but some demand does not register as CPU right away. Adding signals such as request counts and application metrics lets a group respond to the load its users create. By publishing &lt;a href="https://aws.amazon.com/cloudwatch/" target="_blank" rel="noopener"&gt;Amazon CloudWatch&lt;/a&gt; custom metrics and application-driven triggers, you give Auto Scaling more information to act on.&lt;/p&gt; 
&lt;p&gt;In our testing, a group that scaled only on CPU rejected about 7,000 checkout sessions during a demand spike, and a stronger baseline that added Application Load Balancer request count still rejected about 6,900. A group that added an application metric rejected none, and it held p99 latency to about 0.43 seconds against 2.25 seconds for the CPU-only group. Predictive scaling can add a forecasting layer for cyclical demand, but it needs days of history to be useful, so we treat it as a complement. In this post, we show you how to implement multi-modal autoscaling on EC2 Auto Scaling, with code samples and results from a controlled test.&lt;/p&gt; 
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;/h2&gt; 
&lt;p&gt;To follow along, you need access to the following AWS services with appropriate permissions:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt; &lt;p&gt;EC2 Auto Scaling, for scaling policies and group management.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;CloudWatch, for metrics, alarms, and dashboards.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;a href="https://aws.amazon.com/cloudformation/" target="_blank" rel="noopener"&gt;AWS CloudFormation&lt;/a&gt;, for infrastructure deployment.&lt;/p&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2 id="expanding-beyond-single-metric-scaling"&gt;Expanding beyond single-metric scaling&lt;/h2&gt; 
&lt;p&gt;The default target tracking policy in EC2 Auto Scaling uses average CPU utilization, a practical starting point because CPU usage is a universal characteristic of compute workloads. Adding complementary signals, such as application-level metrics or predictive forecasting, gives Auto Scaling more information to make timely capacity decisions.&lt;/p&gt; 
&lt;p&gt;For workloads that need a faster response from target tracking alone, see &lt;a href="https://aws.amazon.com/blogs/compute/faster-scaling-with-amazon-ec2-auto-scaling-target-tracking/" target="_blank" rel="noopener"&gt;Faster scaling with Amazon EC2 Auto Scaling target tracking&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;In distributed architectures, different components can have distinct scaling characteristics. An API gateway might correlate well with request rate, while a background processor scales better on queue depth. With multi-modal scaling, you can match each component’s policy to its actual workload pattern. For containerized workloads, consider &lt;a href="https://aws.amazon.com/solutions/guidance/event-driven-application-autoscaling-with-keda-on-amazon-eks/" target="_blank" rel="noopener"&gt;event-driven autoscaling with KEDA on Amazon Elastic Kubernetes Service (Amazon EKS)&lt;/a&gt;.&lt;/p&gt; 
&lt;h2 id="multi-modal-autoscaling-architecture"&gt;Multi-modal autoscaling architecture&lt;/h2&gt; 
&lt;p&gt;Multi-modal autoscaling combines three approaches to capacity management. Reactive scaling responds to current CloudWatch metrics, such as CPU utilization, memory, network throughput, response times, and custom application indicators. Application-metric scaling brings workload-specific signals into the decision, using custom CloudWatch metrics like active user sessions, queue depth, or transaction volume. These application metrics are often the closest measurable proxy for business activity such as orders or sign-ups. Predictive scaling uses machine learning in EC2 Auto Scaling to forecast capacity needs from historical patterns, so infrastructure scales before demand increases.&lt;/p&gt; 
&lt;p&gt;With application-metric scaling, applications can scale on signals that infrastructure metrics miss. An ecommerce platform might scale on active checkout sessions, while a streaming service scales on concurrent stream counts. In the test later in this post, we use active checkout sessions as the custom metric.&lt;/p&gt; 
&lt;h2 id="implementing-multi-modal-autoscaling"&gt;Implementing multi-modal autoscaling&lt;/h2&gt; 
&lt;p&gt;This section builds the configuration in layers. Start with CPU target tracking as a baseline that every group keeps, then add a custom application metric that reflects real user load. The test later in this post compares these signals against a request-count baseline. Predictive scaling is an optional forecasting layer described at the end.&lt;/p&gt; 
&lt;h3 id="step-1-cpu-target-tracking"&gt;Step 1: CPU target tracking&lt;/h3&gt; 
&lt;p&gt;Start with the foundation that most workloads already use: a target tracking policy on average CPU utilization. Target tracking is a managed policy that adjusts capacity to keep a metric at or near a target value. It supports predefined metrics, including CPU utilization and request count per target, and custom CloudWatch metrics. When multiple target tracking policies are active, Auto Scaling coordinates them: it scales out if any policy requires it, but scales in only when all policies agree, which helps prevent oscillation.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-yaml"&gt;# CPU target tracking scaling policy (ASG A)
CPUTargetTrackingPolicy:
  Type: AWS::AutoScaling::ScalingPolicy
  Properties:
    AutoScalingGroupName: !Ref AutoScalingGroupName
    PolicyType: TargetTrackingScaling
    TargetTrackingConfiguration:
      PredefinedMetricSpecification:
        PredefinedMetricType: ASGAverageCPUUtilization
      TargetValue: 70&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Our test also included a second infrastructure baseline, a target tracking policy on the load balancer’s request count per target. It uses the same structure with a predefined metric:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-yaml"&gt;# Request count target tracking (ASG B)
RequestCountPTTargetTrackingPolicy:
  Type: AWS::AutoScaling::ScalingPolicy
  Properties:
    AutoScalingGroupName: !Ref AutoScalingGroupName
    PolicyType: TargetTrackingScaling
    TargetTrackingConfiguration:
      PredefinedMetricSpecification:
        PredefinedMetricType: ALBRequestCountPerTarget
        ResourceLabel: !Sub "${Alb.LoadBalancerFullName}/${TargetGroupB.TargetGroupFullName}"
      TargetValue: 300
      DisableScaleIn: false&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Step scaling is another option for spike handling. With step scaling, you can define different capacity increments for different alarm thresholds. It keeps evaluating the alarm during scaling activities, which can make it react faster than target tracking’s default evaluation window. Step scaling policies do not coordinate with each other.&lt;/p&gt; 
&lt;h3 id="step-2-add-a-custom-application-metric"&gt;Step 2: Add a custom application metric&lt;/h3&gt; 
&lt;p&gt;Next, add a second target tracking policy on a custom CloudWatch metric that reflects application load. In our test, instances publish an active checkout sessions metric at a 10-second resolution. To act on that resolution, set a Period of 10 seconds on the policy. Without it, the policy waits for three 1-minute datapoints like any other and the high-resolution metric only adds publishing cost. With it, a scale-out can begin in about 30 seconds. The policy includes the Auto Scaling group dimension so it tracks the metric for the right group. We set the target to 100 active sessions per instance, about 75 percent of the measured per-instance capacity of 135. This leaves headroom to absorb a spike while new instances boot.&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-yaml"&gt;# Custom application metric target tracking (ASG C)
CustomMetricTargetTrackingPolicy:
  Type: AWS::AutoScaling::ScalingPolicy
  Properties:
    AutoScalingGroupName: !Ref AutoScalingGroupName
    PolicyType: TargetTrackingScaling
    TargetTrackingConfiguration:
      CustomizedMetricSpecification:
        MetricName: ActiveCheckoutSessions
        Namespace: ECommerce/CheckoutMetrics
        Dimensions:
          - Name: AutoScalingGroupName
            Value: !Ref AutoScalingGroupName
        Statistic: Average
        Period: 10
      TargetValue: 100
      DisableScaleIn: false&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h3 id="step-3-add-predictive-scaling"&gt;Step 3: Add predictive scaling&lt;/h3&gt; 
&lt;p&gt;Predictive scaling is an optional forecasting layer. It uses machine learning in EC2 Auto Scaling to analyze historical load and scale ahead of recurring, cyclical demand, using customized metric specifications in ForecastAndScale mode. You need to provide several days of history for it to forecast well, so it complements reactive signals rather than replacing them. Start in ForecastOnly mode to watch the forecast before it drives any scaling.&lt;/p&gt; 
&lt;h3 id="monitoring"&gt;Monitoring&lt;/h3&gt; 
&lt;p&gt;Use CloudWatch dashboards to track how each policy contributes to scaling decisions, and set alarms on the metrics that matter for your workload, such as per-instance load or latency. Enable detailed monitoring on the launch template, with Monitoring set to true, so that the system publishes CPU metrics every minute. Without it, you cannot complete the CPU policy’s scale-in evaluation and your group will stop scaling in. Watching the policies side by side is what surfaced this scale-in behavior.&lt;/p&gt; 
&lt;h2 id="performance-results"&gt;Performance results&lt;/h2&gt; 
&lt;p&gt;We compared three Auto Scaling groups under an identical load profile in a single 75-minute test in the us-east-1 Region. Each group used c8g.large instances with a minimum of 6 and a maximum of 40 instances, and every group carried the same CPU target tracking policy at 70 percent as a fallback:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;ASG A&lt;/strong&gt;: CPU target tracking only. This is the single-signal infrastructure baseline.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;ASG B&lt;/strong&gt;: CPU target tracking plus an Application Load Balancer request-count policy. Request rate is a stronger infrastructure baseline than CPU alone.&lt;/p&gt; &lt;/li&gt; 
 &lt;li&gt; &lt;p&gt;&lt;strong&gt;ASG C&lt;/strong&gt;: CPU target tracking plus the custom checkout-sessions metric at 10-second resolution, published with a Period of 10 seconds.&lt;/p&gt; &lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;All the groups received the same load at the same time. During the shared ramp, arrival rate rose and every group scaled correctly, which makes the comparison fair. CPU crossed 70 percent on the CPU group, request count crossed its target of 300 on the request-count group, and all three converged to a similar size.&lt;/p&gt; 
&lt;table border="1px" cellpadding="10px" width="100%"&gt; 
 &lt;tbody&gt;
  &lt;tr&gt; 
   &lt;td&gt;&lt;strong&gt;Ramp phase (arrivals 30% → 85%)&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;A: CPU only&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;B: A + ALB requests&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;C: A + app sessions&lt;/strong&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Instances (start → peak)&lt;/td&gt; 
   &lt;td&gt;6 → 9&lt;/td&gt; 
   &lt;td&gt;6 → 10&lt;/td&gt; 
   &lt;td&gt;6 → 10&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;CPU&lt;/td&gt; 
   &lt;td&gt;73.6%&lt;/td&gt; 
   &lt;td&gt;74.0%&lt;/td&gt; 
   &lt;td&gt;69.0%&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Requests per target (target 300)&lt;/td&gt; 
   &lt;td&gt;319&lt;/td&gt; 
   &lt;td&gt;323&lt;/td&gt; 
   &lt;td&gt;297&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt;
&lt;/table&gt; 
&lt;p&gt;Then arrival rate was held flat while the number of concurrent checkout sessions kept rising, a shape that infrastructure signals cannot see. The next table reports that divergence phase, measured directly from CloudWatch and the load balancer.&lt;/p&gt; 
&lt;table border="1px" cellpadding="10px" width="100%"&gt; 
 &lt;tbody&gt;
  &lt;tr&gt; 
   &lt;td&gt;&lt;strong&gt;Measured metric (divergence)&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;A: CPU only&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;B: A + ALB requests&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;C: A + app sessions&lt;/strong&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Instances (start → end)&lt;/td&gt; 
   &lt;td&gt;11 → 11&lt;/td&gt; 
   &lt;td&gt;11 → 11&lt;/td&gt; 
   &lt;td&gt;11 → 22&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Rejected checkouts&lt;/td&gt; 
   &lt;td&gt;7,064&lt;/td&gt; 
   &lt;td&gt;6,886&lt;/td&gt; 
   &lt;td&gt;0&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;CPU (start → end)&lt;/td&gt; 
   &lt;td&gt;67.2% → 45.1%&lt;/td&gt; 
   &lt;td&gt;66.5% → 45.5%&lt;/td&gt; 
   &lt;td&gt;66.2% → 36.8%&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Peak sessions per instance&lt;/td&gt; 
   &lt;td&gt;135&lt;/td&gt; 
   &lt;td&gt;135&lt;/td&gt; 
   &lt;td&gt;116&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Requests per target&lt;/td&gt; 
   &lt;td&gt;285 → 279&lt;/td&gt; 
   &lt;td&gt;282 → 279&lt;/td&gt; 
   &lt;td&gt;277 → 154&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt;
&lt;/table&gt; 
&lt;p&gt;The difference is what each group could see. Arrival rate was held flat while the number of concurrent sessions rose, so CPU and request count stayed in range while the application saturated. The CPU-only and request-count groups held at 11 instances and rejected 7,064 and 6,886 checkouts. Their CPU even fell, from about 67 percent to about 45 percent, because a rejected request never reaches the work it would have done, so a policy targeting 70 percent saw spare capacity at the moment the application was failing users. The application-metric group read the rising sessions directly and scaled from 11 to 22 instances, rejecting none.&lt;/p&gt; 
&lt;h3 id="effect-on-latency-and-errors"&gt;Effect on latency and errors&lt;/h3&gt; 
&lt;p&gt;We measured latency and rejected checkouts on the load balancer during the test. At rest, all groups were identical. The gap opened only in the divergence phase, when concurrency rose without a matching change in arrival rate. Session slots are the scarce resource here, so sessions per instance is the causal driver of latency. The application group scales on sessions and we report latency as the outcome, rather than scaling on latency directly, which is not recommended for target tracking. The latency figures come from the load balancer’s TargetResponseTime at the end of the divergence phase. A client-side number measured over the internet would reflect network round-trip rather than the service.&lt;/p&gt; 
&lt;table border="1px" cellpadding="10px" width="100%"&gt; 
 &lt;tbody&gt;
  &lt;tr&gt; 
   &lt;td&gt;&lt;strong&gt;Measured metric&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;A: CPU only&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;B: A + ALB requests&lt;/strong&gt;&lt;/td&gt; 
   &lt;td&gt;&lt;strong&gt;C: A + app sessions&lt;/strong&gt;&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;TargetResponseTime (average), end of divergence&lt;/td&gt; 
   &lt;td&gt;1.122 s&lt;/td&gt; 
   &lt;td&gt;1.120 s&lt;/td&gt; 
   &lt;td&gt;0.284 s&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;TargetResponseTime (p99), end of divergence&lt;/td&gt; 
   &lt;td&gt;2.254 s&lt;/td&gt; 
   &lt;td&gt;2.235 s&lt;/td&gt; 
   &lt;td&gt;0.431 s&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;TargetResponseTime (average) at warm-up&lt;/td&gt; 
   &lt;td&gt;0.283 s&lt;/td&gt; 
   &lt;td&gt;0.283 s&lt;/td&gt; 
   &lt;td&gt;0.284 s&lt;/td&gt; 
  &lt;/tr&gt; 
  &lt;tr&gt; 
   &lt;td&gt;Rejected checkouts, drain phase&lt;/td&gt; 
   &lt;td&gt;4,115&lt;/td&gt; 
   &lt;td&gt;3,631&lt;/td&gt; 
   &lt;td&gt;0&lt;/td&gt; 
  &lt;/tr&gt; 
 &lt;/tbody&gt;
&lt;/table&gt; 
&lt;p&gt;The application-metric group, ASG C, kept per-instance load near its target and rejected no checkouts. Its average latency at the end of the divergence phase was 0.284 seconds against 1.122 for the CPU-only group, and its p99 was 0.431 seconds against 2.254. The request-count group, ASG B, tracked its own signal within range the whole time, which is exactly why it could not react: request rate was flat while concurrency climbed.&lt;/p&gt; 
&lt;p&gt;Once every group has enough capacity, they perform the same. The value of the application signal is in the transition, the gap between when demand arrives and when the fleet is ready, which the infrastructure signals here never detected.&lt;/p&gt; 
&lt;h3 id="handling-known-high-traffic-events"&gt;Handling known high-traffic events&lt;/h3&gt; 
&lt;p&gt;For planned events like flash sales, &lt;a href="https://docs.aws.amazon.com/autoscaling/ec2/userguide/ec2-auto-scaling-scheduled-scaling.html" target="_blank" rel="noopener"&gt;scheduled scaling&lt;/a&gt; can pre-scale capacity ahead of time. Multi-modal scaling complements scheduled scaling by handling unplanned spikes and organic traffic that does not follow a fixed schedule.&lt;/p&gt; 
&lt;h3 id="understanding-cost-implications"&gt;Understanding cost implications&lt;/h3&gt; 
&lt;p&gt;Running the application signal requires more instances. During the spike it held about 22 instances, against 11 on the infrastructure-only groups. That extra capacity is what kept sessions per instance near the target and stopped the group from turning checkouts away. For your own workload, the question is whether a spike’s worth of extra instances costs less than the checkouts you would otherwise reject.&lt;/p&gt; 
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt; 
&lt;p&gt;Multi-modal autoscaling combines infrastructure metrics with application-level signals so a group scales on the demand its users create, not only on how busy its servers look. In our test, a group that scaled only on CPU rejected about 7,000 checkout sessions during a demand spike, and a stronger baseline that added load balancer request count still rejected about 6,900. A group that added a custom application metric rejected none, and held p99 latency near 0.43 seconds against 2.25 seconds for the CPU-only group. Its CPU even fell while the infrastructure groups were failing requests, which shows why an infrastructure signal alone can miss the demand that matters.&lt;/p&gt; 
&lt;p&gt;Start with CPU target tracking as a fallback. Add a signal that reflects the load your users create, and pick the one that tracks closest to a business outcome like orders or active users. Set a Period on a high-resolution custom metric so the policy can act on it, and enable detailed monitoring so scale-in works. Predictive scaling is worth adding for demand you can forecast, once the group has days of history to learn from.&lt;/p&gt; 
&lt;p&gt;To implement multi-modal autoscaling, you can open &lt;a href="https://console.aws.amazon.com/ec2autoscaling/" target="_blank" rel="noopener"&gt;Amazon EC2 Auto Scaling&lt;/a&gt; in the AWS Management Console and add a second scaling signal to one of your existing groups, following the configuration steps in this post. For a deeper look at target tracking behavior, see &lt;a href="https://aws.amazon.com/blogs/compute/faster-scaling-with-amazon-ec2-auto-scaling-target-tracking/" target="_blank" rel="noopener"&gt;Faster scaling with Amazon EC2 Auto Scaling target tracking&lt;/a&gt;. The &lt;a href="https://docs.aws.amazon.com/autoscaling/ec2/userguide/" target="_blank" rel="noopener"&gt;Amazon EC2 Auto Scaling User Guide&lt;/a&gt; covers predictive scaling policies, custom metrics, and scaling cooldowns in detail.&lt;/p&gt;</content:encoded>
					
		
		
			</item>
		<item>
		<title>Deploying regulated workloads on AWS Local Zones and AWS Outposts</title>
		<link>https://aws.amazon.com/blogs/compute/deploying-regulated-workloads-on-aws-local-zones-and-aws-outposts/</link>
		
		<dc:creator><![CDATA[Brianna Rosentrater]]></dc:creator>
		<pubDate>Thu, 17 Sep 2026 17:29:40 +0000</pubDate>
				<category><![CDATA[Advanced (300)]]></category>
		<category><![CDATA[AWS Local Zones]]></category>
		<category><![CDATA[AWS Outposts]]></category>
		<category><![CDATA[Technical How-to]]></category>
		<guid isPermaLink="false">f530496389817aa7460be89a3363546afa37926a</guid>

					<description>AWS Local Zones and AWS Outposts help you keep regulated workloads within specific geographic boundaries. This post presents a framework of technologies, including the AWS Nitro System, AWS Organizations SCPs with AWS Control Tower, and Amazon VPC Traffic Mirroring, to help you build auditable, secure architectures for data residency.</description>
										<content:encoded>&lt;p&gt;Customers in many industries and geographic locations have specific data sovereignty and residency objectives. &lt;a href="https://aws.amazon.com/about-aws/global-infrastructure/localzones/" target="_blank" rel="noopener"&gt;AWS Local Zones&lt;/a&gt; and &lt;a href="https://aws.amazon.com/outposts/" target="_blank" rel="noopener"&gt;AWS Outposts&lt;/a&gt; are fully managed infrastructure solutions for customers that need to keep data within specific geographic boundaries and also want the scalability and innovation of cloud services. The challenge lies not only in where data resides, but in how to architect, secure, and audit these deployments effectively. Whether you’re architecting a new solution or migrating existing regulated workloads to AWS hybrid edge infrastructure, this post provides an overview of key technologies to help you build auditable and secure architectures that support your organization’s data residency objectives.&lt;/p&gt; 
&lt;h2 id="solution-framework"&gt;Solution framework&lt;/h2&gt; 
&lt;p&gt;Building a solution for data residency deployments on AWS hybrid infrastructure requires a thoughtful, layered approach. Rather than a prescriptive solution, this post presents a flexible framework that you can adapt to your specific operational requirements.&lt;/p&gt; 
&lt;p&gt;The AWS Shared Responsibility Model clearly delineates where the responsibilities of AWS end and yours begin. This model provides a critical separation: AWS controls the management infrastructure, while your data remains inaccessible to AWS operators, as enforced by the &lt;a href="https://docs.aws.amazon.com/whitepapers/latest/security-design-of-aws-nitro-system/security-design-of-aws-nitro-system.html" target="_blank" rel="noopener"&gt;hardware-based isolation&lt;/a&gt; of the Nitro System. There is no operator access to the instances, applications, or data. This architectural separation provides the foundation for implementing stringent data residency controls.&lt;/p&gt; 
&lt;p&gt;To build upon this foundation, you can implement security best practices by following the guidance in the &lt;a href="https://docs.aws.amazon.com/wellarchitected/latest/security-pillar/welcome.html" target="_blank" rel="noopener"&gt;AWS Well-Architected security pillar&lt;/a&gt;, which helps you strengthen application-level protections and data security controls. For deeper guidance, see the &lt;a href="https://docs.aws.amazon.com/wellarchitected/latest/data-residency-hybrid-cloud-services-lens/data-residency-with-hybrid-cloud-services-lens.html" target="_blank" rel="noopener"&gt;Data Residency with Hybrid Cloud Services Lens&lt;/a&gt;, which covers considerations for operations, security, cost, performance, and reliability for regulated workloads.&lt;/p&gt; 
&lt;p&gt;When implementing data residency controls, you might need auditable evidence of traffic patterns for your internal governance processes. By using third-party monitoring tools combined with port mirroring capabilities, you can generate reports that show all traffic between your applications and databases remains within your Outpost environment. This visibility provides auditable evidence that traffic remains within your designated boundaries. You can also use &lt;a href="https://aws.amazon.com/artifact/" target="_blank" rel="noopener"&gt;AWS Artifact&lt;/a&gt; to access audit reports for your hybrid infrastructure.&lt;/p&gt; 
&lt;p&gt;Governance tools form the final layer of this regulatory framework, establishing guardrails around your deployment. These tools continuously monitor and enforce configuration policies, verifying that your environment stays aligned with your security and governance policies, operates within required parameters, and alerts you proactively when issues arise. This shift from reactive to proactive management helps you maintain consistent governance of your environment at scale.&lt;/p&gt; 
&lt;p&gt;Together, these layered technologies create a framework for deploying regulated workloads designed to support your data residency objectives while benefiting from the innovation and scalability of AWS services.&lt;/p&gt; 
&lt;h3 id="shared-responsibility-model"&gt;Shared responsibility model&lt;/h3&gt; 
&lt;p&gt;When extending workloads to Local Zones and Outposts, the shared responsibility model adapts to these hybrid cloud environments while maintaining the same core principles. AWS continues to manage the underlying infrastructure and services, while you retain control over your data, applications, and configurations. This supports consistent security postures whether workloads run in &lt;a href="https://aws.amazon.com/about-aws/global-infrastructure/regions_az/" target="_blank" rel="noopener"&gt;AWS Regions&lt;/a&gt;, Local Zones, or on Outposts infrastructure. You deploy Outposts in a data center or colocation facility of your choice. Under the shared responsibility model, you are responsible for meeting site requirements for power, cooling, on-premises networking, and the &lt;a href="https://docs.aws.amazon.com/outposts/latest/network-userguide/service-links.html" target="_blank" rel="noopener"&gt;Outpost service link&lt;/a&gt; connection to the Region. All traffic between the Outpost and the parent Region traverses an encrypted set of VPN connections over the service link, protecting communications in transit without requiring additional configuration. AWS continues to be responsible for maintaining the Outposts hardware as a managed service.&lt;/p&gt; 
&lt;p&gt;This partnership approach to security means you can build auditable solutions with data residency controls without compromising on the innovation and scalability that AWS provides.&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/08/28/ComputeBlog-2620-1.png" alt="AWS Shared Responsibility Model showing AWS responsibility for infrastructure and customer responsibility for data and configurations" width="800"&gt;
 &lt;p class="wp-caption-text"&gt;Figure 1: The AWS Shared Responsibility Model in a hybrid edge deployment&lt;/p&gt;
&lt;/div&gt; 
&lt;h3 id="aws-nitro-system"&gt;AWS Nitro System&lt;/h3&gt; 
&lt;p&gt;The &lt;a href="https://aws.amazon.com/ec2/nitro/" target="_blank" rel="noopener"&gt;AWS Nitro System&lt;/a&gt; is the virtualization platform that powers &lt;a href="https://aws.amazon.com/ec2/" target="_blank" rel="noopener"&gt;Amazon Elastic Compute Cloud (Amazon EC2)&lt;/a&gt; instances. It uses dedicated hardware and software to offload virtualization functions from the server CPU and delivers near-bare-metal performance. Both Outposts and Local Zones also use the Nitro System. By design, the Nitro System has &lt;a href="https://docs.aws.amazon.com/whitepapers/latest/security-design-of-aws-nitro-system/no-aws-operator-access.html" target="_blank" rel="noopener"&gt;no operator access&lt;/a&gt;. There is no way for AWS or any entity to log into the EC2 Nitro hosts, access compute resources, or reach encrypted customer data remotely. The following diagram shows the purpose-built hardware components of the Nitro System.&lt;/p&gt; 
&lt;div style="width: 756px" class="wp-caption alignnone"&gt;
 &lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/08/28/ComputeBlog-2620-2.png" alt="AWS Nitro System stack showing the Nitro Card, Nitro Security Chip, and Nitro Hypervisor components" width="746"&gt;
 &lt;p class="wp-caption-text"&gt;Figure 2: The AWS Nitro System hardware and software stack&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;The Nitro System combines purpose-built hardware consisting of the following key security components:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;The &lt;a href="https://docs.aws.amazon.com/whitepapers/latest/security-design-of-aws-nitro-system/the-components-of-the-nitro-system.html#the-nitro-cards" target="_blank" rel="noopener"&gt;Nitro Card&lt;/a&gt; – provides I/O interfaces used for &lt;a href="https://aws.amazon.com/vpc/" target="_blank" rel="noopener"&gt;Amazon Virtual Private Cloud&lt;/a&gt; (Amazon VPC) network virtualization, &lt;a href="https://aws.amazon.com/ebs/" target="_blank" rel="noopener"&gt;Amazon Elastic Block Store&lt;/a&gt; (Amazon EBS), and instance storage, freeing up host CPU resources. Nitro Cards are logically isolated from the system main board that runs customer workloads and can be live-updated, reducing the need for maintenance windows and workload disruption.&lt;/li&gt; 
 &lt;li&gt;The &lt;a href="https://docs.aws.amazon.com/whitepapers/latest/security-design-of-aws-nitro-system/the-components-of-the-nitro-system.html#the-nitro-security-chip" target="_blank" rel="noopener"&gt;Nitro Security Chip&lt;/a&gt; – provides the link between the Nitro Controller (used for orchestration) and the system main board. It intercepts and controls all firmware updates, preventing the main CPUs from being used to modify system firmware. This is particularly important when running bare metal EC2 instances. This chip is also used for boot control to validate system firmware integrity.&lt;/li&gt; 
 &lt;li&gt;The &lt;a href="https://docs.aws.amazon.com/whitepapers/latest/security-design-of-aws-nitro-system/the-components-of-the-nitro-system.html#the-nitro-hypervisor" target="_blank" rel="noopener"&gt;Nitro Hypervisor&lt;/a&gt; – designed to receive EC2 instance management commands sent by the Nitro Controller, provide compute virtualization and logical instance isolation, and assign &lt;a href="https://en.wikipedia.org/wiki/Single-root_input/output_virtualization" target="_blank" rel="noopener"&gt;SR-IOV&lt;/a&gt; virtual functions as needed. It includes no general-purpose operating system features, only the features absolutely necessary for its function, and works with other purpose-built Nitro components to maintain its small size and bare-metal-like performance. This simple design reduces the risk for remote networking attacks and driver-based privilege escalations.&lt;/li&gt; 
 &lt;li&gt;The &lt;a href="https://docs.aws.amazon.com/outposts/latest/userguide/data-protection.html#encryption-rest" target="_blank" rel="noopener"&gt;Nitro Security Key&lt;/a&gt; (Outposts only) – a removable device that stores the external key required to decrypt all data at rest on your Outpost. At the end of your Outposts commitment, after migrating your data off the Outpost, you can destroy this key to cryptographically shred any remaining data on the Outpost.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;These components work together to provide a layered security approach that doesn’t compromise performance. By designing each component to have a specific function decoupled from the main system board, the Nitro System provides non-disruptive firmware updates and reduces classes of security issues often found in other hypervisor systems.&lt;/p&gt; 
&lt;h3 id="aws-organizations-service-control-policies"&gt;AWS Organizations Service Control Policies&lt;/h3&gt; 
&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_scps.html" target="_blank" rel="noopener"&gt;AWS Organizations Service Control Policies (SCPs)&lt;/a&gt; are a governance tool that helps you enforce data residency requirements by controlling where resources can be created and where data can be stored or processed. SCPs function as permission guardrails that define the maximum available permissions for IAM users and roles across your organization’s accounts. By implementing deny guardrails through SCPs, you can prevent resource provisioning in unwanted locations by restricting access to AWS APIs at the infrastructure level.&lt;/p&gt; 
&lt;p&gt;When deploying regulated workloads on Local Zones and Outposts, SCPs work in conjunction with &lt;a href="https://aws.amazon.com/controltower/" target="_blank" rel="noopener"&gt;AWS Control Tower&lt;/a&gt; landing zones to create custom guardrails that control data movement, processing, and storage. These policies can be designed with either preventative rules (blocking actions before they occur) or detective rules (identifying compliance violations after the fact). SCPs can restrict data transfer, saving, or snapshot creation outside a specified AWS location, and they can isolate workloads to a specific location. You can apply SCPs across accounts and organizational units (OUs) within your organization. For more information, see &lt;a href="https://aws.amazon.com/blogs/compute/best-practices-for-managing-data-residency-in-aws-local-zones-using-landing-zone-controls/" target="_blank" rel="noopener"&gt;Best practices for managing data residency in AWS Local Zones using landing zone controls&lt;/a&gt; and &lt;a href="https://aws.amazon.com/blogs/compute/architecting-for-data-residency-with-aws-outposts-rack-and-landing-zone-guardrails/" target="_blank" rel="noopener"&gt;Architecting for data residency with AWS Outposts rack and landing zone guardrails&lt;/a&gt;.&lt;/p&gt; 
&lt;p&gt;Here’s an example SCP that restricts EC2 instance launches and network interface creation to only specified AWS Local Zone subnets:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-json"&gt;{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "DenyNotLocalZonesSubnet",
            "Effect": "Deny",
            "Action": [
                "ec2:RunInstances",
                "ec2:CreateNetworkInterface"
            ],
            "Resource": [
                "arn:aws:ec2:*:*:network-interface/*"
            ],
            "Condition": {
                "ForAllValues:ArnNotEquals": {
                    "ec2:Subnet": [
                        "arn:aws:ec2:us-west-2:123456789012:subnet/subnet-localzone1",
                        "arn:aws:ec2:us-west-2:123456789012:subnet/subnet-localzone2"
                    ]
                }
            }
        }
    ]
}&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;h2 id="compliance-monitoring"&gt;Compliance monitoring&lt;/h2&gt; 
&lt;p&gt;After you implement the security and governance best practices described in the preceding sections, you can demonstrate that traffic remains within your designated boundaries by using &lt;a href="https://docs.aws.amazon.com/vpc/latest/mirroring/what-is-traffic-mirroring.html" target="_blank" rel="noopener"&gt;Amazon VPC Traffic Mirroring&lt;/a&gt; (also called port mirroring outside of AWS). This mirrors traffic between your application servers and databases. You can use a mirror target report to show that the traffic does not transit the AWS Region. For step-by-step instructions, see &lt;a href="https://docs.aws.amazon.com/vpc/latest/mirroring/traffic-mirroring-getting-started.html" target="_blank" rel="noopener"&gt;Get started using Traffic Mirroring to monitor network traffic&lt;/a&gt;. The key configuration steps include the following:&lt;/p&gt; 
&lt;ol type="1"&gt; 
 &lt;li&gt;&lt;strong&gt;Configure security groups&lt;/strong&gt; – Allow inbound UDP port 4789 only from the security group of the source instances being mirrored, or from specific private CIDR ranges within the VPC. Do not open this port to &lt;code&gt;0.0.0.0/0&lt;/code&gt;.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Create a traffic mirror target&lt;/strong&gt; – Use the elastic network interface (ENI) of your monitoring instance.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Create a traffic mirror filter&lt;/strong&gt; – Define which traffic to capture, either all traffic or specific traffic.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Create mirror sessions&lt;/strong&gt; – Create one for each source instance you want to monitor. Lower session numbers are evaluated first when multiple sessions exist.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Capture traffic&lt;/strong&gt; – Use &lt;code&gt;tcpdump&lt;/code&gt; on the target instance to analyze mirrored packets.&lt;/li&gt; 
&lt;/ol&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/08/28/ComputeBlog-2620-3.png" alt="Amazon VPC Traffic Mirroring architecture on Outposts, mirroring traffic between application servers and databases to a monitoring instance" width="800"&gt;
 &lt;p class="wp-caption-text"&gt;Figure 3: Amazon VPC Traffic Mirroring architecture on an Outpost&lt;/p&gt;
&lt;/div&gt; 
&lt;p&gt;All instances must be in the same VPC or connected through &lt;a href="https://docs.aws.amazon.com/vpc/latest/peering/what-is-vpc-peering.html" target="_blank" rel="noopener"&gt;VPC peering&lt;/a&gt;. Traffic Mirroring encapsulates the mirrored traffic using VXLAN on UDP port 4789. Traffic Mirroring might impact network performance on source instances, so test in a development environment before deploying to production. The following image shows a sample traffic mirroring report that uses NetFlow Analyzer. For this post, all network traffic shown is simulated.&lt;/p&gt; 
&lt;div style="width: 810px" class="wp-caption alignnone"&gt;
 &lt;img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2026/08/28/ComputeBlog-2620-4.png" alt="NetFlow Analyzer sample report showing traffic captured from an environment with VPC Traffic Mirroring configured" width="800"&gt;
 &lt;p class="wp-caption-text"&gt;Figure 4: Sample traffic mirroring report in NetFlow Analyzer&lt;/p&gt;
&lt;/div&gt; 
&lt;h2 id="clean-up"&gt;Clean up&lt;/h2&gt; 
&lt;p&gt;If you tested the VPC Traffic Mirroring architecture described in the preceding section, terminate any unnecessary resources to avoid ongoing costs. Remove the resources in the following order to avoid dependency errors:&lt;/p&gt; 
&lt;ol type="1"&gt; 
 &lt;li&gt;&lt;strong&gt;Delete the traffic mirror sessions&lt;/strong&gt; – In the Amazon VPC console, navigate to &lt;strong&gt;Traffic Mirroring&lt;/strong&gt;, &lt;strong&gt;Mirror Sessions&lt;/strong&gt;. Select each mirror session you created and choose &lt;strong&gt;Actions&lt;/strong&gt;, &lt;strong&gt;Delete&lt;/strong&gt;. Repeat for all sessions associated with your source instances.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Delete the traffic mirror filter&lt;/strong&gt; – Navigate to &lt;strong&gt;Traffic Mirroring&lt;/strong&gt;, &lt;strong&gt;Mirror Filters&lt;/strong&gt;. Select the filter you created and choose &lt;strong&gt;Actions&lt;/strong&gt;, &lt;strong&gt;Delete&lt;/strong&gt;. You must delete all associated mirror sessions before you can delete the filter.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Delete the traffic mirror target&lt;/strong&gt; – Navigate to &lt;strong&gt;Traffic Mirroring&lt;/strong&gt;, &lt;strong&gt;Mirror Targets&lt;/strong&gt;. Select the target pointing to the ENI of your monitoring instance and choose &lt;strong&gt;Actions&lt;/strong&gt;, &lt;strong&gt;Delete&lt;/strong&gt;.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Revoke security group rules&lt;/strong&gt; – Navigate to &lt;strong&gt;Security Groups&lt;/strong&gt; and select the security group attached to your monitoring instance. Remove the inbound rule that allows UDP port 4789 from the security group or CIDR range of the source instances.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Terminate the monitoring instance (optional)&lt;/strong&gt; – If you launched a dedicated EC2 instance solely for traffic capture and analysis, navigate to the EC2 console and terminate the instance. This also releases the associated ENI used as the mirror target.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Delete any stored packet captures (optional)&lt;/strong&gt; – If you saved &lt;code&gt;tcpdump&lt;/code&gt; output to &lt;a href="https://aws.amazon.com/s3/" target="_blank" rel="noopener"&gt;Amazon Simple Storage Service&lt;/a&gt; (Amazon S3) or local storage on the instance, delete those files if they are no longer needed for audit reporting.&lt;/li&gt; 
&lt;/ol&gt; 
&lt;p&gt;You can verify that all Traffic Mirroring resources have been removed by running the following AWS Command Line Interface (AWS CLI) commands:&lt;/p&gt; 
&lt;div class="hide-language"&gt; 
 &lt;pre&gt;&lt;code class="language-bash"&gt;aws ec2 describe-traffic-mirror-sessions
aws ec2 describe-traffic-mirror-targets
aws ec2 describe-traffic-mirror-filters&lt;/code&gt;&lt;/pre&gt; 
&lt;/div&gt; 
&lt;p&gt;Each command should return an empty list, confirming that no mirroring resources remain active in your account.&lt;/p&gt; 
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt; 
&lt;p&gt;In this post, we covered how the AWS Nitro System, AWS Organizations SCPs with an AWS Control Tower landing zone, and VPC Traffic Mirroring provide capabilities for governing workloads with data residency requirements. Apply the SCP example in this post to test restricting instance launches and network interface creation to specific subnets. To learn more about Outposts for hybrid deployments, review the &lt;a href="https://docs.aws.amazon.com/outposts/latest/network-userguide/get-started-outposts.html" target="_blank" rel="noopener"&gt;Getting started with AWS Outposts&lt;/a&gt; guide and submit the &lt;a href="https://pages.awscloud.com/GLOBAL_PM_LN_outposts-features_2020084_7010z000001Lpcl_01.LandingPage.html" target="_blank" rel="noopener"&gt;AWS Outposts contact form&lt;/a&gt;. To get started with Local Zones, review the &lt;a href="https://docs.aws.amazon.com/local-zones/latest/ug/getting-started.html" target="_blank" rel="noopener"&gt;Getting started with AWS Local Zones&lt;/a&gt; guide, opt in to a Local Zone, and begin trying some of the architecture patterns described in this post.&lt;/p&gt;</content:encoded>
					
		
		
			</item>
	</channel>
</rss>