# SSHPiper on Incus SSH 리버스 프록시 서버로, 사용자 이름 기반 라우팅을 통해 여러 백엔드 서버에 SSH 접속을 중계합니다. ## 개요 | 항목 | 값 | |------|-----| | 컨테이너 이름 | `sshpiper` | | 호스트 OS | Debian 12 (bookworm) | | SSHPiper 버전 | 1.5.1 | | 리스닝 포트 | 2222 | | IP 주소 | 10.253.100.34 | | 플러그인 | yaml | ## 아키텍처 ``` 클라이언트 → [호스트:2222] → [sshpiper 컨테이너:2222] → 백엔드 서버:22 proxy device sshpiperd ``` ## 접속 방법 ```bash # 형식: ssh -p 2222 @<호스트> ssh -p 2222 baserow@localhost ssh -p 2222 caddy@localhost ssh -p 2222 k8s@localhost ``` ## 등록된 파이프 | Alias | 백엔드 서버 | 대상 사용자 | |-------|------------|-------------| | `baserow` | 10.253.103.104 | root | | `caddy` | 10.253.103.139 | root | | `crowdsec` | 10.253.100.240 | root | | `hey` | 10.253.103.80 | root | | `k8s` | 10.253.103.124 | root | | `log-collector`, `log` | 10.253.100.55 | root | | `tor`, `tor-server` | 10.253.101.178 | root | | `vaultwarden`, `vault` | 10.253.100.48 | root | ## Alias와 실제 접속 사용자 현재 설정에서는 모든 파이프가 `to.username: root`로 되어 있어서, **어떤 alias로 접속하든 백엔드 서버에는 root로 접속**합니다. ``` ssh -p 2222 baserow@host → root@10.253.103.104 ssh -p 2222 caddy@host → root@10.253.103.139 ssh -p 2222 k8s@host → root@10.253.103.124 ``` - `from.username`: sshpiper에 접속할 때 사용하는 **라우팅용 alias** - `to.username`: 실제 백엔드 서버에 접속하는 **계정** ### 다른 사용자로 접속하려면 ```yaml # 예: deploy 사용자로 접속 - from: - username: "baserow" to: host: 10.253.103.104:22 username: deploy # root 대신 다른 계정 ignore_hostkey: true # 또는 원래 입력한 사용자 이름 유지 (username 생략) - from: - username_regex: ".*" # 모든 사용자 to: host: 10.253.103.104:22 # username 생략 → 클라이언트가 입력한 사용자명 그대로 사용 ignore_hostkey: true ``` ## SSH 키 인증 SSHPiper는 비밀번호 인증 외에 SSH 키 인증도 지원합니다. ### 인증 방향 ``` 클라이언트 ──[①]──→ sshpiper ──[②]──→ 백엔드 서버 from.authorized_keys to.private_key ``` | 방향 | 설정 | 설명 | |------|------|------| | ① 클라이언트 → sshpiper | `from.authorized_keys` | 클라이언트 공개키 검증 | | ② sshpiper → 백엔드 | `to.private_key` | 백엔드 접속용 개인키 | ### 백엔드 키 인증 설정 (sshpiper → 백엔드) 클라이언트는 비밀번호로 접속하고, sshpiper가 백엔드에는 키로 접속하는 방식입니다. **1. sshpiper에서 키 생성** ```bash incus exec sshpiper -- ssh-keygen -t ed25519 -f /etc/sshpiper/id_backend -N '' ``` **2. 백엔드 서버에 공개키 등록** ```bash # 공개키 확인 incus exec sshpiper -- cat /etc/sshpiper/id_backend.pub # 백엔드 서버의 authorized_keys에 추가 incus exec <백엔드> -- bash -c 'echo "<공개키내용>" >> /root/.ssh/authorized_keys' ``` **3. pipes.yaml 설정** ```yaml - from: - username: "myserver" to: host: 10.x.x.x:22 username: root private_key: /etc/sshpiper/id_backend # 백엔드 접속용 개인키 ignore_hostkey: true ``` ### 클라이언트 키 인증 설정 (클라이언트 → sshpiper) 특정 클라이언트 공개키만 허용하는 방식입니다. **1. 허용할 공개키 파일 생성** ```bash # 클라이언트의 공개키를 sshpiper에 등록 incus exec sshpiper -- bash -c 'cat > /etc/sshpiper/authorized_keys_myserver << EOF ssh-ed25519 AAAA... user@client EOF' ``` **2. pipes.yaml 설정** ```yaml - from: - username: "myserver" authorized_keys: - /etc/sshpiper/authorized_keys_myserver # 허용할 클라이언트 공개키 to: host: 10.x.x.x:22 username: root private_key: /etc/sshpiper/id_backend ignore_hostkey: true ``` ### 양방향 키 인증 (가장 안전) 클라이언트도 키로, 백엔드도 키로 접속하는 방식입니다. ```yaml - from: - username: "secure-server" authorized_keys: - /etc/sshpiper/authorized_keys_secure # 클라이언트 공개키 to: host: 10.x.x.x:22 username: root private_key: /etc/sshpiper/id_secure # 백엔드용 개인키 ignore_hostkey: true ``` ### 인라인 키 데이터 파일 경로 대신 base64 인코딩된 키를 직접 설정할 수도 있습니다. ```yaml - from: - username: "inline-example" authorized_keys_data: - "c3NoLWVkMjU1MTkgQUFBQS4uLg==" # base64 인코딩된 공개키 to: host: 10.x.x.x:22 username: root private_key_data: "LS0tLS1CRUdJTi4uLg==" # base64 인코딩된 개인키 ignore_hostkey: true ``` ## 설정 파일 ### 파이프 설정 (`/etc/sshpiper/pipes.yaml`) ```yaml version: "1.0" pipes: - from: - username: "서버별칭" to: host: 10.x.x.x:22 username: root ignore_hostkey: true ``` ### Systemd 서비스 (`/etc/systemd/system/sshpiper.service`) ```ini [Unit] Description=SSHPiper - SSH Reverse Proxy After=network.target [Service] Type=simple ExecStart=/usr/local/bin/sshpiperd -l 0.0.0.0 -p 2222 -i /etc/sshpiper/host_key /usr/local/bin/plugins/yaml --config /etc/sshpiper/pipes.yaml Restart=always RestartSec=5 [Install] WantedBy=multi-user.target ``` ## 관리 명령어 ```bash # 서비스 상태 확인 incus exec sshpiper -- systemctl status sshpiper # 서비스 재시작 incus exec sshpiper -- systemctl restart sshpiper # 로그 확인 incus exec sshpiper -- journalctl -u sshpiper -f # 설정 파일 편집 incus exec sshpiper -- nano /etc/sshpiper/pipes.yaml ``` ## 새 서버 추가 1. `pipes.yaml`에 새 파이프 추가: ```yaml - from: - username: "새서버" to: host: 10.x.x.x:22 username: root ignore_hostkey: true ``` 2. 서비스 재시작: ```bash incus exec sshpiper -- systemctl restart sshpiper ``` ## 사용 가능한 플러그인 | 플러그인 | 설명 | |---------|------| | `yaml` | YAML 파일 기반 라우팅 (현재 사용 중) | | `docker` | Docker 컨테이너 라우팅 | | `kubernetes` | Kubernetes Pod 라우팅 | | `workingdir` | 작업 디렉토리 기반 라우팅 | | `fixed` | 고정 대상 라우팅 | | `failtoban` | 실패 시 차단 기능 | | `username-router` | 사용자 이름 기반 라우팅 | ## Incus 프록시 설정 컨테이너에 `proxy2222` 디바이스가 설정되어 호스트의 2222 포트가 컨테이너의 2222 포트로 포워딩됩니다. ```bash # 프록시 설정 확인 incus config device show sshpiper # 프록시 추가 (이미 설정됨) incus config device add sshpiper proxy2222 proxy listen=tcp:0.0.0.0:2222 connect=tcp:127.0.0.1:2222 ``` ## 트러블슈팅 ### 접속 불가 시 ```bash # 서비스 상태 확인 incus exec sshpiper -- systemctl status sshpiper # 포트 리스닝 확인 incus exec sshpiper -- ss -tlnp | grep 2222 # 프로세스 확인 incus exec sshpiper -- ps aux | grep sshpiper ``` ### 로그 확인 ```bash # 실시간 로그 incus exec sshpiper -- journalctl -u sshpiper -f # 최근 에러 incus exec sshpiper -- journalctl -u sshpiper -p err --since "1 hour ago" ``` ## 참고 - [SSHPiper GitHub](https://github.com/tg123/sshpiper) - [SSHPiper 문서](https://github.com/tg123/sshpiper/wiki)