본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 12. 18. · 11 Views
Lambda 함수 연동 완벽 가이드
AWS Lambda와 Bedrock Agent를 연동하는 방법을 실무 중심으로 설명합니다. 이벤트 처리부터 응답 형식, 배포, 권한 설정까지 단계별로 배웁니다.
목차
1. Lambda 함수 기초
클라우드 팀으로 막 배치받은 김개발 씨는 팀장님으로부터 "Lambda 함수 하나 만들어서 Agent랑 연동해줘"라는 미션을 받았습니다. Lambda?
서버 없이 코드가 실행된다고? 김개발 씨는 당황했지만, 선배 박서버 씨가 차근차근 알려주기로 했습니다.
AWS Lambda는 서버를 관리하지 않고도 코드를 실행할 수 있는 서비스입니다. 마치 필요할 때만 켜지는 전등처럼, 요청이 들어올 때만 함수가 실행되고 비용이 청구됩니다.
이를 서버리스(Serverless) 아키텍처라고 부릅니다.
다음 코드를 살펴봅시다.
import json
def lambda_handler(event, context):
# Lambda 함수의 진입점입니다
print("Lambda 함수가 시작되었습니다!")
# event: 입력 데이터
# context: 실행 환경 정보
return {
'statusCode': 200,
'body': json.dumps('Hello from Lambda!')
}
김개발 씨는 입사 2개월 차 주니어 개발자입니다. 그동안 회사 서버실의 물리 서버를 관리하며 배포할 때마다 SSH로 접속하고, 프로세스를 재시작하고, 로그를 확인하는 일을 반복했습니다.
그런데 오늘 팀장님이 새로운 프로젝트를 맡기며 이렇게 말씀하셨습니다. "이번엔 Lambda로 해봐요.
서버 관리 안 해도 돼요." 서버 관리를 안 한다고? 김개발 씨는 의아했습니다.
그럼 코드는 어디서 실행되는 걸까요? 박서버 씨가 커피를 한 잔 건네며 설명을 시작했습니다.
"Lambda는 쉽게 말하면 택시 같은 거예요. 자가용은 주차장에 항상 세워둬야 하지만, 택시는 필요할 때만 부르잖아요?" 김개발 씨는 고개를 끄덕였습니다.
그렇다면 기존 서버는 자가용이고, Lambda는 택시라는 건가요? "정확해요.
기존 EC2 서버는 24시간 내내 켜져 있어야 하니까 돈이 계속 나가죠. 근데 Lambda는 함수가 실행될 때만 비용이 청구됩니다.
하루에 10번만 쓴다면? 그 10번에 대한 비용만 내면 돼요." Lambda의 핵심 개념은 간단합니다.
여러분이 작성한 함수를 AWS에 올려두면, 특정 이벤트가 발생했을 때 AWS가 알아서 그 함수를 실행해줍니다. 서버를 준비하고, 스케일링하고, 패치하는 모든 작업을 AWS가 대신 처리합니다.
위의 코드를 살펴보면 lambda_handler라는 함수가 보입니다. 이것이 Lambda 함수의 심장입니다.
Lambda는 항상 이 함수를 찾아서 실행합니다. 첫 번째 매개변수인 event는 입력 데이터입니다.
API 요청이든, S3 이벤트든, Bedrock Agent의 호출이든 모든 정보가 여기 담겨 옵니다. 두 번째 매개변수인 context는 실행 환경 정보를 담고 있습니다.
얼마나 메모리를 쓸 수 있는지, 타임아웃은 언제인지 같은 정보들이죠. 반환값은 항상 딕셔너리 형태입니다.
statusCode는 HTTP 상태 코드이고, body는 실제 응답 내용입니다. 웹 개발 경험이 있다면 익숙한 구조일 겁니다.
실무에서는 어떻게 활용할까요? 예를 들어 이미지 리사이징 서비스를 만든다고 가정해봅시다.
사용자가 S3에 이미지를 업로드하면 Lambda가 자동으로 실행되어 썸네일을 만들어줍니다. 하루에 100번 업로드되든 10000번 업로드되든 자동으로 확장됩니다.
하지만 주의할 점도 있습니다. Lambda는 최대 15분까지만 실행할 수 있습니다.
따라서 몇 시간씩 걸리는 작업에는 적합하지 않습니다. 또한 함수가 완전히 종료되면 메모리 상태가 사라지므로, 상태를 유지해야 한다면 DynamoDB나 S3 같은 외부 저장소를 활용해야 합니다.
김개발 씨는 박서버 씨의 설명을 들으며 점점 이해가 되기 시작했습니다. "그럼 제가 해야 할 일은 함수만 잘 작성하면 되는 거네요?" "맞아요.
서버 관리는 AWS에 맡기고, 우리는 비즈니스 로직에만 집중하면 됩니다. 그게 바로 서버리스의 철학이죠."
실전 팁
💡 - Lambda 함수는 가능한 한 작고 단순하게 작성하세요. 하나의 함수가 하나의 책임만 갖도록 합니다.
- 콜드 스타트를 줄이려면 함수를 warm하게 유지하거나, Provisioned Concurrency를 활용하세요.
2. Bedrock Agent용 핸들러 구조
Lambda 기초를 이해한 김개발 씨는 이제 본격적으로 Bedrock Agent와 연동할 차례입니다. 박서버 씨가 코드 템플릿을 보여주며 말했습니다.
"Agent가 Lambda를 호출할 때는 특별한 구조가 있어요. 이 구조를 정확히 따라야 합니다."
Bedrock Agent는 Lambda 함수를 호출할 때 특정한 이벤트 구조를 전달합니다. 핸들러는 이 이벤트를 파싱하고, 적절한 **액션(Action)**을 실행한 뒤, Agent가 이해할 수 있는 형식으로 응답해야 합니다.
마치 레스토랑에서 주문을 받고 요리를 내놓는 것과 같습니다.
다음 코드를 살펴봅시다.
def lambda_handler(event, context):
# Agent가 어떤 액션을 요청했는지 확인
action = event.get('actionGroup', '')
api_path = event.get('apiPath', '')
print(f"액션: {action}, API 경로: {api_path}")
# 액션별 라우팅
if api_path == '/get-weather':
result = get_weather_info(event)
elif api_path == '/send-email':
result = send_email(event)
else:
result = {'error': 'Unknown action'}
# Agent용 응답 형식으로 반환
return format_response(result)
김개발 씨는 Lambda 기본 구조를 이해했지만, Bedrock Agent와의 연동은 또 다른 세계였습니다. 평범한 API 호출과는 뭔가 달랐습니다.
박서버 씨가 화면을 가리키며 설명했습니다. "일반 Lambda는 자유 형식으로 입력을 받을 수 있지만, Bedrock Agent는 약속된 구조가 있어요.
생각해보세요. Agent는 AI잖아요?
AI가 Lambda를 호출하려면 표준화된 프로토콜이 필요합니다." 김개발 씨는 이해가 되기 시작했습니다. 사람과 사람이 대화할 때는 유연하게 말할 수 있지만, 기계와 기계가 통신할 때는 정확한 약속이 필요하다는 거군요.
Bedrock Agent가 Lambda를 호출할 때는 actionGroup과 apiPath라는 핵심 필드를 전달합니다. actionGroup은 큰 카테고리이고, apiPath는 구체적인 기능을 나타냅니다.
마치 음식점에서 "한식" 카테고리 안에 "김치찌개"라는 메뉴가 있는 것처럼요. 위의 코드를 보면 먼저 event에서 actionGroup과 apiPath를 추출합니다.
이것이 첫 번째 단계입니다. Agent가 "무엇을 원하는지" 파악하는 거죠.
다음으로 apiPath에 따라 적절한 함수로 라우팅합니다. /get-weather라면 날씨 정보를 가져오고, /send-email이라면 이메일을 보냅니다.
이것을 **라우팅(Routing)**이라고 부릅니다. 마지막으로 결과를 Agent가 이해할 수 있는 형식으로 포맷팅해서 반환합니다.
이 부분이 핵심입니다. 아무리 완벽한 데이터를 만들어도 형식이 틀리면 Agent는 이해하지 못합니다.
실무에서는 보통 하나의 Lambda 함수에 여러 액션을 처리하도록 만듭니다. 예를 들어 고객 서비스 Agent라면 "주문 조회", "배송 추적", "환불 요청" 같은 여러 기능을 하나의 Lambda에서 처리할 수 있습니다.
하지만 액션이 너무 많아지면 함수가 복잡해집니다. 이럴 때는 라우터 패턴을 활용합니다.
메인 Lambda가 요청을 받아서 적절한 하위 함수나 다른 Lambda로 전달하는 거죠. 마치 전화 교환원처럼요.
초보 개발자들이 자주 하는 실수는 event 구조를 잘못 파싱하는 것입니다. event.get('actionGroup')으로 안전하게 가져오지 않고 event['actionGroup']으로 직접 접근하면, 키가 없을 때 에러가 발생합니다.
항상 안전한 방식으로 파싱하세요. 김개발 씨는 코드를 보며 점점 감이 잡히기 시작했습니다.
"그럼 제가 할 일은 Agent가 보내는 이벤트 구조를 이해하고, 그에 맞게 응답하는 거네요?" 박서버 씨가 웃으며 답했습니다. "정확해요.
이제 슬슬 감이 오는군요!"
실전 팁
💡 - 액션이 많아지면 별도의 라우터 함수를 만들어 코드를 구조화하세요.
- event 구조를 파싱할 때는 항상 .get() 메서드를 사용해 안전하게 접근하세요.
3. 이벤트 파싱하기
이제 김개발 씨는 실제 이벤트 데이터를 뜯어보기로 했습니다. 박서버 씨가 CloudWatch 로그를 열어 보여주며 말했습니다.
"실전에서는 이런 데이터가 들어와요. 하나씩 파싱해봅시다."
Bedrock Agent가 전달하는 이벤트에는 parameters, requestBody, sessionAttributes 등 다양한 정보가 담겨 있습니다. 이를 정확히 파싱해야 원하는 데이터를 추출할 수 있습니다.
마치 택배 상자를 열어 내용물을 꺼내는 것과 같습니다.
다음 코드를 살펴봅시다.
def parse_event(event):
# 파라미터 추출 (URL 쿼리나 경로 파라미터)
parameters = event.get('parameters', [])
param_dict = {p['name']: p['value'] for p in parameters}
# 요청 본문 추출 (POST 데이터)
request_body = event.get('requestBody', {})
body_content = request_body.get('content', {})
# 세션 속성 (대화 컨텍스트)
session_attrs = event.get('sessionAttributes', {})
# 파싱된 데이터 반환
return {
'params': param_dict,
'body': body_content,
'session': session_attrs
}
김개발 씨는 CloudWatch 로그를 보고 깜짝 놀랐습니다. 이벤트 데이터가 생각보다 복잡했기 때문입니다.
JSON이 여러 층으로 중첩되어 있고, 필드 이름도 낯설었습니다. 박서버 씨가 진정시키며 말했습니다.
"처음엔 다들 그래요. 하지만 핵심 필드만 알면 간단합니다.
세 가지만 기억하세요. parameters, requestBody, sessionAttributes." 먼저 parameters는 URL 파라미터나 쿼리 스트링과 비슷합니다.
예를 들어 "서울의 날씨를 알려줘"라고 사용자가 물어보면, Agent는 city=서울 같은 파라미터를 Lambda에 전달합니다. 문제는 parameters가 리스트 형태로 온다는 점입니다.
각 항목이 {'name': 'city', 'value': '서울'} 같은 딕셔너리죠. 이걸 사용하기 편한 딕셔너리로 변환하는 게 위 코드의 첫 번째 부분입니다.
리스트 컴프리헨션을 사용해서 한 줄로 변환합니다. 파이썬에 익숙하다면 자주 쓰는 패턴이죠.
결과적으로 {'city': '서울'} 같은 깔끔한 딕셔너리가 만들어집니다. 다음은 requestBody입니다.
이건 POST 요청의 본문이라고 생각하면 됩니다. 복잡한 데이터나 긴 텍스트는 여기에 담겨 옵니다.
예를 들어 "이메일 보내줘"라는 요청이라면, 이메일 제목과 내용이 requestBody에 들어있을 겁니다. requestBody는 또 한 번 중첩되어 있습니다.
content라는 필드 안에 실제 데이터가 있죠. AWS가 왜 이렇게 구조를 복잡하게 만들었는지는 모르겠지만, 아마도 확장성을 고려한 설계일 겁니다.
마지막으로 sessionAttributes는 대화의 컨텍스트를 유지하는 데 사용됩니다. 챗봇이 이전 대화 내용을 기억하려면 어딘가에 저장해야 하는데, 그게 바로 여기입니다.
예를 들어 사용자가 "그 영화 예매해줘"라고 말했을 때, "그 영화"가 뭔지 알려면 이전 대화에서 언급된 영화 제목을 sessionAttributes에서 찾아야 합니다. 실무에서는 이런 파싱 로직을 별도의 유틸리티 함수로 분리하는 게 좋습니다.
여러 액션에서 반복적으로 사용되기 때문이죠. 위의 parse_event 함수처럼 재사용 가능하게 만들어두면 코드가 훨씬 깔끔해집니다.
초보 개발자들이 자주 하는 실수는 필드가 없을 때를 대비하지 않는 것입니다. 예를 들어 requestBody가 항상 있다고 가정하고 코드를 짜면, 실제로 없을 때 KeyError가 발생합니다.
항상 .get() 메서드를 사용하거나 try-except로 감싸세요. 김개발 씨는 코드를 따라 쳐보며 이해하기 시작했습니다.
"아, parameters는 간단한 값, requestBody는 복잡한 데이터, sessionAttributes는 컨텍스트를 담는 거네요!" 박서버 씨가 엄지를 치켜세웠습니다. "완벽해요!
이제 실전 데이터도 거뜬히 처리할 수 있을 겁니다."
실전 팁
💡 - parameters는 리스트로 오므로 딕셔너리로 변환해서 사용하세요.
- 필드가 없을 경우를 항상 대비하고, 기본값을 제공하세요.
4. 응답 형식 맞추기
데이터를 파싱했으니 이제 응답을 만들 차례입니다. 김개발 씨는 자신 있게 딕셔너리를 만들어 반환했지만, Agent가 이해하지 못한다는 에러를 받았습니다.
박서버 씨가 웃으며 말했습니다. "응답 형식이 정확해야 해요.
Bedrock Agent는 까다롭거든요."
Bedrock Agent는 ActionResponse 형식의 응답을 기대합니다. responseBody와 actionGroup 정보를 포함해야 하며, 응답 본문은 TEXT 형식으로 구조화해야 합니다.
형식이 틀리면 Agent는 응답을 이해하지 못합니다.
다음 코드를 살펴봅시다.
import json
def format_response(result_data):
# Agent가 요구하는 응답 형식 생성
response = {
'messageVersion': '1.0',
'response': {
'actionGroup': 'WeatherActions',
'apiPath': '/get-weather',
'httpMethod': 'GET',
'httpStatusCode': 200,
'responseBody': {
'TEXT': {
'body': json.dumps(result_data)
}
}
}
}
return response
김개발 씨는 당황했습니다. 분명히 올바른 데이터를 반환했는데 Agent가 오류를 뱉어냈습니다.
로그를 확인해보니 "Invalid response format"이라는 메시지가 보였습니다. 박서버 씨가 화면을 보더니 바로 문제를 파악했습니다.
"응답 형식이 잘못됐어요. Bedrock Agent는 자유 형식을 받지 않습니다.
정해진 구조가 있죠." 일반적인 Lambda 함수라면 그냥 딕셔너리를 반환해도 됩니다. 하지만 Bedrock Agent는 특별합니다.
AI 모델이 응답을 이해하고 처리해야 하므로, 표준화된 형식이 필요한 거죠. 먼저 messageVersion은 프로토콜 버전입니다.
현재는 항상 '1.0'을 사용합니다. 나중에 프로토콜이 업데이트되면 버전이 바뀔 수도 있겠죠.
다음은 response 객체입니다. 이 안에 모든 실제 데이터가 들어갑니다.
actionGroup과 apiPath는 요청받았던 값을 그대로 돌려주면 됩니다. Agent가 "아, 내가 요청한 액션에 대한 응답이구나"라고 인식하는 거죠.
httpMethod와 httpStatusCode는 HTTP 프로토콜을 따라합니다. GET 요청이었다면 'GET', POST였다면 'POST'를 적습니다.
상태 코드는 성공이면 200, 에러면 400이나 500을 사용하죠. 가장 중요한 부분은 responseBody입니다.
이 안에 TEXT라는 필드가 있고, 그 안에 또 body가 있습니다. 왜 이렇게 중첩되어 있을까요?
AWS는 나중에 TEXT 외에 다른 형식(IMAGE, AUDIO 등)을 지원할 수 있도록 확장성을 고려한 겁니다. body에는 반드시 문자열이 들어가야 합니다.
딕셔너리나 리스트를 그대로 넣으면 안 됩니다. json.dumps()를 사용해서 JSON 문자열로 변환해야 하죠.
이 부분을 놓치는 개발자가 정말 많습니다. 실무에서는 이런 응답 생성 로직을 헬퍼 함수로 만들어두는 게 좋습니다.
매번 복잡한 중첩 구조를 손으로 작성하면 실수하기 쉽습니다. 위의 format_response 함수처럼 재사용 가능한 형태로 만들어두세요.
또 한 가지 팁은 에러 응답도 같은 형식을 따라야 한다는 점입니다. 에러가 발생했다고 해서 예외를 던지면 안 됩니다.
httpStatusCode를 400이나 500으로 설정하고, body에 에러 메시지를 담아서 정상적인 응답 형식으로 반환해야 합니다. 김개발 씨는 코드를 수정해서 다시 테스트했습니다.
이번에는 Agent가 완벽하게 이해하고 응답을 처리했습니다. "드디어 됐어요!" 박서버 씨가 미소 지으며 말했습니다.
"응답 형식만 제대로 맞추면 나머지는 쉬워요. 이게 가장 까다로운 부분이거든요." 응답 형식을 정확히 이해하면 Bedrock Agent와의 연동이 훨씬 수월해집니다.
처음엔 복잡해 보이지만, 한 번 익숙해지면 자연스럽게 작성할 수 있습니다.
실전 팁
💡 - responseBody의 body는 반드시 JSON 문자열로 변환해야 합니다.
- 에러 응답도 동일한 형식을 따르되, httpStatusCode만 변경하세요.
5. Lambda 배포하기
로컬에서 완벽하게 작동하는 함수를 만들었으니, 이제 AWS에 올릴 차례입니다. 김개발 씨는 콘솔에서 함수를 만들고 코드를 복사 붙여넣기 했지만, 뭔가 비효율적이라는 생각이 들었습니다.
박서버 씨가 말했습니다. "제대로 된 배포 방법을 알려드릴게요."
Lambda 함수를 배포하는 방법은 여러 가지가 있습니다. AWS 콘솔에서 직접 코드를 작성하거나, ZIP 파일로 업로드하거나, AWS CLI를 사용할 수 있습니다.
프로덕션 환경에서는 자동화된 배포 파이프라인을 구축하는 게 일반적입니다.
다음 코드를 살펴봅시다.
# requirements.txt 파일 생성
# boto3==1.26.0
# requests==2.28.0
# 배포용 패키지 생성
mkdir package
pip install -r requirements.txt -t package/
cp lambda_function.py package/
cd package
zip -r ../lambda-deployment.zip .
cd ..
# AWS CLI로 Lambda 함수 업데이트
aws lambda update-function-code \
--function-name my-bedrock-agent-function \
--zip-file fileb://lambda-deployment.zip
김개발 씨는 Lambda 콘솔의 코드 에디터에서 직접 코드를 수정하고 있었습니다. 10줄 정도의 간단한 함수라면 괜찮지만, 프로젝트가 커지면서 파일도 늘어나고 외부 라이브러리도 필요해졌습니다.
박서버 씨가 화면을 보더니 고개를 저었습니다. "콘솔에서 직접 수정하면 버전 관리도 안 되고, 팀원들과 협업도 어려워요.
제대로 된 배포 프로세스가 필요합니다." Lambda 배포의 첫 단계는 의존성 관리입니다. 파이썬이라면 requirements.txt에 필요한 패키지를 명시합니다.
boto3는 AWS SDK이고, requests는 HTTP 요청을 위한 라이브러리죠. 다음은 패키징입니다.
Lambda는 모든 의존성을 함께 업로드해야 합니다. 로컬 개발 환경처럼 pip install로 설치된 패키지를 쓸 수 없습니다.
따라서 package 폴더를 만들고, 그 안에 모든 라이브러리를 설치합니다. -t 옵션은 "target directory"를 의미합니다.
즉, 현재 환경이 아니라 package 폴더에 설치하라는 뜻이죠. 그 다음 내가 작성한 lambda_function.py도 같은 폴더에 복사합니다.
이제 ZIP 파일로 압축합니다. -r 옵션은 recursive, 즉 하위 폴더까지 모두 포함한다는 뜻입니다.
결과물은 lambda-deployment.zip이라는 파일입니다. AWS CLI를 사용하면 명령어 한 줄로 배포할 수 있습니다.
update-function-code 명령어는 기존 함수의 코드를 업데이트합니다. --zip-file 옵션으로 방금 만든 ZIP 파일을 지정하면 됩니다.
fileb://는 바이너리 파일을 의미합니다. ZIP은 텍스트가 아니라 바이너리니까요.
이런 세세한 부분을 놓치면 업로드가 실패할 수 있습니다. 실무에서는 보통 CI/CD 파이프라인을 구축합니다.
GitHub Actions나 GitLab CI에서 코드를 커밋하면 자동으로 테스트하고, 패키징하고, 배포까지 해줍니다. 매번 수동으로 명령어를 실행할 필요가 없죠.
또 다른 방법은 Serverless Framework나 **SAM(Serverless Application Model)**을 사용하는 겁니다. YAML 파일에 설정을 정의하면, 복잡한 배포 과정을 프레임워크가 알아서 처리해줍니다.
초보 개발자들이 자주 하는 실수는 로컬 환경과 Lambda 환경의 차이를 간과하는 것입니다. 예를 들어 Mac에서 개발했는데 Lambda는 Linux 환경입니다.
일부 패키지는 플랫폼별로 바이너리가 다르기 때문에, Docker를 사용해 Linux 환경에서 패키징하는 게 안전합니다. 김개발 씨는 명령어를 따라 실행해보니 함수가 성공적으로 업데이트되었습니다.
"와, 이제 Git으로 관리하고 자동으로 배포할 수 있겠네요!" 박서버 씨가 고개를 끄덕였습니다. "맞아요.
처음엔 번거로워 보이지만, 장기적으로는 이게 훨씬 효율적입니다." 배포 프로세스를 자동화하면 실수를 줄이고, 배포 속도를 높이고, 롤백도 쉬워집니다. Lambda 개발의 핵심은 코드 작성만큼이나 배포 전략에 있습니다.
실전 팁
💡 - Docker를 사용해 Linux 환경에서 패키징하면 호환성 문제를 피할 수 있습니다.
- 작은 프로젝트라도 CI/CD를 구축하면 장기적으로 시간을 절약할 수 있습니다.
6. 권한 설정 (IAM)
함수를 배포했지만 실행해보니 "Access Denied" 에러가 발생했습니다. 김개발 씨는 당황했지만, 박서버 씨는 예상했다는 듯이 말했습니다.
"권한 설정을 안 했네요. AWS에서는 모든 것이 권한으로 통제됩니다."
Lambda 함수가 다른 AWS 서비스를 사용하려면 IAM Role과 **정책(Policy)**이 필요합니다. Bedrock Agent와 연동하려면 bedrock:InvokeModel 권한이, DynamoDB를 쓰려면 dynamodb:GetItem 권한이 필요합니다.
권한은 최소 권한 원칙을 따라야 합니다.
다음 코드를 살펴봅시다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"bedrock:InvokeModel",
"bedrock:InvokeAgent"
],
"Resource": "arn:aws:bedrock:*:*:agent/*"
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
}
]
}
김개발 씨는 완벽하게 작성된 코드를 배포했지만, 실행하자마자 에러가 발생했습니다. 로그를 확인해보니 "User is not authorized to perform bedrock:InvokeModel"이라는 메시지가 보였습니다.
박서버 씨가 설명을 시작했습니다. "AWS는 보안이 정말 철저해요.
기본적으로 모든 것이 차단되어 있고, 명시적으로 허용한 것만 할 수 있죠. 이게 바로 **최소 권한 원칙(Principle of Least Privilege)**입니다." Lambda 함수는 실행될 때 특정 IAM Role을 사용합니다.
이 Role에 어떤 권한이 부여되어 있느냐에 따라 함수가 할 수 있는 일이 결정됩니다. 마치 회사에서 사원증으로 출입할 수 있는 구역이 정해지는 것처럼요.
위의 JSON은 IAM 정책의 예시입니다. Statement는 권한 규칙들의 배열입니다.
각 규칙은 "무엇을", "어디에", "어떻게" 할 수 있는지 정의합니다. 첫 번째 Statement를 보면 Effect가 "Allow"입니다.
즉, 허용한다는 뜻이죠. Action은 bedrock:InvokeModel과 bedrock:InvokeAgent입니다.
Bedrock 모델을 호출하고 Agent를 실행할 수 있다는 의미입니다. Resource는 어떤 리소스에 대해 이 권한이 적용되는지 지정합니다.
arn:aws:bedrock:::agent/*는 모든 리전, 모든 계정의 모든 Agent를 의미합니다. 실무에서는 보통 특정 Agent ARN을 지정해서 범위를 좁힙니다.
두 번째 Statement는 로그 관련 권한입니다. Lambda는 CloudWatch Logs에 로그를 쓰는데, 이것도 권한이 필요합니다.
CreateLogGroup, CreateLogStream, PutLogEvents 세 가지 액션을 허용합니다. 권한을 설정할 때 가장 중요한 원칙은 필요한 것만 부여하는 겁니다.
예를 들어 DynamoDB에서 읽기만 한다면 GetItem만 주고, PutItem이나 DeleteItem은 주지 않습니다. 만약 함수가 해킹당해도 피해를 최소화할 수 있죠.
실무에서는 Managed Policy를 활용하기도 합니다. AWS가 미리 만들어둔 정책들인데, 예를 들어 AWSLambdaBasicExecutionRole은 기본적인 로그 쓰기 권한을 포함합니다.
커스텀 정책과 함께 사용하면 편리합니다. 초보 개발자들이 자주 하는 실수는 권한 에러가 나면 무조건 AdministratorAccess를 부여하는 것입니다.
이건 마치 모든 직원에게 CEO 권한을 주는 것과 같습니다. 당장은 편하지만, 보안상 매우 위험합니다.
또 다른 실수는 Resource를 *로 설정하는 겁니다. 모든 리소스에 대해 권한을 주는 건데, 이것도 피해야 합니다.
가능한 한 구체적인 ARN을 지정하세요. 김개발 씨는 필요한 권한만 정확히 부여하고 다시 테스트했습니다.
이번에는 완벽하게 작동했습니다. "권한 관리가 이렇게 중요한 줄 몰랐어요!" 박서버 씨가 진지하게 말했습니다.
"AWS에서는 코드보다 권한이 더 중요할 때도 있어요. 보안은 타협할 수 없으니까요." Lambda 함수 개발에서 IAM 권한 설정은 필수입니다.
처음엔 복잡해 보이지만, 원칙을 이해하면 어렵지 않습니다. 필요한 최소한의 권한만 부여하고, 정기적으로 검토하세요.
실전 팁
💡 - 권한 에러가 나면 CloudWatch Logs를 먼저 확인해서 어떤 액션이 거부되었는지 파악하세요.
- 개발 환경과 프로덕션 환경의 권한을 분리해서 관리하세요.
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
Helm 마이크로서비스 패키징 완벽 가이드
Kubernetes 환경에서 마이크로서비스를 효율적으로 패키징하고 배포하는 Helm의 핵심 기능을 실무 중심으로 학습합니다. Chart 생성부터 릴리스 관리까지 체계적으로 다룹니다.
보안 아키텍처 구성 완벽 가이드
프로젝트의 보안을 처음부터 설계하는 방법을 배웁니다. AWS 환경에서 VPC부터 WAF, 암호화, 접근 제어까지 실무에서 바로 적용할 수 있는 보안 아키텍처를 단계별로 구성해봅니다.
AWS Organizations 완벽 가이드
여러 AWS 계정을 체계적으로 관리하고 통합 결제와 보안 정책을 적용하는 방법을 실무 스토리로 쉽게 배워봅니다. 초보 개발자도 바로 이해할 수 있는 친절한 설명과 실전 예제를 제공합니다.
AWS KMS 암호화 완벽 가이드
AWS KMS(Key Management Service)를 활용한 클라우드 데이터 암호화 방법을 초급 개발자를 위해 쉽게 설명합니다. CMK 생성부터 S3, EBS 암호화, 봉투 암호화까지 실무에 필요한 모든 내용을 담았습니다.
AWS Secrets Manager 완벽 가이드
AWS에서 데이터베이스 비밀번호, API 키 등 민감한 정보를 안전하게 관리하는 Secrets Manager의 핵심 개념과 실무 활용법을 배워봅니다. 초급 개발자도 쉽게 따라할 수 있도록 실전 예제와 함께 설명합니다.