Blog on Iterating

qweqeq

Tailscale - 로그인기반 VPN

질문으로 이해하는 Tailscale

로그인만 했는데 어떻게 서로 다른 컴퓨터가 연결될까?

대상 독자: VPN과 네트워크를 처음 접하는 사람부터 개인 서버와 Kubernetes를 운영하는 사람까지


시작하며: 단순한 의문 하나

집에 서버가 있고, 외부에서 노트북으로 그 서버에 접속하고 싶다고 가정해 본다.

보통 집 서버는 공유기 내부에 있다. 192.168.0.10 같은 사설 IP를 사용하기 때문에 외부 인터넷에서 접근할 수 없다.

일반적인 해결책으로는 포트포워딩이 있다. 그런데 Tailscale은 양쪽 컴퓨터에 프로그램을 설치하고 로그인하기만 하면 연결된다고 한다.

로그인만으로 네트워크가 만들어진다

로그인 자체가 두 컴퓨터를 물리적으로 연결하는 것은 아니다. Tailscale은 로그인한 장치들을 하나의 가상 사설 네트워크인 Tailnet에 등록합니다.

예를 들어 다음과 같습니다.

  • IP집 서버192.168.0.10 -> 100.100.0.1

  • 외부 노트북192.168.1.20 -> 100.100.0.2

두 장치는 여전히 각자의 공유기에 연결되어 있지만, Tailscale이 제공하는 별도의 IP 주소를 갖게 됩니다.

Tailscale은 서로의 장치 정보와 암호화 공개키 등을 전달하고, 장치 간 통신 경로를 찾도록 돕습니다.

따라서 두 장치가 하나의 물리적 LAN이 되는 것이 아니라, 인터넷 위에 별도의 논리적인 네트워크를 만드는 것입니다.

이것을 Overlay Network라고 부릅니다.

여기서 생기는 다음 질문

"Tailscale이 장치를 등록하고 연결을 관리한다면, Tailscale 회사의 서버를 믿어도 될까요?"

2장. Tailscale 서버를 어떻게 믿을 수 있을까?

Q. Tailscale 서버가 내 데이터를 훔쳐보는 것은 아닌가요?

Tailscale에는 서로 다른 역할을 담당하는 구성요소가 있습니다.

  • 조정 서버(Control Plane): 장치 인증, 공개키, 연결 정보, 접근 정책 관리

  • 데이터 전송 경로(Data Plane): 장치 사이에서 실제 데이터를 전달하는 경로

실제 데이터는 WireGuard를 사용하여 암호화됩니다.

일반적으로 두 장치는 직접 통신하므로 실제 데이터가 Tailscale의 조정 서버를 통과하지 않습니다.

직접 통신할 수 없어 중계 서버를 이용하더라도 WireGuard 종단 간 암호화는 유지됩니다.

하지만 여기서 중요한 보안 문제가 남습니다.

조정 서버가 악의적인 공개키를 배포한다면 어떻게 될까요?

암호화된 통신에서도 상대방의 신원을 잘못 확인하면 위험해질 수 있습니다.

Tailscale은 이러한 문제를 줄이기 위해 Tailnet Lock을 제공합니다. 이를 활성화하면 신뢰된 서명이 없는 장치 키를 거부할 수 있습니다.

또한 Headscale처럼 조정 서버 역할을 직접 운영하는 선택지도 있습니다.

이 장에서 얻은 이해

암호화된 통신을 신뢰하는 것과, 장치의 신원을 관리하는 회사를 신뢰하는 것은 서로 다른 문제입니다.

3장. VPN 내부 서비스와 인터넷 공개 서비스는 다르다

Q. Tailscale Funnel이라는 기능이 있던데, 이것은 무엇인가요?

Funnel은 Tailscale을 사용하지 않는 외부 사용자에게도 웹서비스를 공개하는 기능입니다.

그런데 혼자 사용할 목적으로 VPN을 구성했다면 굳이 인터넷 전체에 공개할 필요가 없습니다.

여기서 Serve와 Funnel을 구분할 수 있습니다.

기능접속할 수 있는 사람Tailscale 기본 연결접근 정책에서 허용한 Tailnet 장치Tailscale Serve접근 정책에서 허용한 Tailnet 사용자·장치Tailscale Funnel인터넷 사용자

예를 들어 집 서버에서 웹서비스를 실행하고 있다면 Tailscale Serve를 이용해 Tailnet 내부 사용자에게 HTTPS 주소를 제공할 수 있습니다.

다음 질문

"그런데 내 웹서비스는 브라우저에서 마이크를 사용해야 합니다. HTTPS가 필요한데, 내가 소유한 도메인을 사용해도 될까요?"

4장. VPN과 HTTPS, 도메인은 별개다

브라우저의 마이크 기능인 getUserMedia()는 일반적으로 HTTPS와 같은 보안 컨텍스트에서 사용해야 합니다. localhost 등 일부 예외도 있습니다.

그렇다고 웹서비스를 인터넷 전체에 공개해야 하는 것은 아닙니다.

예를 들어 다음 구성이 가능합니다.

  • www.example.com: 누구나 접근할 수 있는 공개 웹사이트

  • admin.example.com: Tailscale VPN 안에서만 접근할 수 있는 관리자 페이지

두 서비스 모두 HTTPS를 사용할 수 있고, 하나의 Kubernetes 클러스터에서 운영할 수도 있습니다.

Tailscale Serve는 기본적으로 Tailscale이 관리하는 *.ts.net 도메인을 이용합니다.

자체 도메인을 사용하려면 일반적으로 DNS 설정과 별도의 HTTPS 인증서 구성이 필요합니다.

Let's Encrypt의 DNS-01 인증 방식은 인터넷에서 웹서버에 직접 접근하지 않고도 도메인 소유권을 검증할 수 있습니다.

따라서 VPN 내부 서비스에도 공개적으로 신뢰받는 HTTPS 인증서를 발급할 수 있습니다.

5장. 도메인은 누가 실제 IP로 변환할까?

Q. 도메인을 고정해도 결국 DNS 서버에 접근해야 하는 것 아닌가요?

맞습니다.

브라우저는 admin.example.com이라는 이름만으로 서버를 찾을 수 없습니다. DNS를 통해 접속할 IP 주소를 알아내야 합니다.

DNS 운영 방식에는 여러 가지가 있습니다.

방식설명공개 DNSCloudflare, Route 53 등의 DNS를 이용MagicDNSTailscale 장치 이름을 Tailscale IP로 변환Split DNS특정 도메인에 대한 조회를 지정한 DNS 서버로 전달

예를 들어 공개 DNS에 다음 레코드를 등록할 수 있습니다.

admin.example.com → 100.100.0.1

이 경우 인터넷 사용자도 DNS 조회 결과를 확인할 수 있습니다.

하지만 해당 IP가 Tailscale 사설 네트워크의 주소이므로, DNS 정보를 안다고 해서 누구나 접속할 수 있는 것은 아닙니다.

다만 DNS rebinding 보호나 DNS 서비스의 정책에 따라 사설 IP 응답이 제한될 수 있습니다.

또한 Tailscale IP는 일반적으로 유지되지만 장치를 삭제하고 다시 등록하는 등의 상황에서는 변경될 수 있습니다. DNS 레코드도 이에 맞춰 관리해야 합니다.

중요한 구분

DNS는 목적지 주소를 알려주는 역할입니다.

실제 접근이 가능한지는 라우팅, VPN 연결, 방화벽과 서비스 설정이 결정합니다.

6장. 서버도 Tailscale에 접속해야 할까?

Q. 클라이언트만 Tailscale에 접속한다고 서버에 접근할 수 있는 건 아니지 않나요?

맞습니다.

서버에 접근하려면 서버 자체 또는 서버로 트래픽을 전달할 수 있는 장치가 Tailnet에 참여해야 합니다.

일반적인 서버라면 양쪽에 Tailscale을 설치합니다.

노트북(Tailscale) ↔ 집 서버(Tailscale)

하지만 Kubernetes에서는 모든 Pod에 Tailscale을 설치할 필요가 없습니다.

Tailscale Kubernetes Operator가 Proxy Pod를 생성하도록 구성할 수 있습니다.

통신 경로는 다음과 같습니다.

노트북 → Tailscale → Proxy Pod → Kubernetes Service → App Pod

여기서 Proxy Pod가 Tailscale에 참여하는 장치 역할을 합니다.

애플리케이션 Pod는 일반적인 Kubernetes 네트워크를 그대로 사용할 수 있습니다.

그런데 여기서 더 근본적인 질문이 생깁니다.

"Proxy Pod는 외부에서 들어오는 패킷을 도대체 어떻게 받는 걸까요? 포트포워딩도 없는데 말입니다."

이 질문에 답하려면 먼저 Linux의 라우팅과 네트워크 인터페이스를 이해해야 합니다.

7장. Tailscale은 운영체제의 라우팅을 어떻게 바꿀까?

Q. Tailscale을 설치하면 라우팅 테이블이 변경되나요?

일반적인 Linux 환경에서는 Tailscale 연결이 활성화되면 필요한 라우팅 설정이 추가됩니다.

여기서 라우팅 테이블은 단순한 설정 파일이 아닙니다.

실제 라우팅 테이블은 Linux 커널이 메모리에서 관리하는 자료구조입니다.

프로그램은 Netlink 같은 인터페이스를 이용하여 커널의 라우팅 정보를 실시간으로 변경할 수 있습니다.

Q. 라우팅 테이블은 프로그램을 가리키나요?

정확하게는 네트워크 인터페이스나 다음 홉을 지정합니다.

Linux에서 Tailscale은 일반적으로 tailscale0이라는 가상 네트워크 인터페이스를 사용합니다.

통신은 다음과 같이 진행됩니다.

  1. 브라우저가 100.100.0.1로 패킷을 전송합니다.

  2. Linux 커널이 라우팅 설정을 확인합니다.

  3. 해당 패킷을 tailscale0으로 전달합니다.

  4. tailscaled 프로그램이 TUN 인터페이스를 통해 패킷을 읽습니다.

  5. 패킷을 암호화하고 실제 네트워크 인터페이스를 통해 전송합니다.

즉, 라우팅은 가상 인터페이스를 지정하고, 그 인터페이스와 연결된 Tailscale 프로그램이 패킷을 처리합니다.

이는 일반적인 TUN 모드 기준이며, Tailscale에는 별도의 TUN 인터페이스 없이 실행하는 방식도 있습니다.

라우팅 테이블 번호에 대한 의문

Linux에서는 다음과 같은 출력을 볼 수 있습니다.

32766: from all lookup main

여기서 32766은 라우팅 테이블 ID가 아니라 규칙의 우선순위입니다.

main 테이블의 ID는 254입니다.

Tailscale은 일반적인 Linux 환경에서 별도의 52번 라우팅 테이블을 사용할 수 있습니다.

명령어역할ip rule show어떤 라우팅 테이블을 조회할지 확인ip route show table all전체 라우팅 테이블 확인ip route get 100.100.0.1특정 목적지로 향하는 경로 확인

Windows에 Tailscale을 설치하고 WSL에서 명령어를 실행하면 Windows의 라우팅 설정이 WSL 내부에 그대로 나타나지 않을 수 있습니다.

따라서 라우팅을 검사할 때는 Tailscale이 실제로 동작하는 운영체제에서 확인하는 것이 중요합니다.

8장. 가상 인터페이스까지는 이해했다. 그다음은?

이제 Tailscale이 패킷을 전달받았다고 가정하겠습니다.

노트북의 Tailscale IP는 100.100.0.2이고 집 서버의 Tailscale IP는 100.100.0.1입니다.

하지만 이 주소들은 인터넷의 일반적인 라우터가 직접 전달하는 공인 IP가 아닙니다.

Tailscale은 상대방이 실제 인터넷에서 어떤 주소와 포트를 사용하고 있는지 알아야 합니다.

여기서 조정 서버가 등장합니다.

Q. Tailscale 서버가 사용자 장치의 IP를 매핑하고 관리하는 건가요?

개념적으로 맞습니다.

다만 단순히 공인 IP와 사설 IP의 대응표만 관리하는 것은 아닙니다.

