<!-- canonical: https://docs.axelabs.ai/services/gate -->
<!-- source: content/services/gate.mdx -->

---
title: Gate
description: 내부 결재 + 외부 계약 e-sign 거버넌스 — 결정 SoR + gate-native CAdES-T 전자서명 봉인 + 원본 암호 보존. Rust + Postgres + axum.
---

# Gate

**한 줄 소개**: 의사결정을 *증명 가능하게* 남기는 거버넌스 서비스. 내부 결재(기안 → 상신 → 승인 → 시행)와 외부 계약 e-sign 을 한 곳에서 처리하고, 시행 시 gate-native CAdES-T(RFC3161 TSA) 봉인을 동기 생성해 결정 자체를 위·변조 불가한 SoR 로 만든다. 원본 문서는 암호화해 같은 곳에 보존한다. ([D-gate-5](/ops/decisions))

서비스 경계(어떤 문서가 gate 에, 무엇이 index/hive 로) = [D-gate-index-boundary](/ops/decisions) · [/architecture/data](/architecture/data).

## 기술 스택

| 항목 | 값 |
|---|---|
| 언어 | Rust |
| 프레임워크 | axum + maud (서버렌더 HTML) |
| DB | PostgreSQL 16 + sqlx (compile-time embedded migrations) |
| 암호 | e-sign 자체 엔진(`crypto.rs`/`tsa.rs`/`pades.rs`/`hsm.rs`); PII·해시는 pgcrypto in-SQL (Rust 대칭암호 dep 0) |
| e-sign | CAdES-T (detached CMS RSA-2048+SHA256 + RFC3161 TSA) · PAdES-B-T (typst + pyHanko) |
| 배포 | build-from-SHA blue/green + Caddy proxy (cortex 패턴) |
| repo | `github.com/axelabs-ai/gate` (canonical `/Users/axe/gate`) |

## 포트 (41xx)

| 포트 | 용도 |
|---|---|
| 4100 | PostgreSQL 16 (gate-postgres) |
| 4110 | gate-mcp-blue (active, docker alias `gate-mcp`) |
| 4111 | gate-mcp-green (passive) |
| 127.0.0.1:4112 | axe-gate-proxy (Caddy blue/green selector, loopback 바인딩) |

- **공개**: `axe.axelabs.ai/gate/mcp` (MCP) + `gate.axelabs.ai` (웹 UI, Entra SSO). **내부**: Tailscale `100.127.210.30:4112` · `127.0.0.1:4112`.
- ⚠️ **Phase-1 internal** — `_HEALTH_SERVICES` 제외(auto-reconcile / `axe health` 비대상, auto-deploy 서프라이즈 방지). MCP edge(`/gate/mcp`) cloudflared origin 은 Phase-5 deferred(edge-probe informational·non-fatal); 웹 UI 터널은 live.

## 인증 — 3단 래더

순서대로 시도, 먼저 통과하는 분기가 actor 를 확정:

1. **HS256 gate JWT** (1순위) — `GATE_JWT_SECRET` 서명, claims `{sub, email, iss:"gate"}`. gate OAuth AS 발급분(claude.ai 등이 항상 보내는 형태). 외부세션(`knd="ext"`)은 MCP 거부 → fall-through.
2. **Blueprint RS256 플랫폼 토큰** — `BLUEPRINT_ISSUER=https://axe.axelabs.ai` 설정 시 ON. **`axe login` 통합 SSO** — 2026-06-14 issuer flip([D-bp-oidc-issuer-1](/ops/decisions))으로 동작. gate 는 토큰의 `scope` 를 전혀 참조하지 않음 → 서명(RS256) + `iss` + `aud`(`axe.axelabs.ai`) + `exp` 만 검증하므로, frame/hive 와 같은 토큰 한 장이 그대로 통과.
3. **Entra ID 직접 RS256** (기본) — Microsoft JWKS, operator dev / `az` cli / claude.ai confidential client.

공통: `alg=RS256` 고정(alg-confusion 차단), peek-then-fully-verify (frame `auth_blueprint.py` 미러).

**RLS = 두 갈래 OR (가시성)**: ① participant-RLS `gate_is_participant(wf_id)` = 기안자 ∪ 결재선 · ② entity_membership `gate_member_of_*` ([D-gate-7](/ops/decisions)) = axec/axev 내부 멤버는 그 법인의 **전체 결정기록 read**(additive `FOR SELECT`, 읽기 전용 — 결재 전이는 participant 만). 비참여·비멤버 = 빈 결과(기밀 경계). CLI `gate add-member/rm-member/list-members`.

## MCP 도구 (18)

`axe.axelabs.ai/gate/mcp` (Bearer JWT). 결재 라이프사이클 → 원본·전문 → 외부 e-sign → 메타 순:

| 도구 | rw | 용도 |
|---|---|---|
| `draft_document` | write | HTML 기안 문서 생성 |
| `create_workflow` | write | 문서 위 결재 워크플로 생성 |
| `submit_workflow` | write | 상신 (draft → in_review, 결재선 생성) |
| `act_on_step` | write | 결재 — 승인 / 반려 / 보류 |
| `execute_workflow` | write | 시행 — 전자서명 봉인 (approved → done) |
| `withdraw_workflow` | write | 기안자 철회 |
| `set_doa_policy` | write | 전결규정(결재선 template) 등록 |
| `get_workflow` | read | 워크플로 전체 타임라인 조회 |
| `list_inbox` | read | 내 결재함 + 내 차례 표시 |
| `verify_seal` | read | CAdES-T 봉인 암호학적 검증 |
| `attach_evidence` | write | 결정기록에 원본 문서 암호화 첨부 |
| `set_evidence_content` | write | 추출한 계약 전문 HTML 저장 (upsert) |
| `get_evidence` | read | 첨부 원본 메타 + 무결성검증 |
| `list_evidence` | read | 워크플로 첨부 원본 메타 목록 |
| `create_signing_envelope` | write | 외부 계약 서명 요청 발송 (`sign_url` 반환) |
| `get_envelope_status` | read | 외부 서명 envelope 상태 조회 |
| `whoami` | read | 인증 actor + DB actor 확인 |
| `list_entities` | read | 법인 entity 카탈로그 (axec / axev) |

