리눅스 커널에 정식 채택되기 3년 전인 2017년, WireGuard 저자 Jason A. Donenfeld는 NDSS(Network and Distributed System Security Symposium)에서 이 프로토콜을 4,000줄 미만의 코드로 구현했다고 발표했어요. IPsec을 구현하는 리눅스 xfrm 서브시스템이나 OpenVPN이 얹고 있는 TLS 스택과 비교하면 감사(audit)해야 할 코드량 자체가 자릿수부터 다른 셈이에요. WireGuard로 직접 VPN 서버를 구축하는 방법은 이미 다뤘으니, 이번에는 그 뒤에 있는 논문 “WireGuard: Next Generation Kernel Network Tunnel”과 이 프로토콜이 빌려 쓴 Trevor Perrin의 Noise Protocol Framework를 근거로, 도대체 왜 이렇게 작은 코드로 이 정도 성능과 보안을 동시에 낼 수 있었는지 짚어볼게요.
WireGuard 코드는 왜 이렇게 작을까?
WireGuard가 코드베이스를 극단적으로 줄일 수 있었던 핵심은 계층을 의도적으로 무너뜨렸기 때문이에요. 논문 1절에서 저자는 리눅스의 표준 암호화 터널인 IPsec을 두고 “계층 분리 자체는 올바르지만, 이 엄격하게 올바른 계층화가 구현과 배포의 복잡도를 감당할 수 없는 수준으로 키운다(this strictly correct layering approach increases complexity and makes correct implementation and deployment prohibitive)“고 지적해요. IPsec은 키 교환(IKEv2), 변환 규칙을 담는 xfrm 레이어, 방화벽 시맨틱을 각각 별도 계층으로 분리해두는데, WireGuard는 이 분리를 걷어내고 wg0 같은 가상 인터페이스 하나에 개인키만 설정하면 키 교환·세션 관리·암호화가 전부 뒤에서 알아서 돌아가게 만들었어요.
OpenVPN 쪽 비교도 흥미로운데, 논문은 OpenVPN이 사용자 공간에서 동작하는 TLS 기반 솔루션이라 패킷을 커널과 사용자 공간 사이에서 여러 번 복사해야 하는 구조적 오버헤드를 안고 있다고 짚어요. 여기에 TLS 스택 전체와 ASN.1·x509 파서까지 끌고 들어오는데, 논문은 실제로 리눅스 커널의 x509 파서에서 발생했던 CVE-2008-1673, CVE-2016-2053 같은 취약점 사례를 직접 언급하며 “TLS 스택을 추가하는 건 이 문제를 더 악화시킬 뿐(adding a TLS stack would only make that issue worse)“이라고 못박아요. 결국 WireGuard가 작은 이유는 단순히 코드를 적게 짜서가 아니라, 애초에 옮겨올 필요 없는 복잡도(IKEv2, TLS 상태 머신, 인증서 파서)를 설계 단계에서 통째로 잘라냈기 때문이에요.
Noise의 IK 패턴이 어떻게 1-RTT 키 교환을 만들어낼까?
WireGuard의 핸드셰이크는 왕복 한 번(1-RTT)만으로 완성되며, 이는 Noise Protocol Framework의 IK 패턴을 그대로 채택한 결과예요. Noise 스펙은 각 핸드셰이크 패턴을 문자 하나로 압축해 이름 붙이는데, “I”는 개시자(initiator)의 정적 공개키가 아이덴티티 은닉을 다소 포기하더라도 첫 메시지에 즉시 실려 전송된다는 뜻이고, “K”는 응답자(responder)의 정적 공개키를 개시자가 이미 사전에 알고(Known) 있다는 뜻이에요. Noise 스펙 원문의 패턴 정의는 다음과 같아요.
IK:
<- s
...
-> e, es, s, ss
<- e, ee, se
첫 줄 <- s는 대역 외(out-of-band) 경로로 이미 교환해둔 응답자의 정적 공개키를 나타내는 사전 메시지고, 그 아래 두 줄이 실제로 오가는 메시지 두 개예요. WireGuard 논문 5.4절의 그림도 정확히 이 구조를 따라요. 개시자가 Handshake Initiation을 보내면 응답자가 Handshake Response 한 번으로 답하고, 그 직후 양쪽 모두 Transport Data를 곧바로 주고받기 시작해요. 논문은 이를 “대부분의 경우 핸드셰이크는 1-RTT 안에 완료되며, 그 뒤로 트랜스포트 데이터가 이어진다(In the majority of cases, the handshake will complete in 1-RTT, after which transport data follows)“고 못박고 있어요.
실제로 WireGuard가 쓰는 정식 Noise 프로토콜 이름은 Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s예요. 뒤에 붙은 psk2는 5.2절에서 설명하는 선택적 사전공유키(pre-shared symmetric key) 모드를 반영한 변형인데, 지금 당장 안전한 Curve25519 기반 키 교환이 훗날 양자컴퓨터로 깨질 가능성에 대비해 256비트 대칭키 한 겹을 추가로 얹을 수 있게 한 거예요. 지금 기록해둔 암호화 트래픽을 나중에 통째로 복호화하려는 “장기 저장 후 복호화” 공격을 막기 위한 장치인 셈이에요. 여기서 끝이 아니에요 — 이 짧은 두 메시지 안에서도 타임스탬프 기반 리플레이 방어, 정적 키만으로 개시 메시지를 인증하는 얕은 부인 가능성(deniability)까지 챙기고 있어, 메시지 개수는 최소화하면서 보안 속성은 오히려 촘촘하게 쌓아올린 설계라고 볼 수 있어요.
왜 암호화 어질리티를 아예 포기했을까?
WireGuard는 런타임에 암호 알고리즘을 협상하는 기능 자체를 없앴고, 논문은 이 선택을 “암호학적으로 다분히 의도적(cryptographically opinionated)“이라고 표현해요. 논문 1절 원문은 이렇게 말해요. “만약 기반 알고리즘에서 구멍이 발견되면, 모든 엔드포인트가 업데이트해야 할 것이다. 계속 이어지는 SSL/TLS 취약점의 홍수가 보여주듯, 암호 어질리티는 복잡도를 기하급수적으로 늘린다(If holes are found in the underlying primitives, all endpoints will be required to update. As shown by the continuing torrent of SSL/TLS vulnerabilities, cipher agility increases complexity monumentally).” TLS나 IKEv2처럼 협상 가능한 암호 스위트 목록을 두는 프로토콜은 그 협상 로직 자체, 그리고 다운그레이드 공격에 노출될 여지가 별도의 공격 표면으로 남는데, WireGuard는 이 표면 자체를 설계에서 지워버린 거예요.
대신 고정된 스위트 하나만 쓰는 만큼 알고리즘에 문제가 생기면 프로토콜 버전을 통째로 올리는 방식으로 대응해요. 실제로 WireGuard는 처음 발표된 Curve25519·ChaCha20Poly1305·BLAKE2s 조합을 지금까지 그대로 유지하고 있는데, 이건 협상 로직이 없어서 구현이 단순해진 결과이기도 하지만 동시에 검증 대상이 “이 알고리즘 조합 하나”로 고정된다는 뜻이기도 해요. wireguard.com 공식 페이지는 이 지점을 두고 “*Swan/IPsec이나 OpenVPN/OpenSSL 같은 거대 코드베이스는 대규모 보안 전문가 팀에게도 감당하기 벅찬 감사 대상인 반면, WireGuard는 개인 한 명이 전체를 포괄적으로 리뷰할 수 있도록 만들어졌다”고 설명하고 있어요. 결론부터 말하면 어질리티를 포기한 대가로 유연성은 줄었지만, 그 대가로 검증 가능한 공격 표면 자체가 확 줄어든 셈이에요.
실측 성능은 논문 안에서 얼마나 차이가 났을까?
논문 8절의 벤치마크에서 WireGuard는 IPsec 두 모드와 OpenVPN을 처리량·지연 두 지표 모두에서 앞섰어요. Intel Core i7-3820QM과 i7-5200U에 각각 Intel 82579LM, I218LM 기가비트 이더넷 카드를 장착한 환경에서 iperf3(1)로 30분간 측정한 결과, WireGuard는 처리량 1,011Mbps·핑 0.403ms를 기록했고, AES-GCM을 쓴 IPsec은 881Mbps·0.508ms, ChaCha20Poly1305를 쓴 IPsec은 825Mbps·0.501ms, OpenVPN은 258Mbps·1.541ms에 그쳤어요. 논문은 이 격차의 원인도 명확히 짚는데, OpenVPN과 IPsec 테스트에서는 CPU가 100% 점유된 반면 WireGuard 테스트에서는 CPU가 완전히 소진되지 않았고도 기가비트 링크를 포화시킬 수 있었다고 밝혀요.
특히 OpenVPN과의 격차가 유독 큰 이유는 사용자 공간 구조 자체에 있어요. 논문은 “OpenVPN과 WireGuard 사이의 이 엄청난 격차는 핑 시간과 처리량 양쪽 모두에서 예견된 결과인데, OpenVPN이 사용자 공간 애플리케이션이기 때문에 스케줄러 오버헤드와 커널-사용자 공간 사이의 패킷 복사에 따른 지연이 추가되기 때문(the enormous gap between OpenVPN and WireGuard is to be expected, both in terms of ping time and throughput, because OpenVPN is a user space application)“이라고 설명해요. 커널 안에서 직접 패킷을 처리하는 구조와, 4천 줄이라는 작은 코드량이 성능 수치로도 그대로 드러난 셈이에요.
이 논문의 설계가 실제 홈랩 운영에는 어떤 의미가 있을까?
이 논문에서 확인한 세 가지 설계 결정(레이어 축소, Noise IK 1-RTT, 고정 암호 스위트)은 실제 홈랩에서 WireGuard를 고를 이유를 그대로 뒷받침해요. 코드가 작다는 건 스마트폰이나 저사양 라즈베리파이처럼 자원이 빠듯한 기기에서도 감사된 구현을 믿고 올릴 수 있다는 뜻이고, 1-RTT 핸드셰이크는 WireGuard 서버를 직접 구축하는 가이드에서 다뤘던 “유휴 상태일 때는 트래픽을 전혀 만들지 않는” 조용한 프로토콜 특성과 맞닿아 있어요. 협상 과정 없이 곧바로 세션이 열리니 배터리를 아끼면서도 재연결이 빠른 거예요.
암호 스위트가 고정되어 있다는 점은 Tailscale이 WireGuard 위에 메시 네트워크를 얹는 방식을 이해하는 데도 중요한 전제가 돼요. Tailscale은 키 교환과 NAT 통과, 피어 탐색을 자동화하는 조정 계층을 얹었을 뿐, 실제 데이터 암호화는 여전히 이 논문에서 다룬 Noise IK 기반 WireGuard 프로토콜 그대로 동작해요. 즉 관리형 서비스를 쓰든 순정 WireGuard를 직접 구축하든, 트래픽을 지키는 암호학적 기반은 이 논문 한 편으로 수렴한다는 뜻이에요.
결론
WireGuard 논문이 증명한 건 “작은 코드 = 부족한 기능”이 아니라 “레이어를 걷어내고 알고리즘 협상을 포기하면 코드도 작아지고 검증도 쉬워지며 성능까지 따라온다”는 역설이었어요. Noise Protocol Framework의 IK 패턴을 빌려 1-RTT로 세션을 열고, 알고리즘 선택권을 아예 프로토콜 이름 안에 봉인해버린 이 설계 철학은 지금도 리눅스 커널 안에서, 그리고 Tailscale 같은 서비스 아래에서 그대로 돌아가고 있어요. 4천 줄짜리 VPN이 어떻게 수십만 줄짜리 IPsec 스택을 벤치마크에서 이겼는지, 그 답은 결국 “무엇을 뺐는가”에 있었던 셈이에요.
참고 자료
- Jason A. Donenfeld, “WireGuard: Next Generation Kernel Network Tunnel”, Proceedings of NDSS 2017 (Draft Revision, 2020년 6월 갱신본 기준)
- Trevor Perrin, The Noise Protocol Framework
- WireGuard 공식 사이트
자주 묻는 질문
Q1. WireGuard 논문에서 밝힌 정확한 코드 라인 수는 몇 줄인가요?
논문 초록과 결론에서 저자 Jason A. Donenfeld는 리눅스 커널용 WireGuard 구현을 4,000줄 미만(less than 4,000 lines)으로 명시하고 있고, 이 규모 덕분에 소수의 감사자만으로도 코드 전체를 검증할 수 있다고 설명해요.
Q2. WireGuard가 쓰는 Noise 패턴 이름이 정확히 뭔가요?
논문 9쪽에 명시된 정식 프로토콜 이름은 Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s로, 핸드셰이크 패턴(IKpsk2)과 타원곡선(Curve25519), 암호(ChaCha20Poly1305), 해시 함수(BLAKE2s)가 모두 이름 안에 고정되어 있어요.
Q3. 1-RTT 핸드셰이크라는 게 정확히 무슨 뜻인가요?
개시자가 첫 메시지(Handshake Initiation)를 보내고 응답자가 두 번째 메시지(Handshake Response)만 돌려주면 곧바로 양쪽 모두 암호화된 Transport Data를 주고받을 수 있는 구조를 뜻하며, 왕복 한 번으로 세션이 완성된다는 의미예요.
Q4. WireGuard 논문이 실제로 측정한 성능 수치는 어느 정도인가요?
논문 8절의 iperf3 벤치마크에서 WireGuard는 처리량 1,011Mbps, 핑 0.403ms를 기록해, OpenVPN(258Mbps, 1.541ms)은 물론 IPsec 두 모드(825~881Mbps, 0.501~0.508ms)보다도 앞섰어요.
Q5. 암호화 어질리티(cipher agility)를 포기하면 왜 더 안전해지나요?
런타임에 알고리즘을 협상하는 기능 자체가 공격 표면이 되기 때문인데, 논문은 SSL/TLS가 겪어온 끊임없는 취약점 행렬(continuing torrent of SSL/TLS vulnerabilities)을 근거로 들며 협상 로직을 아예 없애는 편이 복잡도와 위험을 동시에 줄인다고 설명해요.
Q6. WireGuard가 사전공유키(PSK) 모드를 추가로 지원하는 이유는 뭔가요?
네, 미래에 양자컴퓨터가 Curve25519를 깨뜨릴 가능성에 대비해 256비트 대칭키를 추가로 겹쳐 쓸 수 있게 한 옵션 모드로, 지금 기록되고 있는 암호화 트래픽이 나중에 통째로 복호화되는 상황을 막기 위한 방어선이에요.
관련 글