Tailscale은 장치의 공개키, 연결 후보 주소와 포트, 접근 정책 등의 정보를 관리하고 필요한 장치들에게 배포합니다.

Q. 상대방이 와이파이를 바꾸면 어떻게 되나요?

장치의 실제 IP나 포트가 달라지면 Tailscale이 네트워크 변경을 감지하고 새로운 연결 정보를 교환합니다.

조정 서버는 클라이언트들과 지속적으로 통신하며 필요한 업데이트를 전달합니다.

또한 각 장치는 연결 탐색 메시지를 사용하여 상대방에게 실제로 도달할 수 있는지 확인합니다.

즉, Tailscale은 로그인할 때 한 번만 정보를 교환하는 시스템이 아닙니다.

네트워크 상태 변화에 대응하면서 통신 경로를 지속적으로 관리합니다.

9장. 직접 연결과 중계 연결

Q. 그러면 모든 통신이 Tailscale 회사 서버를 거치나요?

그렇지 않습니다.

통신 경로를 크게 두 가지로 나눌 수 있습니다.

Direct 연결

노트북과 서버가 인터넷을 통해 암호화된 데이터를 직접 교환합니다.

DERP 중계 연결

직접 통신이 어려운 경우 Tailscale의 DERP 서버를 거쳐 암호화된 데이터를 전달합니다.

DERP는 현재 Designated Encrypted Relay for Packets의 약어입니다.

실제로 DERP는 연결을 찾기 위한 메시지만 전달하는 것이 아닙니다.

필요한 경우 실제 암호화된 WireGuard 패킷도 중계합니다.

하지만 직접 연결이 가능하면 실제 데이터는 DERP를 거치지 않습니다.

Tailscale이 무료 개인 서비스를 제공할 수 있는 이유 중 하나도 이러한 직접 연결 중심의 구조입니다. 물론 Tailscale은 조정 서버와 전 세계의 중계 서버를 운영하므로 실제 운영비가 발생합니다.

그런데 다시 의문이 생깁니다.

"집 공유기가 외부에서 시작한 연결을 막고 있을 텐데 어떻게 Direct 통신이 가능한 걸까요?"

10장. NAT Traversal과 UDP Hole Punching

먼저 NAT부터 이해해야 합니다.

가정용 공유기는 여러 내부 장치가 하나의 공인 IP를 공유할 수 있도록 주소와 포트를 변환합니다.

예를 들어 집 PC가 외부로 통신하면 공유기는 다음과 같은 임시 매핑을 만들 수 있습니다.

192.168.0.10:41641 ↔ 공인IP:55001

공유기는 이 매핑을 이용해 해당 통신의 인바운드 패킷을 적절한 내부 장치로 전달합니다.

여기서 중요한 개념이 두 가지 있습니다.

  • NAT Mapping: 공인 주소와 내부 주소의 변환 관계

  • NAT Filtering: 어떤 외부 주소에서 오는 패킷을 허용할지 결정하는 조건

가정용 공유기는 보통 NAT와 Stateful 방화벽 기능을 함께 제공합니다.

UDP Hole Punching은 무엇인가요?

두 장치가 서로를 향해 UDP 패킷을 보내 각 공유기에 동적인 매핑과 통신 상태가 형성되도록 시도하는 기술입니다.

예를 들어 다음과 같습니다.

  1. 노트북 A가 집 서버 B를 향해 UDP 패킷을 전송합니다.

  2. A의 공유기가 매핑과 통신 상태를 생성합니다.

  3. 집 서버 B도 노트북 A를 향해 UDP 패킷을 전송합니다.

  4. B의 공유기도 매핑과 통신 상태를 생성합니다.

  5. 각 NAT의 조건이 맞으면 양방향 패킷이 통과합니다.

이때 수동으로 포트포워딩 규칙을 만들지 않아도 될 수 있습니다.

포트포워딩 정책을 우회하거나 무력화하는 것이 아닙니다.

공유기가 원래 제공하는 동적인 NAT 및 상태 추적 기능을 이용하는 것입니다.

