포스트

Real IP를 노출하지 않고 SSH 접속하기

나는 VPN이 싫어요!

Real IP를 노출하지 않고 SSH 접속하기

언제 어디서나 당당하게 SSH

무수한 악수의 요청 당당하게 그냥 아무 비밀번호나 입력했더니, 대부분의 서버가 호응해주더군요. 다른 서버들도 ‘나는 Ubuntu 24.04.2, OpenSSH를 사용한다!’라면서 자기소개를 하더군요…

밖에서 어디서든 SSH 접속을 하려고 포트를 외부에 개방한 채 둔다면, 수많은 봇들이 당신의 SSH 로그인 창과 악수를 하고 있을 것이다. 보통은 레인보우 테이블 같은 사전 공격을 통해 무차별 대입(Brute-force)을 시도하는 것이다. 물론, 비밀번호를 적당히 어렵게 해둔다면 뚫릴 일은 없다. 1q2w3e4r@# 같은 것만 아니라면

하지만 SSH 서비스 자체(OpenSSH 등)에 예상치 못한 보안 취약점이 발견되면 어떨까? 포트가 열려 있다면 패치를 하기도 전에 공격을 당할 것이고, 나같은 초보 엔지니어라면 언제/어디서/어떻게 뚫렸고 공격자가 내 서버로 무슨 위험한 짓을 할지 빠르게 파악하기 어려울 것이다. 온갖 민감한 정보가 다 털리지나 않길 빌어야한다.

이렇게 만약의 사태를 막기 위해서 서버의 포트는 전부 닫아야한다. 그럼 어떻게 외부에서 철벽을 친 내 서버에 접속할 수 있을까?

방화벽

클라우드를 사용한다면 각 VM에 할당된 네트워크 인터페이스(혹은 가상 네트워크 카드, VNC)에서 방화벽 설정을 구성한다.

보통은 대상 포트에 서버의 SSH 포트를 투고, 소스(대상) IP를 내 컴퓨터의 IP로 지정한다. 그럼 내 컴퓨터에서만 서버에 접속이 가능해진다.

VPN

WireGuard, OpenVPN을 통해 내 서버와 컴퓨터 간 가상 사설망(VPN)을 구성하여, 밖에서 어디서든 가상 사설망 내 서버에 접속할 수 있다.

이건 널리 알려져있고 기업도 사용하는 식상한(?) 방법이라, 내가 필요하게 되면 나중에 다뤄보겠다.

진짜로, 언제 어디서나 당당하게 SSH

하지만 위의 방법으로는 밖에서 어디서든 SSH 접속을 하기에는 귀찮다. 컴퓨터가 아니라 노트북이면 연결하는 와이파이 환경이 달라질 때 마다 클라우드 콘솔에 접속해 VM에 연결된 네트워크 인터페이스 구성을 변경해야한다.

이미 VPN을 사용 중일 경우 내 서버에 연결하기 위한 VPN과 동시에 사용하기에는 어렵다. 혹은, VPN을 사용 시 웹서핑에 제한이 생기기도 해서 VPN을 껐다 켰다 해야한다.

그럼, 좀 더 심플하게 서버의 IP 노출 없이 SSH 접속을 하려면 어떻게 해야할까? 필자는 클라우드를 사용할 경우 각 솔루션을 우선 사용하고, 솔루션이 없거나 홈서버의 경우 이미 웹 서버에 사용 중인 Cloudflare Tunnel을 이용한다. Tailscale을 이용한 방법도 있지만, 이미 Cloudflare의 여러 서비스를 사용하고 있으므로 이번에도 Cloudflare Tunnel를 이용한 방법만을 소개한다. 그리고 Tailscale을 이용한 방법도 흔하니까 패스…

Google Cloud Platform

GCP에서 가장 간단한 방식은 IAP(Identity-Aware Proxy)를 사용하는 것이다. 서버에 공인 IP가 없어도 Google의 인프라를 통해 SSH 터널을 생성할 수 있다.

준비

