
AWS Site-to-Site VPN은 AWS VPC와 On-Premise 네트워크 간에 암호화된 IPsec 터널을 구성하여 서로 다른 네트워크를 안전하게 연결할 수 있도록 하는 서비스입니다. 일반적인 환경에서는 실제 IDC나 사내 네트워크의 VPN 장비를 Customer Gateway로 사용하지만, 이번 실습에서는 별도의 VPC와 EC2 인스턴스를 On-Premise 환경으로 구성하여 실제 Hybrid Cloud 네트워크와 유사한 환경을 구현합니다.
Cloud 환경에는 Public/Private Subnet과 Virtual Private Gateway를 구성하고, On-Premise 환경에는 별도의 VPC와 EC2 인스턴스를 구성합니다. On-Premise EC2는 Elastic IP를 할당받아 고정된 공인 IP를 가지며, strongSwan을 설치하여 AWS Site-to-Site VPN의 Customer Gateway 역할을 수행하도록 구성합니다.
VPN 연결에는 IKEv2와 Pre-Shared Key 기반 인증을 사용하며, strongSwan의 기존 ipsec.conf 및 ipsec 명령 기반의 Legacy 방식 대신 swanctl.conf와 VICI 인터페이스를 사용하는 swanctl 기반 방식으로 VPN 연결을 구성합니다. 이를 통해 두 개의 AWS VPN Tunnel에 대한 IKE SA와 CHILD SA를 정의하고, 각 Tunnel을 독립적인 XFRM Interface와 연결하여 Route-based 형태로 트래픽을 전달합니다.
또한 NAT Traversal(NAT-T), DPD, Rekey, Traffic Selector 등의 IPsec 설정과 Linux IP Forwarding 및 XFRM Interface Routing을 함께 구성하여 On-Premise 네트워크와 Cloud VPC 사이의 양방향 통신이 가능하도록 구성합니다.
VPC는 Cloud와 On-Premise용 VPC를 각각 생성합니다.
Public Subnet과 Private Subnet을 구성합니다. Availability Zone A에 구성합니다.




| VPC | Subnet | Route Table | Gateway |
|---|---|---|---|
| demo-cloud-vpc | demo-cloud-public-a | demo-cloud-public-rtb | demo-cloud-igw |
| demo-cloud-private-a | demo-cloud-private-a-rtb | demo-cloud-natgw-a |
Public Subnet과 Private Subnet을 구성합니다. Availability Zone A에 구성합니다.





| VPC | Subnet | Route Table | Gateway |
|---|---|---|---|
| demo-onprem-vpc | demo-onprem-public-a | demo-onprem-public-rtb | demo-onprem-igw |
| demo-onprem-private-a | demo-onprem-private-a-rtb | demo-onprem-natgw-a |
Inbound
| Type | Port Range | Source | Description |
|---|---|---|---|
| SSH | 22 | 0.0.0.0/0 | EC2 접근 |
| ALL ICMP - IPv4 | ALL | 0.0.0.0/0 | ICMP |
Outbound
| Type | Port Range | Source | Description |
|---|---|---|---|
| HTTP | 80 | 0.0.0.0/0 | 패키지 다운로드 및 외부 통신 |
| HTTPS | 443 | 0.0.0.0/0 | 패키지 다운로드 및 API 통신 |
| ALL ICMP - IPv4 | ALL | 0.0.0.0/0 | ICMP |
Inbound
| Type | Port Range | Source | Description |
|---|---|---|---|
| SSH | 22 | 0.0.0.0/0 | EC2 접근 |
| ALL ICMP - IPv4 | ALL | 0.0.0.0/0 | ICMP |
Outbound
| Type | Port Range | Source | Description |
|---|---|---|---|
| HTTP | 80 | 0.0.0.0/0 | 패키지 다운로드 및 외부 통신 |
| HTTPS | 443 | 0.0.0.0/0 | 패키지 다운로드 및 API 통신 |
| ALL ICMP - IPv4 | ALL | 0.0.0.0/0 | ICMP |
| Custom UDP | 500 | 0.0.0.0/0 | IKE 통신 연결 |
| Custom UDP | 4500 | 0.0.0.0/0 | NAT-T (NAT Traversal) NAT 감지 |






