본문으로 건너뛰기

© 2026 Molayo

Qiita헤드라인2026. 06. 15. 11:12

【실기 검증】 AWS MCP Server를 '보안 관점'에서 해부했더니, 조건 키 하나로 최소 권한 및 샌드박스가 상상 이상으로 견고했던 이야기

요약

AWS MCP Server의 보안성을 실기 검증을 통해 심층 분석한 기술 기사입니다. Python 샌드박스의 격리 수준, 툴별 권한 경계, 그리고 CloudTrail을 통한 에이전트 활동 감사 가능성을 중점적으로 다룹니다.

핵심 포인트

  • AWS MCP Server의 Python 샌드박스 격리 수준 검증
  • 조건 키를 활용한 에이전트와 인간의 권한 분리 및 최소 권한 원칙 적용
  • CloudTrail을 통한 에이전트 기점 요청의 기계적 구분 및 감사 방법
  • call_aws와 run_script 간의 권한 경계 일관성 확인

면책 사항

본 기사는 필자 개인의 견해이며, 소속 조직의 공식 견해, 개발 체제, 업무 내용을 나타내는 것이 아닙니다. 기사 내의 기술적 표현은 2026년 6월 시점의 실기 검증에 기반한 것이며, 특정 제품 및 서비스의 성능과 사양을 보증하지 않습니다.

또한, AWS 계정 ID, IP 주소, 리소스 이름 등은 검증 환경의 실제 값을 마스킹 또는 치환하였습니다. 또한 일부 동작(CloudTrailsourceIPAddress / userAgent 등)은 실기 관측값이며, 공식 문서의 기재 내용과 다를 수 있습니다. 실제 운용 전에 본인의 환경 및 최신 공식 문서에서 확인하시기 바랍니다.

안녕하세요! Dirbato의 사내 기술 횡단 지원 조직 Backbeat에 소속된 시바타입니다!

2026년 5월, AWS로부터 AWS MCP Server(매니지드 원격 MCP)가 GA(General Availability)되었습니다.

AWS CLI 상당의 조작을 MCP 툴(call_aws / run_script 등)로서 에이전트에게 공개하는, AWS 매니지드 원격 MCP 서버입니다. 로컬의 mcp-proxy-for-aws가 SigV4 서명을 하여 원격 엔드포인트로 중계합니다.

공식 (GA 발표): The AWS MCP Server is now generally available -
공식 문서: Agent Toolkit for AWS

AWS MCP Server의 보안에 대해서는 이미 훌륭한 선행 기사들이 있습니다. Accenture(acntechjp)님의 기사는 조건 키(Condition Key)를 통한 인간과 에이전트의 권한 분리를, Future님의 기사는 IAM 가드레일 설계와 CloudTrail 감사를 각각 정중하게 검증하셨습니다 (매우 참고가 되었습니다. 감사합니다).

본 기사는 그것들과 중복되는 조건 키(검증 A)·CloudTrail 감사(검증 B)는 '재현과 보강'에 그치고, 아직 아무도 실측하지 않은 다음 3가지 점에 주안점을 둡니다.

(검증 C) — 무엇이 차단되고 어디까지 격리되어 있는가: run_script의 Python 샌드박스(Sandbox)를 내부까지 해부

(검증 C+) — 툴마다 정책을 나누어 작성해야 하는가: call_awsrun_script로 권한 경계는 동일한가

(검증 E) — 매니지드 MCP와 로컬 MCP의 구분 사용

"에이전트에게 AWS의 키를 넘겨줘도 괜찮은가?"를 한 단계 더 깊은 구현 레벨에서 확인합니다. 검증은 총 5개(A~E) 구성입니다.

최소 권한 — MCP를 경유한 요청만을 노려 Deny 할 수 있는가 (조건 키 /재현·보강)
감사 — CloudTrail에서 '에이전트 기점'을 기계적으로 구분할 수 있는가 (재현·보강)
샌드박스 (Sandbox)run_script의 Python 실행 환경은 어디까지 격리되어 있는가
권한의 일관성call_awsrun_script로 권한 경계는 동일한가
멀티 계정 / 로컬 MCP와의 구분 사용

