Architecture
Architecture documentation including Infrastructure (02), Network (03), and Security (04).
02. Infrastructure Architecture
Overview Diagram
┌─────────────────────────────────────────────────────────────────────────────────┐
│ AWS Cloud - ap-northeast-1 │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─── Public Subnet ───┐ ┌─── Private Subnets (Multi-AZ) ────────────────┐ │
│ │ │ │ │ │
│ │ ┌─────────────┐ │ │ ┌─────────────────────────────────────────┐ │ │
│ │ │ Bastion │ │ │ │ ECS Fargate Cluster │ │ │
│ │ │ (t2.micro)│ │ │ │ ┌─────┐ ┌─────┐ ┌─────┐ ┌──────┐ │ │ │
│ │ └─────────────┘ │ │ │ │ API │ │ Web │ │Admin│ │ Push │ │ │ │
│ │ │ │ │ └─────┘ └─────┘ └─────┘ └──────┘ │ │ │
│ │ ┌─────────────┐ │ │ └─────────────────────────────────────────┘ │ │
│ │ │ IGW │ │ │ │ │
│ │ └─────────────┘ │ │ ┌─────────────────────────────────────────┐ │ │
│ │ │ │ │ Data Layer │ │ │
│ │ ┌─────────────┐ │ │ │ ┌─────────┐ ┌───────────┐ ┌─────────┐ │ │ │
│ │ │ NAT GW │◄───┼─────┼──│ │ Aurora │ │ElastiCache│ │MemoryDB│ │ │ │
│ │ │ (regional) │ │ │ │ │ MySQL │ │ Valkey │ │ Valkey │ │ │ │
│ │ └─────────────┘ │ │ │ └─────────┘ └───────────┘ └─────────┘ │ │ │
│ └─────────────────────┘ │ │ ┌─────────┐ │ │ │
│ │ │ │DocumentDB│ │ │ │
│ ┌─── GA Subnets ──────┐ │ │ └─────────┘ │ │ │
│ │ │ │ └─────────────────────────────────────────┘ │ │
│ │ ┌─────────────┐ │ └────────────────────────────────────────────────┘ │
│ │ │ ECS on EC2 │ │ │
│ │ │ Node Cluster│ │ ┌─── VPC Endpoints ────────────────────────────┐ │
│ │ │ ┌─────────┐ │ │ │ ECR.dkr, ECR.api, Logs, ECS, ECS-Agent, │ │
│ │ │ │ World │ │ │ │ ECS-Telemetry, SSM Messages, S3 │ │
│ │ │ │ Commu │ │ │ └──────────────────────────────────────────────┘ │
│ │ │ │ Battle │ │ │ │
│ │ │ │ Chat │ │ │ │
│ │ │ │ Center │ │ │ │
│ │ │ └─────────┘ │ │ │
│ │ └─────────────┘ │ │
│ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────────┘
ECS Fargate Cluster
| Service | Containers | CPU/Memory | Port |
|---|
| API | nginx + php-fpm | 1024/2048 | 8082 |
| Web | nginx + php-fpm | 1024/2048 | 8083 |
| Admin | nginx + php-fpm | 1024/2048 | 8081 |
| Push | node:24-alpine | 256/512 | 3001 |
Features: CodeDeploy Blue/Green deployment, App Auto Scaling (CPU/Memory based), Fargate Spot support (configurable)
ECS on EC2 Cluster (Game Nodes)
| Server | Protocol | Port Range | Purpose |
|---|
| World | UDP | 7551-7999 | World game logic |
| Commu | UDP | 9551-9999 | Community |
| Battle | UDP | 8551-8999 | Battle system |
| Chat | TCP | 8101-8499 | Socket.io chat |
| Center | - | 3000 (health) | Coordination |
Features: Bridge networking mode, Auto Scaling Group per node type, ECS Managed Scaling (target 100%)
Load Balancers
Internal ALB (Application Load Balancer)
CloudFront → VPC Origin → ALB (port 80)
│
├─ X-Forwarded-App: api → API TG (8082)
├─ X-Forwarded-App: web → Web TG (8083)
├─ X-Forwarded-App: admin → Admin TG (8081)
└─ X-Forwarded-App: push → Push TG (3001)Internal NLB (Network Load Balancer)
Global Accelerator → NLB
│
├─ World (UDP 7551+)
├─ Commu (UDP 9551+)
├─ Battle (UDP 8551+)
├─ Chat (TCP 8101+)
└─ Center (TCP 3000 health only)CloudFront Distributions
| Distribution | Origin | Caching |
|---|
| web | ALB (VPC Origin) | Static 7d, dynamic off |
| admin | ALB (VPC Origin) | Static 7d, dynamic off |
| api | ALB (VPC Origin) | Caching off |
| assets | S3 (OAC) | 7 days |
Global Accelerator (Custom Routing)
| Listener | Port Range | Destination |
|---|
| World | 10000-19999 | EC2 UDP 7550-7999 |
| Commu | 20000-29999 | EC2 UDP 9551-9999 |
| Battle | 30000-39999 | EC2 UDP 8550-8999 |
| Chat | 40000-48999 | EC2 TCP 8101-8499 |
S3 Buckets
| Bucket | Purpose | Lifecycle |
|---|
| *-images-tmp | Temp image uploads | 1 day |
| *-images-dest | Processed images | Indefinite |
| *-videos-tmp | Temp video uploads | 1 day |
| *-videos-quarantine | Moderation queue | 3 days |
| *-videos-dest | Approved videos | Indefinite |
| *-logs | ALB/CloudFront logs | 365 days |
| *-logs-virginia | WAF logs | 365 days |
Database Tier
| Service | Engine | Port | Features |
|---|
| Aurora | MySQL 8.0 Serverless v2 | 3307 | Auto-pause 5min, KMS |
| ElastiCache | Valkey 8.0 | 6380 | Cluster mode, TLS |
| MemoryDB | Valkey 7.2 | 6380 | Durable, ACL |
| DocumentDB | 5.0 Serverless | 27027 | TLS, audit logs |
Lambda Functions
| Function | Trigger | Purpose |
|---|
| image-validator | SQS | Image processing & moderation |
| video-validator | SQS | Video processing, start Rekognition |
| video-moderation-result | SNS | Handle Rekognition results |
| cache-invalidator | EventBridge | CloudFront invalidation |
| ga-port-mapping-resolver | Sync invoke | GA port mapping lookup |
| scale-node-service | Manual | Scale game node channels |
03. Network Architecture
VPC Diagram
┌─────────────────────────────────────────────────────────────────────────────┐
│ VPC (var.vpc_cidr) │
│ │
│ ┌──────────────────────────────────────────────────────────────────────┐ │
│ │ Public Subnet (single AZ) │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Bastion │ │ IGW │ │ NAT GW │ │ │
│ │ │ + EIP │ │ │ │ (regional) │ │ │
│ │ └─────────────┘ └─────────────┘ └──────┬──────┘ │ │
│ └──────────────────────────────────────────────┬────────────────────────┘ │
│ │ │
│ ┌──────────────────────────────────────────────┼────────────────────────┐ │
│ │ Private Subnets (Multi-AZ) │ │ │
│ │ ▼ │ │
│ │ ┌───────────────────────────────────────────────────────────────┐ │ │
│ │ │ ECS Fargate Tasks │ RDS Aurora │ ElastiCache │ │ │
│ │ │ (api/web/admin/push)│ Writer+Reader│ MemoryDB, DocDB │ │ │
│ │ └───────────────────────────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────────────────────┐ │
│ │ GA Subnets (/28 per AZ) │ │
│ │ │ │
│ │ ┌───────────────────────────────────────────────────────────────┐ │ │
│ │ │ ECS on EC2 (Game Nodes) │ │ │
│ │ │ World / Commu / Battle / Chat / Center │ │ │
│ │ └───────────────────────────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────────────────────┐ │
│ │ VPC Endpoints │ │
│ │ S3, ECR.dkr, ECR.api, Logs, ECS, ECS-Agent, ECS-Telemetry, SSM │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────────────┘
VPC Endpoints (9 total)
| Endpoint | Type | Purpose |
|---|
| s3 | Gateway | S3 access without NAT |
| ecr.dkr | Interface | Docker image pull |
| ecr.api | Interface | ECR API calls |
| logs | Interface | CloudWatch Logs |
| ecs | Interface | ECS API |
| ecs-agent | Interface | ECS Agent communication |
| ecs-telemetry | Interface | ECS telemetry |
| ssmmessages | Interface | SSM Session Manager |
Benefits: Reduces NAT Gateway data transfer costs, Improves security (traffic stays in AWS network), Lower latency for AWS service calls
Security Groups (14 total)
| SG Name | Inbound | Purpose |
|---|
| ${env}-alb | 80 from CloudFront | Internal ALB |
| ${env}-api | 8082 from ALB | API service |
| ${env}-web | 8083 from ALB | Web service |
| ${env}-admin | 8081 from ALB | Admin service |
| ${env}-push | 3001 from ALB, nodes | Push service |
| ${env}-world | UDP 7551-7999 | World server |
| ${env}-commu | UDP 9551-9999 | Community server |
| ${env}-battle | UDP 8551-8999 | Battle server |
| ${env}-chat | TCP 8101-8499 | Chat server |
| ${env}-center | 3000 (health) | Center server |
| ${env}-rds | 3307 from app SGs | Aurora MySQL |
| ${env}-elasticache | 6380 from app SGs | ElastiCache Valkey |
| ${env}-memorydb | 6380 from app SGs | MemoryDB Valkey |
| ${env}-documentdb | 27027 from app SGs | DocumentDB |
04. Security Architecture
Security Layers
┌─────────────────────────────────────────────────────────────────┐
│ Layer 1: Edge Security │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ CloudFront │ │ WAFv2 │ │ Global │ │
│ │ + TLS │ │ (Rate limit)│ │ Accelerator │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────────────┐
│ Layer 2: Network Security │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ VPC │ │ Security │ │ VPC │ │
│ │ Isolation │ │ Groups │ │ Endpoints │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────────────┐
│ Layer 3: Data Security │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ KMS │ │ Secrets │ │ TLS/Auth │ │
│ │ Encryption │ │ Manager │ │ (cache) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────────────┐
│ Layer 4: IAM Security │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ GitHub │ │ Task/Exec │ │ Scoped │ │
│ │ OIDC │ │ Roles │ │ Policies │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘WAFv2 Configuration (PHP WAF ACL)
| Rule | Type | Action | Threshold |
|---|
| Rate Limit | RateBasedRule | Block | 600 req/60s/IP |
| IP Reputation | ManagedRule | Block | - |
| Anonymous IP | ManagedRule | Block | - |
| Common Rules | ManagedRule | Block* | *SizeRestrictions_BODY = Count |
| Known Bad Inputs | ManagedRule | Block | - |
| Linux/Unix | ManagedRule | Block | - |
| SQLi | ManagedRule | Block | - |
| PHP Rules | ManagedRule | Block | - |
| Bot Control | ManagedRule | Challenge | COMMON level |
KMS Encryption
Multi-Region Key Setup
┌─────────────────────┐ ┌─────────────────────┐
│ Tokyo (Primary) │ ──────► │ Virginia (Replica) │
│ ap-northeast-1 │ │ us-east-1 │
└─────────────────────┘ └─────────────────────┘
What's Encrypted
| Resource | KMS Key | Notes |
|---|
| ECR repositories | Tokyo | Container images |
| RDS Aurora | Tokyo | Storage + Performance Insights |
| RDS master secret | Tokyo | Secrets Manager |
| ElastiCache | Tokyo | At-rest + in-transit |
| MemoryDB | Tokyo | At-rest |
| DocumentDB | Tokyo | Storage |
| S3 media buckets | Tokyo | SSE-KMS |
| S3 logs bucket | - | AES256 (ALB limitation) |
| S3 logs-virginia | Virginia | SSE-KMS |
| CloudWatch Logs | Tokyo/Virginia | Log groups |
| SQS queues | Tokyo | Lambda triggers |
| SNS topics | Tokyo | Rekognition results |
IAM Roles
| Role | Purpose | Key Permissions |
|---|
| ecs_task_role | Application permissions | S3, DynamoDB, Secrets Manager |
| ecs_execution_role | Task startup | ECR pull, Secrets, Logs |
| ecs_instance_role | EC2 node agent | EC2ContainerService, SSM |
| milu2-github-actions-infra | Infra deploy | AdministratorAccess |
| milu2-github-actions-app-deploy | App deploy | ECR/ECS/CodeDeploy/Lambda |
GitHub OIDC Security
┌──────────────┐ 1. Request token ┌──────────────┐
│ GitHub │ ──────────────────────► │ GitHub │
│ Actions │ │ OIDC │
│ Workflow │ ◄────────────────────── │ Provider │
└──────────────┘ 2. JWT token └──────────────┘
│
│ 3. AssumeRoleWithWebIdentity
▼
┌──────────────┐ ┌──────────────┐
│ AWS │ ◄───────────────────── │ IAM Role │
│ STS │ │ (trust OIDC) │
└──────────────┘ 4. Temporary creds └──────────────┘Security Features:
- No long-lived AWS credentials in GitHub
- Scoped to specific repositories
- Session duration: 1 hour max
- Thumbprint validation via
get_thumbprint.sh