Skip to main content

Ensure There Are VPCs in More Than One Region

Overview

This check verifies that your AWS account has Virtual Private Clouds (VPCs) deployed across multiple AWS regions. A VPC is your isolated network within AWS where you run your resources. Having VPCs in only one region means all your network infrastructure is concentrated in a single geographic location.

Risk

If all your VPCs exist in a single region, you face significant availability and resilience risks:

  • Regional outages: If that region experiences problems, your entire network infrastructure becomes unavailable
  • Single point of failure: Service disruptions, misconfigurations, or security incidents in one region affect everything
  • Limited disaster recovery: No network foundation exists in other regions for failover
  • Compliance gaps: Some regulations require geographic distribution of infrastructure

Remediation Steps

Prerequisites

You need permission to create VPCs in your AWS account. This typically requires the AmazonVPCFullAccess policy or equivalent permissions.

Required IAM permissions

At minimum, you need these permissions:

  • ec2:CreateVpc
  • ec2:DescribeVpcs
  • ec2:CreateTags
  • ec2:CreateInternetGateway (if adding internet access)
  • ec2:AttachInternetGateway

AWS Console Method

  1. Check your current VPCs: Go to the VPC Dashboard and note which regions have VPCs
  2. Select a secondary region: In the top-right corner of the console, click the region dropdown and choose a different region (e.g., us-west-2)
  3. Create a new VPC:
    • Click Create VPC
    • Choose VPC and more for a complete setup (recommended) or VPC only for just the network
    • Enter a name tag (e.g., production-vpc-west)
    • Enter an IPv4 CIDR block that does not overlap with your other VPCs (e.g., 10.1.0.0/16)
    • Keep DNS options enabled (DNS resolution and DNS hostnames)
    • Click Create VPC
  4. Verify: Return to the VPC Dashboard and confirm the new VPC appears in the secondary region
AWS CLI (optional)

Check existing VPCs across regions

# List non-default VPCs in us-east-1
aws ec2 describe-vpcs \
--region us-east-1 \
--filters "Name=is-default,Values=false" \
--query "Vpcs[*].[VpcId,CidrBlock,Tags[?Key=='Name'].Value|[0]]" \
--output table

# List non-default VPCs in us-west-2
aws ec2 describe-vpcs \
--region us-west-2 \
--filters "Name=is-default,Values=false" \
--query "Vpcs[*].[VpcId,CidrBlock,Tags[?Key=='Name'].Value|[0]]" \
--output table

Create a VPC in a secondary region

# Create VPC in us-west-2
aws ec2 create-vpc \
--region us-west-2 \
--cidr-block 10.1.0.0/16 \
--tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=production-vpc-west},{Key=Environment,Value=production}]'

Enable DNS support (recommended)

# Replace <vpc-id> with your new VPC ID
aws ec2 modify-vpc-attribute \
--region us-west-2 \
--vpc-id <vpc-id> \
--enable-dns-support '{"Value":true}'

aws ec2 modify-vpc-attribute \
--region us-west-2 \
--vpc-id <vpc-id> \
--enable-dns-hostnames '{"Value":true}'
CloudFormation (optional)

Deploy this template in a secondary region to create a VPC. Save it as vpc-secondary-region.yaml:

AWSTemplateFormatVersion: '2010-09-09'
Description: Creates a VPC in the specified region for multi-region architecture

Parameters:
VpcCidrBlock:
Type: String
Default: '10.1.0.0/16'
Description: The IPv4 CIDR block for the VPC
AllowedPattern: '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$'

EnableDnsSupport:
Type: String
Default: 'true'
AllowedValues:
- 'true'
- 'false'
Description: Enable DNS resolution support for the VPC

EnableDnsHostnames:
Type: String
Default: 'true'
AllowedValues:
- 'true'
- 'false'
Description: Enable DNS hostnames for instances launched in this VPC

Environment:
Type: String
Default: 'production'
Description: Environment tag for the VPC

Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCidrBlock
EnableDnsSupport: !Ref EnableDnsSupport
EnableDnsHostnames: !Ref EnableDnsHostnames
Tags:
- Key: Name
Value: !Sub '${Environment}-vpc'
- Key: Environment
Value: !Ref Environment

InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub '${Environment}-igw'
- Key: Environment
Value: !Ref Environment

InternetGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway

Outputs:
VpcId:
Description: VPC ID
Value: !Ref VPC
Export:
Name: !Sub '${AWS::StackName}-VpcId'

VpcCidr:
Description: VPC CIDR block
Value: !GetAtt VPC.CidrBlock

Deploy to a secondary region:

aws cloudformation deploy \
--region us-west-2 \
--stack-name secondary-vpc \
--template-file vpc-secondary-region.yaml \
--parameter-overrides VpcCidrBlock=10.1.0.0/16 Environment=production
Terraform (optional)

This configuration creates VPCs in two regions using provider aliases:

terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 4.0"
}
}
}

# Primary region provider (us-east-1)
provider "aws" {
region = "us-east-1"
alias = "primary"
}

# Secondary region provider (us-west-2) - for multi-region architecture
provider "aws" {
region = "us-west-2"
alias = "secondary"
}

variable "primary_vpc_cidr" {
description = "CIDR block for the primary VPC"
type = string
default = "10.0.0.0/16"
}

variable "secondary_vpc_cidr" {
description = "CIDR block for the secondary VPC"
type = string
default = "10.1.0.0/16"
}

variable "environment" {
description = "Environment name for tagging"
type = string
default = "production"
}

# Primary VPC in us-east-1
resource "aws_vpc" "primary" {
provider = aws.primary
cidr_block = var.primary_vpc_cidr
enable_dns_support = true
enable_dns_hostnames = true

tags = {
Name = "${var.environment}-vpc-primary"
Environment = var.environment
Region = "us-east-1"
}
}

# Secondary VPC in us-west-2
resource "aws_vpc" "secondary" {
provider = aws.secondary
cidr_block = var.secondary_vpc_cidr
enable_dns_support = true
enable_dns_hostnames = true

tags = {
Name = "${var.environment}-vpc-secondary"
Environment = var.environment
Region = "us-west-2"
}
}

# Internet Gateway for primary VPC
resource "aws_internet_gateway" "primary" {
provider = aws.primary
vpc_id = aws_vpc.primary.id

tags = {
Name = "${var.environment}-igw-primary"
Environment = var.environment
}
}

# Internet Gateway for secondary VPC
resource "aws_internet_gateway" "secondary" {
provider = aws.secondary
vpc_id = aws_vpc.secondary.id

tags = {
Name = "${var.environment}-igw-secondary"
Environment = var.environment
}
}

output "primary_vpc_id" {
description = "ID of the primary VPC"
value = aws_vpc.primary.id
}

output "secondary_vpc_id" {
description = "ID of the secondary VPC"
value = aws_vpc.secondary.id
}

Apply the configuration:

terraform init
terraform plan
terraform apply

Verification

After creating VPCs in multiple regions, verify the fix:

  1. Go to the VPC Dashboard
  2. Switch between regions using the region selector in the top-right corner
  3. Confirm that non-default VPCs exist in at least two different regions
  4. Re-run the Prowler check to confirm it passes
CLI verification
# Check for non-default VPCs across multiple regions
for region in us-east-1 us-west-2 eu-west-1; do
echo "Region: $region"
aws ec2 describe-vpcs \
--region $region \
--filters "Name=is-default,Values=false" \
--query "Vpcs[*].[VpcId,CidrBlock]" \
--output table
done

Additional Resources

Notes

  • CIDR planning: Choose non-overlapping CIDR blocks for VPCs in different regions if you plan to connect them via VPC Peering or Transit Gateway
  • Cost considerations: VPCs themselves are free, but resources within them (NAT Gateways, data transfer between regions) incur costs
  • This check excludes default VPCs: AWS creates a default VPC in each region automatically. This check looks for custom (non-default) VPCs that you create for your workloads
  • Multi-region is not always necessary: For development or non-critical workloads, a single-region deployment may be acceptable based on your risk tolerance
  • Compliance frameworks: This check maps to C5, ENS, ISO27001, and KISA-ISMS-P frameworks that require geographic distribution for resilience