본문으로 건너뛰기
Kreath Archive
TechProjectsBooksAbout
TechProjectsBooksAbout

내비게이션

  • Tech
  • Projects
  • Books
  • About
  • Tags

카테고리

  • AI / ML
  • 웹 개발
  • 프로그래밍
  • 개발 도구

연결

  • GitHub
  • Email
  • RSS
© 2026 Kreath Archive. All rights reserved.Built with Next.js + MDX
홈TechProjectsBooksAbout
//
  1. 홈
  2. 테크
  3. 9장: 보안과 거버넌스
2026년 3월 17일·AI / ML·

9장: 보안과 거버넌스

최소 권한 원칙, 도구별 권한 제어, 비밀 관리, 입출력 검증, 비용 제어, 에이전트 거버넌스 프레임워크, 위험 평가, 모니터링과 알림 전략을 다룹니다.

17분1,389자11개 섹션
workflowaiautomation
공유
agentic-workflow9 / 10
12345678910
이전8장: 엔터프라이즈 시스템 통합다음10장: 실전 프로젝트 -- Agentic Workflow 시스템 구축

이 장에서 배울 내용

  • 에이전트 보안의 핵심 원칙과 위협 모델
  • 최소 권한 원칙의 에이전트 환경 적용
  • 도구별 권한 제어와 비밀 관리
  • 입출력 검증을 통한 안전성 확보
  • 비용 제어와 예산 한도 설정
  • 거버넌스 프레임워크와 운영 모니터링

에이전트 보안의 특수성

Agentic Workflow의 보안은 전통적인 소프트웨어 보안과 근본적으로 다른 도전 과제를 가집니다. 에이전트는 자율적으로 판단하고 도구를 사용하기 때문에, 잘못된 판단이 보안 사고로 직결될 수 있습니다.

에이전트 특유의 위협

위협 유형설명예시
프롬프트 인젝션악의적 입력이 에이전트의 행동을 조작고객 문의에 숨겨진 명령어
도구 남용에이전트가 의도하지 않은 방식으로 도구 사용데이터 삭제 API를 잘못 호출
권한 상승에이전트가 허용된 범위를 넘어서는 행동관리자 전용 API에 접근 시도
데이터 유출민감 정보가 외부로 노출LLM 응답에 개인정보 포함
비용 폭주무한 루프나 대량 API 호출로 비용 급증재시도 로직 오류로 수만 건 호출

최소 권한 원칙

**최소 권한 원칙(Principle of Least Privilege)**은 에이전트에게 작업 수행에 필요한 최소한의 권한만 부여하는 원칙입니다. 이는 에이전트 보안의 가장 기본적인 방어선입니다.

에이전트별 권한 정의

agent_permissions.py
python
from dataclasses import dataclass
from enum import Enum
 
class Permission(Enum):
    READ = "read"
    WRITE = "write"
    DELETE = "delete"
    EXECUTE = "execute"
    APPROVE = "approve"
 
@dataclass
class ResourcePermission:
    resource: str       # 리소스 식별자
    permissions: set[Permission]
    conditions: dict | None = None  # 조건부 권한
 
@dataclass
class AgentPermissionSet:
    agent_id: str
    role: str
    allowed_tools: list[str]
    resource_permissions: list[ResourcePermission]
    max_token_budget: int       # 토큰 사용 한도
    max_tool_calls: int         # 도구 호출 횟수 한도
    allowed_models: list[str]   # 사용 가능한 LLM 모델
    time_restrictions: dict | None = None  # 시간 기반 제한
 
# 고객 지원 에이전트 권한 예시
cs_agent_permissions = AgentPermissionSet(
    agent_id="cs-triage-agent",
    role="customer_support_triage",
    allowed_tools=[
        "customer_lookup",
        "ticket_history",
        "knowledge_base_search",
        "draft_response",
    ],
    resource_permissions=[
        ResourcePermission(
            resource="customer_db",
            permissions={Permission.READ},
        ),
        ResourcePermission(
            resource="ticket_db",
            permissions={Permission.READ, Permission.WRITE},
            conditions={"write_fields": ["status", "category", "priority"]},
        ),
        ResourcePermission(
            resource="knowledge_base",
            permissions={Permission.READ},
        ),
    ],
    max_token_budget=100_000,
    max_tool_calls=50,
    allowed_models=["claude-sonnet", "claude-haiku"],
)

권한 검증 미들웨어

