0Pricing
AI Engineering Academy · 강의

에이전트 도구 접근 보안

에이전트 도구 권한에 최소 권한 원칙을 적용하고, 파괴적 작업 전에 확인 단계를 구현하며, 비정상적인 동작을 감지하도록 에이전트 작업 기록을 감사합니다.

에이전트 도구 접근 보안은(는) CoddyKit의 무료 AI Engineering Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 AI Engineering Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. AI Engineering Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

도구 접근 보안 문제

AI 에이전트에 도구를 제공한다는 것은 에이전트가 실제 세계에서 작업을 수행할 수 있도록 권한을 부여한다는 의미입니다. 이메일을 보내거나, SQL 쿼리를 실행하거나, 결제 API를 호출하거나, 파일을 수정하는 도구는 에이전트가 프롬프트 인젝션으로 손상되거나 단순히 실수했을 때 큰 피해를 일으킬 수 있습니다. 에이전트 도구 접근 보안은 개별 도구 사용으로 인한 피해 범위를 제한하고, 감사할 수 있으며, 가능한 경우 되돌릴 수 있도록 도구 계층을 설계하는 것을 의미합니다.

최소 권한 원칙

모든 도구에 최소 권한 원칙을 적용하세요. 에이전트가 할당된 작업을 완료하는 데 필요한 최소한의 접근 권한만 제공하고, 그 이상은 제공하지 않아야 합니다. 에이전트가 고객 기록을 읽어야 한다면 유지 관리에 사용하는 전체 관리자 연결이 아니라 읽기 전용 데이터베이스 연결을 제공하세요. 알림을 보내는 경우에는 API 키의 범위를 알림 엔드포인트로만 제한하세요. 최소 권한은 보안 사고가 발생했을 때 피해 범위를 제한합니다.

from enum import Enum
from dataclasses import dataclass

class Permission(Enum):
    READ_CUSTOMER_PROFILE = 'read_customer_profile'
    SEND_NOTIFICATION = 'send_notification'
    READ_ORDER_HISTORY = 'read_order_history'
    WRITE_CUSTOMER_PROFILE = 'write_customer_profile'  # higher privilege
    PROCESS_REFUND = 'process_refund'                  # highest risk

@dataclass
class AgentIdentity:
    agent_id: str
    allowed_permissions: set[Permission]

# Support chat agent: read-only + send notification only
SUPPORT_AGENT = AgentIdentity(
    agent_id='support-agent-v1',
    allowed_permissions={
        Permission.READ_CUSTOMER_PROFILE,
        Permission.READ_ORDER_HISTORY,
        Permission.SEND_NOTIFICATION  # can notify, but NOT write or refund
    }
)

# NOT: give every agent all permissions for convenience

권한 확인을 거치는 도구 실행

최소 권한은 설계 계층뿐 아니라 실행 계층에서도 적용해야 합니다. 모든 도구 호출은 권한 확인을 거쳐야 하며, 이 확인 과정에서 호출하는 에이전트가 해당 작업에 필요한 권한을 보유했는지 검증해야 합니다. 이는 LLM의 프롬프트가 아니라 코드에서 강제되므로 에이전트나 프롬프트 인젝션으로 우회할 수 없습니다.

class ToolGateway:
    def __init__(self, agent: AgentIdentity):
        self.agent = agent
        self.audit_log = []

    def execute_tool(self, tool_name: str, required_permission: Permission, tool_fn, **kwargs) -> dict:
        # Permission check - enforced in code, not in the LLM prompt
        if required_permission not in self.agent.allowed_permissions:
            self.log_denied(tool_name, required_permission, kwargs)
            raise PermissionError(
                f'Agent {self.agent.agent_id} does not have permission: {required_permission.value}'
            )
        
        # Execute tool
        result = tool_fn(**kwargs)
        self.log_allowed(tool_name, kwargs, result)
        return result

    def log_denied(self, tool: str, permission: Permission, args: dict):
        entry = {'type': 'DENIED', 'agent': self.agent.agent_id, 'tool': tool, 'permission': permission.value, 'args': args}
        self.audit_log.append(entry)
        print(f'SECURITY: Permission denied - {entry}')

    def log_allowed(self, tool: str, args: dict, result):
        entry = {'type': 'ALLOWED', 'agent': self.agent.agent_id, 'tool': tool, 'args': args}
        self.audit_log.append(entry)

gateway = ToolGateway(SUPPORT_AGENT)

# This will succeed (agent has READ permission)
gateway.execute_tool('read_profile', Permission.READ_CUSTOMER_PROFILE, read_customer_profile, user_id='123')

# This will raise PermissionError (agent lacks PROCESS_REFUND permission)
gateway.execute_tool('process_refund', Permission.PROCESS_REFUND, process_refund, order_id='456', amount=50.00)

파괴적 작업에 대한 확인 단계

기록 삭제, 대량 이메일 전송, 금융 거래 처리처럼 되돌릴 수 없거나 영향이 큰 작업이 있습니다. 에이전트가 이러한 작업을 실행하기 전에 명시적인 사람의 확인을 요구하세요. 에이전트가 수행하려는 작업과 그 이유를 제안하면 사람이 승인하거나 거부하고, 그 후에만 실행이 진행됩니다. 이 확인 단계는 에이전트의 오류와 인젝션으로 인한 악용을 막는 가장 효과적인 단일 방어 수단입니다.

HIGH_RISK_ACTIONS = {
    'delete_customer_record',
    'send_bulk_email',
    'process_refund_over_100',
    'deploy_code',
    'revoke_user_access'
}

def execute_with_confirmation(tool_name: str, tool_args: dict, agent_reasoning: str) -> dict:
    if tool_name in HIGH_RISK_ACTIONS:
        # Pause and request human approval
        approval_request = {
            'action': tool_name,
            'arguments': tool_args,
            'agent_reasoning': agent_reasoning,
            'risk_level': 'HIGH'
        }
        approval = request_human_approval(approval_request)  # blocks until human responds
        
        if not approval.approved:
            return {'status': 'rejected', 'reason': approval.rejection_reason}
        
        # Log the approval for audit trail
        log_approval(tool_name, tool_args, approved_by=approval.approver_id)
    
    # Execute only after confirmation
    return execute_tool(tool_name, **tool_args)

도구 범위 제한: 시간, 사용자, 데이터 경계

권한 유형 외에도 세 가지 기준으로 도구 접근 범위를 제한하세요. 시간 경계: 에이전트의 세션이 끝나면 만료되는 API 키 또는 토큰입니다. 사용자 경계: 사용자 A를 돕는 에이전트는 에이전트가 그렇게 지시받더라도 사용자 B의 데이터에 접근해서는 안 됩니다. 데이터 경계: 고객 지원 에이전트는 모든 고객의 데이터가 아니라 현재 지원 중인 고객의 데이터에만 접근해야 합니다. 이러한 경계는 에이전트 프롬프트가 아니라 도구 구현에 적용하세요.

class ScopedCustomerTool:
    def __init__(self, current_user_id: str, session_token: str):
        self.user_id = current_user_id  # agent can only access THIS user's data
        self.token = session_token       # expires at end of session

    def get_customer_profile(self) -> dict:
        # Hardcoded to current user - agent cannot change this via prompt
        return db.query(
            'SELECT * FROM customers WHERE id = %s',
            (self.user_id,)  # parameterized, always this user's ID only
        )

    def get_order_history(self, limit: int = 10) -> list:
        # Even if the agent says 'get orders for user 999', it gets self.user_id
        return db.query(
            'SELECT * FROM orders WHERE customer_id = %s ORDER BY date DESC LIMIT %s',
            (self.user_id, min(limit, 50))  # cap limit too
        )

# Inject scoped tool into agent - cannot be overridden by prompt
def create_support_agent(user_id: str, session_token: str):
    scoped_tools = ScopedCustomerTool(user_id, session_token)
    return AgentExecutor(llm=llm, tools=[scoped_tools.get_customer_profile, scoped_tools.get_order_history])

도구 인자 입력 검증

에이전트는 도구 인자를 텍스트로 생성합니다. 어떤 도구든 실행하기 전에 모든 인자를 엄격한 스키마에 따라 검증하세요. 이렇게 하면 도구 매개변수를 통한 SQL 인젝션, 경로 순회 공격(에이전트가 파일 경로로 '../../../etc/passwd'를 전달하는 경우), SSRF 공격(에이전트가 '원격 URL' 매개변수로 내부 서비스 URL을 전달하는 경우), 그리고 예기치 않은 동작을 일으킬 수 있는 정수 오버플로 또는 범위를 벗어난 값을 방지할 수 있습니다.

from pydantic import BaseModel, validator, constr, confloat
import re

class SendEmailArgs(BaseModel):
    to: str
    subject: constr(max_length=200)
    body: constr(max_length=10000)

    @validator('to')
    def must_be_company_email(cls, v):
        if not re.match(r'^[^@]+@(?:yourcorp\.com|partner\.com)$', v):
            raise ValueError('Email must be sent to yourcorp.com or partner.com domains only')
        return v

class ReadFileArgs(BaseModel):
    filename: constr(pattern=r'^[a-zA-Z0-9_\-\.]+$')  # alphanumeric only, no path traversal

    @validator('filename')
    def no_parent_directory(cls, v):
        if '..' in v or '/' in v or '\\' in v:
            raise ValueError('Path traversal detected')
        return v

# Validate before execution
def validated_send_email(args_dict: dict) -> dict:
    args = SendEmailArgs(**args_dict)  # raises ValueError on invalid input
    return send_email(args.to, args.subject, args.body)

변경할 수 없는 감사 로깅

에이전트가 수행하는 모든 도구 호출은 변경할 수 없는 감사 로그에 기록해야 합니다. 로그 항목에는 에이전트 ID와 세션 ID, 도구 이름과 모든 인자, 반환 값, 타임스탬프, 그리고 에이전트가 밝힌 호출 이유가 포함되어야 합니다. 변경할 수 없다는 것은 에이전트나 공격자가 로그 항목을 삭제하거나 수정할 수 없다는 뜻입니다. 추가 전용 저장소(클라우드 로깅 서비스, 한 번만 쓸 수 있는 데이터베이스 또는 WORM 저장소)를 사용하세요.

import hashlib
import json
import time

class ImmutableAuditLog:
    def __init__(self, log_backend):
        self.backend = log_backend  # e.g., CloudWatch, BigQuery, or append-only file
        self.previous_hash = '0' * 64  # genesis hash

    def record(self, agent_id: str, tool_name: str, args: dict, result, reasoning: str):
        entry = {
            'agent_id': agent_id,
            'tool': tool_name,
            'args': args,
            'result_summary': str(result)[:500],  # truncate large results
            'reasoning': reasoning[:1000],
            'timestamp': time.time(),
            'previous_hash': self.previous_hash  # chain entries like a blockchain
        }
        
        entry_json = json.dumps(entry, sort_keys=True)
        entry['hash'] = hashlib.sha256(entry_json.encode()).hexdigest()
        
        self.backend.append(entry)  # append-only, never update
        self.previous_hash = entry['hash']
        
        return entry['hash']

비정상적인 에이전트 동작 탐지

권한 확인 단계와 감사 로그가 있더라도 에이전트가 손상되었거나 예기치 않게 동작하고 있음을 나타내는 비정상 동작 패턴을 주의 깊게 관찰하세요. 이상 징후에는 지원 에이전트가 이전에는 한 번도 호출하지 않았던 도구를 갑자기 호출하는 경우, 한 에이전트의 도구 호출 빈도가 비정상적으로 급증하는 경우, 정상적인 범위와 의심스러운 방식으로 다른 인자(지나치게 긴 문자열이나 이상한 문자 시퀀스 등), 또는 평소와 다른 시간대에 발생하는 호출이 포함됩니다.

from collections import Counter

class AgentBehaviorMonitor:
    def __init__(self):
        self.tool_call_counts = Counter()  # tracks historical tool usage
        self.arg_length_history = {}       # tracks typical argument lengths

    def record_and_check(self, agent_id: str, tool_name: str, args: dict) -> list[str]:
        key = f'{agent_id}:{tool_name}'
        anomalies = []
        
        self.tool_call_counts[key] += 1
        
        # Flag tools never called before by this agent
        if self.tool_call_counts[key] == 1 and tool_name not in COMMON_TOOLS:
            anomalies.append(f'First time agent {agent_id} called unusual tool: {tool_name}')
        
        # Flag unusually long arguments (potential injection payload)
        total_arg_length = sum(len(str(v)) for v in args.values())
        if tool_name not in self.arg_length_history:
            self.arg_length_history[tool_name] = []
        self.arg_length_history[tool_name].append(total_arg_length)
        
        if len(self.arg_length_history[tool_name]) > 10:
            avg = sum(self.arg_length_history[tool_name]) / len(self.arg_length_history[tool_name])
            if total_arg_length > avg * 5:
                anomalies.append(f'Unusually long arguments for {tool_name}: {total_arg_length} chars (avg: {avg:.0f})')
        
        return anomalies

토큰 만료와 세션 범위 제한

에이전트 세션에는 정해진 수명이 있어야 합니다. 세션이 시작될 때 에이전트에 단기간만 유효한 토큰 또는 자격 증명을 발급하고, 세션이 끝나면 폐기하세요. 에이전트의 세션이 실행 중간에 손상되더라도 공격자가 손상된 세션을 악용할 수 있는 범위는 토큰의 만료 시점으로 제한됩니다. 세션 범위 제한은 손상된 에이전트 하나가 며칠 후 후속 공격에 사용되는 것도 방지합니다.

import secrets
import time

class SessionTokenManager:
    def __init__(self, ttl_seconds=3600):
        self.tokens = {}  # token -> (agent_id, user_id, expires_at)
        self.ttl = ttl_seconds

    def issue_token(self, agent_id: str, user_id: str) -> str:
        token = secrets.token_urlsafe(32)
        expires_at = time.time() + self.ttl
        self.tokens[token] = (agent_id, user_id, expires_at)
        return token

    def validate_token(self, token: str) -> dict | None:
        if token not in self.tokens:
            return None
        agent_id, user_id, expires_at = self.tokens[token]
        if time.time() > expires_at:
            del self.tokens[token]  # clean up expired token
            return None
        return {'agent_id': agent_id, 'user_id': user_id}

    def revoke_token(self, token: str):
        self.tokens.pop(token, None)

token_manager = SessionTokenManager(ttl_seconds=1800)  # 30-minute sessions

도구 보안 테스트

공격을 모의하여 도구 보안 계층을 테스트하세요. 권한이 없는 에이전트로 제한된 도구를 호출하고, 경로 순회 인자를 제공하고, 도구 매개변수에 지침 문자열을 삽입하고, 만료된 토큰으로 도구를 호출해 보세요. 종합적인 도구 보안 테스트 모음은 모든 권한 경계, 모든 검증 규칙, 모든 이상 탐지 트리거를 다뤄야 합니다.

되돌릴 수 있도록 설계하기

가능하면 도구를 되돌릴 수 있거나 단계적으로 실행되도록 설계하세요. 기록을 즉시 삭제하는 대신 삭제 표시를 남기는 삭제 표식을 사용하여 복원할 수 있게 하세요. 이메일을 즉시 보내는 대신 5분의 검토 시간이 지난 후 실행되는 '전송 대기' 대기열에 넣으세요. 금융 거래는 정산 전에 보류 상태로 단계적으로 처리하세요. 되돌릴 수 있게 설계한다고 해서 보안 위험이 사라지는 것은 아니지만, 공격이 성공했을 때의 영향을 크게 줄일 수 있습니다.

빠른 확인

이 lesson에서 배운 에이전트 도구 접근 보안 내용을 얼마나 이해했는지 확인해 보세요.

레슨 요약

이 lesson에서는 다음을 배웠습니다. 최소 권한 원칙은 각 에이전트 역할에 실제로 필요한 범위로 도구 권한을 제한합니다. 코드 수준의 권한 확인 단계는 프롬프트 인젝션으로 우회할 수 없는 방식으로 이러한 권한을 강제합니다. 또한 고위험 작업에 대한 사람의 확인 단계는 되돌릴 수 없는 작업이 실행되기 전에 최종 안전망을 제공합니다. 다음으로는 LLM 애플리케이션을 대상으로 구조화된 레드팀 훈련을 진행하겠습니다.

자주 묻는 질문

“에이전트 도구 접근 보안” 강의는 무료인가요?

네 — “에이전트 도구 접근 보안” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 AI Engineering Academy 강의 전체를 잠금 해제할 수 있습니다. AI Engineering Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“에이전트 도구 접근 보안”에서 뭘 배우나요?

에이전트 도구 권한에 최소 권한 원칙을 적용하고, 파괴적 작업 전에 확인 단계를 구현하며, 비정상적인 동작을 감지하도록 에이전트 작업 기록을 감사합니다. 브라우저에서 직접 실행하는 실습 코드로 AI Engineering Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

AI Engineering Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 AI Engineering Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.

“에이전트 도구 접근 보안” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 AI Engineering Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 AI Engineering Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 프롬프트 삽입 공격 분류
  2. RAG 시스템의 삽입 공격 방어
  3. 에이전트 도구 접근 보안
  4. LLM 애플리케이션 레드팀 테스트
← AI Engineering Academy(으)로 돌아가기