빠른 시작
지원 모드: Hosted Hybrid Local 제공 플랜: Free Solo Teams
5분 이내에 에이전트에 AI 거버넌스를 추가하세요. 배포 경로는 두 가지입니다. 상황에 맞는 경로를 선택하세요.
| 경로 | 적합한 경우 | 코드 변경 |
|---|---|---|
| 게이트웨이 (옵션 A) | 기존 에이전트, 빠른 도입 | 없음. URL 하나만 변경 |
| SDK (옵션 B) | 새 에이전트, 가장 긴밀한 통합 | 패키지 설치, 도구 호출 감싸기 |
두 경로 모두 대시보드에서 정의한 동일한 정책을 적용합니다.
1단계: 가입
- app.controlzero.ai에 접속하여 계정을 만드세요.
- 먼저 둘러보고 싶으신가요? app.controlzero.ai/demo에서 대화형 데모를 사용해 보세요. 계정이 필요 없습니다.
Free 플랜에는 월 5,000건의 통제된 액션이 포함되며 신용카드가 필요 없습니다.
2단계: 프로젝트 만들기
- 로그인하면 2단계 온보딩이 첫 프로젝트 생성을 안내합니다.
- 프로젝트 이름(예:
my-agent)을 정하고 환경을 선택하세요. - 프로젝트 설정 페이지에서 API 키(예:
cz_live_abc123...)를 복사하세요.
환경 변수로 설정하세요.
export CONTROLZERO_API_KEY="cz_live_your_key_here"
3단계: 대시보드에서 정책 정의하기
정책은 정책 라이브러리의 조직 수준에 존재하며 프로젝트에 연결됩니다. 이를 통해 하나의 정책이 프로젝트별 재정의와 함께 여러 프로젝트를 통제할 수 있습니다.
3a. 라이브러리 정책 만들기
사이드바에서 Library를 클릭한 다음 New policy를 클릭하세요.
- 이름:
db-read-only - 설명: 에이전트는 데이터베이스를 조회할 수 있지만 데이터를 수정할 수 없습니다.
- 규칙(JSON 배열): 아래 스니펫을 붙여넣거나 Insert sample를 클릭하세요.
[
{ "effect": "allow", "actions": ["database:read"], "resources": ["*"] },
{ "effect": "deny", "actions": ["database:write"], "resources": ["*"] },
{ "effect": "deny", "actions": ["database:admin"], "resources": ["*"] }
]
Create & publish v1을 클릭하세요. 정책이 저장되고 버전 1로 자동 게시되므로 즉시 연결할 수 있습니다.
actions, resources, principals는 배열입니다. 생성 대화상자는 이전 문서의 단일 값 형식인 action / resource도 받아들이며 자동으로 정규화합니다.
database:read는 방언의 키워드 표기와 관계없이 SELECT, EXPLAIN, SHOW, DESCRIBE, CTE 문을 포괄하는 이식 가능한 표준 클래스입니다. database:write는 INSERT/UPDATE/DELETE/MERGE 및 기타 데이터 수정 문을 포괄합니다. database:admin은 스키마와 권한 변경을 포괄합니다. SELECT 1; DROP TABLE x처럼 여러 문장을 끼워 넣는 경우는 database:admin으로 해석되므로, deny: database:admin 규칙이 게시된 모든 버전에서 이를 잡아냅니다. 허용 전용 형태(명시적 deny 규칙이 없는 경우)에서 method를 전달했을 때 파괴적인 SQL을 올바르게 차단하려면 controlzero 1.13.13+가 필요합니다. 이전 버전에서는 인자에서 도출된 클래스를 확인하기 전에 메서드에서 도출된 클래스가 허용 규칙을 충족할 수 있어 허용되었습니다. 더 세밀한 제어가 필요하면 특정 키워드(예: database:DROP)를 지정할 수도 있습니다. 전체 매핑은 Canonical Tool Names를 참고하세요.
3b. 프로젝트에 정책 연결하기
프로젝트를 열고 Attach policy를 클릭한 뒤 db-read-only를 선택하고, 상태를 Active로 유지한 채 확인하세요. 이제 프로젝트의 정책 번들이 해당 규칙을 적용합니다. 클라이언트는 다음 갱신 때 규칙을 반영합니다. Python SDK는 기본적으로 60초마다, Node SDK는 300초마다 폴링합니다.
4단계: 에이전트 통합하기
옵션 A: 게이트웨이 (코드 변경 없음)
게이트웨이는 투명한 프록시입니다. LLM 기본 URL이 게이트웨이를 바라보게 하고 헤더 두 개를 추가하세요. 기존 에이전트 코드는 그대로 동작합니다.
영어 원문 -- 번역은 기술 검토 대기 중입니다
The gateway enforces policies on every request and response automatically.
1. 기본 URL 변경
Anthropic (Claude):
# Before
ANTHROPIC_BASE_URL=https://api.anthropic.com
# After
ANTHROPIC_BASE_URL=https://gateway.controlzero.ai
OpenAI:
# Before
OPENAI_BASE_URL=https://api.openai.com
# After
OPENAI_BASE_URL=https://gateway.controlzero.ai/v1
2. Control Zero 헤더 추가
모든 LLM 요청에 다음 헤더를 추가하세요.
X-ControlZero-API-Key: cz_live_your_key_here
X-ControlZero-Agent-ID: my-first-agent
X-ControlZero-API-Key(필수)는 대시보드에서 발급받은 프로젝트 키입니다.X-ControlZero-Agent-ID(선택)는 감사 귀속을 위해 호출자를 식 별하는 레이블입니다. 생략하면 기본값은<provider>-direct입니다.
3. 테스트하기 (Anthropic)
curl -X POST https://gateway.controlzero.ai/v1/messages \
-H "Content-Type: application/json" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "X-ControlZero-API-Key: $CONTROLZERO_API_KEY" \
-H "X-ControlZero-Agent-ID: my-first-agent" \
-d '{
"model": "claude-sonnet-4-6",
"max_tokens": 100,
"messages": [{"role": "user", "content": "What is 2+2?"}]
}'
Anthropic API 키(x-api-key)는 Anthropic에 인증하는 데 사용됩니다. Control Zero API 키(X-ControlZero-API-Key)는 거버넌스, 감사 로깅, 정책 적용을 활성화합니다. 둘 다 필요합니다.
이게 전부입니다. 게이트웨이는 모든 LLM 응답을 가로채 도구 호출을 정책에 따라 평가하고, 허가되지 않은 액션을 차단합니다. 사전 검사(모델 차단, 비용 한도, PII 탐지)는 모든 요청이 공급자에 도달하기 전에 실행됩니다.
셀프 호스팅 배포, 지원되는 공급자, 구성 세부 사항은 게이트웨이 가이드를 참고하세요.
옵션 B: SDK 통합
SDK를 설치하여 애플리케이션 수준에서 도구 호출을 통제하세요.
영어 원문 -- 번역은 기술 검토 대기 중입니다
With an API key the SDK pulls your signed policy bundle from the dashboard automatically -- no local policy file required.
도구를 실행하기 전에 guard()를 호출하세요.
1. SDK 설치
Python:
pip install controlzero
요구 사항: Python 3.9 이상.
Node.js:
@controlzero 패키지는 Control Zero 레지스트리에서 제공됩니다. 프로젝트 또는
사용자 수준의 .npmrc에서 스코프가 이 레지스트리를 가리키도록 한 번만 설정하세요.
@controlzero:registry=https://npm.controlzero.ai
그런 다음 설치하세요.
npm install @controlzero/sdk
@controlzero 스코프 밖의 의존성은 계 속 npmjs.org에서 가져옵니다.
2. AI 앱에 거버넌스 추가하기 (Hosted 모드)
Python:
from controlzero import Client
# SDK pulls your dashboard policy on first call. Signed bundle, verified
# locally. Audit streams to the dashboard trail.
cz = Client(api_key="cz_live_your_key_here")
# Policies are managed in app.controlzero.ai, not in code. The SDK
# derives the SQL semantic class (read|write|admin|exec) from the
# `sql` argument, so a `database:read` rule fires for SELECT,
# EXPLAIN, SHOW, and CTE statements regardless of dialect.
result = cz.guard("database", method="SELECT", args={"sql": "SELECT id FROM orders"})
print(result.decision) # "allow" or "deny" per dashboard rules
result = cz.guard("database", method="DROP", args={"sql": "DROP TABLE orders"})
print(result.decision) # typically "deny" (matches database:admin)
print(result.reason)
# Or raise on deny:
from controlzero import PolicyDeniedError
try:
cz.guard("database", method="DROP", args={"sql": "DROP TABLE orders"}, raise_on_deny=True)
except PolicyDeniedError as e:
print(f"Blocked: {e.decision.reason}")
cz.close()
Node.js:
import { Client } from '@controlzero/sdk';
// Hosted mode uses the async factory. The SDK pulls your dashboard
// policy on first call, verifies signature, decrypts, and enforces.
const cz = await Client.create({ apiKey: 'cz_live_your_key_here' });
const result = cz.guard('database', {
method: 'SELECT',
args: { sql: 'SELECT id FROM orders' },
});
console.log(result.decision); // "allow" or "deny"
await cz.close();
두 가지 모드, 하나의 클라이언트:
영어 원문 -- 번역은 기술 검토 대기 중입니다
- Hosted mode (
api_key=...): the SDK pulls the signed policy bundle from the dashboard, verifies and decrypts it locally, and ships audit to the remote trail. Keys and bundles are cached under~/.controlzero/cache/so restarts work offline. This is the recommended flow -- policies live where your team can manage them.
영어 원문 -- 번역은 기술 검토 대기 중입니다
- Local mode (
policy=...orpolicy_file=...): zero network for policy eval. Audit stays in a rotating local file. Good for air-gapped deployments andcontrolzero.yamlchecked into the repo.
guard() 메서드는 decision("allow" 또는 "deny")과 reason 필드를 가진
PolicyDecision을 반환합니다. deny 결정을 반환하는 대신
PolicyDeniedError를 발생시키려면 raise_on_deny=True를 전달하세요.
호출이 차단될 때의 동작
guard() 호출이 deny 결정을 반환하면 결과를 확인하거나 예외를 발생시킬 수 있습니다.
from controlzero import Client, PolicyDeniedError
cz = Client(api_key="cz_live_your_key")
# Check the decision object. Note: `database:execute` is a legacy action
# name. The canonical name is `database:write`; both forms match the
# same calls.
result = cz.guard("database", method="execute", args={"sql": "DROP TABLE orders"})
if result.effect == "deny":
print(f"Blocked: {result.reason}")
# result.effect = "deny"
# result.reason = human-readable explanation
# result.policy_id = which policy matched
# Or raise on deny
try:
cz.guard("database", method="execute", args={"sql": "DROP TABLE orders"}, raise_on_deny=True)
except PolicyDeniedError as e:
print(f"Blocked by policy {e.decision.policy_id}: {e.decision.reason}")
5단계: 컨텍스트 매니저 사용하기 (선택 사항)
Client는 컨텍스트 매니저 프로토콜을 지원하며, 종료 시 close()를 호출하여 감사 로그를 플러시합니다.
from controlzero import Client, PolicyDeniedError
with Client(policy_file="./controlzero.yaml") as cz:
result = cz.guard(
"filesystem",
{"path": "/data/report.csv"},
method="read_file",
context={"resource": "/data/report.csv"},
)
if result.denied:
print(f"Access denied: {result.reason}")
else:
print(f"Allowed: {result.reason}")
전체 거버넌스 시나리오
다음 엔드투엔드 예제는 데이터베이스에서 읽고 허가되지 않은 쓰기를 시도하는 현실적인 에이전트를 보여 줍니다. 쓰기는 도구가 호출되기 전에 정책에 의해 차단됩니다.
from controlzero import Client
policy = {
"rules": [
{"allow": "database:read", "reason": "Reads are permitted"},
{"deny": "database:*", "reason": "All other database operations are blocked"},
]
}
def run_analyst_agent(cz: Client) -> None:
# Step 1: check if read is allowed. The SDK derives the SQL
# semantic class (read) from the `sql` argument, so the
# `database:read` rule fires.
read_decision = cz.guard(
"database",
{"sql": "SELECT * FROM orders WHERE region = 'APAC'"},
method="SELECT",
)
print(f"Read decision: {read_decision.decision} - {read_decision.reason}")
# Step 2: check if write is allowed (it will be denied; class is `write`)
write_decision = cz.guard(
"database",
{"sql": "UPDATE orders SET status = 'processed' WHERE region = 'APAC'"},
method="UPDATE",
)
print(f"Write decision: {write_decision.decision} - {write_decision.reason}")
with Client(policy=policy) as cz:
run_analyst_agent(cz)
예상 출력:
Read decision: allow - Reads are permitted
Write decision: deny - All other database operations are blocked
감사 로그 보기
영어 원문 -- 번역은 기술 검토 대기 중입니다
Every guard() decision, allowed or denied, is automatically logged.
대시보드에서 프로젝트로 이동하여 Audit Log를 클릭하면 다음을 볼 수 있습니다.
영어 원문 -- 번역은 기술 검토 대기 중입니다
This is a complete decision trail, not a sample. Each entry records coverage for that event, so “did not run” is distinguishable from “ran and found nothing.”
| 타임스탬프 | 도구 | 메서드 | 결정 | 에이전트 |
|---|---|---|---|---|
| 12:00:01 | database | SELECT | allow | agent-analyst |
| 12:00:02 | database | UPDATE | deny | agent-analyst |