permission_middleware.py
python
class PermissionMiddleware:
    """에이전트 행동에 대한 권한 검증"""
 
    def __init__(self, permission_store: PermissionStore):
        self.store = permission_store
 
    async def check_tool_access(
        self, agent_id: str, tool_name: str
    ) -> bool:
        """에이전트의 도구 사용 권한 확인"""
        permissions = await self.store.get(agent_id)
 
        if tool_name not in permissions.allowed_tools:
            await self.audit_logger.log(
                event="permission_denied",
                agent_id=agent_id,
                tool=tool_name,
                reason="도구가 허용 목록에 없음",
            )
            return False
 
        return True
 
    async def check_resource_access(
        self, agent_id: str, resource: str, permission: Permission
    ) -> bool:
        """리소스 접근 권한 확인"""
        permissions = await self.store.get(agent_id)
 
        for rp in permissions.resource_permissions:
            if rp.resource == resource and permission in rp.permissions:
                return True
 
        await self.audit_logger.log(
            event="permission_denied",
            agent_id=agent_id,
            resource=resource,
            permission=permission.value,
        )
        return False
 
    async def check_budget(self, agent_id: str) -> bool:
        """토큰 예산 확인"""
        permissions = await self.store.get(agent_id)
        usage = await self.usage_tracker.get_current(agent_id)
 
        if usage.total_tokens >= permissions.max_token_budget:
            await self.audit_logger.log(
                event="budget_exceeded",
                agent_id=agent_id,
                budget=permissions.max_token_budget,
                used=usage.total_tokens,
            )
            return False
 
        return True
Warning

에이전트의 권한을 설계할 때 "일단 넓게 주고 나중에 줄이는" 접근은 위험합니다. 반드시 최소 권한으로 시작하여 필요에 따라 점진적으로 확대해야 합니다. 모든 권한 변경은 감사 로그에 기록되어야 합니다.

도구별 권한 제어

도구 수준에서 세밀한 접근 제어를 구현합니다.

도구 허용 목록(Allowlist)

tool_allowlist.py
python
@dataclass
class ToolPolicy:
    tool_name: str
    allowed_agents: list[str]
    rate_limit: int            # 분당 최대 호출 횟수
    requires_approval: bool     # HITL 승인 필요 여부
    allowed_parameters: dict | None  # 허용된 파라미터 범위
    blocked_parameters: dict | None  # 차단된 파라미터 값
 
class ToolAccessController:
    def __init__(self, policies: list[ToolPolicy]):
        self.policies = {p.tool_name: p for p in policies}
        self.rate_counters: dict[str, RateCounter] = {}
 
    async def authorize(
        self,
        agent_id: str,
        tool_name: str,
        params: dict,
    ) -> AuthorizationResult:
        policy = self.policies.get(tool_name)
 
        if policy is None:
            return AuthorizationResult(
                allowed=False, reason=f"도구 {tool_name}에 대한 정책 미정의"
            )
 
        # 에이전트 허용 확인
        if agent_id not in policy.allowed_agents:
            return AuthorizationResult(
                allowed=False, reason=f"에이전트 {agent_id}에게 {tool_name} 미허용"
            )
 
        # Rate Limit 확인
        counter = self.rate_counters.setdefault(
            f"{agent_id}:{tool_name}", RateCounter(policy.rate_limit)
        )
        if not counter.allow():
            return AuthorizationResult(
                allowed=False, reason=f"Rate limit 초과: {policy.rate_limit}/min"
            )
 
        # 파라미터 검증
        if policy.blocked_parameters:
            for key, blocked_values in policy.blocked_parameters.items():
                if params.get(key) in blocked_values:
                    return AuthorizationResult(
                        allowed=False,
                        reason=f"차단된 파라미터 값: {key}={params[key]}"
                    )
 
        # HITL 승인 필요 여부
        if policy.requires_approval:
            return AuthorizationResult(
                allowed=True, requires_human_approval=True
            )
 
        return AuthorizationResult(allowed=True)

입출력 검증

에이전트의 입력과 출력을 검증하여 프롬프트 인젝션과 데이터 유출을 방지합니다.

입력 검증 — 프롬프트 인젝션 방어