보통 나 홀로 프로젝트의 경우 Owner(소유자) 권한 내에는 iap.tunnelResourceAccessor 권한이 포함되어 있지만, 소유자가 아닌 경우에는 포함되어 있지 않아 권한을 추가해 주어야 한다.

  1. Compute Engine에 연결된 NIC의 방화벽에서 35.235.240.0/20 대역(Google 릴레이 IP)만 SSH 포트를 허용한다.
  2. 보안 > IAP 메뉴에서 SSH 및 TCP 리소스 탭을 선택한다.
  3. Cloud IAP 로 접속할 Compute Engine를 선택하고 새 구성원에 내 지메일 주소를 입력한다.
  4. 역할은 IAP-secured Tunnel User로 지정하고 역할을 저장한다.
  5. 내 컴퓨터에 Google Cloud SDK를 설치한다.

사용

  1. Google Cloud Platform에 내 Google 계정으로 로그인
    1
    
     gcloud auth login
    
  2. ssh 접속
    1
    
     gcloud compute ssh [Compute Engine 이름] --tunnel-through-iap
    

    내 서버로 접속이 잘 되었는지 확인해보자.

Oracle Cloud Infrastructure

Oracle Cloud Infrastructure의 경우 Bastion 서비스를 무료로 이용할 수 있다. 대 라 클

다만, Bastion 세션을 만들고 싶다면 결국 Oracle Cloud Infrastructure에 직접 접속을 해야하며, 세션은 최대 3시간 까지만 이용할 수 있다. 어떤 수를 써도 3시간 초과한 세션을 생성할 수 없다. ㅠㅠ.

Oracle 콘솔로 세션 생성을 자동화 해버리는 방법도 있는데 그건 AI에게 물어보시라…

준비

  1. ID & 보안에서 Bastion을 생성한다.
  2. 인스턴스의 Network Security Group이나 인스턴스가 속한 VCN(Virtual Cloud Network)의 Security List에서, Bastion의 Private Endpoint IP 주소에 대하여 (대상) SSH 포트로의 접속을 허용하도록 Security Rules를 수정한다.
  3. Bastion에서 세션 생성을 누르고 설정을 아래와 같이 입력한다.
    • Session Type: SSH port forwarding session
    • Target Resource: Compute Instance 선택 후 타겟 인스턴스 지정
    • Port: 22 (인스턴스의 SSH 포트가 다르다면 수정)
    • SSH Key: 내 컴퓨터의 공개키 파일(id_rsa.pub) 업로드.
  4. Session이 Active 상태가 될 때까지 기다린다.

사용

  1. 세션 우측의 점 3개 메뉴를 누르고 Copy SSH command를 클릭
  2. 터널링 명령어 실행
    1
    
     ssh -i <privateKey> -N -L <localPort>:[인스턴스의 IP]:22 -p 22 ocid1.bastionsession.oc1...
    

    상황에 알맞게 <privateKey>를 수정하고 <localPort>는 임의의 포트를 입력한다.

  3. 명령어를 터미널에 입력하고 Enter를 누르면 아무런 반응이 없다. 이 명령어는 ssh 접속 명령어가 아니라 터널을 뚫고 포트를 넘겨주는 명령어이기 때문이다.
  4. 터미널을 유지하고 새 터미널 창을 열어 ssh -p <localPort> -i <privateKey> [인스턴스의 사용자명]@localhost 명령어로 인스턴스에 접속한다.

Cloudflare Tunnel

클라우드가 아니거나, 특정 클라우드에 종속되지 않고 이용할 수 있는 범용적인 방법이다. 원리는 이전에 작성했던 Cloudflare Tunnel를 통한 리버스 프록시와 비슷하다.

기존처럼 SSH 클라이언트에서 접속하는 방법과 Cloudflare에서 SSH를 웹 브라우저에 렌더링하는 형태가 있다. 나는 터미널이 좋아서 전자의 방법을 쓰기로 했다.

단점으로는 설정이 조금 까다롭고, Cloudflare 에지 서버부터 내 서버에 도달할 때까지 지연 시간이 약간 있다는 것이다. 서버가 먼 거리에 있을 경우 직접 접속한 것에 비해 입력 지연이 조금 늘어난다.