User Data
#!/bin/bash
dnf update -y
dnf upgrade -y
dnf install --allowerasing -y jq curl wget unzip vim
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
sudo dnf install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm
sed -i 's|PasswordAuthentication no|PasswordAuthentication yes|g' /etc/ssh/sshd_config
systemctl restart sshd
echo 'Skill53##' | passwd --stdin ec2-user
echo 'Skill53##' | passwd --stdin root






User Data
#!/bin/bash
dnf update -y
dnf upgrade -y
dnf install --allowerasing -y jq curl wget unzip vim
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
sudo dnf install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm
sed -i 's|PasswordAuthentication no|PasswordAuthentication yes|g' /etc/ssh/sshd_config
systemctl restart sshd
echo 'Skill53##' | passwd --stdin ec2-user
echo 'Skill53##' | passwd --stdin root
On-Premise VM에 Elastic IP를 할당하여 Customer Gateway에서 사용할 공인 IP를 고정합니다.








IP Address에 On-Premise Public IP 넣습니다.

Cloud VPC의 Private Subnet에 Destination IP 부분에 On-Premise VPC CIDR 넣어줍니다.








Amazon Linux 2023에서 strongSwan 패키지를 설치하기 위한 SPAL Repository를 활성화합니다.
sudo dnf install -y spal-release
AWS Site-to-Site VPN과 IPsec Tunnel을 구성하기 위해 strongSwan을 설치합니다.
sudo dnf install -y strongswan
strongSwan 서비스를 시작하고 시스템 부팅 시 자동으로 실행되도록 설정합니다.
sudo systemctl enable --now strongswan
VPN Gateway 역할을 수행할 수 있도록 IP Forwarding을 활성화하고 Reverse Path Filtering을 비활성화합니다.
sudo tee /etc/sysctl.d/99-vpn.conf > /dev/null <<'EOF'
net.ipv4.ip_forward = 1
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.ens5.rp_filter = 0
net.ipv4.conf.xfrm1.rp_filter = 0
net.ipv4.conf.xfrm2.rp_filter = 0
EOF
sysctl에 설정한 네트워크 Kernel Parameter를 시스템에 적용합니다.
sudo sysctl --system
AWS의 두 VPN Tunnel을 연결할 XFRM Interface와 Cloud VPC로 향하는 Route를 구성합니다.
sudo tee /usr/local/bin/setup-xfrm.sh > /dev/null <<'EOF'
#!/bin/bash
sleep 5
WAN_IF=$(ip -4 route show default | awk 'NR==1 {print $5}')
ip link del xfrm1 2>/dev/null || true
ip link del xfrm2 2>/dev/null || true
ip link add xfrm1 type xfrm dev $WAN_IF if_id 1
ip link set xfrm1 mtu 1400 up
ip link add xfrm2 type xfrm dev $WAN_IF if_id 2
ip link set xfrm2 mtu 1400 up
ip route replace 10.0.0.0/16 dev xfrm1 metric 100
ip route append 10.0.0.0/16 dev xfrm2 metric 200
EOF
생성한 XFRM 설정 Script를 실행할 수 있도록 실행 권한을 부여합니다.
sudo chmod +x /usr/local/bin/setup-xfrm.sh
재부팅 이후에도 XFRM Interface와 Route가 자동으로 구성되도록 Systemd Service를 생성합니다.
sudo tee /etc/systemd/system/xfrm-setup.service > /dev/null <<'EOF'
[Unit]
Description=Setup XFRM Interfaces and Routes for IPsec
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/setup-xfrm.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
새롭게 생성한 Systemd Service 설정을 다시 불러옵니다.
sudo systemctl daemon-reload
XFRM 설정 Service를 실행하고 부팅 시 자동으로 실행되도록 설정합니다.
sudo systemctl enable --now xfrm-setup.service
첫 번째 VPN Tunnel에 사용할 xfrm1 Interface의 상태를 확인합니다.
ip -br link show xfrm1

두 번째 VPN Tunnel에 사용할 xfrm2 Interface의 상태를 확인합니다.
ip -br link show xfrm2

Cloud VPC로 향하는 트래픽이 XFRM Interface를 사용하도록 설정되었는지 확인합니다.
ip route show 10.0.0.0/16

