Configuring CloudWatch Synthetics Canaries with VPC Networking Requirements: A Complete Guide

CloudWatch Synthetics canaries require private subnets with NAT Gateway or VPC endpoints to communicate with CloudWatch and S3 when deployed in a VPC, as the underlying Lambda ENIs lack public IP addresses.

When deploying CloudWatch Synthetics canaries within a VPC, understanding the underlying Lambda networking model is critical to prevent silent failures. According to the aws/agent-toolkit-for-aws repository, canaries execute as Lambda functions that create Elastic Network Interfaces (ENIs) in your specified subnets, requiring specific routing configurations to access AWS services. Configuring CloudWatch Synthetics canaries with VPC networking requirements demands careful attention to subnet placement, DNS settings, and IAM permissions to ensure metrics and artifacts reach their destinations.

Understanding Canary VPC Networking Architecture

Under the hood, every CloudWatch Synthetics canary executes as a Lambda function using runtimes like syn-nodejs-puppeteer-15.0. When you configure VPC access, Lambda creates ENIs in the specified subnets. According to skills/core-skills/aws-observability/references/synthetics.md, these ENIs never receive public IP addresses, even when placed in subnets configured with "Auto-assign public IP" enabled. This architectural constraint means VPC-bound canaries cannot communicate with CloudWatch or S3 without explicit routing through private network paths.

Required VPC Configuration Steps

Subnet Placement and ENI Behavior

Deploy your canary exclusively in private subnets. Attempting to launch canaries in public subnets results in ENIs that cannot reach the internet, effectively isolating the canary from AWS service endpoints. The reference documentation in plugins/aws-core/skills/aws-observability/references/synthetics.md emphasizes that subnet type selection determines reachability, not the public IP assignment setting.

Internet Access Patterns

Choose between two connectivity patterns to provide outbound access:

NAT Gateway Pattern: Place a NAT Gateway in a public subnet and configure route tables in your private subnets with a route for 0.0.0.0/0 pointing to the NAT Gateway ID. This pattern suits environments requiring broad internet access.

VPC Endpoints Pattern: Create an Interface VPC endpoint for the CloudWatch Synthetics monitoring service (com.amazonaws.<region>.monitoring) and a Gateway VPC endpoint for S3. This approach keeps traffic within the AWS network and eliminates NAT Gateway costs. The endpoint policy must grant s3:ListAllMyBuckets, s3:GetBucketLocation, and s3:PutObject permissions.

DNS Configuration Requirements

Enable both DNS resolution and DNS hostnames on your VPC. Without these settings, canaries encounter net::ERR_NAME_NOT_RESOLVED errors when attempting to resolve CloudWatch or S3 endpoints. This requirement applies regardless of whether you use NAT Gateway or VPC endpoints for connectivity.

IAM Role Permissions

The canary execution role requires additional S3 permissions beyond standard Lambda execution policies. Grant s3:ListAllMyBuckets, s3:GetBucketLocation, and s3:PutObject across all buckets (Resource: "*") because VPC endpoint policies do not inherit IAM permissions. The role referenced in skills/core-skills/aws-observability/references/synthetics.md must explicitly allow these actions to upload artifacts and reports.

Implementation Examples

CDK Implementation with NAT Gateway

import * as cdk from 'aws-cdk-lib';
import * as synthetics from 'aws-cdk-lib/aws-synthetics';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as iam from 'aws-cdk-lib/aws-iam';

export class CanaryStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string) {
    super(scope, id);

    const vpc = ec2.Vpc.fromLookup(this, 'VPC', { vpcId: 'vpc-0123abcd' });
    const privateSubnets = vpc.privateSubnets;

    const canary = new synthetics.Canary(this, 'MyCanary', {
      runtime: synthetics.Runtime.SYN_NODEJS_PUPPETEER_15,
      vpc,
      vpcSubnets: { subnets: privateSubnets },
      executionRole: new iam.Role(this, 'CanaryRole', {
        assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
        managedPolicies: [
          iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')
        ],
        inlinePolicies: {
          S3Access: new iam.PolicyDocument({
            statements: [new iam.PolicyStatement({
              actions: ['s3:ListAllMyBuckets', 's3:GetBucketLocation', 's3:PutObject'],
              resources: ['*']
            })]
          })
        }
      })
    });