환경: AWS 계정 123456789012 / region ap-northeast-1 / IAM 사용자 amazonq (mcp-proxy-for-aws==1.6.0)

  • 에이전트(Claude Code / Q 등)에게 AWS 조작을 맡기고 싶지만, 권한 설계가 불안한 사람
  • MCP를 경유한 조작을 CloudTrail로 감사 및 구분하고 싶은 사람
  • run_script의 Python 샌드박스가 어디까지 안전한지 알고 싶은 사람
  • 매니지드 AWS MCP Server와 로컬의 awslabs MCP 군의 구분 사용을 결정하고 싶은 사람

바쁜 분들을 위해 먼저 결론부터 말씀드립니다. 모두 실기로 확인한 1차 데이터입니다.

검증 항목한 줄 결과
aws:CalledViaAWSMCP를 통해 "어떤 MCP를 경유했는지"를 엄격하게 식별하여 Deny 가능. S3 버킷 정책(Bucket Policy) 하나로 실증
MCP 기점은 sourceIPAddress / userAgent가 모두 aws-mcp.amazonaws.com이며, userIdentity는 실제 사용자로 유지됨 → 구분과 책임 추적(Responsibility Tracking)이 양립
실행 전 정적 AST 검증으로 os / socket / subprocess / eval 등을 차단. 파일은 /tmp로 제한, 외부 통신은 call_boto3 (AWS API) 경유로만 가능
동일한 조건 키(Condition Key) Deny가 적용됨. "코드는 격리하지만 권한은 격리하지 않는다"는 원칙하에 call_awsrun_script 두 경로 모두에 효과적
기능은 실재하지만 프록시 기동 시 옵트인(Opt-in, aws_profile 파라미터)이 필요함. CLI의 --profile은 거부됨

:key: :key:

최대의 발견: AWS MCP Server는 단순한 "편리한 CLI 래퍼(Wrapper)"가 아니라, 조건 키(Condition Key)·CloudTrail·샌드박스(Sandbox)의 3층 구조로 거버넌스(Governance)가 설계된 서비스였다. aws:CalledViaAWSMCP단 하나의 Deny 문에 넣는 것만으로, 에이전트의 모든 조작 면(CLI 경로 및 샌드박스 내 boto3 경로 모두)을 일괄적으로 제어할 수 있다.

  • 인증은 기존의 AWS 인증 체인(~/.aws/credentials)을 통한 SigV4 서명을 사용한다. 장기 인증 정보는 로컬에 머문다.
  • MCP Server 자체는 무료이다. 과금은 에이전트가 호출하는 AWS API의 실비만 발생한다.
  • 서버 실체는 us-east-1 / eu-central-1에 있다. 호출 대상 리전은 --metadata AWS_REGION=...로 지정한다.

여기서 본 기사의 주인공이 되는 것이, **MCP 경유 요청에 AWS가 자동으로 부여하는 글로벌 조건 키(Global Condition Key)**이다.

조건 키타입의미
aws:ViaAWSMCPServiceBoolAWS 매니지드 MCP 경유 시 true
aws:CalledViaAWSMCPString어떤 MCP 서버를 경유했는지 (예: aws-mcp.amazonaws.com / eks-mcp.amazonaws.com)

📌 프리뷰(Preview) 시기에 있었던 IAM 액션(Action)

aws-mcp:InvokeMcp / CallReadOnlyTool / CallReadWriteTool은 폐지되어 무효화되었다. 현재는 위의 조건 키 방식이 정석(Standard)이다.

출처: How AWS MCP Server works with IAM

S3 버킷에, MCP 경유를 통한 DeleteObject만 거부하는 버킷 정책을 설정한다.

{
"Sid": "DenyDeleteViaAWSMCP",
"Effect": "Deny",
...
}

call_aws를 통해 삭제를 시도하면——

$ aws s3api delete-object --bucket mcp-poc-condkey-test-... --key obj-cplus-callaws.txt
An error occurred (AccessDenied) when calling the DeleteObject operation:
User: arn:aws:iam::123456789012:user/amazonq is not authorized to perform: s3:DeleteObject
...

:white_check_mark: :white_check_mark:

의도대로 AccessDenied 발생. 조건 값을 eks-mcp.amazonaws.com(불일치)으로 설정하면 동일한 삭제가 성공하는 것도 확인했다. 즉, 이 키는 "MCP 경유 여부"뿐만 아니라 "어떤 MCP인지"까지 엄격하게 식별한다.

💡 이 조건 키는 IAM 정책이나 SCP뿐만 아니라 리소스 기반 정책(Resource-based Policy, 버킷 정책)에서도 사용할 수 있다. "이 버킷에 대한 파괴적인 작업은 관리자라 할지라도 MCP를 경유한다면 거부한다"는 설정을 리소스 측면에서 단 한 장의 정책으로 완결 지을 수 있다.

MCP를 경유하여 실행된 하류(Downstream) AWS API 호출 (예: PutBucketPolicy)을 CloudTrail LookupEvents로 확인하면, 실제 기기에서는 다음과 같이 나타났습니다 (이번 작업분에 대해 실측).

// MCP 경유 (aws-mcp로 실행)
{
"eventName": "PutBucketPolicy",
...

🔒

마스킹에 대하여: 본 기사의 AWS 계정 ID (123456789012), IP 주소 (203.0.113.x), 버킷 이름 등은 검증 환경의 실제 값을 마스킹 또는 치환하였습니다. 동작의 본질은 변하지 않습니다.

:white_check_mark: :white_check_mark:

"누가 (실제 사용자)"와 "무엇을 경유하여 (에이전트)"를 동시에 기록할 수 있습니다. 하류 API의 sourceIPAddress / userAgentaws-mcp.amazonaws.com이 되므로, 이를 필터링하면 에이전트 기점의 조작만을 기계적으로 추출할 수 있습니다. AccessDenied로 거부된 조작도 기록됩니다.

📌

주석 (사실의 출처): 상기 sourceIPAddress / userAgent = aws-mcp.amazonaws.com은 본 검증에서의 실제 기기 관측값입니다 (집필 시점 기준으로 공식 문서에 명기된 값은 아닙니다). 문자열 aws-mcp.amazonaws.com은 공식적으로 조건 키(Condition Key)인 aws:CalledViaAWSMCP의 값(서비스 프린시펄, Service Principal)으로 정의되어 있습니다. 또한 유사한 관측 (userAgent / userIdentity.invokedBy = aws-mcp.amazonaws.com, sourceIPAddress는 고정값)은 Future사의 기사에서도 보고되어 본 검증과 일치합니다. userIdentity.invokedBy를 병용하면 더욱 견고하게 분리할 수 있습니다.

조사 결과, MCP 조작은 CloudTrail 상에서 **두 개의 계층 (Layer)**으로 남는다는 것을 알 수 있었습니다.

계층이벤트의 내용주요 필드 (공식 / 실측)용도
하류 API 계층실제로 호출된 AWS API (PutBucketPolicy 등)eventSource=s3.amazonaws.com / sourceIP=userAgent=aws-mcp.amazonaws.com (실측)에이전트가 자원에 무엇을 했는지 추적
MCP 메타 계층MCP 도구(Tool) 호출 그 자체eventSource=aws-mcp.<region>.api.aws / eventName=CallTool / eventType=AwsMcpEvent / requestParameters.method=call_aws (공식 로그 예시)어떤 도구(call_aws/run_script)를 사용했는지 추적

하류 API 계층에서 "자원에 대한 영향"을, MCP 메타 계층에서 "사용된 도구"를 확인합니다. 이 두 가지를 대조하면 감사가 완성됩니다. 공식 준거에 따라 필터링하려면 메타 계층의 eventType=AwsMcpEventrequestParameters.method를 사용하는 것이 확실합니다.

출처 (MCP 메타 계층의 로그 예시): Logging AWS MCP Server with CloudTrail

⚠️ 주의:

DeleteObject와 같은 데이터 이벤트(Data Event)는 관리 이벤트 기록(LookupEvents)에 나타나지 않습니다. 객체 단위로 추적하려면 S3 데이터 이벤트 기록을 활성화해야 합니다.

run_script는 boto3를 작성할 수 있는 Python 실행 환경입니다. "Python이 동작한다"가 곧 "임의 코드(Arbitrary Code)가 동작한다"로 이어지면 위험하므로, 어디까지 격리되어 있는지를 전수 조사하여 실측했습니다.

차단 대상이 포함된 스크립트는 단 한 줄도 실행되지 않고 검증 에러로 전건 나열 및 거부됩니다. 문자열 리터럴의 경로까지 정적으로 확인합니다.

Code validation failed:
Line 2: Blocked import: os
Line 2: Blocked import: socket
...
종류차단 대상 (발췌)
모듈os, sys, socket, subprocess, urllib, http, ssl, ctypes, threading, multiprocessing, pickle, base64, hashlib, inspect, importlib, pathlib, shutil
내장 함수 (Built-in functions)eval, exec, compile, __import__, getattr, setattr, globals, locals, vars, type, hasattr, id, memoryview
속성 접근 (Attribute access).__class__ 등의 dunder 속성도 정적 거부 (타입 → 기반 클래스를 통한 탈출 봉쇄)
파일open()은 허용되나 경로는 /tmp/로 한정. /etc/passwd 등은 정적 거부

허용되는 것은 json, math, datetime, re, collections, asyncio 등과 같은 순수 계산·데이터 정형화 계열뿐입니다.

공격 표면 (Attack surface)결과
외부 네트워크로의 데이터 유출socket / urllib / ssl 불가 → 외부 통신은 call_boto3 (AWS API)를 통해서만 가능
IMDS로부터의 인증 정보 탈취socket 불가 → 169.254.169.254로의 접속 코드조차 작성할 수 없음
로컬 비밀 정보 읽기os / sys 불가 → 환경 변수에 도달 불가능. 파일 시스템(FS)은 /tmp만 가능
샌드박스 탈출 (Sandbox escape)eval / exec / __import__ / getattr / .__class__를 봉쇄

:white_check_mark: :white_check_mark:

외부로 나가는 수단과 내부를 들여다보는 수단을 입구(AST 검증)에서 차단한 강력한 샌드박스였습니다. 또한 run_script최소 1개의 call_boto3를 포함할 것도 강제됩니다 (AWS API를 호출하지 않는 스크립트는 "No AWS API call found" 메시지와 함께 거부됩니다).

이 부분이 본 기사의 핵심입니다. run_script의 샌드박스 내부 call_boto3 역시, 실제 IAM Principal인 user/amazonq 상태 그대로 실행됩니다 (= 코드는 격리하지만 권한은 격리하지 않음).

그렇다면, 검증 A의 "MCP를 통한 DeleteObject Deny"는 run_script 내부의 삭제에도 적용될까요?

# run_script 내에서 삭제를 시도
await call_boto3(service_name="s3", operation_name="DeleteObject",
params={"Bucket": BUCKET, "Key": "obj-cplus-runscript.txt"})
...

:key: :key:

적용되었습니다. call_awsrun_script(call_boto3) 모두에 동일한 조건 키(Condition Key) 값인 aws-mcp.amazonaws.com이 각인됩니다.

즉, 거버넌스 설계자에게 내릴 수 있는 결론은 심플합니다. ——

aws:CalledViaAWSMCP를 포함한 Deny 문을 한 줄 작성하면, 에이전트가 CLI 경로로 호출하든 샌드박스 내부의 boto3로 호출하든 한꺼번에 제어할 수 있습니다.

경로마다 정책을 따로 작성할 필요가 없습니다.

"다른 계정이나 다른 역할(Role)로 전환할 수 있는지"도 테스트해 보았습니다. 직관적으로 CLI에 --profile을 붙이면 ——

$ aws sts get-caller-identity --profile dev
The following global arguments cannot be set: --profile

:x: :x:

거부됩니다 (cli_command 내의 글로벌 인자는 금지됨 = 올바른 동작). 올바른 메커니즘은 별도로 존재했습니다.

항목사양 (공식 + 실기)
올바른 메커니즘프록시가 수행하며, 값을 통해 프로필별 전용 연결로 라우팅 (백엔드 전송 전 제거). call_aws / run_script 등의 툴 스키마(Tool Schema)에 aws_profile 파라미터를 주입
...

본 세션은 단일 프로필 기동이었기 때문에 aws_profile 파라미터는 나타나지 않았으며, cross-account 경로도 존재하지 않았습니다. sts:AssumeRole 권한도 없는 Principal이었기 때문에, 라이브 크로스 롤(Cross-role)은 재현 불가능했습니다. **"설정되어 있지 않다면, 에이전트는 멋대로 다른 계정으로 넘어갈 수 없다"**는 사실 자체가 보안상의 안심 요소입니다.

출처: Multi-profile support

awslabs는 로컬 실행형 MCP 군(aws-api-mcp-server, 서비스별 MCP 등)도 제공하고 있습니다. 매니지드(Managed) AWS MCP Server와 어떻게 구분하여 사용할까요?

관점매니지드 AWS MCP Server로컬 MCP (awslabs 각종)
실행 장소리모트 (aws-mcp.*.api.aws). 로컬은 SigV4 서명 중계만 수행자신의 머신에서 실행
인증 정보 경로로컬 자격 증명으로 서명, API 실행은 매니지드 측에서 수행로컬 자격 증명을 직접 사용
aws:CalledViaAWSMCP 각인있음 (조건 키(Condition Key)로 일원화된 거버넌스 가능)없음 (일반 사용자 API와 구별 불가)
CloudTrail 상의 모습sourceIP/userAgent = aws-mcp.amazonaws.com일반적인 API 호출과 동일
샌드박스 (Sandbox)run_script의 AST 정적 검증으로 강제서버 구현에 의존 (격리 보장은 기본적으로 없음)
커버리지AWS CLI에 상응하는 넓은 범위서비스 특화 및 전용 툴이 충실함
오프라인 / 폐쇄망불가 (리모트 전제)가능 (로컬 완결)

:bulb: :bulb:

사용 구분 지침:

  • 거버넌스 및 감사를 적용하여 폭넓게 AWS를 다루게 하고 싶다 $\rightarrow$ 매니지드 AWS MCP Server (조건 키 + CloudTrail + 샌드박스의 3중 보안이 작동)
  • 폐쇄망, 특정 서비스 전용 툴, 자체 제어가 필요하다 $\rightarrow$ 로컬 MCP
검증결론
A 최소 권한aws:CalledViaAWSMCP를 통해 "어떤 MCP를 경유했는지"를 엄격히 식별하여 Deny. 리소스 기반 정책(Resource-based policy)으로도 가능
B 감사sourceIP/userAgent = aws-mcp.amazonaws.com + 실제 사용자 정보를 유지하여 구분과 추적을 양립
C 샌드박스AST 정적 검증으로 os / socket / eval 등을 차단, 파일 시스템(FS)은 /tmp만 허용, 외부 호출은 call_boto3만 허용
C+ 권한의 일관성동일한 Deny 정책이 CLI 경로와 샌드박스 boto3 경로를 모두 차단
D 멀티 계정aws_profile 파라미터 (기동 시 옵트인). 미설정 시 계정 간 이동 불가
E 사용 구분거버넌스 중시 = 매니지드 / 폐쇄망·특화 = 로컬

에이전트에게 AWS를 맡기는 불안의 상당 부분은, **"조건 키 하나를 통한 Deny"와 "CloudTrail의 필터 하나"**로 실무적으로 해소할 수 있다는 것이 실기 검증의 결론이었습니다. AWS MCP Server는 단순한 편의 도구가 아니라, 거버넌스를 전제로 설계된 서비스입니다.

본 기사는 실기 검증에 기반한 드래프트입니다. 검증은 단일 계정, 단일 프로필, 제한된 권한의 Principal로 실시되었으므로, 멀티 계정(검증 D)은 문서 사양 확인에 그친다는 점을 양해 부탁드립니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0