Lewati ke isi

Network Diagram β€” Infrastruktur Produksi

Version: 1.0 Last Updated: 2026-05-26 Owner: DevOps Lead

Dokumen ini menggambarkan arsitektur jaringan, firewall rules, dan konektivitas antar komponen sistem ERP migrasi.


πŸ“Š High-Level Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                         INTERNET                                β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              β”‚
                              β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Cloudflare Tunnel                            β”‚
β”‚              (AI Orchestration, SSL Termination)                β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              β”‚
                              β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    VPC Production (10.0.0.0/16)                 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                   β”‚
β”‚  β”‚   Public Subnet β”‚     β”‚   Private Subnetβ”‚                   β”‚
β”‚  β”‚   (10.0.1.0/24) β”‚     β”‚   (10.0.2.0/24) β”‚                   β”‚
β”‚  β”‚                 β”‚     β”‚                 β”‚                   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚     β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚                   β”‚
β”‚  β”‚  β”‚  Nginx    β”‚  β”‚     β”‚  β”‚  Backend  β”‚  β”‚                   β”‚
β”‚  β”‚  β”‚  :443     β”‚  β”‚     β”‚  β”‚  NestJS   β”‚  β”‚                   β”‚
β”‚  β”‚  β”‚  :80      β”‚  β”‚     β”‚  β”‚  :3000    β”‚  β”‚                   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚     β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚                   β”‚
β”‚  β”‚                 β”‚     β”‚                 β”‚                   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚     β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚                   β”‚
β”‚  β”‚  β”‚  Firebase β”‚  β”‚     β”‚  β”‚  CDC      β”‚  β”‚                   β”‚
β”‚  β”‚  β”‚  Gateway  β”‚  β”‚     β”‚  β”‚  Monitor  β”‚  β”‚                   β”‚
β”‚  β”‚  β”‚  :443     β”‚  β”‚     β”‚  β”‚  :5000    β”‚  β”‚                   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚     β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚                   β”‚
β”‚  β”‚                 β”‚     β”‚                 β”‚                   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚                   β”‚
β”‚                          β”‚  β”‚ PostgreSQLβ”‚  β”‚                   β”‚
β”‚                          β”‚  β”‚ :5432     β”‚  β”‚                   β”‚
β”‚                          β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚                   β”‚
β”‚                          β”‚                 β”‚                   β”‚
β”‚                          β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚                   β”‚
β”‚                          β”‚  β”‚ ClickHouseβ”‚  β”‚                   β”‚
β”‚                          β”‚  β”‚ :9000     β”‚  β”‚                   β”‚
β”‚                          β”‚  β”‚ :8123     β”‚  β”‚                   β”‚
β”‚                          β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚                   β”‚
β”‚                          β”‚                 β”‚                   β”‚
β”‚                          β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚                   β”‚
β”‚                          β”‚  β”‚ Kafka     β”‚  β”‚                   β”‚
β”‚                          β”‚  β”‚ :9092     β”‚  β”‚                   β”‚
β”‚                          β”‚  β”‚ :2181     β”‚  β”‚                   β”‚
β”‚                          β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚                   β”‚
β”‚                          β”‚                 β”‚                   β”‚
β”‚                          β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚                   β”‚
β”‚                          β”‚  β”‚ Debezium  β”‚  β”‚                   β”‚
β”‚                          β”‚  β”‚ :8083     β”‚  β”‚                   β”‚
β”‚                          β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚                   β”‚
β”‚                          β”‚                 β”‚                   β”‚
β”‚                          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                   β”‚
β”‚                                                                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              β”‚
                              β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Tailscale Private Network                    β”‚
β”‚              (Ops Access: 100.64.x.x/10)                        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              β”‚
                              β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Legacy MariaDB (External)                    β”‚
β”‚              (u1566482.maria.db.*.my.id)                        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ” Security Groups & Firewall Rules

1. Public Subnet (Nginx + Firebase Gateway)

Port Protocol Source Destination Purpose
443 TCP 0.0.0.0/0 Nginx HTTPS traffic
80 TCP 0.0.0.0/0 Nginx HTTP β†’ HTTPS redirect
443 TCP 0.0.0.0/0 Firebase Gateway FCM webhook

Security Group: sg-public-web