VPN 구성에서 사용할 AWS Resource Name과 각 Tunnel의 Pre-Shared Key를 변수로 지정합니다.
CLOUD_VPC_NAME="demo-cloud-vpc"
ONPREM_VPC_NAME="demo-onprem-vpc"
ONPREM_VM_NAME="demo-onprem-vm"
S2S_VPN_NAME="demo-cloud-onprem-vpn"
TUNNEL1_PSK="demokey1"
TUNNEL2_PSK="demokey2"
AWS CLI를 이용해 VPC CIDR, EC2 IP, VPN Connection ID와 Tunnel Outside IP를 조회합니다.
CLOUD_VPC_CIDR=$(aws ec2 describe-vpcs --filters "Name=tag:Name,Values=$CLOUD_VPC_NAME" --query 'Vpcs[0].CidrBlock' --output text)
ONPREM_VPC_CIDR=$(aws ec2 describe-vpcs --filters "Name=tag:Name,Values=$ONPREM_VPC_NAME" --query 'Vpcs[0].CidrBlock' --output text)
ONPREM_VM_PUBLIC_IP=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=$ONPREM_VM_NAME" "Name=instance-state-name,Values=running" --query 'Reservations[0].Instances[0].PublicIpAddress' --output text)
ONPREM_VM_PRIVATE_IP=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=$ONPREM_VM_NAME" "Name=instance-state-name,Values=running" --query 'Reservations[0].Instances[0].PrivateIpAddress' --output text)
S2S_VPN_CONNECTION_ID=$(aws ec2 describe-vpn-connections --filters "Name=tag:Name,Values=$S2S_VPN_NAME" --query 'VpnConnections[0].VpnConnectionId' --output text)
VPN_TUNNEL_OUTSIDE_IP1=$(aws ec2 describe-vpn-connections --vpn-connection-ids $S2S_VPN_CONNECTION_ID --query 'VpnConnections[0].VgwTelemetry[0].OutsideIpAddress' --output text)
VPN_TUNNEL_OUTSIDE_IP2=$(aws ec2 describe-vpn-connections --vpn-connection-ids $S2S_VPN_CONNECTION_ID --query 'VpnConnections[0].VgwTelemetry[1].OutsideIpAddress' --output text)
swanctl.conf에 두 개의 AWS VPN Tunnel에 대한 IKEv2, IPsec, PSK 및 XFRM 설정을 정의합니다.
sudo tee /etc/strongswan/swanctl/swanctl.conf > /dev/null <<EOF
connections {
aws-tunnel1 {
version = 2
local_addrs = ${ONPREM_VM_PRIVATE_IP}
remote_addrs = ${VPN_TUNNEL_OUTSIDE_IP1}
proposals = aes256-sha256-prfsha256-modp2048
rekey_time = 28800s
reauth_time = 0s
dpd_delay = 30s
encap = yes
mobike = no
local {
auth = psk
id = ${ONPREM_VM_PUBLIC_IP}
}
remote {
auth = psk
id = ${VPN_TUNNEL_OUTSIDE_IP1}
}
children {
aws-tunnel1-child {
local_ts = ${ONPREM_VPC_CIDR}
remote_ts = ${CLOUD_VPC_CIDR}
esp_proposals = aes256-sha256-modp2048
rekey_time = 3600s
rekey_bytes = 0
rekey_packets = 0
mode = tunnel
if_id_in = 1
if_id_out = 1
start_action = start
close_action = restart
dpd_action = restart
}
}
}
aws-tunnel2 {
version = 2
local_addrs = ${ONPREM_VM_PRIVATE_IP}
remote_addrs = ${VPN_TUNNEL_OUTSIDE_IP2}
proposals = aes256-sha256-prfsha256-modp2048
rekey_time = 28800s
reauth_time = 0s
dpd_delay = 30s
encap = yes
mobike = no
local {
auth = psk
id = ${ONPREM_VM_PUBLIC_IP}
}
remote {
auth = psk
id = ${VPN_TUNNEL_OUTSIDE_IP2}
}
children {
aws-tunnel2-child {
local_ts = ${ONPREM_VPC_CIDR}
remote_ts = ${CLOUD_VPC_CIDR}
esp_proposals = aes256-sha256-modp2048
rekey_time = 3600s
rekey_bytes = 0
rekey_packets = 0
mode = tunnel
if_id_in = 2
if_id_out = 2
start_action = start
close_action = restart
dpd_action = restart
}
}
}
}
secrets {
ike-tunnel1 {
id-local = ${ONPREM_VM_PUBLIC_IP}
id-remote = ${VPN_TUNNEL_OUTSIDE_IP1}
secret = "${TUNNEL1_PSK}"
}
ike-tunnel2 {
id-local = ${ONPREM_VM_PUBLIC_IP}
id-remote = ${VPN_TUNNEL_OUTSIDE_IP2}
secret = "${TUNNEL2_PSK}"
}
}
EOF
Pre-Shared Key가 포함된 VPN 설정 파일을 root 사용자만 접근할 수 있도록 제한합니다.
sudo chmod 600 /etc/strongswan/swanctl/swanctl.conf
변경한 VPN 설정을 적용하기 위해 strongSwan 서비스를 재시작합니다.
sudo systemctl restart strongswan
swanctl.conf에 정의한 VPN Connection과 인증 정보를 strongSwan에 로드합니다.
sudo swanctl --load-all

