Skip to main content

Networking Module

Overview

The Networking Module creates a secure, isolated network infrastructure for the Artos platform. It establishes a Virtual Private Cloud (VPC) with private subnets for application workloads, isolated database subnets, comprehensive security groups, and VPC endpoints for accessing AWS services without internet connectivity. The architecture supports both new VPC creation and integration with existing VPCs.

Key Features

  • Private Architecture: All workloads run in private subnets with no direct internet access
  • Network Isolation: Separate subnets for applications, databases, and network tiers
  • Security Groups: Fine-grained traffic control between components
  • VPC Endpoints: Private connectivity to AWS services (S3, ECR, Secrets Manager, etc.)
  • Flow Logging: Network traffic monitoring and audit trails
  • Flexible Deployment: Support for new VPC creation or existing VPC integration

Network Architecture

VPC Configuration

The VPC provides the isolated network boundary for all Artos resources. Default CIDR: 10.0.0.0/16 (65,536 IP addresses) Key Settings:
  • DNS Hostnames: Enabled (required for EKS and VPC endpoints)
  • DNS Support: Enabled (enables DNS resolution within VPC)
Existing VPC Support: The module can use an existing VPC instead of creating a new one. When vpc_id is provided, the module:
  • Creates only the required subnets (if not provided)
  • Integrates with existing networking infrastructure

Subnet Design

The module creates three types of subnets distributed across availability zones for high availability.

1. Private Subnets

Purpose: Host EKS worker nodes, application pods, and internal services. Default CIDRs:
  • 10.0.10.0/24 (254 IPs per subnet)
  • 10.0.20.0/24
Deployed Across: 2 availability zones (configurable) Key Characteristics:
  • No public IP assignment
  • No direct internet access
  • Traffic routed within VPC or through VPC endpoints
  • Used for EKS control plane and worker nodes
Workloads:
  • EKS worker nodes
  • Application pods (backend API, Celery workers)
  • Internal load balancers
  • Bastion hosts

2. Database Subnets

Purpose: Completely isolated subnets for RDS databases. Default CIDRs:
  • 10.0.100.0/24
  • 10.0.200.0/24
Deployed Across: 2 availability zones (required for RDS Multi-AZ) Key Characteristics:
  • Fully isolated from internet
  • Only accessible from EKS nodes via security groups
  • Separate route table with no routes (isolated)
  • Used exclusively for database instances
Workloads:
  • RDS PostgreSQL instances
  • Database replicas
  • Read replicas (if configured)

Route Tables

Route tables control how traffic flows between subnets and external networks.

Private Route Table

Associated With: Private subnets Routes:
  • Local VPC traffic only (automatic)
  • No internet gateway route (no internet access)
  • Enterprise connectivity via VPC peering or VPN (configured separately)
Purpose: Keeps application workloads isolated from internet while allowing VPC-internal communication.

Database Route Table

Associated With: Database subnets Routes:
  • Local VPC traffic only (automatic)
  • No other routes (maximum isolation)
Purpose: Ensures databases are completely isolated and only accessible via security group rules.

Security Groups

Security groups act as virtual firewalls controlling inbound and outbound traffic for resources.

1. EKS Cluster Security Group

Attached To: EKS control plane Ingress Rules:
PortProtocolSourceDescription
443TCPEKS Nodes SGHTTPS API server from nodes
443TCPAdditional SGsHTTPS from bastion/other resources
443TCPVPC CIDRHTTPS from all VPC resources
2379-2380TCPSelfetcd client/server communication
12379TCPSelfetcd metrics
Egress Rules:
  • All traffic: 0.0.0.0/0 (required for cluster operations and AWS API calls)
Purpose: Controls access to the Kubernetes API server and enables control plane components to communicate.

2. EKS Nodes Security Group

Attached To: EKS worker nodes (EC2 instances) Ingress Rules:
Port RangeProtocolSourceDescription
AllTCPSelfNode-to-node communication
AllTCPVPC CIDRCommunication from cluster
1025-65535TCPSelfDynamic port range for services
AllUDPSelfPod-to-pod UDP traffic
10250TCPVPC CIDRkubelet API
30000-32767TCPSelfNodePort services
443TCPVPC CIDRHTTPS API access
2379-2380TCPVPC CIDRetcd communication
12379TCPVPC CIDRetcd metrics
Egress Rules:
  • All traffic to VPC CIDR (allows communication within VPC)
Purpose: Enables Kubernetes networking, pod-to-pod communication, and service exposure.
Port 10250: The kubelet API port is critical for Kubernetes operations. The control plane uses this port to execute commands on nodes, collect metrics, and manage pod lifecycle.

3. RDS Security Group

Attached To: RDS database instances Ingress Rules:
PortProtocolSourceDescription
5432TCPEKS Nodes SGPostgreSQL from application pods
Egress Rules:
  • All traffic to VPC CIDR
