Post

[AWS-Security] 8.4. 애플리케이션 로그 중앙 집중화

[AWS-Security] 8.4. 애플리케이션 로그 중앙 집중화

1. 분산 환경에서의 로깅 문제점

  1. 로그 파편화 : 트래픽이 많아 여러 대의 EC2 인스턴스가 실행 중일 때, 에러 로그를 찾으려면 모든 인스턴스에 일일이 접속해서 로그 파일을 가져와 결합해야 하는 번거로움이 있다.
  2. 로그 영구 손실 : Auto Scaling을 사용하면 트래픽이 줄어들 때 인스턴스가 자동으로 삭제(Terminated)된다. 이때 서버 내부에 있던 로그 파일도 모두 영구적으로 삭제된다. 이러한 문제를 해결하기 위해 Amazon CloudWatch Logs가 사용된다.

2. CloudWatch Logs 기본 및 구조

CloudWatch로 로그를 보내기 위해 매번 코드로 PutLogEvents API 로그를 호출할 수도 있지만, 이는 매우 비효율적인 방법이다.
대부분의 경우 서버에 ‘CloudWatch 에이전트(Agent)’를 설치하여, 에이전트가 백그라운드에서 주기적으로 로그 파일을 읽어 자동으로 전송하게 한다.

2.1. AWS Lambda

AWS Lambda는 서버리스 환경으로, 사전 구성된 CloudWatch Logs 에이전트가 이미 내장되어 있다.

  • 파이썬의 print("Hello, World!")나 자바의 System.out.println()처럼 표준 출력(stdout)으로 텍스트를 찍기만 하면, 별도의 설정 없이 해당 텍스트가 즉시 CloudWatch Logs로 전송되어 기록된다.

2.2. CloudWatch Logs의 데이터 계층 구조

CloudWatch 콘솔에 접속하면 로그 데이터가 다음과 같은 3단계로 이루어져 있다.

  1. 로그 그룹 (Log Group)
    • 가장 큰 단위의 폴더 역할을 한다.
    • Ex. 특정 Lambda 함수(/aws/lambda/TestLogs) 단위나, 특정 애플리케이션 단위(my_application/apache/access_logs)로 이름을 지정하여 관련된 모든 로그를 모아둔다.
  2. 로그 스트림 (Log Stream)
    • 하나의 로그 그룹 안에는 여러 개의 로그 스트림이 존재한다. 스트림은 동일한 소스(Ex. 특정 EC2 인스턴스 1대)에서 발생한 로그 항목들의 통로이다.
    • 여러 서버가 동시에 수많은 로그를 생성할 때, 특정 스트림만 클릭해서 보면 다른 서버의 로그와 섞이지 않아 스택 추적(Stack trace)이나 에러 흐름을 끊김 없이 분석할 때 유용하다.
  3. 로그 이벤트 (Log Event)
    • 로그 스트림 안에 들어있는 가장 작은 단위의 실제 텍스트 데이터이다.
    • 타임스탬프와 메시지 본문으로 구성된다.
    • Lambda의 경우 사용자가 작성한 Hello, Wolrd! 외에도 시스템이 자동으로 생성하는 START, END, REPORT와 같은 메타데이터 기록이 함께 남는다.

3. CloudWatch 에이전트

Amazon Linux 2 인스턴스에서 Apache 웹 서버를 실행 중이고, 해당 서버의 접근 로그가 /var/log/www/access 경로에 로컬 파일로 쌓이고 있다고 가정한다.
웹 서버의 코드나 설정을 전혀 수정하지 않고 이 로그들을 CloudWatch로 자동 업로드하려면 CloudWatch 에이전트를 설치해야 한다.

3.1. 에이전트 설치

AL2 인스턴스에 접속하여 yum 패키지 관리자를 통해 에이전트를 설치한다.

1
2
# Amazon Linux 2 호스트에 Amazon CloudWatch 에이전트 설치
$ sudo yum install amazon-cloudwatch-agent

3.2. 구성 마법사(Wizard) 실행 및 설정

설치가 완료되면 내장된 마법사를 실행하여 어떤 로그 파일을 수집할지 설정한다. (JSON 형태의 구성 파일)

1
2
# Amazon CloudWatch 에이전트 구성 마법사 실행
$ sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-config-wizard

