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
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ENTERPRISE NETWORK ARCHITECTURE โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ โโโโโโโโโโโโโโโโโโ ON-PREMISES โโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Data Center โ VPN โ Direct Connect โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ โ
โ โโโโโโโโโโโโโโโโโโ TRANSIT GATEWAY โโโโโโโโโโโโโโโโโโ โ
โ โ โ โ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
โ โ โ Transit Gateway โ โ โ
โ โ โ (Hub-and-Spoke Topology) โ โ โ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
โ โ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ โ
โ โโโโโโโโโโโโโโโโโโ VPC LAYER โโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ โ โ
โ โ โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโ โ โ
โ โ โ VPC โ โ VPC โ โ VPC โ โ โ
โ โ โ (Shared) โ โ (App) โ โ (Data) โ โ โ
โ โ โ โ โ โ โ โ โ โ
โ โ โ โโโโโโโโ โ โ โโโโโโโโ โ โ โโโโโโโโ โ โ โ
โ โ โ โSubnetโ โ โ โSubnetโ โ โ โSubnetโ โ โ โ
โ โ โ โโโโโโโโ โ โ โโโโโโโโ โ โ โโโโโโโโ โ โ โ
โ โ โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโ โ โ
โ โ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ โ
โ โโโโโโโโโโโโโโโโโโ SECURITY LAYER โโโโโโโโโโโโโโโโโโ โ
โ โ NACLs โ Security Groups โ WAF โ Firewall โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
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 |