
제로 트러스트 SSH 배스천 프록시로, Vault 기반 키 관리, RBAC 정책 적용, 전체 세션 녹화, 그리고 프로덕션 인프라에 대한 감사 가능한 접근을 위한 관리자 TUI를 제공합니다.
강화된 자체 호스팅 SSH 배스천 호스트 — Vault 기반 키 관리, RBAC 정책 적용, 전체 세션 녹화, 대화형 관리자 TUI를 갖추고 있으며, 감사 가능한 제로 트러스트 방식으로 프로덕션 인프라에 접근해야 하는 팀을 위해 설계되었습니다.
현대 엔지니어링 팀은 개발자에게 업무 수행에 필요한 최소한의 접근 권한을 부여할 방법이 필요합니다 — 그 이상도 이하도 아닙니다. 기존의 SSH 키 배포 방식은 오류가 발생하기 쉽습니다. 키가 공유되고, 노트북에 잊혀진 채 남아 있으며, 철회도 너무 늦게 이루어집니다.
ZTTP는 인프라로 들어가는 단일 문 역할을 하여 이 문제를 해결합니다:
| 문제 | ZTTP 솔루션 |
|---|
개발자 노트북
│
│ zttp
│ (내부적으로: 포트 2224의 SSH)
▼
┌─────────────────────────────────────────────────────────┐
│ ZTTP 프록시 │
│ │
│ ① 인증 게이트 — bcrypt/Argon2id 로그인 TUI │
│ ② RBAC 엔진 — 환경 인식 정책 검사 │
│ ③ Vault 조회 — 임시 SSH 키 검색 │
│ ④ 브리지 — 투명 TCP 터널 │
│ ⑤ 감사 기록기 — ttyrec 프레임 레코더 │
└──────────┬──────────────────────────────────────────────┘
│ ssh (사설 IP, 임시 키)
▼
대상 서버
인프라 서비스 (Docker Compose):
.ttyrec 형식으로 기록됨서버 (프록시 호스트):
2224의 공용 또는 LAN 접근 가능 IPmake (선택 사항이지만 권장)개발자 (클라이언트):
ssh 명령)git clone https://gitlab.com/Nihal799/zttp.git
cd zttp
cp .env.example .env
.env를 편집하고 최소한 다음을 설정하세요:
PROXY_NODE_IP=<your-server-public-ip>
POSTGRES_PASSWORD=<a-strong-password>
VAULT_TOKEN=<a-strong-vault-token>
⚠️
.env파일을 절대 커밋하지 마세요..gitignore에 포함되어 있습니다.
make docker-up
# 또는 직접:
docker compose -f deploy/docker-compose.yml up -d --build
make docker-ps
curl http://localhost:8080/healthz
make release PROXY_ADDR=<your-server-ip>:2224
이 명령은 모든 플랫폼용 클라이언트를 크로스 컴파일하고 올바른 서버 URL로 dist/install.sh 및 dist/install.ps1을 자동 업데이트합니다. Nginx 컨테이너는 이를 http://<your-server-ip>:8555/에서 제공합니다.
curl -fsSL http://<proxy-ip>:8555/install.sh | bash
irm http://<proxy-ip>:8555/install.ps1 | iex
설치가 완료되면 ZTTP 게이트웨이에 연결합니다:
zttp
# 또는 직접:
ssh -p 2224 <your-username>@<proxy-ip>
터미널 로그인 화면이 표시됩니다. 인증 후 접근 권한이 있는 서버 목록이 표시됩니다.
모든 구성은 환경 변수(또는 .env 파일)를 통해 이루어집니다. 전체 참조는 .env.example을 참조하세요.
ZTTP는 역할 기반 모델을 사용합니다. 각 사용자에게는 역할이 할당되며, 각 역할에는 접근할 수 있는 서버 환경을 정의하는 정책이 있습니다.
역할 및 서버 할당은 관리자 콘솔을 통해 관리됩니다 (아래 참조). RBAC 엔진은 모든 검사를 단일 PostgreSQL 쿼리로 수행하며, 클라이언트에게 접근이 거부된 이유를 절대 노출하지 않습니다 (열거 방지).
게이트웨이 메뉴에서 zttp-admin 서버에 연결하거나 security-admin 역할이 있는 계정으로 로그인하세요.
관리자 콘솔에서 제공하는 기능:
모든 관리자 작업은 감사 볼륨 내의
admin-actions.log에 기록됩니다.
모든 세션은 zttp-audit-logs Docker 볼륨(컨테이너 내부의 /var/log/zttp/audit/)에 저장됩니다.
security-admin으로 로그인Ctrl+C를 눌러 돌아가기# 녹화 목록
sudo ls /var/lib/docker/volumes/zttp-audit-logs/_data/
# ttyplay로 녹화 재생
sudo ttyplay /var/lib/docker/volumes/zttp-audit-logs/_data/<session-id>.ttyrec
# 관리자 작업 로그 읽기
sudo cat /var/lib/docker/volumes/zttp-audit-logs/_data/admin-actions.log
요구 사항: Go 1.25+, Docker (크로스 컴파일용)
# 현재 플랫폼용 프록시 + CLI 빌드
make build
# 모든 플랫폼용 CLI 크로스 컴파일 (Linux, macOS, Windows)
make release PROXY_ADDR=<proxy-ip>:2224
# 테스트 실행
make test
# 프록시 로컬 실행 (Postgres 및 Vault가 이미 실행 중이어야 함)
make run-proxy
zttp/
├── cmd/
│ ├── proxy/ # 프록시 서버 진입점
│ └── zttp/ # CLI 클라이언트 진입점
├── db/
│ └── migrations/ # PostgreSQL 스키마 마이그레이션
├── deploy/
│ ├── docker-compose.yml
│ ├── Dockerfile.proxy
│ └── vault-seed.sh # 테스트 SSH 키를 Vault에 시드
├── dist/
│ ├── install.sh # Linux/macOS 설치 스크립트
│ └── install.ps1 # Windows 설치 스크립트
├── internal/
│ ├── audit/ # 관리자 작업 로깅
│ ├── auth/ # 사용자 인증 (bcrypt, 잠금)
│ ├── cli/ # CLI 클라이언트 TUI 및 연결 로직
│ ├── config/ # 환경 기반 구성
│ ├── killswitch/ # gRPC 킬 스위치 서비스
│ ├── proxy/ # SSH 프록시, 게이트웨이 TUI, 관리자 TUI, 브리지
│ ├── rbac/ # 역할 기반 접근 제어 엔진
│ ├── ratelimit/ # IP별 속도 제한
│ ├── session/ # 세션 추적 및 DB 저장소
│ └── vault/ # HashiCorp Vault SSH 키 클라이언트
├── proto/ # gRPC 프로토콜 정의
├── tools/
│ └── hashpw/ # CLI 도구: bcrypt 비밀번호 해시 생성
├── .env.example # 구성 템플릿
├── go.mod
└── Makefile
git checkout -b feat/your-featuremake test다음은 커밋하지 마세요:
.env 또는 비밀을 포함한 모든 파일zttp 바이너리는 .gitignore 처리됨)이 프로젝트는 독점 소프트웨어입니다. 모든 권리 보유.
Go, PostgreSQL, HashiCorp Vault 및 Docker로 구축되었습니다.
| 노트북에 공유되는 SSH 키 | 키는 HashiCorp Vault에만 저장 — 디스크에는 절대 저장되지 않음 |
| 누가 무엇을 했는지에 대한 가시성 부족 | 모든 키 입력이 .ttyrec 형식으로 기록됨 |
| 막연한 프로덕션 접근 권한 | 역할 기반 정책 엔진이 환경별 규칙을 적용 |
| 활성 세션을 중지할 방법 없음 | 킬 스위치 gRPC 엔드포인트가 모든 활성 세션을 즉시 종료 |
| 감사자에게 불투명한 접근 | 세션 재생, 텍스트 로그, 관리자 작업 로그를 제공하는 관리자 TUI |
| 서비스 | 용도 |
|---|
zttp-proxy | SSH 배스천 (Go 바이너리) |
zttp-postgres | 컨트롤 플레인 데이터베이스 (사용자, 서버, RBAC 정책) |
zttp-vault | HashiCorp Vault — SSH 개인 키 저장 |
zttp-nginx | /release/에서 CLI 설치 프로그램 제공 |
zttp-init-audit | 볼륨 권한을 수정하는 일회성 컨테이너 |
| 변수 | 기본값 | 설명 |
|---|
PROXY_LISTEN_ADDR | 0.0.0.0:2222 | SSH 프록시 바인드 주소 |
HTTP_LISTEN_ADDR | 0.0.0.0:8080 | 상태 확인 HTTP 주소 |
GRPC_LISTEN_ADDR | 0.0.0.0:9090 | 킬 스위치 gRPC 주소 |
PROXY_NODE_IP | 127.0.0.1 | CLI 바이너리에 포함된 외부 IP |
DATABASE_URL | postgres://zttp:... | PostgreSQL 연결 문자열 |
VAULT_ADDR | http://localhost:8201 | Vault 서버 URL |
VAULT_TOKEN | dev-root-token-zttp | Vault 루트 토큰 (개발 전용 — 프로덕션에서는 AppRole 사용) |
MAX_FAILED_ATTEMPTS | 5 | 잠금 임계값 |
LOCKOUT_DURATION | 15m | 계정 잠금 기간 |
RATE_LIMIT_PER_MIN | 10 | IP당 분당 최대 로그인 시도 횟수 |
AUDIT_LOG_DIR | /var/log/zttp/audit | 세션 녹화 디렉터리 경로 |
SOC_WEBHOOK_URL | (비어 있음) | SOC 알림용 선택적 웹훅 |
| 역할 | 접근 권한 |
|---|
security-admin | 모든 환경에 대한 전체 접근 + 관리자 콘솔 |
sre-tier1 | 프로덕션을 포함한 모든 환경 |
sre-tier2 | 스테이징 및 개발 전용 |
dev | 개발 환경 전용 |
readonly | 개발 환경, 제한된 명령 집합 |
| 메뉴 옵션 | 설명 |
|---|
| 사용자 추가 | 역할 할당과 함께 새 사용자 생성 |
| 서버 추가 | 대상 서버 등록 (호스트 이름, IP, 환경, SSH 사용자) |
| 서버 접근 관리 | 특정 서버에 대한 사용자 접근 권한 부여 또는 철회 |
| 사용자 보기 | 모든 사용자 및 해당 역할 나열 |
| 서버 보기 | 등록된 모든 서버 나열 |
| 감사 로그 보기 | 세션 탐색, 녹화 재생, 텍스트 로그 읽기 |
| [ 뒤로 ] | 서버 게이트웨이로 돌아가기 |
| 명령 | 설명 |
|---|
make build | 현재 플랫폼용 프록시 및 CLI 빌드 |
make release | 모든 플랫폼용 CLI 바이너리 크로스 컴파일 |
make release-docker | Docker 컨테이너 내부에서 크로스 컴파일 (snap/WSL 문제 방지) |
make docker-up | 모든 Docker Compose 서비스 시작 |
make docker-down | 모든 서비스 중지 및 볼륨 삭제 |
make docker-logs | 프록시 로그 추적 |
make docker-ps | 컨테이너 상태 표시 |
make test | 모든 Go 테스트 실행 |
make migrate | 데이터베이스 마이그레이션 적용 |
make seed | 개발 데이터 시드 |
make hashpw PW=mypassword | 수동 DB 시드를 위한 bcrypt 해시 생성 |
make clean | 컴파일된 바이너리 및 빌드 캐시 제거 |
| 계층 | 메커니즘 |
|---|
| 전송 | 모든 클라이언트 연결은 SSH (전송 중 암호화) |
| 인증 | bcrypt (비용 12) / Argon2id — 스키마에서 평문이 구조적으로 금지됨 |
| 무차별 대입 방지 | 계정 잠금 (5회 시도 / 15분) + IP별 속도 제한기 |
| 권한 부여 | 단일 JOIN RBAC 쿼리 — 거부는 항상 일반적임 ("Permission denied") |
| 비밀 관리 | SSH 개인 키는 HashiCorp Vault에만 저장, 임시로 가져옴 |
| 감사 추적 | .ttyrec 형식의 전체 키 입력 녹화, 변경 불가능한 추가 전용 관리자 로그 |
| 프로세스 격리 | 프록시는 distroless 컨테이너 내부에서 비루트 (UID 65532)로 실행 |
| 킬 스위치 | 프록시를 재시작하지 않고 gRPC를 통해 모든 활성 세션 종료 가능 |