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