# AWS CLI example
aws ec2 authorize-security-group-ingress \
  --group-id sg-public-web \
  --protocol tcp \
  --port 443 \
  --cidr 0.0.0.0/0

aws ec2 authorize-security-group-ingress \
  --group-id sg-public-web \
  --protocol tcp \
  --port 80 \
  --cidr 0.0.0.0/0

2. Private Subnet (Backend + Database)

Backend (NestJS)

Port Protocol Source Destination Purpose
3000 TCP Nginx SG Backend API traffic
3000 TCP Tailscale Backend Ops access
aws ec2 authorize-security-group-ingress \
  --group-id sg-backend \
  --protocol tcp \
  --port 3000 \
  --source-group sg-public-web

PostgreSQL

Port Protocol Source Destination Purpose
5432 TCP Backend SG PostgreSQL App connections
5432 TCP Tailscale PostgreSQL Ops access (psql)
aws ec2 authorize-security-group-ingress \
  --group-id sg-postgres \
  --protocol tcp \
  --port 5432 \
  --source-group sg-backend

Restrictions: - ❌ NO public access - βœ… Only from backend SG + Tailscale


ClickHouse

Port Protocol Source Destination Purpose
9000 TCP CDC Monitor SG ClickHouse Native client
8123 TCP CDC Monitor SG ClickHouse HTTP interface
8123 TCP Tailscale ClickHouse Ops access
aws ec2 authorize-security-group-ingress \
  --group-id sg-clickhouse \
  --protocol tcp \
  --port 9000 \
  --source-group sg-cdc-monitor

aws ec2 authorize-security-group-ingress \
  --group-id sg-clickhouse \
  --protocol tcp \
  --port 8123 \
  --source-group sg-cdc-monitor

Kafka

Port Protocol Source Destination Purpose
9092 TCP Debezium SG Kafka Producer/Consumer
9092 TCP CDC Monitor SG Kafka Consumer
2181 TCP Kafka (self) Kafka Zookeeper internal
aws ec2 authorize-security-group-ingress \
  --group-id sg-kafka \
  --protocol tcp \
  --port 9092 \
  --source-group sg-debezium

aws ec2 authorize-security-group-ingress \
  --group-id sg-kafka \
  --protocol tcp \
  --port 9092 \
  --source-group sg-cdc-monitor

Debezium (Kafka Connect)

Port Protocol Source Destination Purpose
8083 TCP Tailscale Debezium Connector management
8083 TCP Kafka SG Debezium Health checks
aws ec2 authorize-security-group-ingress \
  --group-id sg-debezium \
  --protocol tcp \
  --port 8083 \
  --source-group sg-kafka

CDC Monitor

Port Protocol Source Destination Purpose
5000 TCP Tailscale CDC Monitor Web dashboard
5000 TCP Public SG CDC Monitor Status polling
aws ec2 authorize-security-group-ingress \
  --group-id sg-cdc-monitor \
  --protocol tcp \
  --port 5000 \
  --source-group sg-public-web

3. Tailscale Access (Ops)

Component Tailscale IP Access
PostgreSQL 10.0.2.10 psql via tailscale up --ssh
ClickHouse 10.0.2.20 clickhouse-client
Kafka 10.0.2.30 kafka-console-consumer
Backend 10.0.2.40 SSH + port forward
CDC Monitor 10.0.2.50 http://100.64.x.x:5000

Setup:

# Install tailscale on ops machine
curl -fsSL https://tailscale.com/install.sh | sh

# Authenticate
tailscale up --ssh

# Connect to production
ssh admin@10.0.2.10  # PostgreSQL
ssh admin@10.0.2.20  # ClickHouse


πŸ”— Connection Strings

PostgreSQL

# Internal (from backend)
DATABASE_URL="postgresql://erp_app:***@10.0.2.10:5432/erp"

# External (via Tailscale)
psql "postgresql://erp_app:***@10.0.2.10:5432/erp"

ClickHouse

# Native client (from CDC monitor)
clickhouse-client --host 10.0.2.20 --port 9000 --user knavinkids --password ***

# HTTP API
curl "http://10.0.2.20:8123/?user=knavinkids&password=***"

Kafka

# From CDC monitor / Debezium
BOOTSTRAP_SERVERS="10.0.2.30:9092"