input_validation.py
python
class InputValidator:
    """에이전트 입력 검증"""
 
    INJECTION_PATTERNS = [
        r"ignore\s+(previous|above|all)\s+(instructions?|prompts?)",
        r"system\s*:\s*",
        r"you\s+are\s+now\s+",
        r"forget\s+(everything|all|your)",
        r"new\s+instructions?\s*:",
    ]
 
    def __init__(self):
        self.patterns = [re.compile(p, re.IGNORECASE) for p in self.INJECTION_PATTERNS]
 
    def validate(self, input_text: str) -> ValidationResult:
        # 프롬프트 인젝션 패턴 탐지
        for pattern in self.patterns:
            if pattern.search(input_text):
                return ValidationResult(
                    valid=False,
                    risk="prompt_injection",
                    detail=f"의심스러운 패턴 감지: {pattern.pattern}",
                )
 
        # 입력 길이 제한
        if len(input_text) > 50_000:
            return ValidationResult(
                valid=False,
                risk="excessive_input",
                detail=f"입력 길이 초과: {len(input_text)} > 50000",
            )
 
        return ValidationResult(valid=True)

출력 검증 — 민감 정보 필터링

output_filter.py
python
class OutputFilter:
    """에이전트 출력에서 민감 정보 필터링"""
 
    PII_PATTERNS = {
        "주민등록번호": r"\d{6}-[1-4]\d{6}",
        "전화번호": r"01[016789]-?\d{3,4}-?\d{4}",
        "카드번호": r"\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}",
        "이메일": r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}",
    }
 
    def filter(self, output: str) -> FilterResult:
        masked_output = output
        detected_pii = []
 
        for pii_type, pattern in self.PII_PATTERNS.items():
            matches = re.findall(pattern, output)
            if matches:
                detected_pii.append((pii_type, len(matches)))
                # 마스킹 처리
                masked_output = re.sub(
                    pattern,
                    lambda m: self._mask(m.group(), pii_type),
                    masked_output,
                )
 
        return FilterResult(
            original_had_pii=bool(detected_pii),
            detected_types=detected_pii,
            filtered_output=masked_output,
        )
 
    def _mask(self, value: str, pii_type: str) -> str:
        if pii_type == "이메일":
            parts = value.split("@")
            return f"{parts[0][:2]}***@{parts[1]}"
        return value[:2] + "*" * (len(value) - 4) + value[-2:]
Info

프롬프트 인젝션 방어는 패턴 매칭만으로는 완벽하지 않습니다. 구조적 방어(시스템 프롬프트와 사용자 입력의 명확한 분리), 행동 제한(허용 목록 기반 도구 접근), 출력 검증(결과의 타당성 확인)을 함께 적용하는 다층 방어가 필요합니다.

비밀 관리

에이전트가 사용하는 API 키, 토큰, 비밀번호 등을 안전하게 관리합니다.

secret_management.py
python
class SecretManager:
    """에이전트 비밀 관리"""
 
    def __init__(self, backend: SecretBackend):
        self.backend = backend  # Vault, AWS Secrets Manager 등
        self.cache: dict[str, tuple[str, datetime]] = {}
        self.cache_ttl = timedelta(minutes=15)
 
    async def get_secret(self, agent_id: str, secret_name: str) -> str:
        """에이전트별 비밀 조회 (캐싱 포함)"""
        # 에이전트의 비밀 접근 권한 확인
        if not await self._authorize(agent_id, secret_name):
            raise SecretAccessDenied(
                f"에이전트 {agent_id}는 {secret_name}에 접근할 수 없습니다"
            )
 
        # 캐시 확인
        cache_key = f"{agent_id}:{secret_name}"
        if cache_key in self.cache:
            value, cached_at = self.cache[cache_key]
            if datetime.utcnow() - cached_at < self.cache_ttl:
                return value
 
        # 백엔드에서 조회
        value = await self.backend.get(secret_name)
        self.cache[cache_key] = (value, datetime.utcnow())
 
        # 접근 기록
        await self.audit_logger.log(
            event="secret_accessed",
            agent_id=agent_id,
            secret_name=secret_name,
        )
 
        return value

비용 제어

에이전트의 LLM 호출, API 사용, 컴퓨팅 리소스 비용을 제어합니다.

cost_control.py
python
@dataclass
class BudgetConfig:
    daily_limit_usd: float
    monthly_limit_usd: float
    per_workflow_limit_usd: float
    alert_threshold: float = 0.80  # 80% 사용 시 알림
 
