Cloud Networking: VPC, Transit Gateway, PrivateLink
Difficulty: Senior Level | Companies: AWS, Google, Microsoft, Cloudflare, Akamai
Interview Question
"Design a VPC architecture for a multi-account AWS environment with 50+ VPCs. How do you handle connectivity, security, and DNS resolution?"
âšī¸Key Concepts
This question tests your understanding of cloud networking, VPC design patterns, and enterprise connectivity.
Complete Networking Architecture
Architecture Overview
Mathematical Foundation: Network Planning
IP Address Planning:
- Total VPCs: V = 50
- Subnets per VPC: S = 10
- IP addresses per subnet: I = 256 (/24)
- Total IP addresses needed: T = V Ã S Ã I = 1,280,000
- Available in /16 VPC: 65,536
Network Capacity:
- Bandwidth per link: B = 10Gbps
- Number of links: L = 10
- Total bandwidth: T = B Ã L = 100Gbps
- Throughput with redundancy: T = 90Gbps (10% overhead)
Latency Calculations:
- Intra-AZ latency: L_az = 0.5ms
- Inter-AZ latency: L_inter = 2ms
- Inter-region latency: L_region = 50ms
- On-premises latency: L_prem = 10ms
VPC Design
# Hub VPC for shared services
resource "aws_vpc" "hub" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "hub-vpc"
Environment = "shared"
}
}
# Spoke VPC for application
resource "aws_vpc" "app" {
cidr_block = "10.1.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "app-vpc"
Environment = "production"
}
}
# Subnets in hub VPC
resource "aws_subnet" "hub_public" {
count = 3
vpc_id = aws_vpc.hub.id
cidr_block = cidrsubnet(aws_vpc.hub.cidr_block, 8, count.index)
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = {
Name = "hub-public-${count.index + 1}"
}
}
resource "aws_subnet" "hub_private" {
count = 3
vpc_id = aws_vpc.hub.id
cidr_block = cidrsubnet(aws_vpc.hub.cidr_block, 8, count.index + 10)
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = {
Name = "hub-private-${count.index + 1}"
}
}
# Subnets in app VPC
resource "aws_subnet" "app_public" {
count = 3
vpc_id = aws_vpc.app.id
cidr_block = cidrsubnet(aws_vpc.app.cidr_block, 8, count.index)
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = {
Name = "app-public-${count.index + 1}"
}
}
resource "aws_subnet" "app_private" {
count = 3
vpc_id = aws_vpc.app.id
cidr_block = cidrsubnet(aws_vpc.app.cidr_block, 8, count.index + 10)
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = {
Name = "app-private-${count.index + 1}"
}
}
Transit Gateway Configuration
# Transit Gateway
resource "aws_ec2_transit_gateway" "main" {
description = "Main Transit Gateway"
default_route_table_association = "disable"
default_route_table_propagation = "disable"
tags = {
Name = "main-tgw"
}
}
# Transit Gateway VPC Attachment for hub
resource "aws_ec2_transit_gateway_vpc_attachment" "hub" {
transit_gateway_id = aws_ec2_transit_gateway.main.id
vpc_id = aws_vpc.hub.id
subnet_ids = aws_subnet.hub_private[*].id
transit_gateway_default_route_table_association = false
transit_gateway_default_route_table_propagation = false
tags = {
Name = "hub-attachment"
}
}
# Transit Gateway VPC Attachment for app
resource "aws_ec2_transit_gateway_vpc_attachment" "app" {
transit_gateway_id = aws_ec2_transit_gateway.main.id
vpc_id = aws_vpc.app.id
subnet_ids = aws_subnet.app_private[*].id
transit_gateway_default_route_table_association = false
transit_gateway_default_route_table_propagation = false
tags = {
Name = "app-attachment"
}
}
# Transit Gateway Route Table
resource "aws_ec2_transit_gateway_route_table" "main" {
transit_gateway_id = aws_ec2_transit_gateway.main.id
tags = {
Name = "main-rt"
}
}
# Route table associations
resource "aws_ec2_transit_gateway_route_table_association" "hub" {
transit_gateway_attachment_id = aws_ec2_transit_gateway_vpc_attachment.hub.id
transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.main.id
}
resource "aws_ec2_transit_gateway_route_table_association" "app" {
transit_gateway_attachment_id = aws_ec2_transit_gateway_vpc_attachment.app.id
transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.main.id
}
# Routes
resource "aws_ec2_transit_gateway_route" "hub_to_app" {
destination_cidr_block = aws_vpc.app.cidr_block
transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.main.id
transit_gateway_attachment_id = aws_ec2_transit_gateway_vpc_attachment.app.id
}
resource "aws_ec2_transit_gateway_route" "app_to_hub" {
destination_cidr_block = aws_vpc.hub.cidr_block
transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.main.id
transit_gateway_attachment_id = aws_ec2_transit_gateway_vpc_attachment.hub.id
}
VPC Peering
# VPC peering management
import boto3
from typing import Dict, Any, List
from dataclasses import dataclass
@dataclass
class VPCPeeringRequest:
request_id: str
requester_vpc_id: str
accepter_vpc_id: str
status: str
requester_cidr: str
accepter_cidr: str
class VPCPeeringManager:
"""VPC peering management"""
def __init__(self):
self.ec2 = boto3.client('ec2')
def create_peering(self, requester_vpc_id: str, accepter_vpc_id: str) -> VPCPeeringRequest:
"""Create VPC peering connection"""
response = self.ec2.create_vpc_peering_connection(
VpcId=requester_vpc_id,
PeerVpcId=accepter_vpc_id
)
peering = response['VpcPeeringConnection']
return VPCPeeringRequest(
request_id=peering['VpcPeeringConnectionId'],
requester_vpc_id=requester_vpc_id,
accepter_vpc_id=accepter_vpc_id,
status=peering['Status']['Code'],
requester_cidr='',
accepter_cidr=''
)
def accept_peering(self, peering_id: str):
"""Accept VPC peering connection"""
self.ec2.accept_vpc_peering_connection(
VpcPeeringConnectionId=peering_id
)
def add_routes(self, peering_id: str, requester_cidr: str, accepter_cidr: str):
"""Add routes for peering connection"""
# Get VPC IDs from peering connection
response = self.ec2.describe_vpc_peering_connections(
VpcPeeringConnectionIds=[peering_id]
)
peering = response['VpcPeeringConnections'][0]
requester_vpc_id = peering['RequesterVpcInfo']['VpcId']
accepter_vpc_id = peering['AccepterVpcInfo']['VpcId']
# Add route in requester VPC
self._add_route_to_vpc(requester_vpc_id, accepter_cidr, peering_id)
# Add route in accepter VPC
self._add_route_to_vpc(accepter_vpc_id, requester_cidr, peering_id)
def _add_route_to_vpc(self, vpc_id: str, destination_cidr: str, peering_id: str):
"""Add route to VPC route table"""
# Get route table for VPC
route_tables = self.ec2.describe_route_tables(
Filters=[
{'Name': 'vpc-id', 'Values': [vpc_id]},
{'Name': 'association.main', 'Values': ['true']}
]
)
if route_tables['RouteTables']:
route_table_id = route_tables['RouteTables'][0]['RouteTableId']
self.ec2.create_route(
RouteTableId=route_table_id,
DestinationCidrBlock=destination_cidr,
VpcPeeringConnectionId=peering_id
)
PrivateLink Configuration
# VPC Endpoint Service
import boto3
from typing import Dict, Any, List
from dataclasses import dataclass
@dataclass
class VPCEndpoint:
endpoint_id: str
service_name: str
vpc_id: str
type: str
status: str
class PrivateLinkManager:
"""VPC PrivateLink manager"""
def __init__(self):
self.ec2 = boto3.client('ec2')
self.elbv2 = boto3.client('elbv2')
def create_endpoint_service(self, load_balancer_arn: str) -> str:
"""Create VPC endpoint service"""
response = self.ec2.create_vpc_endpoint_service_configuration(
NetworkLoadBalancerArns=[load_balancer_arn],
AcceptanceRequired=False,
PayerResponsibility='SERVICE_OWNER'
)
return response['ServiceConfiguration']['ServiceId']
def create_vpc_endpoint(self, vpc_id: str, service_name: str,
subnet_ids: List[str]) -> VPCEndpoint:
"""Create VPC endpoint"""
response = self.ec2.create_vpc_endpoint(
VpcId=vpc_id,
ServiceName=service_name,
SubnetIds=subnet_ids,
VpcEndpointType='Interface'
)
endpoint = response['VpcEndpoint']
return VPCEndpoint(
endpoint_id=endpoint['VpcEndpointId'],
service_name=service_name,
vpc_id=vpc_id,
type='Interface',
status=endpoint['State']
)
def create_gateway_endpoint(self, vpc_id: str, route_table_ids: List[str],
service_name: str = 'com.amazonaws.us-east-1.s3') -> VPCEndpoint:
"""Create gateway endpoint"""
response = self.ec2.create_vpc_endpoint(
VpcId=vpc_id,
ServiceName=service_name,
RouteTableIds=route_table_ids,
VpcEndpointType='Gateway'
)
endpoint = response['VpcEndpoint']
return VPCEndpoint(
endpoint_id=endpoint['VpcEndpointId'],
service_name=service_name,
vpc_id=vpc_id,
type='Gateway',
status=endpoint['State']
)
def create_prefix_list_endpoint(self, vpc_id: str, prefix_list_id: str,
subnet_ids: List[str]) -> VPCEndpoint:
"""Create endpoint for prefix list"""
response = self.ec2.create_vpc_endpoint(
VpcId=vpc_id,
PrefixListId=prefix_list_id,
SubnetIds=subnet_ids,
VpcEndpointType='GatewayLoadBalancer'
)
endpoint = response['VpcEndpoint']
return VPCEndpoint(
endpoint_id=endpoint['VpcEndpointId'],
service_name=f"prefix-list:{prefix_list_id}",
vpc_id=vpc_id,
type='GatewayLoadBalancer',
status=endpoint['State']
)
DNS Resolution
# Route53 private hosted zones
import boto3
from typing import Dict, Any, List
from dataclasses import dataclass
@dataclass
class PrivateHostedZone:
zone_id: str
domain_name: str
vpc_id: str
comment: str
class DNSManager:
"""DNS management for VPC"""
def __init__(self):
self.route53 = boto3.client('route53')
def create_private_hosted_zone(self, domain_name: str, vpc_id: str) -> PrivateHostedZone:
"""Create private hosted zone"""
response = self.route53.create_hosted_zone(
Name=domain_name,
CallerReference=str(hash(domain_name)),
HostedZoneConfig={
'Comment': f'Private zone for {domain_name}',
'PrivateZone': True
},
VPC={
'VPCRegion': 'us-east-1',
'VPCId': vpc_id
}
)
zone = response['HostedZone']
return PrivateHostedZone(
zone_id=zone['Id'].split('/')[-1],
domain_name=domain_name,
vpc_id=vpc_id,
comment=f'Private zone for {domain_name}'
)
def create_record(self, zone_id: str, record_name: str, record_type: str,
record_values: List[str], ttl: int = 300):
"""Create DNS record"""
self.route53.change_resource_record_sets(
HostedZoneId=zone_id,
ChangeBatch={
'Changes': [
{
'Action': 'UPSERT',
'ResourceRecordSet': {
'Name': record_name,
'Type': record_type,
'TTL': ttl,
'ResourceRecords': [
{'Value': value} for value in record_values
]
}
}
]
}
)
def associate_vpc_with_zone(self, zone_id: str, vpc_id: str, vpc_region: str = 'us-east-1'):
"""Associate VPC with private hosted zone"""
self.route53.associate_vpc_with_hosted_zone(
HostedZoneId=zone_id,
VPC={
'VPCRegion': vpc_region,
'VPCId': vpc_id
}
)
def create_resolver_endpoint(self, vpc_id: str, subnet_ids: List[str],
direction: str = 'INBOUND') -> str:
"""Create Route53 Resolver endpoint"""
route53resolver = boto3.client('route53resolver')
response = route53resolver.create_resolver_endpoint(
CreatorRequestId=str(hash(vpc_id)),
Direction=direction,
IpAddresses=[
{
'SubnetId': subnet_id
} for subnet_id in subnet_ids
],
SecurityGroupIds=[self._get_security_group(vpc_id)],
VpcId=vpc_id
)
return response['ResolverEndpoint']['Id']
def _get_security_group(self, vpc_id: str) -> str:
"""Get security group for resolver endpoint"""
ec2 = boto3.client('ec2')
response = ec2.describe_security_groups(
Filters=[
{'Name': 'vpc-id', 'Values': [vpc_id]},
{'Name': 'group-name', 'Values': ['dns-resolver']}
]
)
if response['SecurityGroups']:
return response['SecurityGroups'][0]['GroupId']
return ''
â ī¸DNS Best Practices
Use private hosted zones for internal DNS resolution. Implement DNS failover for high availability. Use Route53 Resolver for hybrid DNS.
Network Security
# Security group management
import boto3
from typing import Dict, Any, List
from dataclasses import dataclass
@dataclass
class SecurityGroupRule:
protocol: str
from_port: int
to_port: int
cidr_blocks: List[str]
description: str
class SecurityGroupManager:
"""Security group management"""
def __init__(self):
self.ec2 = boto3.client('ec2')
def create_security_group(self, vpc_id: str, group_name: str,
description: str, ingress_rules: List[SecurityGroupRule],
egress_rules: List[SecurityGroupRule] = None) -> str:
"""Create security group with rules"""
# Create security group
response = self.ec2.create_security_group(
VpcId=vpc_id,
GroupName=group_name,
Description=description
)
group_id = response['GroupId']
# Add ingress rules
for rule in ingress_rules:
self.ec2.authorize_security_group_ingress(
GroupId=group_id,
IpPermissions=[
{
'IpProtocol': rule.protocol,
'FromPort': rule.from_port,
'ToPort': rule.to_port,
'IpRanges': [
{'CidrIp': cidr, 'Description': rule.description}
for cidr in rule.cidr_blocks
]
}
]
)
# Add egress rules
if egress_rules:
for rule in egress_rules:
self.ec2.authorize_security_group_egress(
GroupId=group_id,
IpPermissions=[
{
'IpProtocol': rule.protocol,
'FromPort': rule.from_port,
'ToPort': rule.to_port,
'IpRanges': [
{'CidrIp': cidr, 'Description': rule.description}
for cidr in rule.cidr_blocks
]
}
]
)
return group_id
def create_nacl(self, vpc_id: str, nacl_name: str,
ingress_rules: List[Dict], egress_rules: List[Dict]) -> str:
"""Create network ACL"""
# Create NACL
response = self.ec2.create_network_acl(
VpcId=vpc_id,
TagSpecifications=[
{
'ResourceType': 'network-acl',
'Tags': [{'Key': 'Name', 'Value': nacl_name}]
}
]
)
nacl_id = response['NetworkAcl']['NetworkAclId']
# Add ingress rules
for i, rule in enumerate(ingress_rules):
self.ec2.create_network_acl_entry(
NetworkAclId=nacl_id,
RuleNumber=rule.get('rule_number', (i + 1) * 100),
Protocol=rule.get('protocol', '-1'),
RuleAction=rule.get('action', 'allow'),
Egress=False,
CidrBlock=rule.get('cidr', '0.0.0.0/0'),
PortRange={
'From': rule.get('from_port', 0),
'To': rule.get('to_port', 65535)
}
)
# Add egress rules
for i, rule in enumerate(egress_rules):
self.ec2.create_network_acl_entry(
NetworkAclId=nacl_id,
RuleNumber=rule.get('rule_number', (i + 1) * 100),
Protocol=rule.get('protocol', '-1'),
RuleAction=rule.get('action', 'allow'),
Egress=True,
CidrBlock=rule.get('cidr', '0.0.0.0/0'),
PortRange={
'From': rule.get('from_port', 0),
'To': rule.get('to_port', 65535)
}
)
return nacl_id
â Networking Benefits
A well-designed network architecture provides security, scalability, and performance. Use Transit Gateway for hub-and-spoke topology and PrivateLink for service access.
Summary
| Component | Purpose | Configuration |
|---|---|---|
| VPC | Network isolation | CIDR, subnets |
| Transit Gateway | Hub connectivity | Route tables, attachments |
| VPC Peering | Direct connectivity | Cross-region, cross-account |
| PrivateLink | Service access | Endpoint services, interfaces |
| Route53 | DNS resolution | Private hosted zones |