    canary.metricSuccessPercent().createAlarm(this, 'CanarySuccessAlarm', {
      threshold: 90,
      evaluationPeriods: 3,
      datapointsToAlarm: 2,
      treatMissingData: cdk.aws_cloudwatch.TreatMissingData.BREACHING,
    });
  }
}

CLI Setup for VPC Endpoints


# S3 gateway endpoint for artifact storage

aws ec2 create-vpc-endpoint \
  --vpc-id vpc-0123abcd \
  --service-name com.amazonaws.$AWS_REGION.s3 \
  --route-table-ids rtb-0a1b2c3d4e5f6g7h

# Interface endpoint for CloudWatch metrics

aws ec2 create-vpc-endpoint \
  --vpc-id vpc-0123abcd \
  --service-name com.amazonaws.$AWS_REGION.monitoring \
  --subnet-ids subnet-abc12345 subnet-def67890 \
  --security-group-ids sg-0123abcd \
  --private-dns-enabled

CDK Implementation with VPC Endpoints

new ec2.InterfaceVpcEndpoint(this, 'MonitoringEndpoint', {
  vpc,
  service: ec2.InterfaceVpcEndpointAwsService.CLOUDWATCH_MONITORING,
  subnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS },
  securityGroups: [sg],
});

Troubleshooting Silent Failures

When VPC networking is misconfigured, canaries enter a silent-failure mode. The canary runtime executes successfully but cannot publish metrics to CloudWatch or store artifacts in S3, making it appear as though the canary never ran. Check aws-observability SKILL.md for debugging guidance that routes to the synthetics reference documentation. Verify your security group egress rules allow traffic to the VPC endpoints or NAT Gateway, and ensure your endpoint policies explicitly permit the required S3 actions.

Summary

  • Deploy canaries in private subnets only, as Lambda ENIs never receive public IPs.
  • Provide outbound connectivity via NAT Gateway or VPC endpoints (Interface for CloudWatch, Gateway for S3).
  • Enable DNS resolution and DNS hostnames on the VPC to prevent resolution errors.
  • Grant the execution role explicit S3 permissions (PutObject, GetBucketLocation, ListAllMyBuckets) across all resources.
  • Reference skills/core-skills/aws-observability/references/synthetics.md for runtime-specific requirements and compatibility matrices.

Frequently Asked Questions

Why does my VPC canary show no data in the CloudWatch console?

Your canary is likely running in a subnet without internet connectivity or VPC endpoints. Because the underlying Lambda ENI lacks a public IP, it cannot reach CloudWatch or S3 without a NAT Gateway or Interface VPC endpoint for the monitoring service. Check the VPC DNS settings and verify route tables point to either a NAT Gateway or S3/CloudWatch endpoints.

Can I place a CloudWatch Synthetics canary in a public subnet?

No. Even when placed in a public subnet with "Auto-assign public IP" enabled, the Lambda ENI created by the canary never receives a public IP address. Always deploy VPC-bound canaries in private subnets with configured routes to the internet or AWS service endpoints.

What S3 permissions does a VPC canary require?

The execution role needs s3:ListAllMyBuckets, s3:GetBucketLocation, and s3:PutObject permissions on all buckets (Resource: "*") because VPC endpoint policies do not implicitly grant these permissions. These actions allow the canary to store screenshots and logs in the results bucket.

How do I troubleshoot DNS resolution errors in VPC canaries?

Enable both DNS resolution and DNS hostnames on your VPC. Without these settings, the canary runtime cannot resolve the CloudWatch or S3 endpoints, resulting in net::ERR_NAME_NOT_RESOLVED errors. This applies regardless of whether you use NAT Gateway or VPC endpoints for connectivity.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →