이 글에서 다루는 내용

외부 사용자에게 서버 접근 권한을 줄 때 SSH 포트를 그냥 열어두는 경우가 많다. 하지만 이는 생각보다 훨씬 위험한 방식이다. 이 글에서는 WireGuard VPN + SSH + 공개키 + 2FA를 조합한 안전한 외부 접근 구성 방법을 정리한다.

SSH 포트 직접 개방의 문제점

공유기에서 SSH 포트(22)를 직접 열면 인터넷 전체에 서비스가 노출된다. 포트를 열고 수분 내에 전 세계 봇이 자동으로 브루트포스 공격을 시작한다.

# 실제 auth.log 예시
Failed password for root from 185.234.x.x
Failed password for admin from 45.142.x.x
Failed password for ubuntu from 103.99.x.x
# 하루에 수천~수만 건

주요 문제점은 다음과 같다.

  • 공격 표면 노출 — 봇넷이 24시간 브루트포스 및 스캐닝 시도
  • 취약점 리스크 — OpenSSH 취약점 발생 시 즉시 공격 대상
  • 포트 스캐닝 — nmap 등으로 누구나 열린 포트 탐지 가능

WireGuard가 더 안전한 이유

WireGuard는 올바른 키 없이 패킷을 보내면 서버가 아무 응답도 하지 않는다. 포트가 열려 있는지조차 알 수 없는 스텔스 방식이다.

항목 SSH 포트 직접 개방 WireGuard VPN
공격 표면 큼 (전체 인터넷 노출) 작음 (UDP 무응답 스텔스)
인증 방식 비밀번호 or 키 공개키 only
포트 스캐닝 탐지됨 응답 없음 (존재 자체가 안 보임)
코드 크기 수십만 줄 약 4,000줄
브루트포스 가능 구조적으로 불가

권장 구성 전체 흐름

외부 사용자
    ↓ WireGuard 연결 (공개키 인증) ← 1차 관문
공유기 VPN
    ↓ AllowedIPs = 192.168.1.100/32 (특정 장비만)
서버 A ← SSH 접속 가능
서버 B, NAS, PC 등 ← 아예 안 보임
    ↓ SSH 공개키 인증 ← 2차 관문
    ↓ OTP 2FA 인증 ← 3차 관문
서버 접근 완료

보안 레이어를 정리하면 아래와 같다.

  • WireGuard — 네트워크 접근 자체를 차단
  • AllowedIPs 제한 — 특정 서버만 보이도록 격리
  • SSH 공개키 — 비밀번호 탈취 방어
  • 2FA OTP — 공개키 탈취 시 추가 방어

WireGuard 설정

공유기 Peer 설정 (사용자별 접근 제한)

[Peer]
PublicKey = 외부사용자_공개키
AllowedIPs = 192.168.1.100/32  # 딱 이 서버만 접근 허용

외부 사용자에게 전달할 wg0.conf

[Interface]
PrivateKey = 사용자_개인키
Address = 10.0.0.2/24

[Peer]
PublicKey = 공유기_공개키
Endpoint = 공인IP:51820
AllowedIPs = 192.168.1.100/32

사용자는 이 파일을 WireGuard 앱에 import하고 토글 ON만 하면 연결된다.

플랫폼별 WireGuard 클라이언트

플랫폼 설치 방법
macOS App Store에서 "WireGuard" 검색
Windows wireguard.com에서 installer 다운로드
iOS App Store
Android Play Store
Linux apt install wireguard

SSH 설정

# /etc/ssh/sshd_config
AllowUsers 외부사용자계정
PermitRootLogin no
PasswordAuthentication no
Port 2222  # 기본 포트 변경 권장

비밀번호 대신 공개키 인증을 사용해야 하는 이유

비밀번호는 로그인할 때마다 네트워크로 전송되지만, 공개키는 개인키가 절대 기기 밖으로 나가지 않는다. 수학적으로 서명값만 주고받기 때문에 탈취 자체가 구조적으로 어렵다.

비밀번호 방식: 클라이언트 → [비밀번호 전송] → 서버
공개키 방식:  클라이언트 → [서명값 전송]  → 서버 (개인키는 이동 안 함)
항목 비밀번호 공개키
브루트포스 가능 구조적으로 불가
탈취 가능성 피싱/키로거로 탈취 가능 개인키 파일 자체를 훔쳐야 함
네트워크 전송 매번 전송됨 전송 안 됨
복잡도 관리 사람이 기억해야 함 수학적으로 복잡도 보장
키 길이 보통 8~20자 2048~4096bit

공개키 생성 및 등록

# 클라이언트에서 키 생성 (ed25519 권장)
ssh-keygen -t ed25519 -C "your_email"
# ~/.ssh/id_ed25519      ← 개인키 (절대 공유 금지)
# ~/.ssh/id_ed25519.pub  ← 공개키 (서버에 등록)

# 서버에 공개키 등록
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@192.168.1.100

# 또는 수동으로 등록
cat ~/.ssh/id_ed25519.pub >> ~/.ssh/authorized_keys

비밀번호 로그인 비활성화

공개키 등록 후 반드시 비밀번호 로그인을 비활성화해야 한다.

# /etc/ssh/sshd_config
PasswordAuthentication no

# 재시작
systemctl restart sshd

2FA 설정 (Google Authenticator)

WireGuard 자체에는 2FA를 적용할 수 없다. 공개키 기반이라 키가 있으면 연결되고 없으면 차단되는 이분법적 구조이기 때문이다. 2FA는 SSH 로그인 단계에 적용한다.

설치

apt install libpam-google-authenticator

사용자 설정

google-authenticator
# 질문들에 y 입력
# QR코드 출력 → Google Authenticator 앱으로 스캔

PAM 설정

# /etc/pam.d/sshd 맨 위에 추가
auth required pam_google_authenticator.so

sshd_config 수정

ChallengeResponseAuthentication yes
AuthenticationMethods publickey,keyboard-interactive

# 재시작
systemctl restart sshd

적용 후 로그인 흐름

$ ssh enes@192.168.1.100

# SSH 공개키 자동 인증
# ↓
Verification code: ______  ← Google Authenticator 앱에서 6자리 입력
# ↓
접속 완료

2FA 앱은 Google Authenticator보다 Authy를 추천한다. 기기 교체 시 백업이 가능해서 실용적으로 더 편리하다.

외부 사용자에게 전달할 정보 정리

WireGuard 설정 파일  : wg0.conf
SSH 접속 명령어      : ssh -p 2222 user@192.168.1.100
OTP 앱               : Google Authenticator 또는 Authy

권한 회수 방법

사용자 접근을 차단하고 싶을 때는 공유기에서 해당 Peer만 삭제하면 즉시 내부망 진입이 불가능해진다. 별도로 SSH 계정을 삭제할 필요도 없다.

보안 수준별 구성 추천

구성 대상
WireGuard + SSH 비밀번호 신뢰할 수 있는 외부인
WireGuard + SSH 공개키 외부인 접근 기본 권장 ✅
WireGuard + SSH 공개키 + 2FA 중요 서버, 팀 운영 ✅✅
WireGuard + SSH 공개키 + 2FA + IP 제한 금융/의료급