End-to-End 암호화 기반 VPN 시스템으로, ChaCha20-Poly1305 AEAD와 Curve25519 ECDH를 사용한 안전한 네트워크 통신을 제공합니다.
본 VPN 시스템은 클라우드 환경에서 안전한 VM 간 통신을 제공하기 위해 개발되었습니다.
- 암호화: ChaCha20-Poly1305 (AEAD)
- 키 교환: Curve25519 ECDH
- 네트워크: TUN 인터페이스, UDP 프로토콜
- 보안: Secure Enclave 격리 환경
- 언어: C (libsodium)
- 백엔드: Spring Boot (Java)
End-to-End 암호화
- ChaCha20-Poly1305 AEAD로 모든 트래픽 암호화
- Curve25519 ECDH 키 교환
Secure Enclave
- 암호화 키를 격리된 프로세스에서 관리
- 메모리 보호 및 키 유출 방지
자동 재연결
- 네트워크 끊김 시 자동 재연결
- 지수 백오프 알고리즘 (1초 ~ 60초)
Keep-alive
- 30초마다 PING/PONG으로 연결 유지
- 60초 타임아웃 감지
동적 클라이언트 관리
- VPN IP 자동 할당 (10.8.0.0/24)
- 최대 254개 클라이언트 동시 지원
Spring Backend 연동
- 사용자 인증 (Spring API)
- VPN IP 자동 등록
- 웹 기반 VM 관리
┌─────────────────────────────────────────────────────┐
│ 클라이언트 │
│ ┌──────────────────────────────────────────────┐ │
│ │ VPN 클라이언트 (vpn_client) │ │
│ │ - TUN 인터페이스 (tun1: 10.8.0.x) │ │
│ │ - 암호화/복호화 │ │
│ │ - Keep-alive │ │
│ └──────────────────────────────────────────────┘ │
└──────────────────────┬──────────────────────────────┘
│ UDP 51820 (암호화)
│ 인터넷
↓
┌─────────────────────────────────────────────────────┐
│ VPN 서버 (EC2) │
│ ┌──────────────────────────────────────────────┐ │
│ │ VPN 서버 (vpn_server) │ │
│ │ - TUN 인터페이스 (tun0: 10.8.0.1) │ │
│ │ - UDP 서버 (0.0.0.0:51820) │ │
│ │ - 클라이언트 관리 │ │
│ └──────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────┐ │
│ │ Secure Enclave (enclave) │ │
│ │ - 키 관리 (VPN IP → Session Key) │ │
│ │ - 암호화/복호화 전담 │ │
│ └──────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────┐ │
│ │ Spring Backend │ │
│ │ - 사용자 인증 (DB) │ │
│ │ - VPN IP 관리 │ │
│ │ - VM 생성/관리 │ │
│ └──────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install -y build-essential libsodium-dev libcurl4-openssl-dev git
# CentOS/RHEL
sudo yum install -y gcc make libsodium-devel libcurl-devel gitgit clone https://github.com/YOUR_USERNAME/VPN.git
cd VPNmake clean
make# 즉시 활성화
sudo sysctl -w net.ipv4.ip_forward=1
# 재부팅 후에도 유지
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf# iptables
sudo iptables -A FORWARD -i tun0 -o tun0 -j ACCEPT
sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
# 규칙 저장
sudo apt-get install -y iptables-persistent
sudo netfilter-persistent save# AWS Security Group (콘솔에서 설정)
Type: Custom UDP
Port: 51820
Source: 0.0.0.0/0# Spring API와 함께 실행 (인증 활성화)
sudo ./bin/vpn_server http://localhost:8080
# 또는 개발 모드 (인증 비활성화)
sudo ./bin/vpn_server# 설치 스크립트 다운로드
curl -o install-vpn-client.sh http://YOUR_SERVER/api/vpn/install-script
chmod +x install-vpn-client.sh
# 설정 파일 다운로드 (Spring API에서 제공)
curl -o vpn_config.conf http://YOUR_SERVER/api/vpn/config/YOUR_USERNAME./install-vpn-client.sh -c vpn_config.conf스크립트가 자동으로:
- 필요한 라이브러리 설치 (libsodium, libcurl)
- 빌드 도구 설치 (gcc, make, git)
- 소스 다운로드 및 빌드
- VPN 클라이언트 실행
# VPN 인터페이스 확인
ip addr show tun1
# inet 10.8.0.x/24
# 서버 연결 테스트
ping 10.8.0.1
# 다른 클라이언트와 통신
ping 10.8.0.2sudo apt-get update
sudo apt-get install -y build-essential libsodium-dev libcurl4-openssl-dev gitgit clone https://github.com/YOUR_USERNAME/VPN.git
cd VPN
make clean
makecat > vpn_config.conf << EOF
server_address=YOUR_SERVER_IP
server_port=51820
username=YOUR_USERNAME
auto_reconnect=1
max_reconnect_attempts=10
keepalive_interval=30
pong_timeout=60
log_level=INFO
EOFsudo ./bin/vpn_client --config vpn_config.conf# Spring API 인증 사용
sudo ./bin/vpn_server http://localhost:8080
# 인증 없이 (개발 모드)
sudo ./bin/vpn_server# 서버 로그에서 확인
# 출력 예시:
# ➕ Client added:
# VPN IP: 10.8.0.2
# Username: alice# Ctrl+C
# 또는
sudo pkill vpn_serversudo ./bin/vpn_client --config vpn_config.confsudo nohup ./bin/vpn_client --config vpn_config.conf > /var/log/vpn-client.log 2>&1 &# Ctrl+C
# 또는
sudo pkill vpn_client# 포그라운드 실행 시: 터미널에 출력
# 백그라운드 실행 시:
tail -f /var/log/vpn-client.logVPN 클라이언트가 자동으로 시작되는 VM Template을 생성할 수 있습니다.
# VM에 SSH 접속
ssh user@vm-ip
# VPN 클라이언트 설치
sudo mkdir -p /opt/vpn
sudo cp vpn_client /opt/vpn/
sudo chmod +x /opt/vpn/vpn_clientsudo tee /etc/systemd/system/vpn-client.service > /dev/null << 'EOF'
[Unit]
Description=VPN Client Service
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/vpn
ExecStartPre=/opt/vpn/setup-vpn.sh
ExecStart=/opt/vpn/vpn_client --config /opt/vpn/vpn_config.conf
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
EOFsudo tee /opt/vpn/setup-vpn.sh > /dev/null << 'EOF'
#!/bin/bash
VM_ID=$(hostname | grep -oP 'vm-\K\d+' || echo "unknown")
USERNAME="vm-${VM_ID}"
sed -i "s/TEMPLATE_USERNAME/${USERNAME}/" /opt/vpn/vpn_config.conf
echo "VPN username set to: ${USERNAME}"
EOF
sudo chmod +x /opt/vpn/setup-vpn.shsudo tee /opt/vpn/vpn_config.conf > /dev/null << 'EOF'
server_address=YOUR_SERVER_IP
server_port=51820
username=TEMPLATE_USERNAME
auto_reconnect=1
max_reconnect_attempts=10
keepalive_interval=30
pong_timeout=60
log_level=INFO
EOFsudo systemctl enable vpn-client
sudo systemctl daemon-reload# 로그 정리
sudo apt-get clean
sudo rm -rf /var/log/*.log
sudo rm -f /etc/machine-id
sudo truncate -s 0 /etc/machine-id
# 히스토리 정리
history -c
rm -f ~/.bash_history
# VM 종료
sudo shutdown -h now# Proxmox 호스트에서
qm template VM_ID
# 또는 Web UI에서
# VM 우클릭 → Convert to template# CLI
qm clone TEMPLATE_ID NEW_VM_ID --name vm-NEW_VM_ID --full
qm start NEW_VM_ID
# Web UI
# Template 우클릭 → Clone서버는 명령행 인자로 Spring API URL을 받습니다:
./bin/vpn_server [SPRING_API_URL]
# 예시:
./bin/vpn_server http://localhost:8080# VPN 서버 주소
server_address=YOUR_SERVER_IP
# VPN 서버 포트
server_port=51820
# 사용자 이름 (Spring에 등록된 username)
username=alice
# 자동 재연결 활성화 (0=비활성화, 1=활성화)
auto_reconnect=1
# 최대 재연결 시도 횟수
max_reconnect_attempts=10
# Keep-alive 간격 (초)
keepalive_interval=30
# PONG 타임아웃 (초)
pong_timeout=60
# 로그 레벨 (ERROR, WARN, INFO, DEBUG)
log_level=INFO- 서버: 10.8.0.1/24
- 클라이언트: 10.8.0.2 ~ 10.8.0.254
- 최대 클라이언트: 254개
- VPN 서버: UDP 51820
- Spring API: HTTP 8080 (선택)
GET /api/vpn/validate/{username}
Response (200 OK):
{
"authorized": true,
"username": "alice"
}
Response (403 Forbidden):
{
"authorized": false,
"message": "User not active"
}
POST /api/vpn/webhook
Request:
{
"event": "client_connected",
"username": "alice",
"vpnIp": "10.8.0.5"
}
Response (200 OK)
GET /api/vpn/config/{username}
Response: vpn_config.conf 파일
GET /api/vpn/install-script
Response: install-vpn-client.sh 파일
확인 사항:
- 서버가 실행 중인지 확인
ps aux | grep vpn_server- 방화벽 포트 열림 확인
# 서버에서
sudo netstat -tulpn | grep 51820
# 0.0.0.0:51820 이어야 함
# AWS Security Group 확인
# UDP 51820 포트가 열려있는지- 네트워크 연결 확인
# 클라이언트에서
nc -vuz SERVER_IP 51820
# Connection succeeded 이어야 함- 설정 파일 확인
cat vpn_config.conf
# server_address가 올바른지 확인해결 방법:
- IP Forwarding 확인
cat /proc/sys/net/ipv4/ip_forward
# 1이어야 함
# 활성화
sudo sysctl -w net.ipv4.ip_forward=1- iptables 규칙 확인
sudo iptables -L FORWARD -v -n
# tun0 → tun0 ACCEPT 규칙이 있어야 함
# 추가
sudo iptables -A FORWARD -i tun0 -o tun0 -j ACCEPT확인 사항:
- Spring API 연결 확인
curl http://localhost:8080/api/vpn/validate/alice
# {"authorized":true} 응답이 와야 함- Spring DB에 사용자 등록 확인
SELECT * FROM vpn_users WHERE username = 'alice';- username 일치 확인
# 설정 파일
cat vpn_config.conf | grep username
# Spring DB의 username과 동일해야 함해결 방법:
NAT 설정 추가:
sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
sudo netfilter-persistent savelibsodium 없음:
sudo apt-get install -y libsodium-devlibcurl 없음:
sudo apt-get install -y libcurl4-openssl-devgcc 없음:
sudo apt-get install -y build-essential네트워크 상황에 따라 조정:
# 안정적인 네트워크
keepalive_interval=60
pong_timeout=120
# 불안정한 네트워크
keepalive_interval=15
pong_timeout=30프로덕션에서는 INFO 또는 WARN 권장:
# 개발: 모든 로그
log_level=DEBUG
# 프로덕션: 중요한 로그만
log_level=INFO-
서버 보안
- 최소 권한 원칙으로 실행
- 정기적인 보안 업데이트
- 로그 모니터링
-
키 관리
- 세션키는 메모리에만 존재 (디스크 저장 안 함)
- Enclave 프로세스 격리
- 주기적인 키 갱신 권장
-
네트워크
- 방화벽으로 불필요한 포트 차단
- Spring API는 localhost만 접근 권장
- VPN 네트워크와 인터넷 분리
https://carlota-used-averi.ngrok-free.dev
문제가 있으면 GitHub Issues에 등록해주세요.