class CostController:
    def __init__(self, config: BudgetConfig):
        self.config = config
        self.usage_tracker = UsageTracker()
 
    async def pre_check(self, agent_id: str, estimated_cost: float) -> CostCheckResult:
        """작업 실행 전 비용 확인"""
        daily_usage = await self.usage_tracker.get_daily(agent_id)
        monthly_usage = await self.usage_tracker.get_monthly(agent_id)
 
        # 일일 한도 확인
        if daily_usage + estimated_cost > self.config.daily_limit_usd:
            return CostCheckResult(
                allowed=False,
                reason=f"일일 예산 한도 초과: "
                       f"현재 ${daily_usage:.2f} + 예상 ${estimated_cost:.2f} > "
                       f"한도 ${self.config.daily_limit_usd:.2f}",
            )
 
        # 월간 한도 확인
        if monthly_usage + estimated_cost > self.config.monthly_limit_usd:
            return CostCheckResult(
                allowed=False,
                reason=f"월간 예산 한도 초과",
            )
 
        # 경고 임계값 확인
        daily_ratio = (daily_usage + estimated_cost) / self.config.daily_limit_usd
        if daily_ratio >= self.config.alert_threshold:
            await self.alerter.send(
                severity="warning",
                message=f"에이전트 {agent_id}: 일일 예산 {daily_ratio:.0%} 사용",
            )
 
        return CostCheckResult(allowed=True, remaining_daily=self.config.daily_limit_usd - daily_usage)
 
    async def record_usage(self, agent_id: str, cost: float, detail: dict) -> None:
        """비용 사용 기록"""
        await self.usage_tracker.record(agent_id, cost, detail)
Tip

비용 제어는 사전 확인(pre-check)과 사후 기록(post-record)을 모두 수행해야 합니다. 사전 확인만으로는 동시 실행 시 한도를 초과할 수 있고, 사후 기록만으로는 초과가 발생한 후에야 알 수 있습니다. 두 가지를 조합하되, 사전 확인에서는 약간의 여유를 두는 것이 실용적입니다.

에이전트 거버넌스 프레임워크

조직 수준에서 에이전트 운영을 관리하는 거버넌스 프레임워크를 수립합니다.

거버넌스 정책 구조

governance_framework.py
python
@dataclass
class GovernancePolicy:
    """에이전트 거버넌스 정책"""
    # 배포 정책
    deployment_approval_required: bool = True
    staging_test_required: bool = True
    rollback_plan_required: bool = True
 
    # 운영 정책
    max_concurrent_workflows: int = 100
    max_workflow_duration: timedelta = timedelta(days=7)
    mandatory_hitl_for_categories: list[str] = None  # HITL 필수 카테고리
 
    # 모니터링 정책
    alert_on_error_rate_above: float = 0.05  # 5%
    alert_on_latency_above_ms: int = 30_000
    daily_report_required: bool = True
 
    # 감사 정책
    audit_log_retention_days: int = 365
    compliance_check_frequency: str = "weekly"
 
    def __post_init__(self):
        if self.mandatory_hitl_for_categories is None:
            self.mandatory_hitl_for_categories = [
                "financial_transaction",
                "personal_data_processing",
                "contract_execution",
            ]

위험 평가

에이전트 배포 전 위험 평가를 수행합니다.

risk_assessment.py
python
class RiskAssessor:
    async def assess(self, agent_config: AgentConfig) -> RiskAssessment:
        """에이전트 배포 전 위험 평가"""
        risks = []
 
        # 도구 위험도 평가
        for tool in agent_config.tools:
            if tool in HIGH_RISK_TOOLS:
                risks.append(Risk(
                    category="tool_risk",
                    level="high",
                    detail=f"고위험 도구 사용: {tool}",
                    mitigation="HITL 승인 게이트 필수",
                ))
 
        # 데이터 접근 위험도
        for resource in agent_config.resources:
            if resource.contains_pii:
                risks.append(Risk(
                    category="data_risk",
                    level="high",
                    detail=f"개인정보 포함 리소스 접근: {resource.name}",
                    mitigation="출력 필터링 및 접근 로깅 필수",
                ))
 
        # 자율성 수준 위험도
        if agent_config.autonomy_level == "autonomous":
            risks.append(Risk(
                category="autonomy_risk",
                level="medium",
                detail="완전 자율 모드 운영",
                mitigation="비용 한도, 행동 모니터링, 롤백 계획 필수",
            ))
 
        overall_level = max(r.level for r in risks) if risks else "low"
 
        return RiskAssessment(
            agent_id=agent_config.agent_id,
            risks=risks,
            overall_risk_level=overall_level,
            deployment_approved=overall_level != "critical",
            required_mitigations=[r.mitigation for r in risks],
        )

모니터링과 알림

에이전트의 행동을 실시간으로 모니터링하고, 이상 상황을 즉시 감지합니다.