Purpose: Restricts database access to only EKS worker nodes (application pods).
Database Isolation: The RDS security group only allows traffic from EKS nodes. Direct access from developer workstations requires SSH tunneling through the bastion host or VPN configuration.

4. ALB Security Group (Internal)

Attached To: Internal Application Load Balancer Ingress Rules:
PortProtocolSourceDescription
80TCPFrontend ALB SGHTTP from frontend
443TCPFrontend ALB SGHTTPS from frontend
443TCPBastion SGHTTPS from bastion (optional)
Egress Rules:
  • All traffic: 0.0.0.0/0 (ALB needs to reach target pods)
Purpose: Controls access to the backend API load balancer.

5. Frontend ALB Security Group

Attached To: Frontend Application Load Balancer Ingress Rules:
PortProtocolSourceDescription
443TCPVPC CIDRHTTPS from VPC resources
443TCPBastion SGHTTPS from bastion (optional)
Egress Rules:
  • All traffic: 0.0.0.0/0 (ALB needs to reach target pods)
Purpose: Controls access to the frontend application.

6. VPC Endpoints Security Group

Attached To: All VPC interface endpoints Ingress Rules:
PortProtocolSourceDescription
443TCPVPC CIDRHTTPS from all VPC resources
Egress Rules:
  • All traffic: 0.0.0.0/0
Purpose: Allows VPC resources to access AWS services via private endpoints.

VPC Endpoints

VPC endpoints enable private connectivity to AWS services without requiring internet access or NAT gateways.

Gateway Endpoints

S3 Endpoint

Type: Gateway endpoint (routes added to route tables) Service: com.amazonaws.{region}.s3 Purpose: Private access to S3 buckets Use Cases:
  • Application file storage and retrieval
  • ECR image layer storage (ECR uses S3 backend)
  • Log archival and backups
  • Static asset delivery

Interface Endpoints

Interface endpoints create Elastic Network Interfaces (ENIs) in your subnets with private IP addresses.

ECR Endpoints

Services:
  • com.amazonaws.{region}.ecr.dkr - Docker Registry API
  • com.amazonaws.{region}.ecr.api - ECR control plane API
Purpose: Pull container images from ECR without internet access Use Cases:
  • EKS nodes pulling container images
  • CI/CD pipelines accessing ECR
  • Image scanning and vulnerability checks
Why Both Are Needed:
  • ecr.dkr: Docker daemon communicates with ECR registry
  • ecr.api: ECR control plane operations (list images, get authorization tokens)

EC2 Endpoint

Service: com.amazonaws.{region}.ec2 Purpose: EC2 API operations from private subnets Use Cases:
  • EKS node bootstrap scripts calling EC2 APIs
  • Auto Scaling Group operations
  • ENI attachment and management
  • Instance metadata access

STS Endpoint

Service: com.amazonaws.{region}.sts Purpose: AWS Security Token Service for IAM role assumption Use Cases:
  • IRSA (IAM Roles for Service Accounts) in EKS
  • Pod service accounts assuming IAM roles
  • Temporary credential generation
  • Cross-account access
Critical For: EKS workloads using IAM roles - without this endpoint, pods cannot assume IAM roles.

EKS Endpoint

Service: com.amazonaws.{region}.eks Purpose: EKS control plane API access Use Cases:
  • kubectl commands from bastion host
  • EKS cluster management operations
  • eksctl operations
  • Cluster configuration updates

Elastic Load Balancing Endpoint

Service: com.amazonaws.{region}.elasticloadbalancing Purpose: Load balancer management APIs Use Cases:
  • AWS Load Balancer Controller creating ALBs
  • Target group registration
  • Health check configuration
  • Listener rule management

Secrets Manager Endpoint

Service: com.amazonaws.{region}.secretsmanager Purpose: Retrieve secrets from AWS Secrets Manager Use Cases:
  • Application pods fetching database credentials
  • API key retrieval
  • Configuration secret access
  • Certificate management

SSM Endpoints

Services:
  • com.amazonaws.{region}.ssm - Systems Manager
  • com.amazonaws.{region}.ssmmessages - Session Manager messaging
  • com.amazonaws.{region}.ec2messages - SSM Agent communication
Purpose: AWS Systems Manager Session Manager connectivity Use Cases:
  • SSH-less bastion host access
  • Node troubleshooting via Session Manager
  • Secure remote command execution
  • Session logging and auditing
Critical For: Bastion host connectivity without SSH or public IPs.

Private DNS

All interface endpoints have Private DNS enabled, which means:
  • AWS service calls automatically resolve to the VPC endpoint IP
  • No application code changes required
  • Services use standard AWS SDK endpoints
  • Traffic stays within VPC
Example:
# This code automatically uses VPC endpoint
import boto3
s3_client = boto3.client('s3')  # Resolves to VPC endpoint, not public internet

