AW
Networking
Aws core v1.0.0
AWS Networking
Overview
This skill covers AWS networking fundamentals including VPC design, subnets, security groups, load balancers, and connectivity options. Proper network architecture is critical for security, performance, and cost optimization.
Key Concepts
VPC Architecture
┌─────────────────────────────────────────────────────────────┐
│ VPC (10.0.0.0/16) │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────────────┐ ┌────────────────────┐ │
│ │ Availability Zone A│ │ Availability Zone B│ │
│ │ │ │ │ │
│ │ ┌──────────────┐ │ │ ┌──────────────┐ │ │
│ │ │Public Subnet │ │ │ │Public Subnet │ │ │
│ │ │ 10.0.1.0/24 │ │ │ │ 10.0.2.0/24 │ │ │
│ │ │ ┌───┐ ┌───┐ │ │ │ │ ┌───┐ ┌───┐ │ │ │
│ │ │ │ALB│ │NAT│ │ │ │ │ │ALB│ │NAT│ │ │ │
│ │ │ └───┘ └───┘ │ │ │ │ └───┘ └───┘ │ │ │
│ │ └──────────────┘ │ │ └──────────────┘ │ │
│ │ │ │ │ │
│ │ ┌──────────────┐ │ │ ┌──────────────┐ │ │
│ │ │Private Subnet│ │ │ │Private Subnet│ │ │
│ │ │ 10.0.11.0/24 │ │ │ │ 10.0.12.0/24 │ │ │
│ │ │ ┌───┐ ┌───┐ │ │ │ │ ┌───┐ ┌───┐ │ │ │
│ │ │ │ECS│ │ECS│ │ │ │ │ │ECS│ │ECS│ │ │ │
│ │ │ └───┘ └───┘ │ │ │ │ └───┘ └───┘ │ │ │
│ │ └──────────────┘ │ │ └──────────────┘ │ │
│ │ │ │ │ │
│ │ ┌──────────────┐ │ │ ┌──────────────┐ │ │
│ │ │Isolated Subnet│ │ │ │Isolated Subnet│ │ │
│ │ │ 10.0.21.0/24 │ │ │ │ 10.0.22.0/24 │ │ │
│ │ │ ┌───┐ │ │ │ │ ┌───┐ │ │ │
│ │ │ │RDS│ │ │ │ │ │RDS│ │ │ │
│ │ │ └───┘ │ │ │ │ └───┘ │ │ │
│ │ └──────────────┘ │ │ └──────────────┘ │ │
│ └────────────────────┘ └────────────────────┘ │
│ │
│ Internet ←→ IGW ←→ Public Subnets │
│ Private Subnets ←→ NAT Gateway ←→ Internet │
│ VPC Endpoints ←→ AWS Services (S3, DynamoDB, etc.) │
│ │
└─────────────────────────────────────────────────────────────┘
Best Practices
1. Use Multiple Availability Zones
Deploy across at least 2 AZs for high availability.
2. Implement Least Privilege Security Groups
Only allow required traffic, deny by default.
3. Use VPC Endpoints
Access AWS services without internet gateway.
4. Enable VPC Flow Logs
Monitor network traffic for security and debugging.
5. Plan IP Address Space
Leave room for growth and avoid overlapping CIDR blocks.
Code Examples
Example 1: VPC with Best Practices
import * as ec2 from 'aws-cdk-lib/aws-ec2';
export class NetworkStack extends cdk.Stack {
public readonly vpc: ec2.Vpc;
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// VPC with 3-tier architecture
this.vpc = new ec2.Vpc(this, 'MainVpc', {
vpcName: 'main-vpc',
ipAddresses: ec2.IpAddresses.cidr('10.0.0.0/16'),
maxAzs: 3,
// Subnet configuration
subnetConfiguration: [
{
name: 'Public',
subnetType: ec2.SubnetType.PUBLIC,
cidrMask: 24,
mapPublicIpOnLaunch: false,
},
{
name: 'Private',
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
cidrMask: 24,
},
{
name: 'Isolated',
subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
cidrMask: 24,
},
],
// NAT Gateway configuration
natGateways: 1, // Cost optimization: 1 for non-prod, 3 for prod
natGatewaySubnets: {
subnetType: ec2.SubnetType.PUBLIC,
},
// DNS settings
enableDnsHostnames: true,
enableDnsSupport: true,
});
// VPC Flow Logs
this.vpc.addFlowLog('FlowLog', {
destination: ec2.FlowLogDestination.toCloudWatchLogs(flowLogGroup, flowLogRole),
trafficType: ec2.FlowLogTrafficType.ALL,
maxAggregationInterval: ec2.FlowLogMaxAggregationInterval.ONE_MINUTE,
});
// Gateway Endpoints (free)
this.vpc.addGatewayEndpoint('S3Endpoint', {
service: ec2.GatewayVpcEndpointAwsService.S3,
});
this.vpc.addGatewayEndpoint('DynamoDBEndpoint', {
service: ec2.GatewayVpcEndpointAwsService.DYNAMODB,
});
// Interface Endpoints (cost per hour + data)
this.vpc.addInterfaceEndpoint('SecretsManagerEndpoint', {
service: ec2.InterfaceVpcEndpointAwsService.SECRETS_MANAGER,
subnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS },
privateDnsEnabled: true,
});
this.vpc.addInterfaceEndpoint('EcrEndpoint', {
service: ec2.InterfaceVpcEndpointAwsService.ECR,
subnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS },
});
this.vpc.addInterfaceEndpoint('EcrDockerEndpoint', {
service: ec2.InterfaceVpcEndpointAwsService.ECR_DOCKER,
subnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS },
});
this.vpc.addInterfaceEndpoint('LogsEndpoint', {
service: ec2.InterfaceVpcEndpointAwsService.CLOUDWATCH_LOGS,
subnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS },
});
}
}
Example 2: Security Groups
export class SecurityGroupsStack extends cdk.Stack {
constructor(scope: Construct, id: string, props: SecurityGroupsStackProps) {
super(scope, id, props);
const { vpc } = props;
// ALB Security Group
const albSecurityGroup = new ec2.SecurityGroup(this, 'AlbSG', {
vpc,
securityGroupName: 'alb-sg',
description: 'Security group for Application Load Balancer',
allowAllOutbound: false,
});
albSecurityGroup.addIngressRule(
ec2.Peer.anyIpv4(),
ec2.Port.tcp(443),
'Allow HTTPS from internet'
);
albSecurityGroup.addEgressRule(
ec2.Peer.ipv4(vpc.vpcCidrBlock),
ec2.Port.tcp(8080),
'Allow to application port'
);
// Application Security Group
const appSecurityGroup = new ec2.SecurityGroup(this, 'AppSG', {
vpc,
securityGroupName: 'app-sg',
description: 'Security group for application containers',
allowAllOutbound: false,
});
// Only allow from ALB
appSecurityGroup.addIngressRule(
albSecurityGroup,
ec2.Port.tcp(8080),
'Allow from ALB'
);
// Allow outbound to AWS services via VPC endpoints
appSecurityGroup.addEgressRule(
ec2.Peer.prefixList(s3PrefixListId),
ec2.Port.tcp(443),
'Allow to S3'
);
appSecurityGroup.addEgressRule(
ec2.Peer.ipv4(vpc.vpcCidrBlock),
ec2.Port.tcp(443),
'Allow to VPC endpoints'
);
// Database Security Group
const dbSecurityGroup = new ec2.SecurityGroup(this, 'DbSG', {
vpc,
securityGroupName: 'db-sg',
description: 'Security group for database',
allowAllOutbound: false, // DB shouldn't initiate outbound
});
dbSecurityGroup.addIngressRule(
appSecurityGroup,
ec2.Port.tcp(5432),
'Allow PostgreSQL from app'
);
// Bastion Security Group (for emergency access)
const bastionSecurityGroup = new ec2.SecurityGroup(this, 'BastionSG', {
vpc,
securityGroupName: 'bastion-sg',
description: 'Security group for bastion host',
});
bastionSecurityGroup.addIngressRule(
ec2.Peer.ipv4('10.0.0.0/8'), // Corporate network only
ec2.Port.tcp(22),
'Allow SSH from corporate network'
);
// Allow bastion to access DB (for debugging)
dbSecurityGroup.addIngressRule(
bastionSecurityGroup,
ec2.Port.tcp(5432),
'Allow PostgreSQL from bastion'
);
}
}
Example 3: Application Load Balancer
import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2';
export class LoadBalancerStack extends cdk.Stack {
constructor(scope: Construct, id: string, props: LoadBalancerStackProps) {
super(scope, id, props);
const { vpc, service, certificate } = props;
// Application Load Balancer
const alb = new elbv2.ApplicationLoadBalancer(this, 'ALB', {
loadBalancerName: 'order-service-alb',
vpc,
internetFacing: true,
vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC },
// Security
securityGroup: albSecurityGroup,
// Access logs
http2Enabled: true,
idleTimeout: cdk.Duration.seconds(60),
});
// Enable access logging
alb.logAccessLogs(accessLogsBucket, 'alb-logs');
// HTTPS Listener
const httpsListener = alb.addListener('HttpsListener', {
port: 443,
certificates: [certificate],
sslPolicy: elbv2.SslPolicy.TLS13_13,
});
// Target Group with health check
const targetGroup = httpsListener.addTargets('AppTargets', {
port: 8080,
protocol: elbv2.ApplicationProtocol.HTTP,
targets: [service],
healthCheck: {
path: '/actuator/health',
interval: cdk.Duration.seconds(30),
timeout: cdk.Duration.seconds(5),
healthyThresholdCount: 2,
unhealthyThresholdCount: 3,
healthyHttpCodes: '200',
},
deregistrationDelay: cdk.Duration.seconds(30),
stickinessCookieDuration: cdk.Duration.hours(1),
});
// HTTP to HTTPS redirect
alb.addListener('HttpListener', {
port: 80,
defaultAction: elbv2.ListenerAction.redirect({
port: '443',
protocol: 'HTTPS',
permanent: true,
}),
});
// Path-based routing
httpsListener.addAction('ApiAction', {
priority: 10,
conditions: [
elbv2.ListenerCondition.pathPatterns(['/api/*']),
],
action: elbv2.ListenerAction.forward([apiTargetGroup]),
});
// Host-based routing
httpsListener.addAction('AdminAction', {
priority: 5,
conditions: [
elbv2.ListenerCondition.hostHeaders(['admin.example.com']),
],
action: elbv2.ListenerAction.forward([adminTargetGroup]),
});
// Default action
httpsListener.addAction('DefaultAction', {
action: elbv2.ListenerAction.forward([targetGroup]),
});
}
}
Example 4: VPC Peering and Transit Gateway
export class ConnectivityStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// VPC Peering (for simple 2 VPC connections)
const peeringConnection = new ec2.CfnVPCPeeringConnection(this, 'VpcPeering', {
vpcId: productionVpc.vpcId,
peerVpcId: managementVpc.vpcId,
peerOwnerId: this.account,
peerRegion: this.region,
});
// Add routes for peering
productionVpc.privateSubnets.forEach((subnet, index) => {
new ec2.CfnRoute(this, `ProdToMgmtRoute${index}`, {
routeTableId: subnet.routeTable.routeTableId,
destinationCidrBlock: managementVpc.vpcCidrBlock,
vpcPeeringConnectionId: peeringConnection.ref,
});
});
// Transit Gateway (for complex multi-VPC/on-premises)
const transitGateway = new ec2.CfnTransitGateway(this, 'TransitGateway', {
amazonSideAsn: 64512,
autoAcceptSharedAttachments: 'enable',
defaultRouteTableAssociation: 'enable',
defaultRouteTablePropagation: 'enable',
dnsSupport: 'enable',
vpnEcmpSupport: 'enable',
tags: [{ key: 'Name', value: 'main-tgw' }],
});
// Attach VPCs to Transit Gateway
const prodAttachment = new ec2.CfnTransitGatewayAttachment(this, 'ProdAttachment', {
transitGatewayId: transitGateway.ref,
vpcId: productionVpc.vpcId,
subnetIds: productionVpc.privateSubnets.map(s => s.subnetId),
});
// Site-to-Site VPN for on-premises
const customerGateway = new ec2.CfnCustomerGateway(this, 'CustomerGateway', {
bgpAsn: 65000,
ipAddress: '203.0.113.1', // On-premises router IP
type: 'ipsec.1',
});
const vpnConnection = new ec2.CfnVPNConnection(this, 'VpnConnection', {
customerGatewayId: customerGateway.ref,
transitGatewayId: transitGateway.ref,
type: 'ipsec.1',
staticRoutesOnly: false, // Use BGP
});
}
}
Example 5: Network ACLs
export class NaclStack extends cdk.Stack {
constructor(scope: Construct, id: string, props: NaclStackProps) {
super(scope, id, props);
const { vpc } = props;
// NACL for public subnets
const publicNacl = new ec2.NetworkAcl(this, 'PublicNacl', {
vpc,
networkAclName: 'public-nacl',
});
// Inbound rules
publicNacl.addEntry('InboundHttps', {
ruleNumber: 100,
cidr: ec2.AclCidr.anyIpv4(),
traffic: ec2.AclTraffic.tcpPort(443),
direction: ec2.TrafficDirection.INGRESS,
ruleAction: ec2.Action.ALLOW,
});
publicNacl.addEntry('InboundHttp', {
ruleNumber: 110,
cidr: ec2.AclCidr.anyIpv4(),
traffic: ec2.AclTraffic.tcpPort(80),
direction: ec2.TrafficDirection.INGRESS,
ruleAction: ec2.Action.ALLOW,
});
// Ephemeral ports for return traffic
publicNacl.addEntry('InboundEphemeral', {
ruleNumber: 200,
cidr: ec2.AclCidr.anyIpv4(),
traffic: ec2.AclTraffic.tcpPortRange(1024, 65535),
direction: ec2.TrafficDirection.INGRESS,
ruleAction: ec2.Action.ALLOW,
});
// Outbound rules
publicNacl.addEntry('OutboundAll', {
ruleNumber: 100,
cidr: ec2.AclCidr.anyIpv4(),
traffic: ec2.AclTraffic.allTraffic(),
direction: ec2.TrafficDirection.EGRESS,
ruleAction: ec2.Action.ALLOW,
});
// Associate with public subnets
vpc.publicSubnets.forEach((subnet, index) => {
new ec2.SubnetNetworkAclAssociation(this, `PublicNaclAssoc${index}`, {
subnet,
networkAcl: publicNacl,
});
});
// NACL for private subnets (more restrictive)
const privateNacl = new ec2.NetworkAcl(this, 'PrivateNacl', {
vpc,
networkAclName: 'private-nacl',
});
// Only allow from VPC
privateNacl.addEntry('InboundFromVpc', {
ruleNumber: 100,
cidr: ec2.AclCidr.ipv4(vpc.vpcCidrBlock),
traffic: ec2.AclTraffic.allTraffic(),
direction: ec2.TrafficDirection.INGRESS,
ruleAction: ec2.Action.ALLOW,
});
// Allow return traffic from internet (for NAT)
privateNacl.addEntry('InboundEphemeral', {
ruleNumber: 200,
cidr: ec2.AclCidr.anyIpv4(),
traffic: ec2.AclTraffic.tcpPortRange(1024, 65535),
direction: ec2.TrafficDirection.INGRESS,
ruleAction: ec2.Action.ALLOW,
});
privateNacl.addEntry('OutboundAll', {
ruleNumber: 100,
cidr: ec2.AclCidr.anyIpv4(),
traffic: ec2.AclTraffic.allTraffic(),
direction: ec2.TrafficDirection.EGRESS,
ruleAction: ec2.Action.ALLOW,
});
}
}
Anti-Patterns
❌ Over-permissive Security Groups
// WRONG - allows all traffic
securityGroup.addIngressRule(
ec2.Peer.anyIpv4(),
ec2.Port.allTraffic(),
'Allow all'
);
// ✅ CORRECT - least privilege
securityGroup.addIngressRule(
albSecurityGroup,
ec2.Port.tcp(8080),
'Allow from ALB only'
);