monitoring.py
python
class AgentMonitor:
    """에이전트 행동 모니터링"""
 
    async def check_anomalies(self, agent_id: str) -> list[Anomaly]:
        anomalies = []
        metrics = await self.metrics_store.get_recent(agent_id, minutes=15)
 
        # 에러율 급증 감지
        if metrics.error_rate > self.thresholds.error_rate:
            anomalies.append(Anomaly(
                type="error_rate_spike",
                severity="high",
                current=metrics.error_rate,
                threshold=self.thresholds.error_rate,
            ))
 
        # 비정상적 도구 호출 패턴
        if metrics.tool_call_rate > self.thresholds.tool_call_rate * 3:
            anomalies.append(Anomaly(
                type="unusual_tool_usage",
                severity="medium",
                current=metrics.tool_call_rate,
                threshold=self.thresholds.tool_call_rate,
            ))
 
        # 응답 지연 증가
        if metrics.p99_latency_ms > self.thresholds.latency_p99:
            anomalies.append(Anomaly(
                type="latency_degradation",
                severity="medium",
                current=metrics.p99_latency_ms,
                threshold=self.thresholds.latency_p99,
            ))
 
        # 반복적 동일 에러
        if metrics.repeated_error_count > 10:
            anomalies.append(Anomaly(
                type="repeated_error",
                severity="high",
                detail=f"동일 에러 {metrics.repeated_error_count}회 반복",
            ))
 
        for anomaly in anomalies:
            await self.alerter.send(agent_id=agent_id, anomaly=anomaly)
 
        return anomalies

정리

이 장에서는 Agentic Workflow의 보안과 거버넌스를 다루었습니다.

  • 에이전트에게는 최소 권한만 부여하고, 도구 사용은 허용 목록으로 제한합니다
  • 프롬프트 인젝션 방어와 민감 정보 필터링으로 입출력을 검증합니다
  • 비밀 관리는 전용 백엔드(Vault, Secrets Manager)를 사용합니다
  • 일일/월간/워크플로우별 비용 한도로 예산을 제어합니다
  • 배포 전 위험 평가를 수행하고, 운영 중 이상 행동을 실시간 모니터링합니다

다음 장 예고

10장에서는 지금까지 배운 모든 내용을 종합하여 실전 프로젝트를 구축합니다. 고객 지원 자동화 워크플로우를 LangGraph로 구현하고, HITL 통합, 감사 로깅, 보안 설정까지 포함한 프로덕션 수준의 시스템을 완성하겠습니다.

이 글이 도움이 되셨나요?

관련 주제 더 보기

#workflow#ai#automation

관련 글

AI / ML

10장: 실전 프로젝트 -- Agentic Workflow 시스템 구축

고객 지원 자동화 워크플로우를 LangGraph로 구현하고, HITL, 감사 로깅, 엔터프라이즈 통합, 보안까지 포함한 프로덕션 수준 시스템을 구축합니다.

2026년 3월 19일·22분
AI / ML

8장: 엔터프라이즈 시스템 통합

ERP/CRM/ITSM 연동, MCP 기반 도구 통합, API 게이트웨이, 이벤트 드리븐 통합, 레거시 시스템 어댑터, 트랜잭션 경계 설계를 다룹니다.

2026년 3월 15일·16분
AI / ML

7장: 감사 로깅과 컴플라이언스

에이전트 행동 추적, 불변 감사 로그 설계, 규제 요구사항 대응, 설명 가능성, 재현 가능성, OpenTelemetry 통합, 보존 정책을 다룹니다.

2026년 3월 13일·16분
이전 글8장: 엔터프라이즈 시스템 통합
다음 글10장: 실전 프로젝트 -- Agentic Workflow 시스템 구축

댓글

목차

약 17분 남음
  • 이 장에서 배울 내용
  • 에이전트 보안의 특수성
    • 에이전트 특유의 위협
  • 최소 권한 원칙
    • 에이전트별 권한 정의
    • 권한 검증 미들웨어
  • 도구별 권한 제어
    • 도구 허용 목록(Allowlist)
  • 입출력 검증
    • 입력 검증 — 프롬프트 인젝션 방어
    • 출력 검증 — 민감 정보 필터링
  • 비밀 관리
  • 비용 제어
  • 에이전트 거버넌스 프레임워크
    • 거버넌스 정책 구조
    • 위험 평가
  • 모니터링과 알림
  • 정리
  • 다음 장 예고