다만 NAT의 종류와 방화벽 정책에 따라 Direct 연결이 실패할 수도 있습니다.

그때 DERP 같은 중계 경로가 필요합니다.

11장. Stateful 방화벽은 무엇을 기억할까?

Q. Stateful의 State는 연결 상태를 의미하나요?

맞습니다.

Stateful 방화벽은 패킷이 어떤 통신에 속하는지 추적합니다.

Linux의 conntrack에서는 대표적으로 다음과 같은 상태를 구분합니다.

상태의미NEW새로운 연결 또는 통신 시작ESTABLISHED이미 추적 중인 양방향 통신RELATED기존 통신과 연관된 별도의 통신INVALID정상적으로 추적하기 어려운 패킷

여기서 State와 Policy를 구분해야 합니다.

  • State: 지금 어떤 통신이 이루어지고 있는가?

  • Policy: 이 통신을 허용할 것인가?

Q. 아웃바운드 연결을 만들었는데 어떻게 인바운드 데이터가 들어오나요?

TCP 연결은 수립된 후 양방향으로 데이터를 주고받을 수 있습니다.

예를 들어 집 서버가 DERP 서버의 TCP 443 포트로 연결을 시작했다고 가정하겠습니다.

연결이 성립하면 DERP 서버도 같은 TCP 연결을 통해 집 서버로 데이터를 보낼 수 있습니다.

이때 집 서버의 공유기나 Stateful 방화벽은 해당 패킷이 이미 허용된 통신에 속한다는 사실을 알고 있습니다.

따라서 새로운 외부 연결을 무조건 허용한 것이 아닙니다.

기존에 허용된 통신을 통해 반대 방향의 데이터를 수신하는 것입니다.

AWS Security Group에서도 같은 개념을 볼 수 있습니다.

Security Group은 Stateful이므로 허용된 연결의 응답 트래픽은 반대 방향의 별도 허용 규칙이 없어도 통과할 수 있습니다.

반대로 Stateless 방화벽은 양방향에 필요한 규칙을 각각 고려해야 합니다.

UDP는 연결이 없는데 Stateful이 가능한가요?

UDP는 TCP처럼 연결을 수립하는 절차가 없습니다.

하지만 방화벽은 IP 주소, 포트 번호, 프로토콜, 패킷의 방향 및 타임아웃 등을 이용해 UDP 통신도 추적할 수 있습니다.

따라서 UDP Hole Punching에서도 동적인 허용 상태를 활용할 수 있습니다.

Q. 왜 Tailscale 설명에서는 UDP가 반복적으로 등장할까요?

Tailscale이 사용하는 WireGuard의 기본 데이터 전송 방식이 UDP이기 때문입니다.

브라우저가 HTTPS/TCP로 통신하더라도 Tailscale은 그 IP 패킷을 암호화한 뒤 UDP 패킷으로 감싸 인터넷을 통해 전달할 수 있습니다.

즉, 내부 통신의 프로토콜과 VPN이 실제 인터넷에서 사용하는 외부 전송 프로토콜은 다를 수 있습니다.

12장. 다시 Kubernetes Proxy Pod로 돌아오면

이제 처음의 의문으로 돌아가겠습니다.

"Proxy Pod는 어떻게 포트포워딩도 없이 외부 패킷을 받을 수 있을까요?"

Tailscale Proxy Pod 안에는 Tailscale을 실행하는 컨테이너가 있습니다.

Proxy Pod도 일반적인 Tailscale 장치처럼 조정 서버와 연결하고 상대 장치의 정보를 받습니다.

그다음 두 가지 경로 중 사용 가능한 경로를 이용합니다.

  • Direct: NAT Traversal을 통해 직접 암호화된 패킷 수신

  • DERP: 미리 만들어 놓은 중계 연결을 통해 암호화된 패킷 수신

따라서 공유기에서 Proxy Pod로 향하는 정적 포트포워딩을 반드시 구성해야 하는 것은 아닙니다.

Proxy Pod에 도착한 패킷은 Tailscale이 복호화하고, Kubernetes Service로 전달합니다.