cloudflared 설정

  1. 서버에 cloudflared 설치 및 구성은 이전에 작성한 홈서버 (재)구축하기 - 5. 웹서버 구성 (2) 게시물의 cloudflared 문단을 따라오면 된다.
  2. config.yml 내용 추가
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
     tunnel: <UUID>
     credentials-file: /home/hgsanguk/.cloudflared/<UUID>.json
    
     ingress:
         - hostname: test.example.com        
             service: http://localhost:1010   
         - hostname: ssh.example.com        # 외부에서 접속할 도메인
             service: ssh://localhost:22    # 서버에서 실행 중인 SSH 서버
         - service: http_status:404
    

    ingress 안에 SSH에 관해 내용을 추가로 작성하면 된다.

OAuth 구성

해당 문단에서는 Github 로그인을 Cloudflare Tunnel을 통한 ssh 접속 인증 수단으로 사용한다.

  1. Github 프로필 > Settings > Developer settings > OAuth Apps로 이동한다.
  2. New OAuth App 클릭 및 정보 입력
    • Application Name: Cloudflare Access (식별 가능한 임의의 이름)
    • Homepage URL: https://<your-team-name>.cloudflareaccess.com
    • Authorization callback URL: https://<your-team-name>.cloudflareaccess.com/cdn-cgi/access/callback
    • <your-team-name>은 Cloudflare 대시보드에서 Zero Trust > Settings에서 확인할 수 있다.
  3. 생성 후 App ID를 복사하고, Generate a new client secret을 눌러 Client Secret도 복사
  4. Cloudflare 대시보드에서 Zero Trust > Integrations > Identity providers 메뉴에 들어간다.
  5. Add an identity provider를 누르고 Github를 선택한 뒤 아까 App IDClient Secret를 입력한 뒤 저장한다.

보안 규칙 구성

  1. Cloudflare 대시보드에서 Zero Trust > Access controls > Policies 메뉴에 들어간다.
  2. Add a policy 클릭 및 정보 입력
    • Policy name: (식별 가능한 임의의 이름)
    • Action: Allow
    • Session Duration: 24 hours (마음대로)
    • Add rules: Include - Login Methods: Github, Require - Emails: (Github에 등록된 Primary 이메일)

SSH 접속 터널 생성

  1. Cloudflare 대시보드에서 Zero Trust > Access controls > Application 메뉴에 들어간 후 Add an application을 누른다.
  2. Self-hosted를 선택한다.
  3. SSH 접속 정보를 입력한다. Add an application 화면
    • Application name: (식별 가능한 임의의 이름)
    • Session Duration: 24 hours (마음대로)
    • Public hostname: ssh.example.com (config.yml 작성할 때 입력한 도메인)
    • Browser rendering settings: 브라우저로 ssh.example.com에 접속해 SSH를 이용하고 싶다면, Browser rendering에서 SSH를 선택
  4. Access policies에선 Select existing policies 버튼을 누른 뒤 위에서 생성한 정책을 선택한다.
  5. Login methods는 Github만 체크하고, Instant Auth를 활성화한다.
  6. 이외의 설정은 필요에 따라 구성한 후 Save를 눌러 설정을 배포한다.

사용

SSH 클라이언트를 통해 Cloudflare Tunnel과 연결된 서버에 접속하기 위해서는 내 컴퓨터에서도 cloudflared 설치가 필요하다. Browser rendering settings를 켠 경우에는 브라우저로 ssh.example.com에 접속해 인증을 따르면 된다.

  1. 간편한 접속을 위해 SSH Config 설정
    1
    2
    3
    4
    
     Host my-server
         HostName ssh.example.com 
         User <서버 계정명>
         ProxyCommand /usr/local/bin/cloudflared access ssh --hostname %h
    
  2. SSH 접속
    1
    
     ssh my-server
    
  3. 브라우저가 열리며 Github OAuth를 통한 인증을 요구한다. 내가 설정한대로 인증을 하면 서버와 연결된다.
이 글은 저작권자의 CC BY 4.0 라이센스를 따릅니다.