VPC Flow Logs

Flow logs capture network traffic metadata for security analysis and troubleshooting. Log Destination: CloudWatch Logs group /vpc/{vpc_id}/flow-logs Retention: 14 days Traffic Captured: ALL (accepted and rejected traffic) Aggregation Interval: 60 seconds Logged Fields:
  • Source and destination IP addresses
  • Source and destination ports
  • Protocol
  • Number of packets
  • Number of bytes
  • Action (ACCEPT or REJECT)
  • Timestamp
Use Cases:
  • Security incident investigation
  • Network troubleshooting
  • Compliance auditing
  • Traffic pattern analysis
  • Unusual traffic detection
Example Flow Log Entry:
2 123456789012 eni-abc123 10.0.10.50 10.0.100.20 45234 5432 6 10 1024 1609459200 1609459260 ACCEPT OK
Interpretation:
  • Source: 10.0.10.50:45234 (EKS node)
  • Destination: 10.0.100.20:5432 (RDS database)
  • Protocol: 6 (TCP)
  • Action: ACCEPT (security groups allowed)

Module Configuration

Basic Configuration (New VPC)

module "networking" {
  source = "./modules/networking"

  name_prefix = "artos-production"
  
  # VPC configuration
  vpc_cidr = "10.0.0.0/16"
  
  # Subnet configuration
  private_subnet_cidrs  = ["10.0.10.0/24", "10.0.20.0/24"]
  database_subnet_cidrs = ["10.0.100.0/24", "10.0.200.0/24"]
  
  # Enable VPC endpoints
  enable_vpc_endpoints = true
  
  tags = {
    Environment = "production"
  }
}

Configuration with Existing VPC

module "networking" {
  source = "./modules/networking"

  name_prefix = "artos-production"
  
  # Use existing VPC
  vpc_id   = "vpc-existing123"
  vpc_cidr = "10.0.0.0/16"  # Must match existing VPC CIDR
  
  # Use existing subnets or create new ones
  private_subnet_ids  = ["subnet-abc123", "subnet-def456"]
  database_subnet_ids = ["subnet-ghi789", "subnet-jkl012"]
  
  # Enable VPC endpoints in existing VPC
  enable_vpc_endpoints = true
  
  tags = {
    Environment = "production"
  }
}

Production Configuration

module "networking_production" {
  source = "./modules/networking"

  name_prefix = "artos-production"
  
  # VPC with larger CIDR for growth
  vpc_cidr = "10.0.0.0/16"
  
  # Multiple AZs for high availability
  private_subnet_cidrs  = [
    "10.0.10.0/24",   # AZ1 - 254 IPs
    "10.0.20.0/24",   # AZ2 - 254 IPs
    "10.0.30.0/24"    # AZ3 - 254 IPs
  ]
  
  database_subnet_cidrs = [
    "10.0.100.0/24",  # AZ1
    "10.0.200.0/24",  # AZ2
    "10.0.210.0/24"   # AZ3
  ]
  
  # Enable all VPC endpoints for private connectivity
  enable_vpc_endpoints = true
  
  # Additional security groups that can access EKS (e.g., bastion)
  additional_security_group_ids = [
    module.bastion.bastion_security_group_id
  ]
  
  # Bastion access to ALBs
  bastion_security_group_id = module.bastion.bastion_security_group_id
  
  tags = {
    Environment = "production"
    ManagedBy   = "terraform"
    CostCenter  = "engineering"
  }
}

Development Configuration

module "networking_dev" {
  source = "./modules/networking"

  name_prefix = "artos-dev"
  
  # Smaller VPC for development
  vpc_cidr = "10.1.0.0/16"
  
  # Single AZ for development
  private_subnet_cidrs  = ["10.1.10.0/24"]
  database_subnet_cidrs = ["10.1.100.0/24"]
  
  # VPC endpoints optional for dev (can reduce costs)
  enable_vpc_endpoints = true
  
  tags = {
    Environment = "development"
    AutoShutdown = "true"
  }
}

Security Best Practices

1. Network Segmentation

The module implements defense-in-depth through multiple isolation layers: Subnet Isolation:
  • Application workloads in private subnets
  • Databases in isolated database subnets
  • No direct communication between tiers without security group rules
Route Table Isolation:
  • Database subnets have no routes (local traffic only)
  • Private subnets have no internet gateway route
  • Each tier has dedicated route table

2. Security Group Rules

Follow the principle of least privilege: Good Practices:
  • Specific port ranges instead of “all ports”
  • Reference security groups instead of CIDR blocks when possible
  • Document each rule’s purpose in descriptions
  • Regular audit of unused rules
Example:
# Good - specific and documented
ingress {
  from_port       = 5432
  to_port         = 5432
  protocol        = "tcp"
  security_groups = [aws_security_group.eks_nodes.id]
  description     = "PostgreSQL access from EKS pods only"
}

# Avoid - too permissive
ingress {
  from_port   = 0
  to_port     = 65535
  protocol    = "tcp"
  cidr_blocks = ["0.0.0.0/0"]
}

3. VPC Endpoint Security

VPC endpoints should be protected:
  • Dedicated security group for endpoints
  • Restrict access to VPC CIDR only
  • Enable Private DNS for transparent access
  • Monitor endpoint usage via VPC Flow Logs

4. Flow Log Analysis

Regularly analyze VPC Flow Logs for: Security Threats:
  • Rejected traffic patterns (potential attacks)
  • Unusual source IPs
  • Port scanning attempts
  • Data exfiltration indicators
Example CloudWatch Insights Query:
fields @timestamp, srcAddr, dstAddr, dstPort, action
| filter action = "REJECT"
| stats count() by srcAddr, dstPort
| sort count desc
| limit 20

5. CIDR Planning

Plan IP address space carefully: Recommendations:
  • Use RFC 1918 private ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
  • Leave room for growth (don’t use /24 for entire VPC)
  • Avoid overlapping CIDRs with corporate networks
  • Reserve ranges for future subnets
Example Allocation:
VPC: 10.0.0.0/16 (65,536 IPs)
├── Private Subnets: 10.0.0.0/20 (4,096 IPs)
├── Database Subnets: 10.0.100.0/22 (1,024 IPs)
├── Reserved for Future: 10.0.104.0/22 (1,024 IPs)
└── Management: 10.0.255.0/24 (256 IPs)

Troubleshooting

Cannot Access AWS Services from Pods

Symptoms: Pods fail to access S3, ECR, Secrets Manager, etc. Troubleshooting:
  1. Verify VPC Endpoints are Created:
aws ec2 describe-vpc-endpoints \
  --filters "Name=vpc-id,Values=<vpc-id>" \
  --query 'VpcEndpoints[*].[ServiceName,State]' \
  --output table
  1. Check Endpoint Security Group:
aws ec2 describe-security-groups \
  --group-ids <endpoint-sg-id> \
  --query 'SecurityGroups[0].IpPermissions'
  1. Verify Private DNS is Enabled:
aws ec2 describe-vpc-endpoints \
  --vpc-endpoint-ids <endpoint-id> \
  --query 'VpcEndpoints[0].PrivateDnsEnabled'
# Should return: true
  1. Test from Pod:
kubectl run test-pod --image=amazon/aws-cli --rm -it -- /bin/bash
# Inside pod:
nslookup s3.amazonaws.com  # Should resolve to VPC endpoint private IP
aws s3 ls  # Should work without internet access

RDS Connection Failures

Symptoms: Applications cannot connect to RDS database. Troubleshooting:
  1. Verify Security Group Rules:
aws ec2 describe-security-groups \
  --group-ids <rds-sg-id> \
  --query 'SecurityGroups[0].IpPermissions[?ToPort==`5432`]'
  1. Check if Source is EKS Nodes Security Group:
# Should show EKS nodes security group as source
  1. Test Connectivity from Pod:
kubectl run -it --rm debug --image=postgres:14 --restart=Never -- \
  psql -h <rds-endpoint> -U <username> -d postgres
  1. Check VPC Flow Logs:
# Look for REJECT actions on port 5432
aws logs filter-log-events \
  --log-group-name /vpc/<vpc-id>/flow-logs \
  --filter-pattern "[version, account, eni, source, destination, srcport, destport=\"5432\", protocol, packets, bytes, windowstart, windowend, action=\"REJECT\", flowlogstatus]"

Bastion Cannot Access EKS API

Symptoms: kubectl commands fail from bastion host. Solutions:
  1. Verify Bastion in Additional Security Groups:
additional_security_group_ids = [
  module.bastion.bastion_security_group_id
]
  1. Check EKS Security Group Ingress:
aws ec2 describe-security-groups \
  --group-ids <eks-cluster-sg> \
  --query 'SecurityGroups[0].IpPermissions[?ToPort==`443`]'
  1. Verify EKS VPC Endpoint:
aws ec2 describe-vpc-endpoints \
  --filters "Name=service-name,Values=com.amazonaws.<region>.eks" \
  --query 'VpcEndpoints[0].[State,PrivateDnsEnabled]'
  • EKS Module - Uses VPC and subnets for cluster deployment
  • RDS Module - Uses database subnets and security groups
  • Bastion Module - Deployed in private subnets with VPC endpoint access
  • IAM Module - IRSA requires STS VPC endpoint

Module Maintenance: This module is compatible with Terraform 1.0+ and AWS Provider 5.x. VPC endpoints and security groups follow AWS best practices for private cloud deployments. Review and adjust CIDR blocks based on your network architecture requirements before deployment.