OPA와 Cedar로 AI 에이전트 권한 제어하기: Policy-as-Code 실전 가이드
(AI agent authorization · fine-grained access control · Policy-as-Code)
AI 에이전트(Agent)란 LLM이 도구(tool)를 직접 선택하고 실행하는 자율적 시스템입니다. 사용자를 대신해 데이터베이스를 조회하고, 외부 API를 호출하고, 파일 시스템에 접근하는 이 에이전트들이 "어디까지 할 수 있는지"를 어떻게 통제하고 있으신가요? 프롬프트로 지시하고 있다면, 그것은 통제가 아닙니다. 프롬프트 인젝션 공격 하나로 에이전트가 허가받지 않은 동작을 실행할 수 있기 때문입니다. OWASP는 2025년 12월 자율 AI 에이전트에 특화된 Agentic Top 10 위협 목록을 발표했으며, 프롬프트 인젝션·도구 오용·신원 남용이 최상위 위험으로 분류됩니다.
멀티 에이전트 시스템의 보안은 에이전트를 신뢰하는 것이 아니라, 에이전트의 모든 행위를 외부에서 검증하는 구조에서 시작됩니다. 이 글에서는 Policy-as-Code 방법론을 활용해 에이전트 레이어 바깥에서 권한을 강제하는 방법을 소개합니다. OPA(Open Policy Agent)와 Cedar라는 두 정책 엔진을 중심으로, "누가, 어떤 도구를, 어떤 조건에서 쓸 수 있는지"를 코드로 선언하고 자동으로 시행하는 아키텍처를 살펴봅니다.
이 글은 LLM 에이전트를 프로덕션에 처음 배포하려는 백엔드·풀스택 개발자를 주요 대상으로 합니다. Rego 정책 작성법, Cedar의 형식 검증 기능, 두 도구의 선택 기준, 그리고 프로덕션 환경에서 흔히 저지르는 실수까지 다룹니다.
핵심 개념
Policy-as-Code란 무엇인가
Policy-as-Code(PaC)는 접근 제어 규칙을 사람이 읽을 수 있는 코드로 선언하고, 인프라 코드처럼 Git에서 버전 관리하며, CI/CD 파이프라인에서 테스트하는 방법론입니다. 기존의 접근 제어 방식이 애플리케이션 코드 안에 if user.role == "admin" 같은 조건문으로 흩어져 있었다면, PaC는 이 결정을 전용 정책 엔진으로 위임합니다.
왜 멀티 에이전트 시스템에서 PaC가 필요한가? AI 에이전트는 자율적으로 도구를 선택하고 실행하기 때문에, 에이전트 내부 로직으로 권한을 통제하면 프롬프트 인젝션이나 모델의 오판으로 쉽게 우회될 수 있습니다. 정책 엔진을 에이전트 외부에 두면, 에이전트가 오염되더라도 실행 전 차단이 보장됩니다.
핵심 구성 요소를 정리하면 다음과 같습니다.
| 개념 | 역할 |
|---|---|
| Policy-as-Code | 접근 규칙을 선언형 코드로 표현·버전관리·테스트 |
| OPA (Open Policy Agent) | 범용 정책 엔진, Rego 언어, 인프라·서비스 수준 제어 |
| Cedar | AWS 개발, 애플리케이션 수준 세분화된 인가(FGAC), 형식 검증 내장 |
| 에이전트 사이드카 패턴 | 모든 도구 호출을 정책 엔진이 인터셉트하는 아키텍처 |
| RBAC / ABAC | 역할 기반 / 속성 기반 접근 제어 모델 |
OPA와 Rego: 범용 정책 엔진
OPA(Open Policy Agent)는 CNCF Graduated 프로젝트로, Kubernetes Admission Controller부터 Envoy 프록시, API Gateway까지 스택 전반의 정책을 단일 엔진으로 통합할 수 있습니다. HTTP REST API나 Go 라이브러리로 애플리케이션에 쉽게 임베드할 수 있으며, Rego라는 선언형 쿼리 언어로 정책을 작성합니다.
Rego는 Datalog에서 파생된 논리 프로그래밍 언어입니다.
allow { ... }블록 안에 조건을 나열하면, 모든 조건이 참일 때만 허용 결정이 내려지는 AND 의미론으로 동작합니다. 절차적 언어에 익숙한 개발자라면 처음에는 낯설게 느껴질 수 있지만, 복잡한 정책을 선언적으로 표현하는 데 매우 강력한 방식입니다.
Cedar: 형식 검증이 가능한 정책 언어
Cedar는 AWS가 2023년 오픈소스로 공개한 목적 지향형 정책 언어로, 애플리케이션 수준의 세분화된 인가(Fine-Grained Authorization, FGAC)에 특화되어 있습니다. **Principal(주체) - Action(행위) - Resource(자원)**의 삼항 모델을 기반으로 하며, 애플리케이션 수준 인가 언어 중 자동 추론(Automated Reasoning)을 내장한 최초의 오픈소스 언어입니다.
Formal Verification(형식 검증): 수학적 증명을 통해 모든 입력 조건에서 정책의 동작을 사전에 보장하는 기법입니다. Cedar는 이 기능을 내장하고 있어, "이 정책은 절대로 관리자 권한 없이 삭제 작업을 허용할 수 없다"는 사실을 코드 실행 전에 검증할 수 있습니다.
에이전트 사이드카 패턴
에이전트 사이드카 패턴은 다음 흐름으로 동작합니다.
[사용자 요청]
↓
[에이전트 (LLM + 도구 선택)]
↓ 도구 호출 시도
[정책 엔진 (OPA / Cedar)] ← 정책 저장소 (Git)
↓ 허용 / 거부
[실제 도구 실행 (API, DB, 파일 시스템)]에이전트는 도구를 직접 실행하지 않고, 먼저 정책 엔진에 "이 작업을 실행해도 되는가?"를 질의합니다. 정책 엔진이 허용 판정을 내릴 때만 실제 도구가 실행됩니다. 에이전트가 프롬프트 인젝션으로 오염되더라도, 정책 엔진은 에이전트 코드 외부에 존재하기 때문에 공격자가 에이전트 내부 로직을 조작해도 정책 레이어를 우회할 수 없습니다.
OPA vs Cedar: 언제 무엇을 선택할까
두 도구는 강점이 다릅니다. 같은 문제를 풀 수 있지만 레이어가 다르기 때문에, 선택 기준을 미리 정리해두면 불필요한 시행착오를 줄일 수 있습니다.
| 기준 | OPA 선택 | Cedar 선택 |
|---|---|---|
| 적용 범위 | K8s, Envoy, API GW 등 인프라 전반 통합 | 애플리케이션 내부 세분화된 인가 |
| 성능 요구 | 일반적인 API 레이턴시 허용 | 서브밀리초 이하 핫패스 처리 필요 |
| 정책 검증 방식 | 유닛 테스트 기반 | 형식 검증(Formal Verification) 필요 |
| 클라우드 환경 | 벤더 중립 멀티클라우드 | AWS 환경 최적화, Amazon Verified Permissions 연동 |
| 생태계 성숙도 | 풍부한 플러그인·커뮤니티 | 빠르게 성장 중이나 OPA 대비 소규모 |
| 정책 언어 친숙도 | 논리형 Rego 학습 필요 | SQL과 유사한 직관적 문법 |
실무 가이드: 이미 Kubernetes나 Envoy를 사용 중이거나 인프라 전반을 하나의 엔진으로 통합하려면 OPA가 자연스러운 출발점입니다. 신규 AI 에이전트 애플리케이션을 AWS 위에 구축하거나 정책 오류 가능성을 수학적으로 검증하고 싶다면 Cedar가 적합합니다. 두 도구는 서로 대체재가 아니라 레이어가 다른 보완재이므로, 인프라 정책에는 OPA를 쓰고 에이전트 도구 인가에는 Cedar를 쓰는 혼합 구성도 실무에서 자주 사용됩니다.
실전 적용
예시 1: Cedar로 결제 에이전트 도구 접근 제어 구현
AWS Bedrock AgentCore는 Cedar를 이용한 에이전트 도구 접근 제어 서비스입니다. 결제 에이전트가 특정 금액 이하의 거래만 처리할 수 있도록 제한하는 정책을 작성해볼 수 있습니다.
// 결제 에이전트는 $1000 미만 거래만 처리 가능 (verified 사용자)
permit (
principal == Agent::"payment-agent",
action == Action::"process_payment",
resource == Tool::"payment-api"
)
when {
context.amount < 1000 &&
context.user_role == "verified"
};
// $1000 이상 $10000 미만 구간:
// 별도 permit 규칙이 없으므로 Cedar의 deny-by-default에 의해 자동 거부됩니다.
// 이 구간을 허용하려면 별도 permit 블록(예: 관리자 승인 조건)을 추가하세요.
// 고액 결제($10000 이상)는 명시적으로 거부
forbid (
principal == Agent::"payment-agent",
action == Action::"process_payment",
resource == Tool::"payment-api"
)
when {
context.amount >= 10000
};| 구문 요소 | 의미 |
|---|---|
principal |
정책의 주체 — 어떤 에이전트에게 적용되는 규칙인지 |
action |
허용할 행위 |
resource |
접근 대상 리소스 |
when { ... } |
허용 조건 — 모든 조건이 참일 때만 적용 |
forbid |
명시적 거부 — permit보다 우선 적용됨 |
deny-by-default: Cedar는 명시적으로
permit이 선언된 경우만 허용하고, 그 외 모든 경우는 기본적으로 거부합니다. 위 예시에서$1000~$9999구간은 별도permit블록 없이 자동으로 거부되어, 실수로 허용 규칙을 누락했을 때도 안전한 상태가 유지됩니다.
예시 2: OPA + Rego로 멀티 에이전트 배포 제어
여러 에이전트가 서로 다른 환경에서 다양한 작업을 수행하는 시스템에서, OPA는 각 에이전트의 행위를 역할 기반으로 제어하는 데 적합합니다. 아래 정책은 DeployAgent가 프로덕션 VM 배포를 요청했을 때 역할을 검사하는 예시입니다.
package agent.deploy
import future.keywords.if
# 기본은 거부
default allow := false
# DevOps 역할만 프로덕션 VM 배포 허용
allow if {
input.agent == "DeployAgent"
input.action == "deploy_vm"
input.environment == "production"
input.user.role == "devops"
}
# 스테이징 환경은 developer 역할도 배포 가능
allow if {
input.agent == "DeployAgent"
input.action == "deploy_vm"
input.environment == "staging"
input.user.role in {"developer", "devops"}
}
# 감사 로그용 이유 반환
reason := "production deployment requires devops role" if {
input.environment == "production"
input.user.role != "devops"
not allow
}OPA REST API는 위 정책 질의에 대해 아래와 같은 JSON 구조를 반환합니다.
// 허용된 경우
{ "result": true }
// 거부된 경우 (reason 규칙 포함 시)
{
"result": false,
"reason": "production deployment requires devops role"
}에이전트 쪽에서는 도구를 실행하기 전 OPA에 HTTP 요청을 보내 결정을 받아옵니다. fail-secure 원칙(OPA 서버 장애 시 기본 거부)을 명시적으로 구현하는 것이 중요합니다.
import httpx
async def check_policy(agent_id: str, action: str, context: dict) -> bool:
"""OPA 정책 엔진에 허용 여부를 질의합니다.
OPA 서버 장애 시 fail-secure 원칙에 따라 False(거부)를 반환합니다.
"""
payload = {
"input": {
"agent": agent_id,
"action": action,
**context
}
}
try:
async with httpx.AsyncClient(timeout=2.0) as client:
response = await client.post(
"http://opa-service:8181/v1/data/agent/deploy/allow",
json=payload
)
response.raise_for_status()
result = response.json()
return result.get("result", False)
except (httpx.HTTPError, httpx.TimeoutException):
# OPA 서버 다운 또는 4xx/5xx 응답 시 기본 거부 (fail-secure)
return False
async def deploy_vm(vm_config: dict, user_context: dict):
allowed = await check_policy(
agent_id="DeployAgent",
action="deploy_vm",
context={
"environment": vm_config["environment"],
"user": user_context
}
)
if not allowed:
raise PermissionError("정책 엔진이 이 작업을 허용하지 않았습니다.")
await execute_deployment(vm_config)| 코드 요소 | 역할 |
|---|---|
default allow := false |
명시적 허용 없이는 기본 거부 |
input.* |
에이전트가 보낸 컨텍스트 데이터 |
input.user.role in {...} |
집합 포함 여부로 다중 역할 검사 |
reason 규칙 |
거부 이유를 반환해 디버깅 지원 |
response.raise_for_status() |
HTTP 오류 발생 시 예외 → except에서 기본 거부 처리 |
예시 3: MCP 게이트웨이 + OPA 사이드카로 도구 호출 중앙 통제
MCP(Model Context Protocol)를 사용하는 환경에서는 MCP 서버 앞에 OPA 사이드카를 배치하여 모든 도구 호출을 중앙에서 평가할 수 있습니다. 흐름은 다음과 같습니다: 에이전트의 도구 호출 요청 → MCP 게이트웨이 인터셉트 → OPA에 허용 여부 질의 → 허용된 경우에만 실제 MCP 서버로 포워딩.
package mcp.tools
import future.keywords.if
import future.keywords.in
default allow := false
# 허용된 도구 목록 (에이전트별)
allowed_tools := {
"research-agent": {"web_search", "read_file", "summarize"},
"code-agent": {"read_file", "write_file", "execute_code"},
"admin-agent": {"read_file", "write_file", "delete_file", "manage_users"}
}
# 에이전트가 해당 도구를 사용할 권한이 있는지 확인
allow if {
permitted := allowed_tools[input.agent_id]
input.tool_name in permitted
}
# 민감 도구는 추가 조건 필요
allow if {
input.tool_name == "execute_code"
input.agent_id == "code-agent"
input.sandbox_enabled == true
input.user_confirmed == true
}이 정책 파일은 OPA 서버 실행 시
--bundle옵션으로 로드하거나, OPAL을 통해 Git 저장소와 실시간 동기화하는 방식으로 배포할 수 있습니다. MCP 게이트웨이에서는 각 도구 호출 요청을 받을 때POST http://opa-service:8181/v1/data/mcp/tools/allow에 에이전트 ID와 도구 이름을 포함한 JSON을 전송하고,result필드의 불리언 값으로 허용 여부를 판단합니다.
이 패턴을 사용하면 감사 로그, 인증, 정책 시행을 단일 게이트웨이에서 처리하는 중앙화된 거버넌스 레이어를 구성할 수 있습니다.
예시 4: 서드파티 거버넌스 도구 — Microsoft Agent Governance Toolkit의 실행 링 기반 격리
앞의 예시 1~3이 OPA/Cedar 정책 코드 작성에 집중했다면, 이 예시는 한 단계 위의 거버넌스 레이어를 다룹니다. Microsoft가 2026년 4월 오픈소스(MIT)로 공개한 Agent Governance Toolkit은 OPA, Cedar, YAML 룰을 모두 지원하면서, 에이전트를 신뢰 레벨에 따라 격리하는 동적 실행 링(Execution Ring) 개념을 제공합니다. CPU 특권 레벨에서 영감을 받은 이 구조는 에이전트 간 침해 반경을 최소화하는 데 효과적입니다.
# agent-governance-policy.yaml
agent_rings:
- ring: 0
name: "trusted-internal"
trust_score_min: 800
allowed_actions: ["*"] # 모든 작업 허용
- ring: 1
name: "verified-partner"
trust_score_min: 600
allowed_actions:
- "read_data"
- "write_data"
- "call_api"
forbidden_actions:
- "delete_data"
- "manage_permissions"
- ring: 2
name: "standard-agent"
trust_score_min: 400
allowed_actions:
- "read_data"
- "call_api"
forbidden_actions:
- "write_data"
- "delete_data"
- "manage_permissions"
- ring: 3
name: "untrusted-external"
trust_score_min: 0
allowed_actions:
- "read_public_data"
require_human_approval: true
sandbox_required: true
trust_score_rules:
- event: "policy_violation"
delta: -100
- event: "successful_task_completion"
delta: +10
- event: "anomalous_behavior_detected"
delta: -200| 링 레벨 | 대상 에이전트 | 신뢰 점수 | 주요 특징 |
|---|---|---|---|
| Ring 0 | 내부 신뢰 에이전트 | 800+ | 모든 작업 허용 |
| Ring 1 | 검증된 파트너 에이전트 | 600+ | 읽기/쓰기 허용, 삭제 불가 |
| Ring 2 | 일반 에이전트 | 400+ | 제한된 읽기·API 접근만 가능 |
| Ring 3 | 외부 비신뢰 에이전트 | 0+ | 공개 데이터 읽기, 사람 승인 필요 |
장단점 분석
장점
| 항목 | 내용 |
|---|---|
| 에이전트 오염 격리 | 프롬프트 인젝션으로 에이전트가 오염되더라도 정책 엔진이 실행 전 차단 |
| 감사 가능성 | 모든 정책 판정이 로그로 기록되어 에이전트 행동 완전 추적 가능 |
| 정책 독립 배포 | 애플리케이션 재배포 없이 정책만 업데이트 가능 |
| 형식 검증 (Cedar) | 정책 충돌·위험 조건을 사전에 자동 감지 |
| 생태계 통합 | Kubernetes, Envoy, API Gateway 등 기존 인프라와 자연스럽게 통합 |
| 표준화된 거버넌스 | 여러 에이전트·서비스에 걸친 일관된 정책 시행 |
단점 및 주의사항
| 항목 | 내용 | 대응 방안 |
|---|---|---|
| Rego 학습 곡선 | Datalog 계열 문법이 절차형 언어 개발자에게 낯설게 느껴질 수 있음 | OPA Playground와 Unit Test 기능으로 단계적 학습 권장 |
| 정책 배포 지연 | 정책 변경이 실시간 전파되지 않으면 에이전트가 구 정책으로 동작 가능 | OPAL로 Git 기반 실시간 동기화 구성 |
| 에이전트 체인 신뢰 전파 | A→B→C 호출 체인에서 각 단계 신원·권한 범위 유실 가능 | JWT 클레임으로 신원 컨텍스트 명시적 전달 |
| OPA 커뮤니티 동향 | Apple의 핵심 기여자 합류 이후 거버넌스 구조 변화 가능성 | 오픈소스 OPA 자체는 유지되므로 커뮤니티 동향 주기적 모니터링 |
| AWS 생태계 의존성 (Cedar) | 멀티클라우드 환경에서 Cedar 유연성 제한 | 벤더 중립이 필요하면 OPA 선택 |
| 복잡한 정책의 레이턴시 | 무거운 Rego 정책은 응답 시간 증가 유발 | 핫패스에는 Cedar 사용 권장 (Teleport 벤치마크 기준 Rego 대비 42~60배 빠름) |
OPAL(Open Policy Administration Layer): OPA 또는 Cedar 정책을 Git 저장소 기반으로 실시간 동기화하는 오픈소스 도구입니다. 정책 변경 시 각 에이전트 인스턴스에 즉시 푸시되어 배포 지연 문제를 해소할 수 있습니다.
실무에서 가장 흔한 실수
- 에이전트 내부에서 권한 결정을 내리는 설계: "이 에이전트는 신뢰할 수 있으니 내부 로직으로 충분하다"는 판단은 프롬프트 인젝션에 취약합니다. 공격자가 에이전트의 시스템 프롬프트를 조작하면 내부 검사 로직을 우회할 수 있습니다. 모든 도구 호출 인가 결정은 정책 엔진 레이어에 위임하는 것을 권장합니다.
- OPA 서버 장애 시 fail-open 설계: 정책 엔진에 연결할 수 없을 때 예외를 그냥 전파하거나
True를 반환하면, OPA가 다운된 순간 모든 제한이 사라집니다. 예시 2에서 보여준 것처럼 네트워크 오류를 잡아 기본 거부(fail-secure)를 명시적으로 반환하는 설계가 보안 코드의 기본 원칙입니다. - 에이전트 체인에서 신원 컨텍스트 누락: Agent A가 Agent B를 호출할 때 원래 사용자의 신원과 권한 범위를 전달하지 않으면, Agent B가 실제 허용 범위를 초과하는 작업을 수행할 수 있습니다. 호출 체인 전체에 JWT 토큰 형태로 신원 컨텍스트를 명시적으로 전파하는 설계가 필요합니다.
- 감사 로그 미비: 정책 허용/거부 결정을 로그로 남기지 않으면 사후 분석이 불가능합니다. 에이전트 ID, 요청 컨텍스트, 판정 결과, 타임스탬프를 포함하는 구조화된 로그를 모든 판정에 남겨두는 것이 좋습니다.
마치며
멀티 에이전트 시스템의 보안은 에이전트를 신뢰하는 것이 아니라, 에이전트의 모든 행위를 외부에서 검증하는 구조에서 시작됩니다. OPA는 인프라 전반에 걸친 통합과 표현력 있는 정책 작성에, Cedar는 애플리케이션 수준 세분화된 인가와 형식 검증이 필요한 곳에 각각 강점이 있습니다. 어느 쪽을 선택하든, 핵심은 에이전트 바깥에 정책 판정 레이어를 두는 아키텍처 원칙입니다.
지금 바로 시작할 수 있는 단계별 가이드:
- 현재 에이전트 시스템 진단하기: 자신의 에이전트가 실행하는 도구 목록을 작성하고, 그 중 제한 없이 허용될 경우 가장 큰 피해를 줄 수 있는 도구 하나를 먼저 식별해보시면 좋습니다. 이 도구가 이후 단계에서 첫 번째 정책 작성 대상이 됩니다.
- OPA 로컬 환경 구성:
docker run -p 8181:8181 openpolicyagent/opa run --server명령어로 OPA 서버를 로컬에 띄우고, OPA Playground에서 Rego 문법을 직접 작성하고 테스트해볼 수 있습니다. Step 0에서 식별한 도구에 대한 간단한allow정책을 작성해보시면 좋습니다. - Cedar 정책 작성 실습: cedar-policy GitHub에서 Cedar 라이브러리를 설치하고, 에이전트가 사용하는 도구 목록을 Principal-Action-Resource 모델로 정리해보시면 좋습니다. AWS 환경을 사용 중이라면 Amazon Verified Permissions 콘솔에서 시각적으로 정책을 관리할 수도 있습니다.
- OPAL로 실시간 정책 동기화 구성:
docker-compose로 OPA + OPAL 스택을 띄우고, GitHub 저장소를 정책 소스로 연결해보시면 좋습니다. 저장소에 정책 변경을 커밋하면 에이전트 재시작 없이 정책이 자동 갱신되는 경험을 해볼 수 있습니다. OPAL 공식 문서의 Quickstart 예제가 출발점으로 적합합니다.
다음 글: OPAL과 GitHub Actions를 연동해 Policy-as-Code CI/CD 파이프라인을 구축하는 방법 — 정책 변경의 자동 테스트, 스테이징 환경 검증, 프로덕션 롤아웃까지 전 과정을 다룹니다.
참고 자료
- OPA vs Cedar vs Zanzibar: 2025 Policy Engine Guide | osohq
- Introducing the Agent Governance Toolkit | Microsoft Open Source Blog
- Agent Governance Toolkit GitHub | microsoft/agent-governance-toolkit
- Agent Governance Toolkit: Architecture Deep Dive | Microsoft Tech Community
- Secure AI Agents with Policy in Amazon Bedrock AgentCore | AWS ML Blog
- Understanding Cedar Policies | Amazon Bedrock AgentCore Docs
- Why Open Policy Agent is the Missing Guardrail for Your AI Agents | CodiLime
- Policy Engine Showdown: OPA vs. OpenFGA vs. Cedar | Permit.io
- MCP Access Control: OPA vs Cedar | Natoma
- Security Benchmarking Authorization Policy Engines | Teleport
- AI Agents, the Model Context Protocol, and Authorization Guardrails | Cerbos
- Open Policy Agent Official Documentation
- Cedar Policy Language | cedar-policy GitHub