[Kubernetes] Tailscale (VPN)

문린이·2025년 5월 29일

VPN

VPN(Virtual Private Network)은 가상 사설망으로, 공용 인터넷을 통해 안전하고 암호화된 연결을 만드는 기술이다. 마치 물리적으로 분리된 전용 네트워크처럼 동작하지만, 실제로는 인터넷 인프라를 활용한다.

핵심 개념

  1. 터널링 : 데이터가 암호화되어 "터널"을 통해 전송
  2. 암호화 : 데이터를 해독 불가능한 형태로 변환, 승인된 수신자만 복호화 가능

WireGuard

WireGuard는 차세대 VPN 프로토콜로, 기존 VPN 기술들의 문제점을 해결하기 위해 개발된 현대적이고 혁신적인 VPN 솔루션이다.

기존 OpenVPN, IPSec의 문제를 해결

  • 상대적으로 느린 성능
  • 복잡한 설정

동작 방식

  1. 클라이언트와 서버 간 연결 설정
    WireGuard는 클라이언트와 서버 간에 안전한 통신 채널을 설정한다. 이를 위해 클라이언트와 서버는 서로의 공개 키를 교환하고, WireGuard는 이를 사용하여 암호화된 터널을 생성한다.

  2. 암호화된 데이터 전송
    클라이언트가 데이터를 전송할 때, WireGuard는 데이터를 암호화하고 서버로 전송한다. 서버는 수신된 데이터를 복호화하여 원래 데이터를 얻는다.

  3. UDP 프로토콜 사용
    WireGuard는 주로 UDP 프로토콜을 사용하여 데이터를 전송한다. UDP 프로토콜은 TCP 프로토콜보다 빠르고 효율적이어서, WireGuard의 고성능 특성을 지원한다.

Tailscale

Tailscale은 Zero-Configuration VPN 서비스로, WireGuard 프로토콜을 기반으로 하여 복잡한 네트워크 설정 없이도 안전하고 빠른 네트워크 연결을 제공하는 현대적인 VPN 솔루션이다.

Kubernetes에서 Tailscale 적용하기

테스트는 Minikube, 맥북 환경입니다.

  1. Tailscale 가입

  2. Tailscale 설치

    저는 앱스토어로 설치했는데 Standalone variant from Tailscale's package server 를 추천한다고 합니다. (https://pkgs.tailscale.com/stable/#macos)

  3. 설치 확인

  4. 샘플 앱 설치 (Minikube)

  • app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          ports:
            - containerPort: 80
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 512Mi

---
apiVersion: v1
kind: Service
metadata:
  name: nginxpod
spec:
  selector:
    app: nginx
  ports:
    - port: 80
      targetPort: 80
  1. 키 생성
  • tailscale-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: tailscale-auth
stringData:
  TS_AUTHKEY: tskey-0123456789abcdef # 방금 생성한 값
  • tailscale-rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: tailscale

---

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: tailscale
rules:
  - apiGroups: [""]
    resourceNames: ["tailscale-auth"]
    resources: ["secrets"]
    verbs: ["get", "update", "patch"]

---

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: tailscale
subjects:
  - kind: ServiceAccount
    name: tailscale
roleRef:
  kind: Role
  name: tailscale
  apiGroup: rbac.authorization.k8s.io
  1. Tailscale Kubernetes 배포
    프록시, 사이드카, 서브넷 라우터 배포등이 있지만 여기서는 tailscale-operator를 사용해서 배포하겠습니다.
  • Access controls 설정
{
  "tagOwners": {
	"tag:k8s-operator": [],
	"tag:k8s": ["tag:k8s-operator"]
  }
}

"tag:k8s": ["tag:k8s-operator"]

의미: k8s 태그를 가진 디바이스/서비스
소유자: tag:k8s-operator

  • Kubernetes 리소스들 (Pod, Service 등)
  • k8s-operator가 이 태그를 관리할 수 있음
  • k8s-operator만이 이 태그를 생성/삭제/할당 가능

  • OAuth 설정

  • helm 설치
helm repo add tailscale https://pkgs.tailscale.com/helmcharts

helm repo update

helm upgrade --install tailscale-operator tailscale/tailscale-operator \
  --namespace=tailscale \
  --create-namespace \
  --set-string oauth.clientId=<oauth_client_id> \
  --set-string oauth.clientSecret=<oauth_client_secret> \
  --wait
  • 설치 확인

  1. 서비스 노출

서비스 metadata.annotations 필드에 tailscale.com/expose: 'true'를 추가하면 된다.

  • app-operator.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          ports:
            - containerPort: 80
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 512Mi

---
apiVersion: v1
kind: Service
metadata:
  name: nginx
  annotations:
    tailscale.com/expose: 'true'
spec:
  selector:
    app: nginx
  ports:
    - port: 80
      targetPort: 80

  1. Access controls 세부 설정

기본값은 모든 게 허용이다.

{
  "acls": [{ "action": "accept", "src": ["*"], "dst": ["*:*"] }]
}

특정 src, dst를 지정하면 지정한 것만 허용한다.

{
  "acls": [{"action": "accept", "src": ["jjmoon4682@gmail.com"], "dst": ["88.88.88.88:80"]}],
}

  1. 추가

휴대폰으로도 가능하다.

동작 방식 (EKS)

  1. curl 172.20.137.80:8004

  2. 내 컴퓨터 Tailscale 클라이언트

    • WireGuard 터널
  3. EKS 노드 (Subnet Router)

    • 로컬 네트워크 포워딩
  4. pod (172.20.137.80:8004)

  • 핵심 포인트 (보안 그룹 (인바운드 차단, 아웃바운드 허용))
    1. 아웃바운드 연결: EKS 노드 → Tailscale (허용됨)
    2. 연결 상태 유지: 양방향 터널 확립
    3. 내부 포워딩: 노드 내부에서 파드로 라우팅
    4. 직접 인바운드: 차단

Exit Node

Exit Node는 Tailscale 네트워크에서 모든 인터넷 트래픽을 특정 디바이스를 통해 라우팅하는 기능이다. 기본적으로 Tailscale은 오버레이 네트워크로 동작하여 Tailscale 디바이스 간의 트래픽만 처리하지만, Exit Node를 사용하면 모든 공용 인터넷 트래픽도 해당 노드를 통해 나가게 된다.

활용 사례

  1. EC2 Exit Node (or eks Node) + 보안 그룹 제한

    1. EC2 Exit Node 설정 (or Pod 배포)

      # EC2 인스턴스에서 Tailscale 설치 및 Exit Node 설정
      sudo tailscale up --advertise-exit-node
      
      # IP 포워딩 활성화
      echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
      sudo sysctl -p /etc/sysctl.d/99-tailscale.conf
    2. 보호된 서비스의 보안 그룹 설정

      인바운드 룰:

      • 포트: 443 (HTTPS)

      • 소스: EC2의 공용 IP (예: 52.79.123.45/32)

      • 설명: "Exit Node를 통한 접근만 허용"

      • 포트: 80 (HTTP)

      • 소스: EC2의 공용 IP (예: 52.79.123.45/32)

      • 설명: "Exit Node를 통한 접근만 허용"

    3. 클라이언트에서 사용

      # 내 컴퓨터에서 EC2 Exit Node 사용
      tailscale set --exit-node ec2-exit-node
      
      # 이제 모든 트래픽이 EC2를 통해 나감
      curl https://protected-service.com
      # → EC2 IP(52.79.123.45)에서 접근한 것으로 인식
  2. 노트북을 Exit Node로 사용 (핸드폰 → 노트북)

profile
Software Developer

0개의 댓글