Project Diary/Cloudtrail-guard

[Cloudtrail-guard] 02. 전체 아키텍처를 구성하며 고민했던 점

seobangwool 2026. 6. 9. 16:32

어떤 클라우드를 로그 분석 대상으로 삼을지 정해졌으니, 해당 클라우드 서비스를 통해 API 시퀀스를 처리하는 전체 아키텍처를 잡아두어야 했다.

CloudTrail 로그를 수집하고 분석하는 기능 자체는 어렵지 않게 설명할 수 있지만, 실제로 프로젝트 구조를 잡는 과정에서는 여러 고민이 있었다. 로그를 어디까지 저장할 것인지, Lambda 내부에서 어떤 로직을 처리할 것인지, 단일 이벤트 중심으로 볼 것인지 API 호출 흐름 중심으로 볼 것인지, 탐지 결과를 어떤 방식으로 남길 것인지 등을 고민하게 되었다.

이번 글에서는 현재 구상한 전체 아키텍처를 간단히 소개하고, 그 과정에서 고민했던 지점들을 중심으로 정리해보려고 한다.

전체 아키텍처 소개

현재까지 구상한 전체 아키텍처는 크게 세 단계로 나눌 수 있다.

  1. 로그 수집 단계
  2. 로그 처리 및 분석 단계
  3. 결과 저장 및 시각화 단계

로그 수집 단계에서는 AWS CloudTrail에서 발생한 이벤트 로그를 S3에 저장한다. 이후 로그 처리 및 분석 단계에서는 S3에 저장된 CloudTrail 로그를 Lambda가 읽어와 파싱하고, API 호출 시퀀스를 특정 기준으로 나눈 뒤 위협 유형을 매핑한다. 마지막으로 결과 저장 및 시각화 단계에서는 분석 결과를 별도의 저장소에 저장하고, 이후 Dashboard를 통해 탐지 결과를 확인할 수 있도록 구성한다.

조금 더 상세한 설명으로는, AWS CloudTrail에서 발생한 이벤트 로그는 S3에 저장된다. 이후 S3에 저장된 CloudTrail 로그를 Lambda가 읽어와 파싱하고, API 호출 시퀀스를 특정 기준으로 나눈 뒤 위협 유형을 매핑한다.

이때 각 API 이벤트와 위협 유형에는 기본 위험 점수를 부여하여 1차적으로 정량적인 위험도를 계산한다. 예를 들어 권한 변경, Access Key 생성, 로그 비활성화, 대량 조회와 같은 행위는 각각의 위험도에 따라 점수화할 수 있다. 이를 통해 어떤 이벤트나 시퀀스가 상대적으로 더 위험한지 대략적인 비교가 가능할 것이다.

다만 위험 점수만으로는 해당 행위가 실제 공격 흐름인지, 정상적인 운영 행위인지 판단하기 어려운 경우가 있다. 같은 API 호출이라도 호출 주체, source IP, 발생 시간, 이전에 수행된 API 흐름에 따라 의미가 달라질 수 있기 때문이다. 예를 들어 IAM 정책 변경이라는 행위 자체는 위험도가 높은 이벤트일 수 있지만, 정상 관리자가 업무 중 수행한 작업인지, 낯선 IP에서 악의적인 목적으로 수행된 권한 상승 시도인지는 추가적인 맥락을 함께 봐야 한다.

따라서 이 프로젝트에서는 위험 점수, API 호출 시퀀스, 위협 유형, 호출 주체, source IP, 시간 흐름 등의 정보를 AI 모델에 함께 입력하여 최종 위험 판단을 보완하는 구조를 고려하고 있다. 여기서 AI 모델은 위험 점수를 대체하는 것이 아니라, 점수 기반 판단에 맥락 해석과 설명 가능성을 더하는 최종 판단 보조 계층으로 사용된다.

 

AI 판단의 범위를 어디까지 지정할 것인가

전체 아키텍처를 구상하면서 가장 많이 고민했던 부분은 AI 모델을 어디까지 사용할 것인지였다.

