13년차의 서버실

서버, 인프라, 홈랩 기술 블로그

[태그:] CloudWatch Logs

  • [k8s] EKS 운영 비용 최적화 전략: 클라우드 지출 효율 높이기

    [k8s] EKS 운영 비용 최적화 전략: 클라우드 지출 효율 높이기

    [클라우드] EKS 비용 최적화 전략: 클라우드 지출 효율 높이기

    EKS 비용 최적화는 AWS를 오래 운영할수록 더 민감해지는 주제입니다. 처음엔 서비스만 잘 뜨면 된다고 생각했는데, 어느 순간 청구서를 보면 CPU는 놀고 있고 노드는 과하게 떠 있고, 로그 저장 비용까지 슬금슬금 올라가더라고요. 저도 홈랩과 실제 운영 환경을 오가면서 비슷한 패턴을 여러 번 봤습니다. 특히 AWS EKS 운영을 하다 보면 워크로드는 늘지 않았는데 비용만 올라가는 구간이 꼭 옵니다. 그 시점부터는 성능 튜닝보다 먼저 해야 할 일이 비용 구조를 보는 일입니다.

    이번 글에서는 제가 직접 현장에서 자주 적용했던 방법들을 공유하려고 합니다. Kubernetes(쿠버네티스) 클러스터에서 어디서 돈이 새는지, 어떤 순서로 손봐야 하는지 정리해볼 거예요. 무작정 인스턴스를 내리는 이야기가 아니라, 서비스 안정성을 최대한 해치지 않으면서 Kubernetes 비용 절감과 클라우드 비용 관리를 같이 가져가는 방법에 가깝습니다.

    EKS 비용 최적화 구조를 보여주는 아키텍처 다이어그램

    EKS 비용 구조를 노드, 스토리지, 네트워크, 관측 영역으로 나눠 보여주는 개요 이미지입니다.

    1. 왜 EKS 비용은 생각보다 빨리 커질까요?

    쉽게 말해 EKS는 “컨테이너만 쓰는 서비스”가 아닙니다. 실제 청구는 여러 층에서 발생하거든요. 컨트롤 플레인(Control Plane, 클러스터 제어 영역), EC2 노드(Node, 워커 서버), EBS(Elastic Block Store, 블록 스토리지), 데이터 전송, 로드밸런서, 로그 수집까지 다 합쳐져서 나옵니다. 그래서 Pod(파드) 몇 개 줄였다고 체감이 바로 안 오는 경우도 많습니다.

    • 노드 과할당: 요청 리소스(request)가 실제 사용량보다 과하게 잡혀서 빈 서버를 계속 유지합니다.
    • 상시 고정 용량: 피크 시간 기준으로 노드를 잡아두고 하루 종일 유지합니다.
    • 분산 실패: 비슷한 워크로드가 여러 노드에 흩어져서 스케일 인(scale-in)이 안 됩니다.
    • 스토리지/로그 방치: 안 쓰는 볼륨, 긴 로그 보관 기간이 누적됩니다.
    • 네트워크 비용 누락: NAT Gateway, AZ 간 트래픽, Load Balancer 비용이 생각보다 큽니다.

    여기서 중요한 포인트! EKS 비용 최적화는 “할인 상품 먼저 사기”보다 현재 사용 패턴을 정상화하는 게 우선입니다. 저도 처음엔 Savings Plans(세이빙 플랜)부터 볼까 했었는데, 실제로는 잘못된 리소스 요청값부터 정리하는 게 훨씬 효과가 컸습니다.

    2. EKS 비용을 볼 때 꼭 나눠야 하는 4가지 축

    제가 비용 분석할 때는 항상 네 가지로 쪼갭니다. 이렇게 나누면 어디를 먼저 줄여야 할지가 보입니다.

    영역 무엇을 보나 자주 나오는 문제 우선 대응
    Compute EC2 노드, Fargate 사용량 낮은 사용률, 과한 노드 수 오토스케일링, Bin Packing
    Storage EBS, 스냅샷, 로그 저장 미사용 볼륨, 긴 보관 기간 수명주기 관리, 정리 자동화
    Network Load Balancer, NAT, 트래픽 불필요한 외부 통신 경로 엔드포인트, 경로 단순화
    Observability 로그, 메트릭, 트레이싱 수집 과다, 샘플링 없음 필드 축소, 보관 기간 재설계

    이 표를 기준으로 보면, 같은 “클라우드 비용 관리”라도 접근 방식이 완전히 달라집니다. 노드 문제를 로그 보관 기간으로 해결할 수는 없으니까요.

    3. 실전 1단계: 먼저 현재 사용량을 수치로 확인합니다

    비용 최적화는 감으로 하면 거의 실패합니다. 저도 예전에 “이 노드가 제일 비싸 보이네” 하고 줄였다가 배치 작업이 밀린 적이 있었습니다. 삽질 좀 했습니다 ㅎㅎ 그래서 지금은 반드시 사용량과 요청값을 같이 봅니다.

    1. namespace(네임스페이스)별로 어떤 팀/서비스가 많이 쓰는지 확인합니다.
    2. CPU/메모리 실제 사용량과 requests/limits 차이를 봅니다.
    3. 노드별 유휴율과 스케일 인 가능 여부를 확인합니다.
    4. Spot(스팟) 전환 가능한 워크로드를 분류합니다.
    kubectl top nodes
    kubectl top pods -A --sort-by=cpu
    kubectl top pods -A --sort-by=memory
    kubectl get pods -A -o wide
    kubectl describe node <node-name>

    여기에 metrics-server(메트릭 서버)나 Prometheus(프로메테우스, 모니터링 시스템)가 붙어 있으면 더 좋습니다. 핵심은 “실사용량 대비 요청값이 얼마나 부풀어 있는가”입니다. 실제로 써보니까 메모리 request를 넉넉하게 잡아둔 서비스들이 클러스터 비용을 조용히 밀어올리는 경우가 정말 많더라고요.

    4. 실전 2단계: Node Group과 Autoscaling 구조부터 손봅니다

    AWS EKS 운영에서 비용이 가장 크게 흔들리는 영역은 대체로 노드입니다. 그래서 저는 여기부터 들어갑니다. 대표적으로 Managed Node Group(관리형 노드 그룹)과 Karpenter(카펜터, 워크로드 기반 노드 프로비저닝 도구), Cluster Autoscaler(클러스터 오토스케일러)를 조합해 구조를 정리합니다.

    운영 팁을 하나 말씀드리면, 모든 워크로드를 한 종류 노드에 태우는 건 나중에 꼭 비용 문제로 돌아옵니다. On-Demand(온디맨드)와 Spot을 분리하고, 시스템 워크로드와 일반 애플리케이션 워크로드를 구분해두는 게 좋습니다.

    EKS 비용 최적화를 위한 온디맨드와 스팟 노드 분리 구성 이미지

    시스템 워크로드는 안정적인 온디맨드 노드에, 일반 서비스는 스팟 노드에도 분산하는 구성 예시입니다.

    추천 접근 방식

    • 기반 시스템용 소규모 온디맨드 노드 그룹 유지
    • 일반 웹/API 워크로드는 오토스케일링 대상 그룹으로 분리
    • 중단 허용 가능한 배치/잡(Job)은 스팟 전용으로 이동
    • Pod Disruption Budget(파드 중단 예산)과 anti-affinity를 같이 점검
    apiVersion: autoscaling/v2
    kind: HorizontalPodAutoscaler
    metadata:
      name: sample-api
      namespace: production
    spec:
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: sample-api
      minReplicas: 2
      maxReplicas: 10
      metrics:
        - type: Resource
          resource:
            name: cpu
            target:
              type: Utilization
              averageUtilization: 70

    HPA(Horizontal Pod Autoscaler, 수평 파드 오토스케일러)를 붙일 때도 request 값이 엉망이면 오토스케일 기준이 제대로 안 먹히더라고요. 그래서 request/right-sizing(라이트사이징, 적정 용량 조정)을 먼저 하고 HPA를 적용하는 순서가 훨씬 안정적입니다.

    5. 실전 3단계: requests/limits를 줄이는 게 진짜 핵심입니다

    많은 분들이 EKS 비용 최적화라고 하면 인스턴스 타입부터 바꾸는데, 제가 직접 해보니 제일 먼저 손대야 할 건 Deployment(디플로이먼트) 리소스 설정이었습니다. 특히 초기값을 넉넉하게 잡아놓고 그대로 운영하는 팀이 많거든요.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: sample-api
    spec:
      replicas: 3
      template:
        spec:
          containers:
            - name: app
              image: example/sample-api:stable
              resources:
                requests:
                  cpu: "250m"
                  memory: "512Mi"
                limits:
                  cpu: "500m"
                  memory: "1Gi"

    여기서 중요한 건 숫자 자체보다 실측 기반으로 줄였는가입니다. CPU는 낮은데 메모리만 치솟는 애플리케이션도 있고, 반대도 있습니다. VPA(Vertical Pod Autoscaler, 수직 파드 오토스케일러)를 참고용으로 쓰거나, 일정 기간 메트릭을 보고 수동 조정해도 충분히 효과를 볼 수 있습니다.

    제가 보통 보는 체크포인트는 이렇습니다.

    • 평균 사용량이 requests의 절반 이하로 오래 유지되는가
    • OOMKilled(메모리 부족 종료) 이력이 있는가
    • 배치 시간대와 일반 시간대 사용 패턴이 다른가
    • limits 때문에 CPU throttling(스로틀링, CPU 제한)이 심한가

    이 단계만 잘해도 Kubernetes 비용 절감 효과가 꽤 크게 납니다. 왜냐하면 스케줄러가 더 촘촘하게 파드를 배치할 수 있어서, 결과적으로 노드 수가 줄어들 가능성이 커지거든요.

    6. 실전 4단계: 로그, 스토리지, 네트워크도 같이 줄여야 합니다

    노드만 줄이고 끝내면 반쪽짜리입니다. CloudWatch Logs(클라우드워치 로그), EBS, Load Balancer, NAT 비용도 무시 못 하거든요. 처음엔 이게 뭔가 싶었는데, 실제 청구를 뜯어보면 로그 저장 비용이 꽤 눈에 띄는 환경도 있습니다.

    aws logs describe-log-groups
    aws ec2 describe-volumes --filters Name=status,Values=available
    aws elbv2 describe-load-balancers
    • 로그: 디버그 로그 상시 수집 금지, 보관 기간을 서비스 성격에 맞게 분리
    • 스토리지: 미사용 EBS와 오래된 스냅샷 주기 점검
    • 네트워크: 내부 통신은 가능하면 Internal Load Balancer와 VPC Endpoint 활용
    • 이미지: 컨테이너 이미지 크기를 줄여 배포 시간과 캐시 비효율 감소
    EKS 비용 최적화에 포함되는 로그 보관과 EBS 정리 운영 다이어그램

    로그 보관 기간 조정, 미사용 볼륨 점검, 네트워크 경로 단순화 흐름을 설명하는 이미지입니다.

    특히 NAT Gateway 비용은 조용히 커집니다. 외부 API 호출이 많은 워크로드나 잘못된 라우팅 구조가 있으면 생각보다 빨리 누적되더라고요. 혹시 청구서에서 네트워크 비용이 이상하게 높다면, 애플리케이션보다 먼저 통신 경로를 의심해보셔도 좋습니다.

    7. ⚠️ 제가 실제로 자주 본 문제와 트러블슈팅

    비용 줄이다가 장애 내면 말짱 도루묵이죠. 그래서 아래 항목은 꼭 같이 보셔야 합니다.

    1) 스팟 노드만 늘렸더니 서비스가 불안정해진 경우

    해결은 단순합니다. 상태 저장성(Stateful) 워크로드나 핵심 시스템 컴포넌트는 온디맨드에 남기고, 스팟은 중단 허용 가능한 서비스 위주로 태워야 합니다.

    2) request를 너무 낮췄더니 HPA가 과민반응하는 경우

    CPU 기준 HPA는 request 영향을 받습니다. request를 급격히 낮추면 스케일 아웃이 너무 빨라질 수 있습니다. 그래서 한 번에 크게 줄이지 말고, 며칠 단위로 관찰하면서 조정하는 게 안전합니다.

    3) Bin Packing이 안 돼서 노드가 안 줄어드는 경우

    Topology Spread Constraints(토폴로지 분산 제약), anti-affinity, DaemonSet(데몬셋) 자원 점유 때문에 흔히 생깁니다. 저도 처음엔 오토스케일러가 이상한 줄 알았는데, 실제로는 배치 정책 때문에 노드가 비워지지 않더라고요.

    4) 로그를 줄였더니 장애 분석이 어려워진 경우

    모든 로그를 다 버리면 안 됩니다. 애플리케이션 로그는 줄이더라도 감사 로그, 에러 로그, 핵심 접근 로그는 남겨야 합니다. 비용과 가시성(observability, 관측 가능성) 사이에서 선을 잘 잡아야 합니다.

    8. 검증 방법: 비용이 정말 줄었는지 어떻게 확인할까?

    최적화는 적용보다 검증이 더 중요합니다. 저는 보통 2주에서 4주 단위로 비교합니다. 하루 이틀 데이터만 보면 배치, 이벤트 트래픽, 배포 타이밍 때문에 판단이 왜곡되거든요.

    1. 변경 전/후 노드 수와 평균 사용률을 비교합니다.
    2. namespace별 requests 합계를 기록합니다.
    3. CloudWatch 또는 Prometheus에서 CPU/메모리 추세를 봅니다.
    4. AWS Cost Explorer에서 서비스별 비용 추세를 확인합니다.
    5. 장애, 재시작, 응답 지연이 늘지 않았는지 같이 체크합니다.
    EKS 비용 최적화 전후를 비교하는 대시보드 이미지

    변경 전후 비용 추이, 노드 수, CPU/메모리 사용률을 함께 보여주는 검증용 대시보드 이미지입니다.

    검증할 때는 이렇게 보시면 됩니다.

    • 비용은 줄었는데 재시작이 늘었다면 과최적화일 수 있습니다.
    • 노드 수는 같아도 여유 자원이 늘었다면 다음 단계 최적화 여지가 생긴 겁니다.
    • 로그 비용만 줄었다면 Compute 최적화는 아직 덜 된 상태일 수 있습니다.

    드디어 됐다! 싶은 순간은 보통 “같은 트래픽인데 노드 수가 줄고, 장애 지표는 그대로일 때”입니다. 이게 가장 건강한 절감입니다.

    9. 정리: EKS 비용 최적화는 할인보다 구조가 먼저입니다

    오늘 내용을 한 줄로 정리하면 이겁니다. EKS 비용 최적화는 인스턴스 가격표를 보는 작업이 아니라, 워크로드 배치 구조와 리소스 설정을 바로잡는 작업입니다. 저도 처음엔 할인 모델만 찾았었는데, 실제로 써보니까 request 조정, 오토스케일링 구조 정리, 로그/스토리지 수명주기 관리가 훨씬 먼저더라고요.

    • 먼저 실제 사용량을 측정합니다.
    • 그다음 requests/limits를 다듬습니다.
    • 오토스케일링과 스팟 전략을 분리 적용합니다.
    • 스토리지, 로그, 네트워크 비용까지 같이 봅니다.
    • 마지막으로 Cost Explorer와 모니터링으로 검증합니다.
    EKS 비용 최적화 실행 우선순위를 요약한 인포그래픽

    사용량 측정부터 검증까지의 실행 순서를 요약한 체크리스트형 인포그래픽입니다.

    혹시 지금 EKS 청구서를 보고 “분명 서비스는 안 늘었는데 왜 이러지?” 싶으셨다면, 오늘 소개한 순서대로 한 번만 점검해보세요. 차이가 확실할 겁니다. 다음 글에서는 Karpenter와 Cluster Autoscaler를 어떤 기준으로 나눠 쓰는지, 그리고 스팟 운영 시 장애 반경을 어떻게 줄이는지 이어서 다뤄볼 예정입니다. 이전 글의 VPC 설계 내용과도 연결해서 보시면 더 이해가 쉬우실 거예요. 🎉

  • [Cloud] AWS Lambda 보안 강화 체크리스트: 10가지 필수 설정

    [Cloud] AWS Lambda 보안 강화 체크리스트: 10가지 필수 설정

    목차

    AWS Lambda 보안 강화 체크리스트: 10가지 필수 설정

    AWS Lambda 보안, 이거 처음엔 되게 단순해 보이는데요. 함수 하나 잘 올리고 이벤트만 연결하면 끝 같지만, 실제 운영으로 들어가면 얘기가 완전히 달라집니다. 저도 홈랩이랑 실제 업무에서 서버리스(Serverless, 서버 관리 부담을 줄인 실행 방식)를 만지다 보니, 초반엔 “관리할 서버가 없으니 더 안전한 거 아닌가?”라고 생각했었는데요. 근데 여기서 많이들 놓치는 포인트가 있습니다. 서버가 안 보일 뿐이지, 권한(IAM), 비밀정보(Secrets), 네트워크(Network), 로깅(Logging), 배포 체계는 그대로 남아 있거든요.

    특히 AWS Lambda 보안은 한두 개 설정만으로 끝나는 문제가 아닙니다. Lambda 보안 설정을 잘못하면 함수 자체보다도, 연결된 IAM Role(아이엠 역할), Secrets Manager(시크릿 매니저), S3, DynamoDB, API Gateway 쪽에서 사고가 나는 경우가 더 많더라고요. 그래서 이번 글에서는 제가 실제로 체크하는 AWS Lambda 베스트 프랙티스 중심의 보안 체크리스트 10가지를 정리해보겠습니다. 체크리스트 형태로 보시면 운영 전에 빠르게 점검하기 좋습니다.

    AWS Lambda 보안 체크리스트 아키텍처 개요 이미지

    AWS Lambda 보안 체크리스트를 한눈에 보여주는 아키텍처 개요 이미지입니다. 함수, IAM, Secrets, 로그, 네트워크 관계를 이해하는 데 도움이 됩니다.

    AWS Lambda 보안, 왜 따로 챙겨야 할까요?

    쉽게 말해 Lambda는 코드만 올리면 돌아가는 서비스지만, 그 코드가 무엇을 할 수 있는지는 주변 설정이 결정합니다. 예를 들어 함수 코드가 단순해도 과도한 IAM 권한이 붙어 있으면 S3 버킷 전체를 읽을 수 있고, 환경 변수(Environment Variables)에 비밀키를 평문으로 넣어두면 사고 범위가 순식간에 커집니다.

    제가 직접 해보니, 서버리스 보안은 EC2처럼 OS 패치만 신경 쓰는 문제가 아니었습니다. 대신 다음 질문을 계속 던져야 하더라고요.

    • 이 함수는 정말 필요한 AWS API만 호출할 수 있나요?
    • 이벤트를 누가 발생시키는지 통제되고 있나요?
    • 에러가 나면 추적 가능한 로그가 남나요?
    • 비밀정보가 코드나 환경 변수에 과하게 노출되지 않나요?

    여기서 중요한 포인트! AWS Lambda 보안은 “실행 코드”보다 “실행 권한과 연결 지점”을 먼저 봐야 합니다.

    핵심 개념 정리: Lambda 보안 설정은 3층으로 봐야 합니다

    저는 Lambda 보안을 볼 때 보통 3층으로 나눠서 봅니다. 저도 처음엔 헷갈렸는데 이렇게 나누니까 머리에 잘 들어오더라고요.

    구분 무엇을 보호하나 대표 설정
    접근 제어 누가 함수를 호출하고 무엇을 하게 할지 IAM Role, Resource-based policy, Function URL 인증
    데이터 보호 비밀정보와 민감 데이터 노출 방지 KMS, Secrets Manager, 환경 변수 암호화
    탐지와 대응 이상 징후 확인과 사고 대응 CloudWatch Logs, CloudTrail, Alarm

    결국 Lambda 보안 설정은 단일 옵션이 아니라, 권한 최소화(Least Privilege, 최소 권한 원칙) + 비밀정보 분리 + 추적 가능성 확보 이 세 가지가 같이 가야 합니다.

    AWS Lambda 보안 체크리스트 10가지

    1. 실행 역할(IAM Execution Role)은 최소 권한으로 시작하세요

    이건 진짜 기본인데, 가장 많이 무너집니다. 처음엔 편하니까 AWSLambdaBasicExecutionRole에 이것저것 붙이다가 나중에 권한이 비대해지거든요. 실제로 써보니까 함수별로 Role을 분리하는 것만 해도 사고 범위를 꽤 줄일 수 있었습니다.

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": [
            "logs:CreateLogGroup",
            "logs:CreateLogStream",
            "logs:PutLogEvents"
          ],
          "Resource": "arn:aws:logs:ap-northeast-2:123456789012:*"
        },
        {
          "Effect": "Allow",
          "Action": [
            "dynamodb:GetItem",
            "dynamodb:PutItem"
          ],
          "Resource": "arn:aws:dynamodb:ap-northeast-2:123456789012:table/app-session"
        }
      ]
    }

    팁: 와일드카드 *는 진짜 마지막 수단으로만 쓰세요. 특히 s3:*, dynamodb:*, kms:*는 운영 들어가면 나중에 반드시 발목 잡습니다.

    2. 환경 변수에 비밀값을 직접 넣지 말고 Secrets Manager를 쓰세요

    처음엔 이게 뭔가 싶었는데, 환경 변수에 토큰이나 DB 비밀번호를 그냥 넣는 습관이 제일 위험합니다. Lambda는 환경 변수 암호화를 지원하지만, 운영 기준에선 AWS Secrets Manager나 SSM Parameter Store를 통해 분리하는 쪽이 훨씬 낫습니다.

    import os
    import json
    import boto3
    
    secrets = boto3.client("secretsmanager")
    
    
    def get_secret(secret_name: str):
        response = secrets.get_secret_value(SecretId=secret_name)
        if "SecretString" in response:
            return json.loads(response["SecretString"])
        return {}
    
    
    def lambda_handler(event, context):
        secret_name = os.environ["APP_SECRET_NAME"]
        app_secret = get_secret(secret_name)
        return {"statusCode": 200, "body": "ok"}

    제가 직접 해보니 비밀값 교체(rotation)나 권한 추적도 쉬워지고, 코드 저장소에 값이 새는 일도 확실히 줄더라고요.

    3. Lambda 리소스 기반 정책(Resource-based Policy)을 점검하세요

    람다 함수는 실행 역할만 보는 게 아니라 누가 이 함수를 invoke(호출)할 수 있는지도 중요합니다. S3, EventBridge, API Gateway, 다른 계정에서 호출하는 구조라면 리소스 기반 정책을 꼭 보셔야 합니다.

    aws lambda get-policy \
      --function-name my-secure-function

    여기서 예상하지 못한 Principal(프린시펄, 권한 주체)이 있으면 바로 점검하셔야 합니다. 특히 멀티 계정 환경에서는 예전에 테스트용으로 열어둔 권한이 남아 있는 경우가 종종 있습니다. 저도 한 번 이거 때문에 한참 뒤졌습니다 ㅎㅎ

    4. Function URL 또는 API 엔드포인트 인증을 반드시 확인하세요

    Lambda Function URL을 쓰는 경우, AuthType 설정을 대충 넘기면 안 됩니다. 공개 엔드포인트가 필요한 상황이 아니라면 IAM 기반 인증이나 API Gateway의 인증 체계를 붙이는 쪽이 안전합니다.

    aws lambda get-function-url-config \
      --function-name my-secure-function

    공개 호출이 필요하다면 WAF(Web Application Firewall, 웹 애플리케이션 방화벽), 인증 토큰, Rate limiting(요청 제한)까지 같이 보셔야 합니다. Lambda 보안 설정에서 의외로 이 부분을 늦게 보는 팀이 많더라고요.

    5. 런타임(Runtime)과 의존성(Dependencies)을 최신 보안 상태로 유지하세요

    서버가 없다고 패치 부담이 완전히 사라지는 건 아닙니다. Lambda 런타임 버전, 배포 패키지 안의 라이브러리, 컨테이너 이미지를 쓰는 경우 베이스 이미지까지 관리 대상입니다. 특히 오래된 Python 패키지나 Node.js 라이브러리에서 취약점이 발견되면 Lambda도 그대로 영향받습니다.

    pip install -r requirements.txt --upgrade
    pip-audit
    npm audit

    중요: 런타임 지원 종료(EOL, End of Life) 일정은 주기적으로 확인하세요. 이건 보안뿐 아니라 배포 지속성에도 영향을 줍니다.

    AWS Lambda 보안 설정과 권한 구조를 보여주는 이미지

    Lambda 보안 설정 화면, IAM 역할, Secrets Manager 연결 흐름을 보여주는 이미지입니다. 어떤 설정이 어디에 있는지 감을 잡기 좋습니다.

    6. CloudWatch Logs와 CloudTrail로 추적 가능성을 확보하세요

    문제가 생겼을 때 “누가 호출했는지”, “어떤 권한으로 실패했는지”, “비정상 호출이 있었는지”를 못 보면 답이 없습니다. 저도 예전에 로그를 대충 남겼다가 원인 분석에 시간을 엄청 썼거든요.

    • CloudWatch Logs: 함수 실행 로그 확인
    • CloudTrail: API 호출 기록 확인
    • Metric Filter + Alarm: 에러 급증, 권한 거부, 비정상 호출 감지
    aws logs describe-log-groups \
      --log-group-name-prefix /aws/lambda/

    함수 로그에는 민감 정보가 찍히지 않도록 조심해야 합니다. 디버깅한다고 이벤트 전체를 그대로 출력하는 습관, 이거 나중에 진짜 위험합니다.

    7. VPC 연결은 필요할 때만, 그리고 보안 그룹(Security Group)을 좁게

    “보안을 위해 일단 VPC에 넣자”라고 생각하기 쉬운데요. 실제로는 모든 Lambda가 VPC에 있어야 하는 건 아닙니다. RDS 같은 프라이빗 리소스 접근이 필요할 때만 넣고, 보안 그룹과 서브넷을 최소화하는 게 핵심입니다.

    여기서 중요한 포인트는 아웃바운드(Egress, 외부로 나가는 통신)도 같이 봐야 한다는 점입니다. 함수가 인터넷으로 나갈 필요가 없다면, 그 경로를 열어둘 이유가 없거든요.

    상황 권장 방식 주의점
    외부 공개 API 호출 기본 네트워크 또는 필요한 경로만 허용 비밀값 유출 로그 주의
    프라이빗 RDS 접근 VPC 연결 + 최소 보안 그룹 불필요한 넓은 CIDR 금지
    내부 서비스 전용 VPC 내부 제한 NAT/엔드포인트 설계 점검

    8. 비동기 호출(Asynchronous Invocation) 실패 처리와 재시도를 설계하세요

    보안 글인데 왜 실패 처리를 넣냐고요? 실제 운영에서는 실패 이벤트가 무한 재시도되거나, Dead Letter Queue(DLQ, 실패 이벤트 보관 큐) 없이 사라지는 게 더 큰 운영 사고로 이어집니다. 보안 사고 탐지 신호도 잃어버릴 수 있고요.

    Resources:
      SecureFunction:
        Type: AWS::Lambda::Function
        Properties:
          FunctionName: secure-function
          Handler: index.handler
          Role: arn:aws:iam::123456789012:role/secure-lambda-role
          Runtime: python3.12
      SecureInvokeConfig:
        Type: AWS::Lambda::EventInvokeConfig
        Properties:
          FunctionName: !Ref SecureFunction
          Qualifier: "$LATEST"
          MaximumRetryAttempts: 2
          MaximumEventAgeInSeconds: 3600

    실패 이벤트를 SQS나 SNS로 보내서 따로 확인하게 해두면 운영 안정성이 확 올라갑니다. 서버리스 보안은 “막는 것”만이 아니라 “문제 발생 시 놓치지 않는 것”도 포함입니다.

    9. 동시성(Concurrency) 제한으로 과다 호출과 비용 폭주를 막으세요

    Reserved Concurrency(예약 동시성)를 적절히 걸어두면 악의적 호출이나 비정상 트래픽 급증 시 피해 범위를 줄일 수 있습니다. 이건 성능 옵션 같지만, 저는 운영 보안 체크리스트에도 꼭 넣습니다.

    aws lambda put-function-concurrency \
      --function-name my-secure-function \
      --reserved-concurrent-executions 20

    드디어 됐다! 싶은 순간이 이런 때입니다. 한 번 제한을 걸어두면 폭주 상황에서도 백엔드 전체가 무너지는 걸 줄일 수 있거든요.

    10. 코드 서명(Code Signing)과 배포 파이프라인 권한을 분리하세요

    마지막으로 놓치기 쉬운 부분이 배포 보안입니다. 함수 실행 권한만 볼 게 아니라, 누가 코드를 배포할 수 있는지, 검증되지 않은 패키지가 올라갈 수 있는지도 봐야 합니다. AWS Lambda는 Code Signing(코드 서명) 기능을 지원하므로, 신뢰된 게시자만 배포되도록 통제할 수 있습니다.

    CI/CD(지속적 통합/배포) 역할과 운영자가 쓰는 수동 권한을 분리하면 실수도 줄고 추적도 쉬워집니다. 실제로 써보니까 운영 계정에서 직접 콘솔 수정하는 습관을 줄이는 것만으로도 보안 수준이 꽤 올라가더라고요.

    실전 구현: 운영 전에 제가 체크하는 순서

    혹시 이런 경험 있으신가요? 함수는 잘 돌았는데 보안 리뷰에서 다 다시 보자는 말 나오는 상황이요. 그래서 저는 아래 순서대로 확인합니다.

    1. IAM Role 확인: 함수별 역할 분리, 액션/리소스 최소화
    2. 비밀값 확인: 환경 변수 평문 여부, Secrets Manager 사용 여부
    3. 호출 경로 확인: API Gateway, Function URL, EventBridge, S3 등 트리거 검토
    4. 로그 확인: CloudWatch 로그 존재, 민감 정보 출력 여부 확인
    5. 재시도/실패 처리 확인: 비동기 호출 정책과 DLQ 여부 확인
    6. 동시성 제한 확인: 비용 폭주와 시스템 영향도 점검
    7. 배포 체계 확인: CI/CD 권한, 코드 서명, 수동 변경 제한 확인
    aws lambda list-functions
    aws lambda get-function-configuration --function-name my-secure-function
    aws iam get-role --role-name secure-lambda-role
    aws lambda get-policy --function-name my-secure-function

    이 정도만 체크해도 Lambda 보안 설정에서 큰 구멍은 상당수 잡힙니다.

    ⚠️ 제가 실제로 많이 본 실수와 트러블슈팅

    • 환경 변수에 토큰 저장: 테스트 때 편해서 넣어뒀다가 운영까지 가는 경우가 많습니다. 해결은 Secrets Manager로 이동하고, 접근 권한을 함수 Role에만 최소로 부여하는 겁니다.
    • CloudWatch 로그에 이벤트 전체 출력: 요청 본문 안에 개인정보나 인증 토큰이 있으면 바로 노출됩니다. 필요한 필드만 마스킹해서 남기세요.
    • IAM 와일드카드 남발: 처음엔 빨리 되지만, 나중엔 뭐가 왜 가능한지 추적이 안 됩니다. 저는 정책 줄이는 작업에서 삽질 좀 했습니다 ㅎㅎ
    • 공개 Function URL 방치: 테스트용 URL이 계속 열려 있는 경우가 있습니다. AuthType과 리소스 정책을 같이 보셔야 합니다.
    • VPC만 넣고 안심: 네트워크에 넣는다고 끝이 아닙니다. 보안 그룹, 엔드포인트, 아웃바운드 경로까지 봐야 진짜 의미가 있습니다.

    근데 여기서 중요한 건, 모든 걸 한 번에 완벽하게 하려다 보면 오히려 놓칩니다. 가장 위험한 것부터 순서대로 줄이는 접근이 현실적이더라고요.

    AWS Lambda 보안 검증을 위한 로그와 알람 대시보드 이미지

    CloudWatch 로그, 에러 지표, 보안 경보를 시각화한 결과 이미지입니다. 검증 단계에서 어떤 항목을 확인해야 하는지 보여줍니다.

    검증: AWS Lambda 보안이 제대로 적용됐는지 확인하는 방법

    설정만 하고 끝내면 안 됩니다. 검증이 있어야 합니다. 제가 보통 보는 확인 포인트는 아래와 같습니다.

    1. 권한 테스트: 허용된 리소스만 접근 가능한지 확인
    2. 비정상 호출 테스트: 권한 없는 주체가 invoke 가능한지 확인
    3. 로그 검토: 민감 정보가 로그에 찍히지 않는지 확인
    4. 실패 이벤트 테스트: 재시도와 실패 보관이 의도대로 동작하는지 확인
    5. 알람 확인: 에러, 스로틀링(Throttling, 요청 제한), 접근 거부가 감지되는지 확인
    aws lambda invoke \
      --function-name my-secure-function \
      response.json
    
    aws cloudtrail lookup-events \
      --lookup-attributes AttributeKey=EventName,AttributeValue=Invoke

    이거 진짜 편하더라고요. 한 번 검증 루틴을 잡아두면 새 함수가 늘어나도 같은 패턴으로 점검할 수 있습니다.

    정리: Lambda 보안 설정은 체크리스트로 운영해야 합니다

    이번 글을 짧게 정리하면 이렇습니다.

    • 최소 권한 IAM이 가장 먼저입니다.
    • 비밀정보는 코드와 환경 변수에서 분리해야 합니다.
    • 호출 경로와 로그를 같이 봐야 합니다.
    • 동시성, 실패 처리, 배포 체계까지 포함해야 운영 보안이 됩니다.

    AWS Lambda 보안은 한 번 설정하고 끝나는 항목이 아니라, 배포할 때마다 반복 점검해야 하는 운영 습관에 가깝습니다. 저도 처음엔 보안 체크리스트가 귀찮았는데, 실제로 사고를 줄여주는 건 이런 반복 작업이더라고요. 다음 글에서는 API Gateway와 Lambda를 함께 쓸 때 인증/인가 구조를 어떻게 나누면 좋은지도 다뤄볼 예정입니다. 이전 글에서 IAM 정책 설계 원칙을 정리해두셨다면 같이 보시면 더 잘 연결될 겁니다.

    AWS Lambda 보안 체크리스트 요약 인포그래픽 이미지

    글 전체 내용을 한눈에 정리한 AWS Lambda 보안 체크리스트 요약 이미지입니다. 운영 전 최종 점검용으로 보기 좋습니다.

    FAQ: 자주 헷갈리는 질문

    Q1. Lambda 환경 변수 암호화만 쓰면 충분한가요?

    간단한 내부 용도라면 도움이 되지만, 운영에선 Secrets Manager 같은 전용 비밀정보 저장소를 쓰는 쪽이 더 낫습니다. 접근 제어와 교체 관리가 훨씬 명확합니다.

    Q2. 모든 Lambda를 VPC 안에 넣어야 하나요?

    아닙니다. 프라이빗 리소스 접근이 필요한 경우에만 검토하세요. 무조건 넣는다고 보안이 자동으로 좋아지는 건 아닙니다.

    Q3. 서버리스 보안에서 가장 먼저 볼 항목 하나만 꼽자면요?

    저는 IAM 최소 권한을 먼저 봅니다. 이유는 사고가 났을 때 피해 범위를 가장 직접적으로 줄여주기 때문입니다.

    Q4. AWS Lambda 베스트 프랙티스는 어디까지가 필수인가요?

    최소 권한, 비밀정보 분리, 로깅, 호출 경로 통제는 사실상 필수라고 보시면 됩니다. 나머지는 워크로드 특성에 따라 깊이를 조절하시면 됩니다.