Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

pickle-sshgw

Pickle(피클) 은 부산대학교 구성원을 위한 셀프서비스 클라우드 플랫폼입니다. 사용자가 신청하고 관리자가 승인한 VM을 Proxmox VE 위에 자동 프로비저닝하고, SSH·브라우저 웹 터미널 접속과 도메인 기반 HTTP(S) 게시를 제공합니다.

이 저장소는 Pickle의 SSH 게이트웨이입니다. ssh <slug>@ssh.pickle.pnuops.com을 pickle-api 인가를 거쳐 사용자 VM으로 라우팅하고, 브라우저 웹 터미널의 서버 측 브리지도 이 저장소의 데몬이 담당합니다.

교외 접근 경로: 학내 방화벽이 인바운드를 차단하므로, 캠퍼스 쪽에서 AWS Lightsail 릴레이로 아웃바운드 WireGuard 터널을 열고, Lightsail의 HAProxy(mode tcp, send-proxy-v2)가 공인 :22 → 터널 → sshgw:22로 전달합니다.

구성 요소

게이트웨이 LXC 안에서 네 개의 프로세스가 동작합니다. 커스텀 Go 데몬 세 개는 이 저장소에서 빌드하고, sshpiperd는 업스트림 배포 바이너리를 그대로 사용합니다.

  1. sshgw-proxyfront (cmd/sshgw-proxyfront, internal/proxyfront): WireGuard 인터페이스 주소에 바인딩되는 :22 인그레스 심. PROXY-v2-REQUIRED 모드를 WireGuard 피어에게만 허용해, 헤더가 없거나 변조됐거나 비피어 소스에서 온 연결은 SSH 바이트 교환 없이 드롭합니다 (raw TCP 소스로의 폴백 없음). 통과한 연결에는 복원한 실제 클라이언트 IP를 담은 PROXY v2 헤더를 새로 붙여 루프백 sshpiperd로 스플라이스합니다.

    심을 두는 이유: stock sshpiperd의 --allowed-proxy-addresses는 go-proxyproto의 lax 정책(헤더 선택적)만 제공해 헤더 없는 연결을 그대로 서비스해 버립니다. 심이 정확히 그 틈을 메우면서 sshpiperd는 stock 상태로 업그레이드 가능하게 유지합니다.

  2. sshpiperd (stock v1.5.4): 127.0.0.1:2222에서 --allowed-proxy-addresses 127.0.0.1/32(심만 접속하므로 lax로 충분)와 라우팅 플러그인을 물고 기동. scp/sftp/VSCode Remote가 그대로 동작하는 투명한 SSH 파이핑을 담당합니다.

  3. sshgw-route-plugin (cmd/sshgw-route-plugin, internal/gateway, internal/route): sshpiperd gRPC 플러그인. SSH 사용자명을 VM slug로 읽고 pickle-api의 내부 라우팅 API(Bearer 토큰)에 인가를 위임합니다.

    • 공개키 인증(기본): 제시된 키의 SHA-256 지문으로 사용자를 식별하고, 업스트림(VM)에는 플랫폼 ed25519 키로 인증합니다. 세션은 사용자 단위로 감사되며, 후보 지문 전체를 전달해 API가 소유자를 확정합니다.
    • 비밀번호 패스스루(옵트인): VM별 설정이 켜진 경우에만 입력한 비밀번호를 VM sshd로 그대로 전달합니다.
    • 호스트키 핀: 응답에 포함된 VM 호스트키 셋과 대조해 검증하며, 핀이 없으면 fail-closed로 거부합니다. 토큰 미설정 시 플러그인 자체가 기동을 거부합니다.
  4. sshgw-terminal-bridge (cmd/sshgw-terminal-bridge, internal/terminal): 웹 터미널의 데이터 플레인. 콘솔이 pickle-api에서 발급받은 원타임 티켓으로 WebSocket(:8082)에 접속하면, 브리지가 티켓을 API에 단일 사용 상환(redeem)하고 VM으로 잠금 SSH 연결(호스트키 핀 fail-closed, 서버 개시 채널 전부 거부, 전용 터미널 키)을 엽니다. 60초마다 인가를 재검증하고 유휴 타임아웃을 적용하며, 컨트롤 포트(:8083)로 관리자 강제 종료를 받습니다. DB·Proxmox 토큰·암호화 키를 전혀 갖지 않는 저권한 데몬이고, pickle-api는 인가 오라클 + 감사 싱크 역할만 합니다(터미널 입출력 내용은 어디에도 기록되지 않음).

인그레스 경로:

[SSH]      client → Lightsail HAProxy(send-proxy-v2) → WireGuard
           → proxyfront:22 (REQUIRE, peer-only) → sshpiperd:2222(loopback)
           → route-plugin → VM:22
[웹 터미널] browser → wss://…/terminal/ws (reverse proxy)
           → terminal-bridge:8082 → locked-down SSH → VM:22

빌드와 배포

scripts/setup-hooks.sh   # 최초 1회: git hook 설치
scripts/verify.sh        # shellcheck + gofmt + go vet/build/test
scripts/build.sh         # → dist/sshgw-proxyfront, dist/sshgw-route-plugin,
                         #    dist/sshgw-terminal-bridge

LXC 생성, WireGuard 엔드포인트, systemd 유닛, 피어 한정 nftables 방화벽은 pickle-infra 저장소의 프로비저닝 스크립트가 담당합니다.

설정 (환경변수)

변수 사용 데몬 의미
PICKLE_SSHGW_API_BASE / PICKLE_SSHGW_TOKEN route-plugin pickle-api 베이스 URL, 공유 Bearer 토큰(필수, 없으면 기동 거부)
PICKLE_SSHGW_UPSTREAM_KEY_FILE route-plugin 업스트림 인증용 플랫폼 개인키 경로
SSHGW_PROXYFRONT_LISTEN / _UPSTREAM / _PEER proxyfront 인그레스 주소, 루프백 sshpiperd, 신뢰 WireGuard 피어 CIDR
PICKLE_TERMINAL_WS_LISTEN / _CONTROL_LISTEN / _CONTROL_TOKEN terminal-bridge WS/컨트롤 리슨 주소와 컨트롤 인증 토큰
PICKLE_TERMINAL_KEY_FILE terminal-bridge 터미널 전용 플랫폼 개인키(라우팅용 키와 분리)
PICKLE_TERMINAL_IDLE_TIMEOUT / _REVALIDATE_INTERVAL / _MAX_SESSIONS terminal-bridge 유휴 종료, 인가 재검증 주기, 세션 상한

핀 버전: Go 1.26, sshpiperd v1.5.4, go-proxyproto v0.15.0.

Pickle 저장소 구성

저장소 역할
pickle-api 백엔드 REST API, 프로비저닝 파이프라인, 접속 인가
pickle-console 웹 콘솔 (사용자·관리자 SPA)
pickle-sshgw SSH 게이트웨이 + 웹 터미널 브리지
pickle-proxy-agent HTTP(S) 게시용 리버스 프록시 제어 에이전트
pickle-infra 인프라 프로비저닝 스크립트·런북

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages