Skip to content

보안 및 프라이버시: auth_mode, allow_lan_access, 그리고 "계정 정보 유출 방지" 설계

Antigravity Tools를 "로컬 AI 게이트웨이"로 사용할 때 보안 문제는 보통 두 가지로 요약됩니다: 누구에게 서비스를 노출하는지(로컬만인지, 전체 LAN/인터넷인지), 외부 요청에 API Key를 가져야 하는지. 이 수업에서는 소스 코드의 규칙을 명확히 설명하고, 바로 따라 할 수 있는 최소 보안 기준을 제공합니다.

수업을 마치면 할 수 있는 것

  • allow_lan_access를 올바르게 선택: 수신 주소(127.0.0.1 vs 0.0.0.0)에 영향을 미치는지 압니다
  • auth_mode를 올바르게 선택: off/strict/all_except_health/auto의 실제 동작을 명확히 합니다
  • api_key를 구성하고 검증: curl을 사용하여 "인증이 켜져 있는지" 한눈에 알 수 있습니다
  • 프라이버시 보호의 경계를 이해: 로컬 proxy key는 업스트림으로 전달되지 않습니다. API 클라이언트의 오류 메시지는 계정 이메일 유출을 피합니다

현재 겪고 있는 문제

  • 휴대폰/다른 PC에서 액세스하고 싶지만, LAN 액세스를 켜면 "노출"이 될까 걱정합니다
  • 인증을 켜고 싶지만 /healthz를 면제해야 할지 확실하지 않고, 헬스 체크를 망가뜨릴까 봐 걱정합니다
  • 로컬 키, 쿠키, 계정 이메일이 외부 클라이언트나 업스트림 플랫폼으로 유출되는 것을 걱정합니다

언제 이 기능을 사용해야 하나요

  • allow_lan_access를 켜려 할 때(NAS, 가정 LAN, 팀 내부 네트워크)
  • cloudflared/리버스 프록시를 사용하여 로컬 서비스를 인터넷에 노출하려 할 때(먼저 **Cloudflared 일클릭 터널**을 보세요)
  • 401을 만나 "키가 없는 것"인지 "모드가 맞지 않는 것"인지 확인해야 할 때

🎒 시작 전 준비

전제 조건

이 수업에서 반복적으로 나타나는 3개 필드

  • allow_lan_access: LAN 액세스 허용 여부
  • auth_mode: 인증 전략(어떤 라우트에 key를 가져야 하는지 결정)
  • api_key: 로컬 프록시의 API Key(로컬 프록시 인증에만 사용, 업스트림으로 전달되지 않음)

auth_mode란 무엇인가?

auth_mode는 Antigravity Tools의 "프록시 인증 스위치 + 면제 전략"입니다. 외부 클라이언트가 로컬 프록시 엔드포인트에 액세스할 때, 어떤 요청에 proxy.api_key를 가져야 하며, /healthz 같은 헬스 체크 라우트를 인증 없이 액세스할 수 있는지를 결정합니다.

핵심 아이디어

  1. 먼저 "노출면"을 결정: allow_lan_access=false일 때는 127.0.0.1만 수신; true일 때는 0.0.0.0 수신
  2. 그 다음 "입구 키"를 결정: auth_mode가 key를 가져야 하는지, /healthz를 면제할지를 결정
  3. 마지막으로 "프라이버시 마무리": 로컬 proxy 키/쿠키를 업스트림으로 전달하지 않음. 대외 오류 메시지는 계정 이메일을 최대한 포함하지 않음

따라해보기

1단계: LAN 액세스를 켤지 먼저 결정(allow_lan_access)

이유 "다른 장치가 액세스해야 할 때"만 LAN 액세스를 켜야 합니다. 기본적으로 로컬만 액세스하는 것이 가장 편리한 보안 전략입니다.

ProxyConfig에서 수신 주소는 allow_lan_access로 결정됩니다:

rust
pub fn get_bind_address(&self) -> &str {
    if self.allow_lan_access {
        "0.0.0.0"
    } else {
        "127.0.0.1"
    }
}

GUI의 API Proxy 페이지에서 "LAN 액세스 허용" 스위치를 요구에 따라 설정하세요.

볼 수 있는 것

  • 끄면: "로컬만 액세스" 의미의 프롬프트가 나타납니다(구체적인 텍스트는 언어 팩에 따름)
  • 켜면: 인터페이스에 명확한 위험 경고가 표시됩니다(이것이 "노출면 확대"라는 것을 상기시킴)

2단계: auth_mode를 선택(먼저 auto 사용 권장)

이유auth_mode는 단순히 "인증 켬기/끄기"가 아니라, /healthz 같은 헬스 체크 엔드포인트를 면제할지도 결정합니다.

프로젝트는 4가지 모드를 지원합니다(docs/proxy/auth.md에서 옴):

  • off: 모든 라우트가 인증 불필요
  • strict: 모든 라우트가 인증 필요
  • all_except_health: /healthz를 제외한 모든 라우트가 인증 필요
  • auto: 자동 모드, allow_lan_access에서 실제 전략을 유도

auto의 유도 로직은 ProxySecurityConfig::effective_auth_mode()에 있습니다:

rust
match self.auth_mode {
    ProxyAuthMode::Auto => {
        if self.allow_lan_access {
            ProxyAuthMode::AllExceptHealth
        } else {
            ProxyAuthMode::Off
        }
    }
    ref other => other.clone(),
}

권장 사항

  • 로컬만 액세스: allow_lan_access=false + auth_mode=auto(결국 off와 동등)
  • LAN 액세스: allow_lan_access=true + auth_mode=auto(결국 all_except_health와 동등)

볼 수 있는 것

  • API Proxy 페이지에서 "Auth Mode" 드롭다운에 off/strict/all_except_health/auto 네 가지 옵션이 있습니다

3단계: api_key 확인(필요하면 재생성)

이유 프록시가 외부에서 액세스할 수 있어야 하면(LAN/인터넷), api_key를 암호로 관리해야 합니다.

기본적으로 ProxyConfig::default()sk-... 형식의 키를 생성합니다:

rust
api_key: format!("sk-{}", uuid::Uuid::new_v4().simple()),

API Proxy 페이지에서 현재 api_key를 편집, 재생성, 복사할 수 있습니다.

볼 수 있는 것

  • 페이지에 api_key 입력란과 편집/재생성/복사 버튼이 있습니다

4단계: /healthz로 "면제 전략"이 예상대로인지 검증

이유/healthz는 가장 짧은 루프: 실제로 모델을 호출하지 않고 "서비스 도달 가능 + 인증 전략 정확"을 확인할 수 있습니다.

<PORT>를 본인의 포트로 바꾸세요(기본값 8045):

bash
curl -sS "http://127.0.0.1:<PORT>/healthz"
powershell
curl.exe -sS "http://127.0.0.1:<PORT>/healthz"

볼 수 있는 것

json
{"status":"ok"}
auth_mode를 strict로 설정한 경우

strict/healthz를 면제하지 않습니다. 키를 가져야 합니다:

bash
curl -sS "http://127.0.0.1:<PORT>/healthz" \
  -H "Authorization: Bearer <API_KEY>"

5단계: "비 health 엔드포인트"로 401 검증(및 키를 가져오면 401이 아님)

이유 인증 미들웨어가 정말 작동하는지 확인하고 싶습니다. UI에서 모드를 선택했지만 실제로 작동하지 않는 것은 아닙니다.

다음 요청 본문은 일부러 불완전하게 작성한 것입니다. "호출 성공"이 목적이 아니라, 인증에 의해 차단되는지 검증하는 것입니다:

bash
#키 없음: auth_mode != off일 때, 직접 401이어야 함
curl -i "http://127.0.0.1:<PORT>/v1/messages" \
  -H "Content-Type: application/json" \
  -d "{}"

#키 있음: 401이 아니어야 함(요청 본문이 불완전하므로 400/422 반환 가능)
curl -i "http://127.0.0.1:<PORT>/v1/messages" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <API_KEY>" \
  -d "{}"

볼 수 있는 것

  • 키 없음: HTTP/1.1 401 Unauthorized
  • 키 있음: 상태 코드가 401이 아님

체크포인트 ✅

  • 현재 노출면을 명확히 설명할 수 있습니다: 로컬만(127.0.0.1)인지 LAN(0.0.0.0)인지
  • auth_mode=auto일 때, 실제 유효 모드를 예측할 수 있습니다(LAN → all_except_health, 로컬 → off)
  • 2개의 curl 명령으로 "키가 없는 401"을 재현할 수 있습니다

함정 경고

잘못된 방법 vs 권장 방법

시나리오❌ 일반적인 오류✓ 권장 방법
LAN 액세스 필요allow_lan_access=true만 켜고, auth_mode=offauth_mode=auto를 사용하고 강력한 api_key를 설정
인증을 켰는데 계속 401클라이언트가 키를 가져오지만 헤더 이름이 호환되지 않음프록시는 Authorization/x-api-key/x-goog-api-key 세 가지 헤더를 호환
인증을 켰지만 키를 구성하지 않음api_key가 비어 있는데도 인증을 켬백엔드가 직접 거부합니다(로그에 키가 비어 있다고 표시됨)

/healthz 면제는 all_except_health에서만 유효

미들웨어는 "유효 모드"가 all_except_health이고 경로가 /healthz일 때 통과합니다. "헬스 체크 포트"로 사용하고, 비즈니스 API로 사용하지 마세요.

프라이버시와 "계정 정보 유출 방지" 설계

1) 로컬 proxy 키는 업스트림으로 전달되지 않음

인증은 로컬 프록시 진입에서만 발생합니다. docs/proxy/auth.md에 명시되어 있습니다: proxy API key는 업스트림으로 전달되지 않습니다.

2) z.ai로 전달할 때, 전달 가능한 헤더를 의도적으로 축소

요청이 z.ai(Anthropic 호환)로 전달될 때, 코드는 소수의 헤더만 통과시켜 로컬 proxy 키나 쿠키가 나가지 않도록 합니다:

rust
// Only forward a conservative set of headers to avoid leaking the local proxy key or cookies.

3) 토큰 새로고침 실패의 오류 메시지는 계정 이메일 포함을 피함

토큰 새로고침이 실패하면 로그에는 구체적인 계정이 기록되지만, API 클라이언트로 반환되는 오류는 이메일을 포함하지 않는 형식으로 다시 작성됩니다:

rust
// Avoid leaking account emails to API clients; details are still in logs.
last_error = Some(format!("Token refresh failed: {}", e));

이 수업 요약

  • 먼저 노출면(allow_lan_access)을 결정하고, 입구 키(auth_mode + api_key)를 결정
  • auth_mode=auto의 규칙은 간단: LAN이면 최소 all_except_health, 로컬만이면 off
  • 프라이버시의 기준은 "로컬 키는 외부로 나가지 않고, 계정 이메일은 대외 오류에 유출되지 않음", 세부 사항은 미들웨어와 업스트림 전달 코드에 있음

다음 수업 예고

다음 수업에서는 **고가용성 스케줄링: 로테이션, 고정 계정, 스티키 세션 및 실패 재시도**를 보며, "보안 입구" 후 "안정된 출구"를 완성합니다.


부록: 소스 코드 참조

펼쳐서 소스 코드 위치 확인

업데이트 시간: 2026-01-23

기능파일 경로행 번호
auth_mode의 네 가지 모드와 auto 의미 설명docs/proxy/auth.md10-24
ProxyAuthMode 열거형 및 기본값(기본값 off)src-tauri/src/proxy/config.rs5-18
ProxyConfig의 핵심 필드 및 기본값(allow_lan_access, api_key)src-tauri/src/proxy/config.rs174-259
수신 주소 유도(127.0.0.1 vs 0.0.0.0)src-tauri/src/proxy/config.rs281-292
---------
인증 미들웨어(OPTIONS 통과, /healthz 면제, 세 가지 헤더 호환)src-tauri/src/proxy/middleware/auth.rs14-78
UI: allow_lan_access 및 auth_mode 스위치/드롭다운src/pages/ApiProxy.tsx943-1046
UI: api_key 편집/재설정/복사src/pages/ApiProxy.tsx1048-1120
invalid_grant 자동 비활성화 및 "이메일 유출 방지" 오류 재작성src-tauri/src/proxy/token_manager.rs841-940
disable_account: disabled/disabled_at/disabled_reason 쓰기 및 메모리 풀에서 제거src-tauri/src/proxy/token_manager.rs942-969
z.ai 전달 시 전달 가능한 헤더 축소(로컬 키/쿠키 유출 방지)src-tauri/src/proxy/providers/zai_anthropic.rs70-89
계정 풀 비활성화 및 UI 표시 동작 설명(문서)docs/proxy/accounts.md9-44