## 빠른 사용 — CLI (`axe gate`)

Web ERP 없이 터미널에서 내부 결재 + 외부 계약. 조회는 웹(`gate.axelabs.ai`)도 가능. 전 라이프사이클 e2e 검증됨.

```bash
# 1회 로그인 (브라우저 SSO — 운영자 토큰 발급 불요)
axe self-update          # 0.1.10+ (gate 명령 포함)
axe login                # Entra / Blueprint 통합 SSO

# 내부 결재 — 기안 → 상신 → 승인 → 시행 → 검증
axe gate inbox                              # 내 결재함 (참여 중 + 내 차례)
axe gate show <id>                          # 상세 (상태·결재선·봉인·원본)
axe gate draft --title "용역 계약" --decision-type contract --kind contract \
               --entity axev --amount 50000000 --self    # 기안+상신 (--line a@x,b@y 로 결재선 지정)
axe gate approve <id> --comment "검토 완료"   # 승인 (reject / hold 동일)
axe gate execute <id> [--pdf]               # 시행 — CAdES-T 봉인 (--pdf 시 PAdES PDF 동시 생성)
axe gate verify <id>                        # 봉인 암호검증 (CMS·TSA·무결성)
axe gate withdraw <id>                      # 기안자 철회

# 외부 계약 e-sign
axe gate sign-send <id> --signer hong@x.com:홍길동 --mode sequential   # 서명자별 링크 발송 (--signer 반복)
axe gate sign-status <id>

# 조회 / 메타
axe gate entities | whoami | tools
```

## e-sign 봉인 + 원본 보존

- **봉인 (`esign_seal`, mig 0005)**: 시행 시 결정 정본 바이트에 detached CAdES-BES CMS(RSA-2048 + SHA256) 서명 → RFC3161 TSA(기본 DigiCert, 한국 prod 은 `GATE_TSA_URL` 로 Koscom/CrossCert swap) 타임스탬프 부착 = **CAdES-T**. append-only(`gate_append_only` 트리거 + `REVOKE UPDATE,DELETE`). `verify_seal` / `/gate/wf/:id/seal` 가 CMS 서명 + TSA + 3-해시 일치 재검증. 서명 신원 = self-signed X.509 또는 PKCS#11 HSM(`load_esign_signer` 우선순위 PKCS#11 → KEY_PEM → KEY_DIR → dev-ephemeral).
- **원본 보존 (`decision_evidence`, [D-gate-6](/ops/decisions))**: 결정기록에 원본 PDF 바이트를 `pgp_sym_encrypt_bytea(원본, GATE_PII_PASSPHRASE_<entity>)` 로 암호 첨부. `sha256` = 원본 평문 해시(봉인된 body 해시와 대조 → '봉인 해시 ↔ 실제 바이트' 고리 닫음). participant-RLS + append-only. read 시 복호화 후 재해시 == 저장 해시 검증(`integrity_ok`). passphrase 미설정 = fail-closed(평문 보관 거부).
- **계약 전문 (`evidence_content`, v7)**: 스캔 날인본(텍스트 레이어 0 → `pdftotext` 빈 결과)을 vision 으로 전사한 HTML 가독 view. body 요약·원본 PDF(법적 정본)와 별개이며 **mutable**(재추출 upsert). RLS = participant OR entity-member(read) / participant(write).

## 웹 (`gate.axelabs.ai`)

Entra SSO 로그인 → 대시보드 `/gate/app` · 결재함 `/gate/inbox` · 계약 `/gate/contracts` · 워크플로 상세 `/gate/wf/:id`(결재선·봉인·**원본 문서** 섹션 + 원본 inline 다운로드 `/gate/wf/:id/evidence/:eid`, 한글 파일명 RFC 5987, `no-store`). 외부 서명자는 무로그인 `/gate/sign/:token`(토큰=인가, RLS 우회), 외부 회원은 매직링크 `/gate/my` 포털(`knd=ext` 세션, email 스코프 IDOR 차단). @axe/ui 디자인 시스템.

## 배포

```bash
axe ship gate          # release-gate + build-from-SHA + blue/green (직접 git push 금지 — pre-push guard)
# 또는: axe deploy gate --apply   (deploy hook gate_blue_green, 무중단 alias swap)

# ⚠️ gate 는 mcp-http 만 → 마이그레이션 자동 적용 안 됨. 배포 후 active color 에 수동:
docker exec gate-mcp-<active> gate migrate
```

- env_file = `.env.local` (vault dump, [D-ops-17](/ops/decisions)). `environment:` 블록은 non-secret/identity 만(`BLUEPRINT_ISSUER`/`JWKS_URL`/`AUDIENCE`, `GATE_DB_HOST` 등 — 비밀 중복 금지).
- secrets 4종: `GATE_DB_PASSWORD` · `GATE_JWT_SECRET` · `GATE_ESIGN_WEBHOOK_SECRET` · `GATE_ESIGN_KEY_PEM`(escrow/DR). per-entity `GATE_PII_PASSPHRASE_<entity>`(vault `gate/axe/pii-passphrase-<entity>`). 서명 키는 `/run/esign`(blue+green 공유 bind-mount, 단일 봉인 신원).