대부분 기본 옵션을 통해 설정 적용 가능하다. (로그 파일 경로만 정확히 입력)

3.3. 신규 구성 파일 적용

마법사를 통해 생성된 구성 파일(config.json)을 에이전트가 사용하도록 적용한다.

1
2
3
4
5
6
# 신규 구성 파일을 사용하도록 CloudWatch 에이전트 구성
$ sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl \
    -a fetch-config \
    -m ec2 \
    -c file:/opt/aws/amazon-cloudwatch-agent/bin/config.json \
    -s

3.4. 에이전트 시작 및 부팅 시 자동 실행 설정

마지막으로 에이전트 서비스를 시작하고, 서버가 재부팅될 때마다 에이전트도 자동으로 실행되도록 설정한다.

1
2
3
4
5
6
7
# CloudWatch 에이전트 시작 및 부팅 시 실행되도록 구성

# 에이전트를 시작
$ sudo systemctl start amazon-cloudwatch-agent.service

# 부팅 시 에이전트가 자동 시작되도록 활성화
$ sudo systemctl enable amazon-cloudwatch-agent.service

IAM 권한 부여 에이전트가 성공적으로 실행되더라도, EC2 인스턴스 자체가 CloudWatch에 로그를 쓸 수 있는 권한이 없다면 업로드가 불가능하다. (CloudWatchAgentServicePolicy라는 AWS 관리형 정책을 연결해야 한다.)

4. 타사 로그 중앙 집중화 도구

CloudWatch 외에도 로깅을 중앙 집중화하는 훌륭한 툴이 많지만, 동작 원리는 대부분 유사하다.

  • Splunk Universal Forwarder / Datadog Agent : CloudWatch 에이전트와 매우 유사하다. 각 서버에 호스트 수준의 에이전트를 설치하고 구성하면 중앙 서버에 로그를 업로드 한다.
  • Prometheus : 단일 호스트 수준의 에이전트 대신, 애플리케이션 별 내보내기를 사용한다. (ex. Apache 서버 로그를 내보내려면 Prometheus용 Apache Exporter를 별도로 사용한다.)

5. 고급 CloudWatch Logs 기능

5.1. CloudWatch Logs Insights (데이터 쿼리 및 시각화)

단순 텍스트 검색을 넘어, 특정 조건의 로그를 집계하고 시각화(그래프)하여 트래픽 패턴이나 성능 병목을 파악할 때 사용하는 기능이다. 전용 쿼리 언어를 사용한다.
Lambda 함수가 남긴 로그 중 실행 시간(duration)에 대한 평균, 최대, 최소값을 5분 간격으로 보고 싶을 때 아래의 쿼리를 작성한다.

1
2
3
4
# Lambda 함수 실행 시간을 구성하는 CloudWatch Logs Insight 쿼리

filter @type = "REPORT" |
stats avg(@duration), max(@duration), min(@duration) by bin(5m)
  • 동작 방식 : 파이프(|)로 명령을 연결한다.먼저 REPORT라는 텍스트가 포함된 로그만 걸러낸(filter) 뒤, 5분 단위(bin(5m))로 실행 시간의 통계를 계산한다.
  • 결과 : 텍스트 결과 뿐만 아니라 직관적인 꺽은선 그래프가 함께 표시되어 성능 변화를 한눈에 파악할 수 있다.

5.2. 로그 구독 (OpenSearch를 활용한 초고속 검색)

  • CloudWatch 자체 검색 기능은 수백만 개의 로그 항목을 확인할 때 10분 이상이 걸릴 정도로 느려질 수 있다.
  • 지속적이고 방대한 검색이 필요하다면 Amazon OpenSearch라는 전용 검색 엔진을 연동해야 한다.
  • 애플리케이션 코드를 고칠 필요 없이, CloudWatch의 로그 구독(Subscription) 기능을 켜면 로그가 OpenSearch로 실시간 스트리밍된다.
    1. 클러스터 생성 : 로그를 받아줄 OpenSearch 클러스터를 생성한다.
      1
      2
      3
      4
      5
      
        # AWS 관리형 OpenSearch 도메인 생성 명령어
        $ aws es create-elasticsearch-domain \
         --domain-name my-logs-cluster \
         --elasticsearch-version 6.2 \
         ... (기타 용량 및 IAM 접근 정책 설정)
      
    2. 구독 필터 생성 : CloudWatch 로그 그룹 콘솔에서 Create Elasticsearch subscription filter를 선택한다.
    3. 포맷 및 패턴 정의 : 대상 OpenSearch 클러스터를 지정한 뒤, 로그의 형식과 필터 패턴을 정의한다.
    4. 테스트 및 스트리밍 : 설정한 패턴이 맞는지 샘플 로그로 테스트(Test pattern)한 뒤, 스트리밍을 시작한다.

