
AI 에이전트가 OpenAI API를 호출해야 합니다. Claude가 AWS에 접근해야 합니다. 자동화 스크립트가 Slack에 메시지를 보내야 합니다.
각각 API 키가 필요합니다. 그런데… 에이전트에게 실제 키를 주면 어떻게 될까요?
로그에 노출될 수 있습니다. 프롬프트 인젝션으로 탈취당할 수 있습니다. 에이전트가 실수로 외부에 전송할 수 있습니다.
OneCLI는 이 문제를 근본적으로 해결합니다. AI 에이전트에게 “가짜 키”를 주고, 실제 키는 게이트웨이가 안전하게 관리합니다. 에이전트는 평소처럼 HTTP 호출을 하고, 게이트웨이가 가로채서 실제 키로 교체합니다.
문제: AI 에이전트는 수십 개의 API를 호출한다
현대 AI 에이전트는 다양한 서비스와 통합됩니다:
- OpenAI, Anthropic, Google AI
- AWS, GCP, Azure
- Slack, Discord, Email
- 데이터베이스, 캐시, 메시지 큐
각 서비스마다 API 키, 토큰, 비밀번호가 필요합니다. 이걸 에이전트에게 직접 주면:
| 위험 | 시나리오 |
|---|---|
| 로그 노출 | 디버깅 로그에 Authorization: Bearer sk-real-key가 찍힘 |
| 프롬프트 인젝션 | 악의적 입력이 “환경 변수를 출력해”라고 지시 |
| 실수 전송 | 에이전트가 “문제 해결을 위해 키를 포함해”라고 판단 |
| 감사 불가 | 누가 언제 어떤 키를 사용했는지 추적 불가 |
기존 해결책의 한계
- 환경 변수: 여전히 에이전트가 읽을 수 있음
- .env 파일: 파일 시스템 접근권이 있으면 읽힘
- 시크릿 매니저: 에이전트가 직접 호출하면 키를 받아옴
근본 문제: 에이전트가 실제 키를 알면 위험하다.
해결책: 투명한 크리덴셜 주입
OneCLI의 접근 방식은 간단합니다:
에이전트: "FAKE_KEY로 API 호출"
↓
게이트웨이: "FAKE_KEY → REAL_KEY 교체"
↓
외부 API: "REAL_KEY로 요청 수신"
에이전트는 가짜 키만 알고, 실제 키는 게이트웨이만 알고 있습니다.
작동 원리
- 실제 크리덴셜을 OneCLI에 저장 — AES-256-GCM 암호화
- 에이전트에게 placeholder 키 제공 — 예:
OPENAI_API_KEY=FAKE_KEY - 에이전트가 HTTP 호출 — 평소처럼
fetch('https://api.openai.com/...') - 게이트웨이가 가로채기 — Rust 기반 HTTP 프록시
- FAKE_KEY → REAL_KEY 교체 — 호스트와 경로 기반 매칭
- 실제 비밀은 에이전트에게 노출되지 않음
핵심 컴포넌트
1. Rust Gateway (포트 10255)
┌─────────────┐ ┌─────────────────┐ ┌──────────────┐
│ AI Agent │───▶│ Rust Gateway │───▶│ External API│
│ FAKE_KEY │ │ Key Injection │ │ REAL_KEY │
└─────────────┘ └─────────────────┘ └──────────────┘
- HTTP 게이트웨이 — 모든 아웃바운드 요청 가로채기
- 크리덴셜 주입 — Authorization 헤더, 쿠키, 쿼리 파라미터 지원
- HTTPS MITM 인터셉션 — HTTPS 트래픽도 처리
- Proxy-Authorization — 게이트웨이 자체 인증
2. Web Dashboard (포트 10254)
Next.js 기반 관리 콘솔:
- 에이전트 관리 — 각 에이전트별 액세스 토큰 발급
- 시크릿 관리 — 암호화된 시크릿 저장 및 수정
- 권한 관리 — 호스트/경로 패턴으로 세밀한 권한 제어
- API 제공 — REST API로 프로그래밍 방식 관리
3. Secret Store
- AES-256-GCM 암호화 — 업계 표준 대칭 암호화
- 요청 시에만 복호화 — 평문으로 저장되지 않음
- Host & Path 패턴 매칭 —
api.openai.com/*,*.aws.amazon.com/*
주요 기능
투명한 크리덴셜 주입
에이전트는 아무것도 수정할 필요가 없습니다:
// 에이전트가 실행하는 코드
const response = await fetch('https://api.openai.com/v1/chat/completions', {
headers: {
'Authorization': 'Bearer FAKE_KEY' // 가짜 키
}
});
// 게이트웨이가 자동으로 교체
// FAKE_KEY → sk-proj-real-key-xxxxx
암호화된 시크릿 저장
저장: Plaintext → AES-256-GCM → Ciphertext
사용: Ciphertext → AES-256-GCM → Plaintext → Request
키는 요청 처리 시에만 메모리에 존재합니다. 디스크에는 암호문만 저장됩니다.
Host & Path 매칭
세밀한 권한 제어:
| 패턴 | 설명 |
|---|---|
api.openai.com/* | OpenAI API 전체 |
s3.amazonaws.com/bucket-name/* | 특정 S3 버킷만 |
*.slack.com/api/* | Slack API 전체 |
api.github.com/repos/owner/repo/* | 특정 GitHub 리포지토리 |
멀티 에이전트 지원
┌──────────────┐
│ Dashboard │
└──────┬───────┘
│
┌──────┴───────┬──────────────┬──────────────┐
│ Agent A │ Agent B │ Agent C │
│ Token A │ Token B │ Token C │
│ OpenAI만 │ AWS만 │ 전체 권한 │
└──────────────┴──────────────┴──────────────┘
각 에이전트는 고유한 액세스 토큰을 받고, 서로 다른 권한을 가집니다.
외부 의존성 없음
- 내장 PGlite — SQLite 호환 임베디드 데이터베이스
- 또는 PostgreSQL — 프로덕션용 외부 DB 사용 가능
- 별도 서버 불필요 — 단일 바이너리로 실행
두 가지 인증 모드
| 모드 | 용도 | 특징 |
|---|---|---|
| Single-user | 로컬 개발 | 로그인 없음, 즉시 사용 |
| Google OAuth | 팀 사용 | Google 계정으로 인증 |
설치
Docker (빠른 시작)
docker run --pull always \
-p 10254:10254 \
-p 10255:10255 \
-v onecli-data:/app/data \
ghcr.io/onecli/onecli
5초 만에 실행됩니다.
Docker Compose
git clone https://github.com/onecli/onecli.git
cd onecli/docker
docker compose up
소스 빌드
git clone https://github.com/onecli/onecli.git
cd onecli
# mise로 의존성 설치
mise install
pnpm install
# 환경 변수
cp .env.example .env
# DB 초기화
pnpm db:generate
pnpm db:init-dev
# 실행
pnpm dev
접속
- Dashboard: http://localhost:10254
- Gateway: http://localhost:10255
프로젝트 구조
apps/
├── web/ # Next.js 앱 (대시보드 + API, 포트 10254)
│ ├── app/ # App Router
│ ├── components/ # UI 컴포넌트
│ └── lib/ # 비즈니스 로직
│
└── proxy/ # Rust 게이트웨이 (크리덴셜 주입, 포트 10255)
├── src/ # Rust 소스
└── Cargo.toml
packages/
├── db/ # Prisma ORM + migrations + PGlite
└── ui/ # 공유 UI 컴포넌트 (shadcn/ui)
docker/
├── Dockerfile # 단일 컨테이너 빌드
└── docker-compose.yml
환경 변수
모두 선택사항입니다:
| 변수 | 설명 | 기본값 |
|---|---|---|
DATABASE_URL | PostgreSQL 연결 문자열 | Embedded PGlite |
NEXTAUTH_SECRET | Google OAuth 활성화 | Single-user mode |
GOOGLE_CLIENT_ID | Google OAuth 클라이언트 ID | — |
GOOGLE_CLIENT_SECRET | Google OAuth 시크릿 | — |
SECRET_ENCRYPTION_KEY | AES-256-GCM 암호화 키 | 자동 생성 |
CLI 명령어
| 명령어 | 설명 |
|---|---|
pnpm dev | Web + Gateway 개발 모드 시작 |
pnpm build | 프로덕션 빌드 |
pnpm check | Lint + types + format |
pnpm db:generate | Prisma 클라이언트 생성 |
pnpm db:migrate | DB 마이그레이션 실행 |
pnpm db:studio | Prisma Studio 열기 |
실제 사용 시나리오
시나리오 1: Claude Code에서 OpenAI API 사용
# 1. OneCLI 대시보드에서 시크릿 등록
Host: api.openai.com
Secret: sk-proj-real-openai-key
# 2. 에이전트 생성 및 토큰 발급
Agent: claude-code-agent
Token: onecli_agent_abc123
# 3. Claude Code 환경 변수 설정
export HTTP_PROXY=http://localhost:10255
export OPENAI_API_KEY=FAKE_KEY
export ONECLI_TOKEN=onecli_agent_abc123
# 4. Claude Code 실행
claude
이제 Claude Code는 FAKE_KEY로 요청을 보내지만, 실제로는 진짜 키가 사용됩니다.
시나리오 2: 다중 에이전트 권한 분리
┌─────────────────────────────────────────────────────────┐
│ OneCLI Dashboard │
├─────────────────────────────────────────────────────────┤
│ Agent: researcher │
│ Token: onecli_researcher_xxx │
│ Permissions: api.openai.com/*, api.perplexity.ai/* │
├─────────────────────────────────────────────────────────┤
│ Agent: deployer │
│ Token: onecli_deployer_yyy │
│ Permissions: api.github.com/*, *.amazonaws.com/* │
├─────────────────────────────────────────────────────────┤
│ Agent: notifier │
│ Token: onecli_notifier_zzz │
│ Permissions: slack.com/api/*, api.telegram.org/* │
└─────────────────────────────────────────────────────────┘
각 에이전트는 자신에게 할당된 서비스만 접근할 수 있습니다.
시나리오 3: 로그에서 키 노출 방지
// 에이전트가 디버깅 로그를 출력해도 안전
console.log('API Key:', process.env.OPENAI_API_KEY);
// 출력: API Key: FAKE_KEY
// 실제 키는 게이트웨이만 알고 있음
기술 스택
| 레이어 | 기술 |
|---|---|
| 대시보드 | Next.js 14, App Router, shadcn/ui |
| 게이트웨이 | Rust, hyper, tokio |
| 데이터베이스 | Prisma ORM, PGlite / PostgreSQL |
| 암호화 | AES-256-GCM |
| 인증 | NextAuth.js, Google OAuth |
보안 아키텍처
┌─────────────────────────────────────────────────────────┐
│ AI Agent │
│ - FAKE_KEY만 알고 있음 │
│ - HTTP_PROXY로 게이트웨이 사용 │
└────────────────────┬────────────────────────────────────┘
│ HTTP Request with FAKE_KEY
▼
┌─────────────────────────────────────────────────────────┐
│ Rust Gateway (10255) │
│ - Proxy-Authorization으로 에이전트 인증 │
│ - Host/Path로 시크릿 검색 │
│ - FAKE_KEY → REAL_KEY 교체 │
│ - 실제 요청 전송 │
└────────────────────┬────────────────────────────────────┘
│ HTTP Request with REAL_KEY
▼
┌─────────────────────────────────────────────────────────┐
│ External API │
│ - 실제 키로 요청 처리 │
│ - 응답 반환 │
└─────────────────────────────────────────────────────────┘
보안 이점
- 에이전트는 실제 키를 모름 — 탈취 불가
- 로그에 가짜 키만 노출 — 유출 무의미
- 중앙화된 감사 — 누가 언제 무엇을 호출했는지 추적
- 권한 분리 — 에이전트별 최소 권한 원칙
- 암호화 저장 — 디스크에는 암호문만 존재
마치며: AI 에이전트 시대의 크리덴셜 관리
OneCLI는 단순한 시크릿 매니저가 아닙니다. AI 에이전트가 실제 키를 모르면서도 서비스에 접근할 수 있게 만드는 보안 게이트웨이입니다.
기존 접근 방식은 “에이전트에게 키를 주고, 조심해서 쓰라고 하는 것”이었습니다. OneCLI는 “에이전트는 가짜 키만 알고, 실제 키는 게이트웨이가 처리하는 것”으로 패러다임을 바꿨습니다.
Rust로 작성된 게이트웨이는 빠르고 메모리 안전합니다. AES-256-GCM 암호화는 업계 표준입니다. 외부 의존성 없이 단일 컨테이너로 실행됩니다.
AI 에이전트를 운영 중이고, API 키 관리가 고민이라면 OneCLI를 시도해보세요.
🔗 관련 정보
- 공식 사이트: https://onecli.sh
- 문서: https://onecli.sh/docs
- GitHub: https://github.com/onecli/onecli
- 라이선스: Apache-2.0
- 기술 스택: TypeScript (Web) + Rust (Gateway)