개인 도메인과 자체 HTTPS 인증서를 사용하는 구성의 예시

  1. 브라우저에서 https://admin.example.com 접속

  2. DNS를 통해 Tailscale IP 확인

  3. 운영체제가 해당 패킷을 Tailscale에 전달

  4. Tailscale이 Direct 또는 Relay 경로를 통해 암호화된 패킷 전송

  5. Kubernetes의 Tailscale Proxy가 패킷 수신 및 복호화

  6. 기존 HTTPS Ingress Controller가 TLS 처리

  7. Kubernetes Service가 App Pod로 요청 전달

이 구성에서 Tailscale은 사설 네트워크 연결을, Ingress는 HTTPS 서비스를 담당합니다.

13장. 전체를 한눈에 정리하기

지금까지 배운 기술들은 각각 다른 문제를 해결합니다.

기술해결하는 문제DNS도메인 이름에 해당하는 IP는 무엇인가?라우팅 테이블목적지로 가기 위해 어떤 경로를 사용할 것인가?가상 네트워크 인터페이스물리 NIC 없이 IP 패킷을 어떻게 주고받을 것인가?Tailscale 조정 서버상대 장치의 연결 정보와 공개키를 어떻게 알 것인가?WireGuard데이터를 어떻게 암호화해서 전달할 것인가?NAT사설 IP 장치가 공인 인터넷과 어떻게 통신할 것인가?Stateful 방화벽어떤 통신이 허용된 상태인지 어떻게 기억할 것인가?UDP Hole PunchingNAT 뒤에 있는 두 장치가 어떻게 직접 통신할 것인가?DERP직접 연결이 불가능하면 어떻게 데이터를 중계할 것인가?Kubernetes ProxyVPN 통신을 Kubernetes 내부 서비스로 어떻게 전달할 것인가?HTTPS브라우저와 웹서비스 사이의 통신을 어떻게 보호할 것인가?

하나의 요청이 이동하는 전체 과정

외부 노트북에서 집 Kubernetes 서버의 웹서비스에 접속하는 상황을 생각해 보겠습니다.

① 목적지 찾기

DNS가 도메인을 IP 주소로 변환합니다.

② 운영체제 라우팅

커널이 목적지 IP를 확인하여 Tailscale 인터페이스로 패킷을 전달합니다.

③ VPN 처리

Tailscale이 상대 장치의 연결 정보를 확인하고 WireGuard로 패킷을 암호화합니다.

④ 실제 인터넷 전송

NAT Traversal로 Direct 연결을 시도합니다. 필요하면 DERP 중계 서버를 사용합니다.

⑤ VPN 패킷 수신

서버 측 Tailscale이 암호화된 패킷을 받아 복호화합니다.

⑥ 애플리케이션 전달

Kubernetes Proxy와 Service가 패킷 또는 요청을 적절한 App Pod로 전달합니다.

⑦ 응답 전송

서버의 응답 역시 Tailscale 네트워크를 통해 클라이언트로 돌아갑니다.


마치며: Tailscale을 이해하려면 VPN부터 공부해야 할까?

오히려 반대일 수 있습니다.

Tailscale을 이해하려고 질문하다 보면 자연스럽게 다음 개념에 도달하게 됩니다.

IP → 라우팅 → 인터페이스 → 소켓 → NAT → Stateful 방화벽 → UDP Hole Punching → 암호화 터널 → VPN

Tailscale은 이러한 기존 네트워크 기술들을 조합하고 자동화한 시스템입니다.

처음에는 "같은 계정으로 로그인하면 연결된다"는 간단한 설명으로 시작했지만, 그 뒤에는 운영체제, 공유기, 방화벽과 암호화 프로토콜의 협력이 존재합니다.

이 모든 과정을 관통하는 핵심은 다음 한 문장입니다.

Tailscale은 인터넷의 기존 네트워크 경로를 이용해 암호화된 가상 사설 네트워크를 구성하고, 가능한 경우 장치끼리 직접 통신하도록 만드는 시스템입니다.

이 원리를 이해하면 Tailscale뿐 아니라 다른 VPN, P2P 통신, WebRTC, Kubernetes 네트워킹을 공부할 때에도 도움이 됩니다.


더 깊이 공부할 자료