5.3. Amazon S3로 로그 내보내기 (Export)

  • 사용 목적 : AWS 계정에 접근 권한이 없는 외부 감사팀과 로그 파일을 공유하거나, 저럼한 비용으로 장기보관하거나, 타사 분석 도구에 데이터를 전송할 때 사용한다. (CloudWatch 밖으로 전송할 때)
  • 방법 : CloudWatch 콘솔의 Action 메뉴에서 Export data to Amazon S3를 클릭한다. 이후 추출할 시간 범위(From/To)오 대상 S3 버킷을 지정하기만 하면 백그라운드에서 로그 파일 추출 및 업로드가 진행된다.

6. 네트워크 트래픽 기록 (VPC Flow Logs)

관리 이벤트(CloudTrail)을 기록하는 것만큼이나 네트워크 트래픽을 기록하는 것도 매우 중요한 감사(Audit) 도구다.
네트워크 기반 공격(DoS 공격, 무차별 대입 공격 등)은 트래픽 로그를 통해 가장 직관적으로 조사할 수 있다.

  • VPC Flow Logs의 특징 : CloudTrail과 달리, VPC Flow Logs 자체에는 수집된 로그를 검색하고 시각적으로 볼 수 있는 내장 화면(UI) 기능이 없다. 따라서 로그를 활용하려면 반드시 대상 목적지를 Amazon S3 또는 CloudWatch Logs로 지정하여 전송해야만 한다.

6.1. CloudWatch Insights를 활용한 위협 탐지

  • VPC Flow Logs를 CloudWatch Logs로 보내도록 구성했다면, CloudWatch Insights를 활용하여 수백만 건의 트래픽 데이터에서 유의미한 정보를 빠르게 뽑아낼 수 있다.
  • Insights는 VPC Flow Logs 분석을 위해 자주 쓰이는 사전 정의된 쿼리들을 기본적으로 제공한다.

6.2. 시나리오: 데이터 유출 및 DoS 공격자 식별

  • 만약 공격자가 데이터베이스에서 대량의 데이터를 외부로 빼돌리거나(데이터 유출), 엄청난 양의 패킷을 보내 서버를 마비(DoS)시키고 있다면 네트워크 대역폭 사용량이 급증할 것이다.
  • 이때 가장 많은 데이터를 주고받은 IP 주소를 찾아내면 공격자를 특정할 수 있다. ```plaintext

    전송 및 수신 IP 쌍을 강조 표시하는 CloudWatch Insights 쿼리

stats sum(bytes) as bytesTransferred by srcAddr, dstAddr | sort bytesTransferred desc | limit 5 ```

  • state sum(bytes) as bytesTransferred : 전송된 전체 바이트(bytes)의 총합을 구하고, 그 결과 열의 이름을 bytesTransferred로 지정한다.
  • by srcAddr, dstAddr : 통신이 이루어진 출발지 IP(srcAddr)와 목적지 IP(dstAddr) 쌍을 기준으로 데이터를 그룹화한다.
  • | sort bytesTransferred desc : 데이터 전송량이 가장 많은 것부터 내림차순(desc)으로 정렬한다.
  • | limit 5 : 전체 결과 중 최상위 5개의 기록만 화면에 출력한다.

위 쿼리를 실행하면, 1~5위까지 가장 트래픽을 많이 발생시킨 IP 쌍이 도출된다. 보안 관리자는 이 목록을 보고 전혀 알 수 없는 외부 IP가 막대한 양의 데이터를 가져갔다면, 즉시 해당 IP를 방화벽에서 차단하는 조치를 취할 수 있다.

This post is licensed under CC BY 4.0 by the author.