@infraless-cdk-constructs/aws-vpc
v1.0.2
Published
AWS CDK L3 construct for VPC with production-ready networking defaults
Maintainers
Readme
AWS VPC L3 Construct
A production-ready AWS CDK L3 construct for creating Virtual Private Clouds (VPCs) with best-practice networking configurations.
Features
- Multi-Tier Subnet Architecture: Automatic creation of Public, Private, Secure, and Database subnet tiers across multiple Availability Zones
- Managed NAT Gateways: Highly available managed NAT Gateways for private subnet internet access
- Security by Default: VPC Flow Logs with KMS encryption, Network ACLs, and security groups
- AWS Service Integration: Built-in support for VPC Endpoints (Interface and Gateway)
- Kubernetes Ready: Optional EKS cluster tagging for seamless Kubernetes integration
- SSM Parameter Store Integration: Automatic export of VPC outputs to SSM Parameter Store for cross-stack references
- Extensible Design: Protected hook methods allow customization without forking
- Type-Safe API: Full TypeScript support with comprehensive type definitions
- Production Tested: Based on battle-tested patterns used in enterprise deployments
Installation
npm install @cdk-constructs/aws-vpcPeer Dependencies
This package requires the following peer dependencies:
npm install aws-cdk-lib constructsQuick Start
import { AwsVpc } from '@cdk-constructs/aws-vpc';
import * as cdk from 'aws-cdk-lib';
const app = new cdk.App();
const stack = new cdk.Stack(app, 'MyStack');
const vpc = new AwsVpc(stack, 'MyVpc', {
vpcName: 'production-vpc',
vpcCidr: '10.0.0.0/16',
publicSubnetCidrMask: 24,
privateSubnetCidrMask: 24,
secureSubnetCidrMask: 24,
maxAzs: 3,
natCount: 3
});
// Access VPC resources
console.log(`VPC ID: ${vpc.vpcId}`);
console.log(`VPC CIDR: ${vpc.vpcCidrBlock}`);Usage Examples
Basic VPC with NAT Gateways
Creates a VPC with public, private, and secure subnets across 3 AZs with managed NAT Gateways.
const basicVpc = new AwsVpc(this, 'BasicVpc', {
vpcName: 'my-vpc',
vpcCidr: '10.0.0.0/16',
publicSubnetCidrMask: 24,
privateSubnetCidrMask: 24,
secureSubnetCidrMask: 24,
maxAzs: 3,
natCount: 3
});VPC with Database Tier
Add a fourth isolated subnet tier for database resources.
const dbVpc = new AwsVpc(this, 'DbVpc', {
vpcName: 'database-vpc',
vpcCidr: '10.2.0.0/16',
publicSubnetCidrMask: 24,
privateSubnetCidrMask: 24,
secureSubnetCidrMask: 24,
databaseSubnetCidrMask: 24, // Add database tier
maxAzs: 3,
natCount: 3
});
// Access database subnets
console.log(`Database subnets: ${dbVpc.databaseSubnets?.length}`);VPC with Kubernetes Integration
Tag subnets for EKS cluster integration.
const eksVpc = new AwsVpc(this, 'EksVpc', {
vpcName: 'eks-vpc',
vpcCidr: '10.3.0.0/16',
publicSubnetCidrMask: 24,
privateSubnetCidrMask: 24,
secureSubnetCidrMask: 24,
maxAzs: 3,
natCount: 3,
kubernetesClusterName: 'my-eks-cluster' // Adds K8s tags
});VPC with Network ACLs
Add Network ACL rules for subnet-level traffic control.
const secureVpc = new AwsVpc(this, 'SecureVpc', {
vpcName: 'secure-vpc',
vpcCidr: '10.4.0.0/16',
publicSubnetCidrMask: 24,
privateSubnetCidrMask: 24,
secureSubnetCidrMask: 24,
databaseSubnetCidrMask: 24,
maxAzs: 3,
natCount: 3,
nacls: {
public: [80, 443, 22], // HTTP, HTTPS, SSH
private: [80, 443, 22], // HTTP, HTTPS, SSH
secure: [443, 22], // HTTPS, SSH only
database: [5432, 3306] // PostgreSQL, MySQL
}
});
// Access security groups created for NACLs
if (secureVpc.publicSecurityGroup) {
console.log(`Public SG: ${secureVpc.publicSecurityGroup.securityGroupId}`);
}VPC with Interface Endpoints
Add VPC endpoints for private access to AWS services.
import * as ec2 from 'aws-cdk-lib/aws-ec2';
const endpointVpc = new AwsVpc(this, 'EndpointVpc', {
vpcName: 'endpoint-vpc',
vpcCidr: '10.5.0.0/16',
publicSubnetCidrMask: 24,
privateSubnetCidrMask: 24,
secureSubnetCidrMask: 24,
maxAzs: 3,
natCount: 3,
nacls: {
private: [443] // Required for interface endpoints
},
interfaceEndpoints: [
ec2.InterfaceVpcEndpointAwsService.SSM,
ec2.InterfaceVpcEndpointAwsService.SSM_MESSAGES,
ec2.InterfaceVpcEndpointAwsService.ECR,
ec2.InterfaceVpcEndpointAwsService.ECR_DOCKER,
ec2.InterfaceVpcEndpointAwsService.CLOUDWATCH_LOGS,
ec2.InterfaceVpcEndpointAwsService.KMS
],
enableSqsEndpoint: true
});VPC with Custom Flow Logs Retention
Configure VPC Flow Logs retention period.
import * as logs from 'aws-cdk-lib/aws-logs';
const customLogsVpc = new AwsVpc(this, 'CustomLogsVpc', {
vpcName: 'custom-logs-vpc',
vpcCidr: '10.6.0.0/16',
publicSubnetCidrMask: 24,
privateSubnetCidrMask: 24,
secureSubnetCidrMask: 24,
maxAzs: 3,
natCount: 3,
flowLogsRetention: logs.RetentionDays.ONE_MONTH
});VPC with Custom KMS Key
Provide your own KMS key for Flow Logs encryption.
import * as kms from 'aws-cdk-lib/aws-kms';
const existingKey = kms.Key.fromKeyArn(
this,
'ExistingKey',
'arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012'
);
const customKeyVpc = new AwsVpc(this, 'CustomKeyVpc', {
vpcName: 'custom-key-vpc',
vpcCidr: '10.7.0.0/16',
publicSubnetCidrMask: 24,
privateSubnetCidrMask: 24,
secureSubnetCidrMask: 24,
maxAzs: 3,
natCount: 3,
encryptionKey: existingKey
});VPC with SSM Parameter Store Outputs
Export VPC information to SSM Parameter Store for cross-stack references.
const ssmVpc = new AwsVpc(this, 'SsmVpc', {
vpcName: 'production-vpc',
vpcCidr: '10.8.0.0/16',
publicSubnetCidrMask: 24,
privateSubnetCidrMask: 24,
secureSubnetCidrMask: 24,
databaseSubnetCidrMask: 24,
maxAzs: 3,
natCount: 3,
enableSsmParameters: true, // Enabled by default
ssmParameterPrefix: '/myapp/vpc/production' // Custom prefix
});
// Parameters created:
// - /myapp/vpc/production/vpc-id
// - /myapp/vpc/production/vpc-cidr
// - /myapp/vpc/production/public-subnet-ids
// - /myapp/vpc/production/private-subnet-ids
// - /myapp/vpc/production/secure-subnet-ids
// - /myapp/vpc/production/database-subnet-ids
// Reference in another stack:
import * as ssm from 'aws-cdk-lib/aws-ssm';
const vpcId = ssm.StringParameter.valueFromLookup(
this,
'/myapp/vpc/production/vpc-id'
);To disable SSM parameter creation:
const devVpc = new AwsVpc(this, 'DevVpc', {
vpcName: 'dev-vpc',
vpcCidr: '10.9.0.0/16',
publicSubnetCidrMask: 24,
privateSubnetCidrMask: 24,
secureSubnetCidrMask: 24,
maxAzs: 2,
natCount: 1,
enableSsmParameters: false // Disable SSM parameters
});Extending the Construct
The AwsVpc construct uses the Template Method pattern with protected hooks for customization.
Custom VPC with Lifecycle Hooks
import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import { AwsVpc } from '@cdk-constructs/aws-vpc';
class CustomAwsVpc extends AwsVpc {
protected onVpcCreated(vpc: ec2.IVpc): void {
// Add custom tags
cdk.Tags.of(vpc).add('CostCenter', '12345');
cdk.Tags.of(vpc).add('Environment', 'production');
// Add custom logic
console.log(`VPC ${vpc.vpcId} created successfully`);
}
protected onConstructComplete(): void {
// Custom logic after all resources are created
console.log('All VPC resources created');
}
}
// Use the custom construct
const customVpc = new CustomAwsVpc(this, 'CustomVpc', {
vpcName: 'custom-vpc',
vpcCidr: '10.8.0.0/16',
publicSubnetCidrMask: 24,
privateSubnetCidrMask: 24,
secureSubnetCidrMask: 24,
maxAzs: 3,
natCount: 3
});Available Hook Methods
Override these protected methods to customize behavior:
createEncryptionKey(props): Customize KMS key creationcreateFlowLogs(props): Customize Flow Logs configurationapplyKubernetesTags(vpc, clusterName): Customize Kubernetes taggingconfigureNacls(vpc, props): Customize Network ACL setupcreateVpcEndpoints(vpc, securityGroup, endpoints): Customize VPC endpointsonVpcCreated(vpc): Post-VPC creation hookonConstructComplete(): Post-construct completion hook
API Reference
AwsVpcProps
| Property | Type | Required | Default | Description |
|----------|------|----------|---------|-------------|
| vpcName | string | Yes | - | Name of the VPC |
| vpcCidr | string | Yes | - | CIDR block (e.g., '10.0.0.0/16') |
| publicSubnetCidrMask | number | Yes | - | CIDR mask for public subnets |
| privateSubnetCidrMask | number | Yes | - | CIDR mask for private subnets |
| secureSubnetCidrMask | number | Yes | - | CIDR mask for secure subnets |
| databaseSubnetCidrMask | number | No | - | CIDR mask for database subnets |
| maxAzs | number | Yes | - | Maximum number of AZs to use |
| natCount | number | Yes | - | Number of NAT Gateways |
| kubernetesClusterName | string | No | - | EKS cluster name for subnet tagging |
| enableSqsEndpoint | boolean | No | false | Create SQS VPC endpoint |
| nacls | object | No | - | Network ACL port configuration |
| interfaceEndpoints | ec2.InterfaceVpcEndpointAwsService[] | No | - | VPC interface endpoints to create |
| encryptionKey | kms.IKey | No | - | KMS key for Flow Logs encryption |
| flowLogsRetention | logs.RetentionDays | No | INFINITE | Flow Logs retention period |
| enableSsmParameters | boolean | No | true | Create SSM parameters for VPC outputs |
| ssmParameterPrefix | string | No | /cdk/${constructId} | Custom prefix for SSM parameter paths |
AwsVpc Properties
| Property | Type | Description |
|----------|------|-------------|
| vpc | ec2.IVpc | The VPC resource |
| vpcId | string | VPC ID |
| vpcCidrBlock | string | VPC CIDR block |
| publicSubnets | ec2.ISubnet[] | Public subnets |
| privateSubnets | ec2.ISubnet[] | Private subnets |
| secureSubnets | ec2.ISubnet[] | Secure subnets |
| databaseSubnets | ec2.ISubnet[] | Database subnets (if created) |
| encryptionKey | kms.IKey | KMS encryption key |
| flowLogGroup | logs.ILogGroup | Flow Logs CloudWatch log group |
| publicSecurityGroup | ec2.ISecurityGroup | Public subnet security group (if NACLs enabled) |
| privateSecurityGroup | ec2.ISecurityGroup | Private subnet security group (if NACLs enabled) |
| secureSecurityGroup | ec2.ISecurityGroup | Secure subnet security group (if NACLs enabled) |
| databaseSecurityGroup | ec2.ISecurityGroup | Database subnet security group (if NACLs enabled) |
Subnet Architecture
The construct creates a multi-tier subnet architecture:
Public Subnets
- Internet-facing resources (ALBs, NAT Gateways)
- Direct internet access via Internet Gateway
- Auto-assigned public IPs: disabled by default
Private Subnets
- Application workloads (ECS, EKS, EC2)
- Outbound internet access via NAT Gateway/Instance
- No inbound internet access
Secure Subnets
- Completely isolated resources
- No internet access (inbound or outbound)
- Internal communication only
Database Subnets (Optional)
- Database instances (RDS, Aurora, ElastiCache)
- Completely isolated
- Access only from private/secure subnets
Security Features
VPC Flow Logs
- Automatically enabled for all traffic
- Encrypted with KMS
- Logged to CloudWatch Logs
- Configurable retention period
Network ACLs
- Optional subnet-level traffic control
- Port-based rules for each tier
- Automatic ephemeral port handling
- Security group integration
Encryption
- KMS encryption for Flow Logs
- Automatic key rotation enabled
- CloudWatch Logs service principal access
Cost Optimization
NAT Gateway Recommendations
NAT Gateway (managed service):
- Managed service with no maintenance required
- High availability within AZ
- Up to 45 Gbps bandwidth
- ~$32/month per gateway + data transfer
Cost Optimization Strategies
Development/Testing Environments: Use fewer NAT Gateways
const devVpc = new AwsVpc(this, 'DevVpc', { vpcName: 'dev-vpc', vpcCidr: '10.0.0.0/16', publicSubnetCidrMask: 24, privateSubnetCidrMask: 24, secureSubnetCidrMask: 24, maxAzs: 2, // Reduce AZs natCount: 1 // Single NAT Gateway });Production Environments: Use one NAT Gateway per AZ for high availability
const prodVpc = new AwsVpc(this, 'ProdVpc', { vpcName: 'prod-vpc', vpcCidr: '10.0.0.0/16', publicSubnetCidrMask: 24, privateSubnetCidrMask: 24, secureSubnetCidrMask: 24, maxAzs: 3, // Multi-AZ natCount: 3 // One NAT per AZ });VPC Endpoints: Reduce NAT Gateway data transfer costs by using VPC endpoints for AWS services
Troubleshooting
VPC Endpoint Connection Issues
Problem: Cannot connect to AWS services via endpoints
Solution: Ensure NACLs allow HTTPS (port 443):
nacls: {
private: [443] // Required for VPC endpoints
}Insufficient Subnet IP Addresses
Problem: Running out of IP addresses in subnets
Solution: Adjust CIDR masks for more IPs (smaller mask = more IPs):
publicSubnetCidrMask: 20, // 4096 IPs per subnet
privateSubnetCidrMask: 20, // 4096 IPs per subnetContributing
Contributions are welcome! Please open an issue or submit a pull request.
License
MIT
Support
For issues, questions, or feature requests, please open a GitHub issue.