현재 연결된 IKE SA와 CHILD SA의 상태를 확인하여 VPN Tunnel이 정상적으로 연결되었는지 확인합니다.
sudo swanctl --list-sas


Cloud VM에 접근하여 On-Premise VM으로 Ping을 요청하여 VPN을 통한 통신을 확인합니다.
ping 192.168.10.10 -c 4

On-Premise VM에서 ICMP 패킷을 캡처하여 Cloud VM에서 전달된 요청을 확인합니다.
sudo tcpdump -i any -p icmp

On-Premise VM에 접근하여 Cloud VM으로 Ping을 요청하여 VPN을 통한 통신을 확인합니다.
ping 10.0.20.20 -c 4

Cloud VM에서 ICMP 패킷을 캡처하여 On-Premise VM에서 전달된 요청을 확인합니다.
sudo tcpdump -i any -p icmp

이번 실습을 통해 AWS Site-to-Site VPN과 strongSwan을 활용하여 Cloud 환경과 가상의 On-Premise 환경을 연결하는 전체 과정을 확인할 수 있었습니다.
Cloud VPC에는 Virtual Private Gateway를 구성하고 On-Premise 환경의 EC2 인스턴스를 Customer Gateway로 사용함으로써, 실제 기업 환경에서 사용되는 Hybrid Cloud 네트워크와 유사한 Site-to-Site VPN 구조를 구성할 수 있었습니다. 또한 Elastic IP, Route Table, Security Group 등의 네트워크 구성 요소가 VPN 연결 과정에서 어떠한 역할을 수행하는지 확인할 수 있었습니다.
특히 strongSwan에서는 기존 ipsec.conf와 ipsec 명령을 사용하는 Legacy 방식 대신 swanctl.conf와 VICI 인터페이스를 사용하는 swanctl 기반 방식을 적용하였습니다. VPN 터널 자체는 IKEv2를 기반으로 구성하면서 swanctl을 통해 IKE SA와 CHILD SA, Pre-Shared Key, Traffic Selector, DPD 및 Rekey 등의 설정을 직접 관리함으로써 strongSwan의 현대적인 VPN 구성 방식을 이해할 수 있었습니다.
또한 AWS에서 제공하는 두 개의 VPN Tunnel을 각각 XFRM Interface와 연결하고 Linux Routing Table을 구성하면서 IPsec 암호화 처리와 실제 패킷 라우팅이 어떻게 연계되는지 확인할 수 있었습니다. NAT Traversal을 위한 UDP 4500 통신과 IKE 협상을 위한 UDP 500의 역할 역시 실습을 통해 확인할 수 있었습니다.
최종적으로 Cloud VM과 On-Premise VM 사이에서 양방향 ICMP 통신이 정상적으로 이루어지는 것을 확인하였으며, tcpdump와 swanctl --list-sas를 통해 VPN Tunnel의 연결 상태와 실제 네트워크 트래픽을 검증할 수 있었습니다.
이러한 과정은 AWS Site-to-Site VPN을 단순히 생성하는 것을 넘어 IKEv2, IPsec, XFRM, Routing, NAT-T와 같은 VPN의 내부 동작 구조를 이해하는 데 중요한 기반이 되며, 실제 Hybrid Cloud 환경의 네트워크 구성과 장애 분석 능력을 향상시키는 데 도움이 되었습니다.