처음에는 API 호출 시퀀스를 분리하는 과정부터 위험 점수 계산, 최종 위험 판단까지 AI 모델을 활용하는 구조도 생각했다. 하나의 모델이 아닌, 3개의 AI 모델을 별개로 학습시켜 순차적으로 적용시키는 것이다. CloudTrail 로그에는 다양한 필드가 포함되어 있고, API 호출 흐름도 상황에 따라 의미가 달라지기 때문에, AI 모델을 활용하면 복잡한 맥락을 더 유연하고 효율적으로 해석할 수 있을 것이라고 생각했기 때문이다.

예를 들어 AI 모델이 연속된 로그를 통으로 받은 뒤, 하나의 공격 흐름으로 볼 수 있는 구간을 판단하게 하는 것이다. 이후에는 다른 AI 모델이 특정 시퀀스가 정찰 행위인지, 권한 상승 시도인지, 데이터 접근 흐름인지 직접 분류하도록 구성하는 방식이다.

하지만 모든 과정을 AI 모델에 맡기는 방식에는 확실한 한계가 있다고 판단했다.

첫 번째는 비용 문제이다. CloudTrail 로그는 이벤트 단위로 지속적으로 쌓이는 데이터이기 때문에, 모든 로그나 모든 API 호출 시퀀스를 AI 모델 추론에 넣으면 호출 비용이 커질 수 있다. 특히 프로젝트가 단순 데모 수준을 넘어 로그 양이 늘어나는 구조를 고려한다면, AI 모델을 무분별하게 사용하는 것은 비용 측면에서 너무 큰 부담이 된다.

두 번째는 설명 가능성 문제이다. 위험 점수나 위협 유형 매핑을 모두 AI 모델에 맡기면, 왜 특정 이벤트가 위험하다고 판단되었는지 명확하게 설명하기 어려워질 수 있다. 보안 탐지에서는 위험하다는 결과도 물론 중요하지만, 어떤 API가 어떤 기준에 의해 위험하다고 판단되었는지 설명하는 것이 더 중요하다. 따라서 기본적인 위험 판단 기준은 규칙과 점수 기반으로 명확하게 남기는 것이 필요하다고 생각했다.

세 번째는 일관성 문제이다. 같은 유형의 API 호출에 대해 매번 다른 판단이 나오면 탐지 시스템으로 사용하기 어렵다. 명확하게 위험도가 높은 행위는 AI 모델의 해석에 의존하는 것 보다는 사전에 정의한 기준에 따라 점수를 부여하는 것이 더 안정적일 것이라고 판단했다.

이러한 이유로 현재는 규칙 기반 분석과 AI 모델의 역할을 분리하는 방향을 고려하고 있다. AI가 판단을 할 때 까지 어떤 단계를 거치는지 간략하게 적어보자면 다음과 같다. 

우선 API 시퀀스 분리를 특정 규칙을 통해 1차적으로 처리한다. 위협 유형 매핑과 위험 점수 계산도 사전에 정의한 기준에 따라 먼저 수행한다. (이 규칙 설정에 대한 고민은 다음 챕터에서 다룰 예정)
이를 통해 기본적인 탐지 기준을 명확하게 유지하고, 비용이 많이 드는 AI 추론을 모든 이벤트에 적용하지 않도록 한다.

이후 AI 모델은 위험 점수, API 호출 시퀀스, 위협 유형, 호출 주체, source IP, 시간 흐름 등의 정보를 입력받아 최종 판단을 보완하는 역할로 사용한다. 즉, AI 모델은 위험 점수를 대체하거나 시퀀스 분리 전체를 담당하는 것이 아니라, 점수 기반 판단만으로 부족한 맥락 해석과 설명 가능성을 더하는 보조 판단 계층으로 활용한다.

 

Lambda 내부에 모든 분석 로직을 넣어도 되는가

다음으로 고민했던 부분은 Lambda 내부에 어느 정도의 로직을 넣을 것인지였다.

현재 아키텍처에서는 Lambda 내부에 CloudTrail Log Parser, API Sequence Builder, Threat Category Mapper, Risk Score Calculator, AI Model Inference를 배치하였다. 구조상으로는 S3에 저장된 CloudTrail 로그를 Lambda가 읽고, 분석한 뒤, 최종 결과를 생성하는 흐름이다.

이 방식의 장점은 구조가 단순하다는 점이다. 별도의 서버를 직접 운영하지 않아도 되고, CloudTrail 로그가 S3에 저장되는 시점에 Lambda를 트리거하면 자동으로 분석을 수행할 수 있다. 프로젝트 초기 단계에서 구현 범위가 명확하고, 전체 흐름을 데모로 보여주기에도 적합하다고 판단했다.

하지만 가장 큰 문제점은 유지보수가 어려워진다는 점이다. Lambda 하나에 너무 많은 로직이 들어가 있다 ...
로그 파싱, 시퀀스 생성, 위협 유형 매핑, 위험 점수 계산, AI 모델 추론은 각각 성격이 다른 작업이다. 이러한 것들을 하나의 함수 내부에 단순히 작성하면 코드가 복잡해지고, 이후 테스트나 유지보수가 어려워질 것이다.

또한 CloudTrail 로그의 양이 많아질 경우 Lambda 실행 시간, 메모리 사용량, 재시도 처리, 중복 이벤트 처리 문제도 고려해야 한다. 특히 AI 모델 추론까지 Lambda 내부에서 직접 수행한다면 실행 시간이 길어질 수 있고, 비용이나 성능 측면에서도 부담이 생길 수 있다.

따라서 현재의 구조가 완벽하다고 볼 수가 없다. Lambda 중심 구조는 로그 양이 증가하거나 분석 로직이 복잡해질수록 실행 시간, 비용, 유지보수 측면에서 한계가 생길 수 있다. 특히 AI 모델 추론까지 포함되기 때문에 Lambda가 단순 처리 계층을 넘어 과도한 책임을 가지게 될 수도 있다.

그럼에도 이러한 구조를 채택한 이유가 있다. 현재 단계에서 구조의 확장성보다는 전체 탐지 흐름을 명확하게 검증하는 것이 더 중요하다. 아직 프로젝트 초기 단계이기 때문에, 처음부터 복잡한 분산 구조를 설계하는 것은 오히려 독이 될 수 있다는 것을 뼈저리게 느껴왔다. 따라서, CloudTrail 로그가 수집되고, 파싱되고, 시퀀스로 구성되며, 위험 점수와 AI 판단을 거쳐 결과로 남는 전체 흐름을 끝까지 구현해보는 것이 우선이라고 생각한다.

현재 구조의 단점은 인지하고 있는 상태에서, 구현의 복잡도를 줄이고 초기 검증 가능성을 높이는 것에 더 높은 가치를 두고 있다. 이후 로그 규모가 커지거나 분석 로직이 복잡해질 경우에 Lambda 내부 로직을 단계별로 분리하거나, AI 추론 계층을 별도 서비스로 분리하는 방식으로 확장할 수 있을 것이다.

 

탐지 결과를 어떤 형태로 저장할 것인가

마지막으로 고민했던 부분은 탐지 결과를 어떤 형태로 저장할 것인지였다.

CloudTrail 원본 로그를 S3에 저장하는 것만으로는 탐지 시스템으로서의 의미가 부족하다. 원본 로그는 이후 분석의 근거가 되는 데이터이지만, 사용자가 바로 이해하기에는 정보가 너무 많고 복잡하다. 따라서 Lambda가 분석한 결과를 Dashboard에서 바로 활용할 수 있는 형태로 정리해서 저장할 필요가 있다고 판단했다.

처음에는 탐지 결과를 단순히 위험 점수와 위협 유형 정도만 저장하는 방식도 생각했다. 예를 들어 특정 API 시퀀스에 대해 High Risk, Privilege Escalation, Risk Score: 95와 같은 결과만 남기는 방식이다. 이 방식은 구조가 단순하지만, 실제 Dashboard에서 탐지 결과를 보여주기에는 정보가 부족하다고 느꼈다.

탐지 결과는 왜 위험하다고 판단했는지까지 함께 저장되어야 한다. Dashboard에서 전체 위험 점수, 위험 점수 추이, 주요 이상 행위, 이벤트 수, Alert 수, Principal 수, Source IP 수 등을 보여주려면 분석 결과가 구조화된 데이터 형태로 저장되어야 한다.

특히 Top Anomalies 영역을 구성하려면 탐지된 주체, 위험 API, 위험 점수, 탐지 사유가 필요하다. 예를 들어 backup-role에서 StopLogging이 발생했기 때문에 위험하다고 판단했다면, 어떤 주체가 어떤 API를 호출했고, 이 API가 어떤 위협 유형에 해당하며, 왜 높은 위험 점수를 받았는지 함께 남겨야 한다.

또한 Event Volume처럼 시간대별 이벤트 수를 보여주기 위해서는 각 이벤트의 발생 시간과 집계 가능한 형태의 데이터가 필요하다. Detection Center에서는 개별 Alert를 확인해야 하고, User Timeline에서는 특정 사용자의 API 호출 흐름을 시간 순서대로 보여줘야 한다. Attack Reconstruction에서는 여러 API 호출이 어떤 공격 흐름으로 이어졌는지 재구성할 수 있어야 한다.

이런 기능들을 고려하면 탐지 결과에는 최소한 다음과 같은 정보가 포함되어야 한다고 생각했다.

  1. 탐지 ID 또는 Alert ID
  2. 호출 주체
  3. source IP
  4. 발생 시간
  5. 탐지된 API 이벤트 목록
  6. API 호출 시퀀스
  7. 매핑된 위협 유형
  8. 위험 점수
  9. AI 모델의 최종 판단 결과
  10. 위험하다고 판단한 근거
  11. 원본 CloudTrail 로그와 연결할 수 있는 식별 정보

이렇게 저장하면 Dashboard는 원본 CloudTrail 로그를 다시 분석하지 않아도 된다. 이미 분석이 끝난 결과를 읽어와 전체 위험 점수를 계산하고, 위험도 추이를 그리며, Top Anomalies와 Alert 목록을 구성할 수 있다. 또한 특정 사용자를 선택했을 때 Timeline을 보여주거나, 특정 Alert를 기준으로 공격 흐름을 재구성하는 것도 가능해진다.

결국 탐지 결과 저장소는 단순히 Lambda의 출력값을 임시로 보관하는 공간이 아니다. Dashboard가 탐지 결과를 해석하고 시각화하기 위한 기준 데이터이며, 이후 탐지 로직을 검증하고 개선하기 위한 기록이기도 하다.

따라서 원본 CloudTrail 로그와 탐지 결과는 분리해서 저장하는 것이 적절하다고 판단했다. 원본 로그는 변경되지 않는 근거 데이터로 남기고, 탐지 결과는 위험 판단, 점수, 시퀀스, 판단 근거를 포함한 분석 데이터로 저장하는 방식이 현재 아키텍처에 더 적합하다고 생각했다.

 

데모페이지 예시 일부

 

마무리하며

이번 아키텍처 설계 과정에서는 CloudTrail 로그를 어떤 관점에서 분석할 것인지에 대한 고민이 더 컸다.

처음에는 CloudTrail 로그를 수집하고 분석하는 구조만 잡으면 된다고 생각했지만, 실제로는 API 시퀀스를 어떤 기준으로 나눌 것인지, AI 모델을 어디까지 사용할 것인지, Lambda 내부에 어느 정도의 책임을 둘 것인지, 탐지 결과를 어떤 형태로 저장할 것인지까지 함께 고려해야 했다.

현재 구조는 완성된 최종 구조라기보다는, 프로젝트 초기 단계에서 전체 흐름의 틀을 잡는 설계도에 가깝다. 진행하면서 부족한 부분이 있거나 개선할 점이 있다면 수정이 많이 일어날지도 모른다. 그럼에도 이번 설계를 통해 CloudTrail Guard가 위험 행위를 해석하고 탐지하고 결과를 설명하는 구조를 더 명확하게 할 수 있었다.

앞으로는 실제 샘플 데이터를 만져가며 API 시퀀스 분리 기준과 위험 점수 산정 방식 등을 구체화해볼 예정이다.