# Console consumer
kafka-console-consumer --bootstrap-server 10.0.2.30:9092 --topic erp.tenant_sparepart.transaksi

Debezium API

# From Tailscale
curl http://10.0.2.30:8083/connectors

# List connectors
curl http://10.0.2.30:8083/connectors/debezium-postgres-erp/status

🚨 Security Best Practices

1. Network Isolation

  • βœ… Database di private subnet (NO public IP)
  • βœ… Security group per komponen
  • βœ… Tailscale untuk ops access (NO bastion host)
  • βœ… Cloudflare Tunnel untuk external traffic

2. Encryption

Layer Method
In-transit (external) TLS 1.3 via Cloudflare
In-transit (internal) TLS 1.2 (backend ↔ DB)
At-rest (PostgreSQL) pgcrypto / TDE
At-rest (ClickHouse) Disk encryption
Secrets AWS Secrets Manager / dotenv

3. Access Control

# PostgreSQL roles
erp_owner     β€” schema owner (NOLOGIN)
erp_migrasi   β€” DDL migrations
erp_app       β€” runtime DML
erp_readonly  β€” SELECT only
erp_pusat     β€” central schema access

# ClickHouse roles
knavinkids    β€” app user (knavinkids database)
default       β€” admin (disabled in production)

4. Audit Logging

-- PostgreSQL
CREATE EXTENSION IF NOT EXISTS pgaudit;

-- Log all DDL
ALTER SYSTEM SET pgaudit.log = 'ddl';

-- Log DML on sensitive tables
ALTER TABLE transaksi SET (pgaudit.log = 'INSERT, UPDATE, DELETE');

πŸ“ˆ Monitoring & Alerting

Network Metrics

Metric Source Alert Threshold
Latency (backend ↔ DB) CloudWatch > 10ms
Packet loss VPC Flow Logs > 0.1%
Connection count Security Group > 80% limit
Bandwidth VPC Flow Logs > 80% capacity

Setup CloudWatch Alarm

aws cloudwatch put-metric-alarm \
  --alarm-name "PostgreSQL-High-Latency" \
  --metric-name DatabaseConnections \
  --namespace AWS/RDS \
  --statistic Average \
  --period 300 \
  --threshold 100 \
  --comparison-operator GreaterThanThreshold \
  --evaluation-periods 2 \
  --alarm-actions arn:aws:sns:region:account:alert-topic

πŸ”§ Troubleshooting

Cannot connect to PostgreSQL

# 1. Check security group
aws ec2 describe-security-groups \
  --group-ids sg-postgres \
  --query 'SecurityGroups[0].IpPermissions'

# 2. Test from backend
telnet 10.0.2.10 5432

# 3. Check PostgreSQL listening
psql -h 10.0.2.10 -U erp_app -c "SELECT 1"

Kafka consumer lag tinggi

# 1. Check consumer group
kafka-consumer-groups --bootstrap-server 10.0.2.30:9092 \
  --group clickhouse-etl-group --describe

# 2. Check network latency
ping 10.0.2.30

# 3. Check firewall rules
aws ec2 describe-security-groups \
  --group-ids sg-kafka \
  --query 'SecurityGroups[0].IpPermissions'

ClickHouse timeout

# 1. Test native port
clickhouse-client --host 10.0.2.20 --port 9000 --query "SELECT 1"

# 2. Test HTTP port
curl "http://10.0.2.20:8123/?query=SELECT+1"

# 3. Check connections
clickhouse-client --host 10.0.2.20 --query "SELECT * FROM system.connections"

πŸ“‹ Checklist Deployment

New Security Group

# Task Status
1 Define SG name & description [ ]
2 List required ports [ ]
3 Define allowed sources (SG ID / CIDR) [ ]
4 Apply via Terraform / AWS Console [ ]
5 Test connectivity [ ]
6 Update this document [ ]

New Component

# Task Status
1 Assign to public/private subnet [ ]
2 Create/attach security group [ ]
3 Configure firewall (iptables / ufw) [ ]
4 Add to Tailscale ACL [ ]
5 Update connection strings [ ]
6 Test end-to-end connectivity [ ]

πŸ”— Referensi


Appendix: Network Diagram v1.0 β€” Last reviewed 2026-05-26