AWS 기술 블로그

Amazon Network Firewall 모범 사례 #4 – 로그 수집 및 분석

1. 시작하며

이 게시물은 AWS Network Firewall(이하 “ANF”) 모범 사례 시리즈의 네 번째 게시물로 ANF의 기능 중 하나인 로그 설정 방안과 특징 및 활용 사례에 대해 알아보도록 하겠습니다.

보안에서 로그는 각종 시스템에서 처리되는 정보와 해당 정보에 대한 처리 메커니즘 등을 이해하고 문제를 해결하거나 내외부에서 발생하는 위협을 탐지하거나 차단하는 데 중요한 정보를 제공합니다. ANF 환경에서 역시 이와 같은 로그의 역할은 보안 관리자 입장에서 아주 중요하다고 볼 수 있습니다. 보안 관리자는 필요에 따라 ANF 로그를 활성화할 수 있으며, 네트워크 트래픽에 대한 모니터링, 외부로부터의 침입 감지와 추적, 시스템 이슈 발생 시의 장애 대처, 법규 및 지침의 감사 대비 자료로 사용할 수 있는 중요한 정보를 제공합니다.

참고 1. ANF의 로그는 ANF 내부적으로 사용하는 Suricata 엔진의 “thread-module”을 통해 제공되며 Stateful 엔진 내에서 플로우 로그(“Flow log”)와 얼럿 로그(“Alert log”)라는 두 가지 로그 타입에 대해서 제공합니다. (TLS 로그 관련 내용은 이 게시물에서 다루지 않습니다.)

참고 2. ANF의 Alert log는 방화벽을 통하는 트래픽이 Pass/Drop/Reject/Alert 액션 규칙에 매칭되는 경우 로그를 남기게 됩니다. 특히, Pass 액션의 경우 2025년 3월 27일에 로그 기능이 추가되었습니다.

2. ANF Log 관리

ANF를 운영하는 환경에서 잘못된 방화벽 규칙을 찾아내거나 방화벽 운영 과정에서 발생하는 다양한 문제를 해결하기 위해서는 로그 수집이 필수입니다. 수집된 로그는 다양한 저장소에 저장이 가능하며 Amazon AthenaAmazon Opensearch Service와 같은 다양한 분석 도구를 이용하여 분석을 수행할 수 있습니다. 또한, 필요한 경우 Amazon S3 와 같은 저장소에 로그 파일을 저장하여 규정 준수를 위해 일정 기간 저렴한 비용으로 로그를 보관하고 백업하는 것 역시 가능합니다.

2.1 로깅 활성화

ANF에서 처리하는 로그를 기록하기 위해서는 관리자에 의한 설정이 필요합니다. 관리자는 Alert Log, Flow Log 및 TLS 로그에 대해 아래의 3가지 목적지 중 하나를 선택하여 로그를 저장할 수 있습니다.

  • Amazon S3
  • Cloudwatch log Group
  • Kinesis Data Firehose

위 3가지 로그의 대상에는 delivery.logs.amazonaws.com의 권한이 필요하며 ANF 콘솔을 통해 설정할 경우 권한은 자동으로 설정되나 Cloudformation을 통해서 로그 설정을 진행할 경우 설정에 유의해 주셔야 합니다. ANF 의 로그 설정에 관한 더 자세한 사항은 링크를 참고하시기를 바랍니다.

그림. ANF 의 로깅 설정

참고로 ANF 로그 설정 시 저장 시 암호화 옵션을 사용하고자 하는 경우 아래의 내용에 유의하시기를 바랍니다.

  • 로그 대상이 KMS 암호화를 사용하는 경우 “고객이 관리하는 KMS 키”가 필요합니다.
  • 키 정책에는 delivery.logs.amazonaws.com 서비스에 필요한 권한이 포함되어야 합니다.
  • ANF는 “AWS에서 관리하는 AWS KMS 키”를 이용한 암호화를 지원하지 않습니다.
  • S3의 경우 ANF에서 다음 두 가지 키 유형을 지원합니다.
    1. Amazon S3 키 (SSE-S3)
    2. AWS 키 관리 서비스 (SSE-KMS)

로깅 설정 시 유의 사항

ANF의 로그를 설정할 때는 몇 가지 유의해야 하는 사항들이 있습니다. 각 로그 대상별로 아래와 같은 유의 사항을 참고하시기를 바랍니다.

S3 버킷에 저장하는 경우 Flow log/Alert log를 구분하기 위해 Prefix를 별도로 설정해 주시기를 권고드리며 로그 적재까지 8-12분이 소요됩니다.

  • Cloudwatch log group은 DescribeLogGroups API의 제한으로 50개의 목록만 표시됩니다.
  • 로그그룹이 이를 초과할 경우 표시가 되지 않아 수기로 입력을 해 줘야 하며 로그 적재까지 3~6분 정도의 시간이 소요됩니다.
  • Kinesis Data Firehose의 경우 목적지에 대해 Direct PUT 설정이 필요하며 LogDeliveryEnabled tag 설정이 True로 설정되어야 합니다.
    또한 별도의 AWSServiceRoleForLogDelivery IAM Role이 필요하며 로그 적재까지 8-12분의 시간이 소요됩니다.
  • ANF의 로그 설정에 대한 더 자세한 사항은 링크를 참고하시기를 바랍니다.

주의할 점은 로그를 설정 뒤 로그 목적지의 변경이 필요한 경우 로그를 비활성화해 주신 뒤 재활성화를 해주셔야 합니다. 로그가 설정된 상태로 로그 설정을 변경하려 할 경우 “Given logging configuration changes a destination type for a log type”에러가 발생하게 되며 로그가 활성화되어 있는 경우 방화벽을 삭제할 수 없기 때문에 로그를 비활성화 해 주셔야 합니다.

그림. 로그 설정 변경 시 에러 화면

2.2 로그 정보 알아보기

ANF의 로그는 이전에 언급한 바와 같이 “Alert Log”, “Flow Log”, “TLS Log” 를 제공하며 각 로그에는 트래픽에 대한 여러 가지 정보를 담고 있으며 로그별로 몇 가지 특징을 가지고 있습니다. 이 단계에서는 “Alert Log” 와 “Flow Log” 의 각 필드가 무엇을 의미하는지를 살펴본 후 각 필드에서 제공되는 정보를 적절하게 사용하는 방법에 대해 알아보겠습니다. (본 게시물은 ANF 모범 사례인 Strict Order Policy를 사용하는 환경을 기반으로 작성되었습니다.)

1. Flow log / Alert log를 통해 트래픽 정보 알아보기

ANF의 Stateful 엔진에서 로깅 대상 액션에 매칭되는 트래픽이 방화벽 엔드포인트를 통과할 때, 기본적으로 3개의 로그 엔트리(“2개의 Flow log”와 “1개의 Alert log”)가 생성됩니다.

로그 확인을 위해 아래와 같이 Suricata 규칙을 작성한 후 해당 규칙에 매칭되는 트래픽을 curl 커맨드를 이용하여 발생한 후 ANF가 어떤 정보를 로그에 기록하는지 살펴보도록 하겠습니다. 아래는 Suricata 규칙입니다.

alert tcp any any -> any any (flow:to_server,established; msg: "ALERT ANY TCP rule"; sid: 100; rev:1;)

아래는 실행 명령어입니다.

curl -I aws.amazon.com

A. Alert log

Alert log는 Stateful 규칙의 매칭에 대한 정보를 갖고 있는 로그입니다. 규칙의 액션에 의해 남게 되는 로그이며 Suricata eve output의 alert의 형식으로 출력됩니다. 또한, 애플리케이션 계층 기록(HTTP, DNS 등)과 같은 메타데이터를 포함할 수 있으며 매칭된 규칙 내의 키워드에 따른 요소들도 포함될 수 있습니다.

참고로, Alert 액션을 사용하는 규칙에 매칭되면 “action:allowed”를 포함하는 Alert 로그 이벤트가 생성되지만 여기서 ‘allowed‘가 반드시 ‘pass‘를 의미하지는 않습니다. Suricata 7.x 버전부터는 Alert 로그에 verdict > action 필드가 포함되어, 최종 판정(pass, drop, reject)을 확인할 수 있습니다. 이 정보를 통해 규칙 매칭 후 패킷에 대한 최종 처리 결과를 정확히 파악할 수 있으며, 특히 여러 규칙이 중첩되어 적용되는 복잡한 환경에서 트래픽 처리 로직을 이해하는 데 유용합니다. 예를 들어, “action:allowed” 이지만 “verdict”가 “drop”인 경우, 해당 패킷이 후속 규칙에 의해 최종적으로 차단되었음을 알 수 있습니다.

{
    "firewall_name": "FW", 
    "availability_zone": "ap-northeast-2a",
    "event_timestamp": "1743531815", 
    "event": {
        "tx_guessed": true,
        "tx_id": 0,
        "app_proto": "http",
        "src_ip": "10.0.4.152",
        "src_port": 58184,
        "event_type": "alert",
        "alert": {
            "severity": 3,
            "signature_id": 100,
            "rev": 1,
            "signature": "ALERT ANY TCP rule",
            "action": "allowed", 
            "category": ""
        },
        "flow_id": 2209900150171410, 
        "dest_ip": "54.230.176.25",
        "proto": "TCP",
        "verdict": {
            "action": "pass"
        },
        "http": {
            "hostname": "aws.amazon.com",
            "url": "/",
            "http_user_agent": "curl/8.3.0",
            "http_method": "HEAD",
            "protocol": "HTTP/1.1",
            "length": 0
        },
        "dest_port": 80,
        "pkt_src": "geneve encapsulation",
        "timestamp": "2025-04-01T18:23:35.061737+0000",
        "direction": "to_server"  
    }
}
- firewall_name : 방화벽 리소스의 이름입니다.
- availability_zone :  방화벽 엔드포인트의 위치를 의미합니다.
- event_timestamp : (UNIX Timestamp)이벤트가 기록된 시간입니다.
- event : 트래픽 이벤트에 대한 정보가 포함되어 있습니다.
- flow_id : 트래픽 식별을 위한 flow_id이며 이는 flow log와 동일하게 매칭됩니다.
- verdict : 트래픽의 최종 action이 어떻게 종료되었는지 표기합니다.
- direction : 클라이언트(내부)에서 서버(외부) 방향으로 발생된 트래픽입니다.

예시. ANF 의 Alert 로그

참고. Suricata는 로그 이벤트에 포함될 고유한 flow_id를 각 플로우에 할당하여 적재하게 됩니다. 해당 flow_id는 Flow/Alert 로그 모두 동일하게 남게 되며, 이를 통해 관리자는 Alert Log와 관련된 Flow Log를 분석하여 특정 트래픽에 대한 트래픽 패턴을 파악할 수 있습니다.

ANF의 Alert 로그는 설정된 키워드에 따라 다양한 필드를 포함할 수 있으며 Alert 로그의 주요 시그니처 관련 필드는 다음과 같은 특징을 가집니다:

  • signature‘ 필드: 규칙에 정의된 ‘msg‘ 키워드의 값이 출력되며 규칙에 ‘msg‘ 키워드가 없는 경우 필드가 비어있게 됩니다.
  • signature_id‘ 필드: 규칙의 ‘sid‘ 값이 표시되며, 개별 규칙을 식별하는 고유 식별자로 사용됩니다.
  • rev‘ 필드: 시그니처의 버전을 나타내며, 일반적으로 ‘sid‘ 키워드와 함께 사용됩니다. 시그니처가 수정될 때마다 이 값을 변경하며, 규칙의 변경 이력을 추적하는 데 활용됩니다.
  • metadata‘ 필드: 시그니처에 추가적인 비기능적 정보를 포함할 수 있게 해주며, [키, 값] 쌍 형태로 사용하는 것을 권장합니다. 단일 값 설정(metadata: key value;) 또는 콤마로 구분된 여러 값(metadata: key value, key value;) 지정이 가능합니다.

예를 들어서, 다음과 같이 suricata 규칙을 통해 msg 항목에 alert_ip_test2를, sid 항목에 3 키워드를 넣었다면, 다음과 같이 로그가 출력됩니다.

alert ip any any -> any any (msg:"alert_ip_test2"; flow:to_client,established; sid:3; rev:1;metadata: key value, key value;)

{
    "firewall_name": "FW",
    "availability_zone": "ap-northeast-2a",
    "event_timestamp": "1743538152",
    "event": {
        "tx_guessed": true,
        "tx_id": 0,
        "app_proto": "http",
        "src_ip": "54.230.176.45",
        "src_port": 80,
        "event_type": "alert",
        "alert": {
            "severity": 3,
            "signature_id": 3,
            "rev": 1,
            "metadata": {
                "key": [
                    "value",
                    "value"
                ]
            },
            "signature": "alert_ip_test2",
            "action": "allowed",
            "category": ""
        },
        "flow_id": 2008547096036831,
        "dest_ip": "10.0.4.152",
        "proto": "TCP",
        "verdict": {
            "action": "alert"
        },
        "http": {
            "hostname": "aws.amazon.com",
            "url": "/",
            "http_user_agent": "curl/8.3.0",
            "http_method": "HEAD",
            "protocol": "HTTP/1.1",
            "length": 0
        },
        "dest_port": 60288,
        "pkt_src": "geneve encapsulation",
        "timestamp": "2025-04-01T20:09:12.502081+0000",
        "direction": "to_client"
    }
}

예시. ANF 의 Alert 로그

ANF는 Suricata와 호환되므로, 더 자세한 키워드 정보는 Suricata 공식 문서를 참조하시기 바랍니다.

B. Flow log

Flow log는 방화벽 엔드포인트를 통해 유입되는 In/Out 트래픽에 대해 발생하기 때문에 In/Out에 대한 로그가 각각 발생하게 됩니다. 또한 Netflow의 형식으로 출력되며 트래픽의 흐름 동안 관찰된 TCP 플래그 목록을 포함합니다. 이는 플로우 수명 동안의 연결 상태를 이해하는 데 유용한 정보를 제공하며, 설정된 플래그는 “syn”: true와 같이 true 값으로 표시됩니다.

참고. proto:TCP에 대한 Flow 로그 이벤트에는 설정된 모든 플래그를 단일 16진수 값으로 나타내는 “tcp_flags” 필드도 포함됩니다. 예를 들어, SYN + FIN + PSH + ACK 플래그가 설정된 경우, 이들의 10진수 값(2 + 1 + 8 + 16 = 27)을 16진수로 변환한 “1b”가 “tcp_flags” 필드에 포함됩니다. 이러한 정보를 활용하여 특정 연결 상태의 플로우를 쿼리할 수 있습니다. 예를 들어, TCP SYN은 관찰되었지만 SYN-ACK가 없는 경우(“tcp_flags” = “02”)를 쿼리하여 비대칭 라우팅 문제, 서버의 보안 그룹 규칙 누락, 또는 NACL/방화벽의 패킷 차단과 같은 문제를 진단할 수 있습니다.

{
    "firewall_name": "FW",
    "availability_zone": "ap-northeast-2a",
    "event_timestamp": "1743531876",
    "event": {
        "tcp": {
            "tcp_flags": "1b", 
            "syn": true,
            "fin": true,
            "psh": true,
            "ack": true
        },
        "app_proto": "http",
        "src_ip": "10.0.4.152", 
        "src_port": 58184,
        "netflow": {
            "pkts": 6, 
            "bytes": 398,
            "start": "2025-04-01T18:23:35.055780+0000",
            "end": "2025-04-01T18:23:35.072630+0000",
            "age": 0,
            "min_ttl": 254,
            "max_ttl": 254
        },
        "event_type": "netflow",
        "flow_id": 2209900150171410, 
        "dest_ip": "54.230.176.25",
        "proto": "TCP",
        "dest_port": 80,
        "timestamp": "2025-04-01T18:24:36.666554+0000"
    }
}
- event 내 tcp_flags : 관찰된 패킷들을 16진수로 나타냅니다.
- src_ip : 엔드포인트 기준으로 출발지 IP가 표시됩니다.
- netflow 내 pkts : 흐름동안 발생된 패킷의 총 갯수를 의미합니다.
- flow_id : Alert log와 동일 flow_id를 보유하게 됩니다.

{
    "firewall_name": "FW",
    "availability_zone": "ap-northeast-2a",
    "event_timestamp": "1743531876",
    "event": {
        "tcp": {
            "tcp_flags": "1b",
            "syn": true,
            "fin": true,
            "psh": true,
            "ack": true
        },
        "app_proto": "http",
        "src_ip": "54.230.176.25", 
        "src_port": 80,
        "netflow": {
            "pkts": 4,
            "bytes": 613,
            "start": "2025-04-01T18:23:35.055780+0000",
            "end": "2025-04-01T18:23:35.072630+0000",
            "age": 0,
            "min_ttl": 239,
            "max_ttl": 252
        },
        "event_type": "netflow",
        "flow_id": 2209900150171410,
        "dest_ip": "10.0.4.152",
        "proto": "TCP",
        "dest_port": 58184,
        "timestamp": "2025-04-01T18:24:36.666599+0000"
    }
}

- src_ip : 엔드포인트 기준으로 src_ip이 이전 로그와 반대로 역방향 표시가 되었습니다.
- flow_id :  트래픽 구분을 해주는 flow_id 필드입니다.

예시. ANF 의 Flow 로그

2. ANF Alert 로그의 Failed 및 Unknown 프로토콜 상태 이해하기

이번에는 ANF를 운영하는 과정에서 발생할 수 있는 ANF의 Alert 로그의 ‘failed‘ 또는 ‘event.app_proto unknown‘ 상태에 대해 알아보겠습니다.

{
    "firewall_name": "FW",
    "availability_zone": "ap-northeast-2a",
    "event_timestamp": "1743601210",
    "event": {
        "app_proto": "failed",
        "src_ip": "3.35.125.120",
        "src_port": 5060,
        "event_type": "alert",
        "alert": {
            "severity": 3,
            "signature_id": 204,
            "rev": 1,
            "signature": "ALERT ANY UDP rule",
            "action": "allowed",
            "category": ""
        },
        "flow_id": 1945077909848730,
        "dest_ip": "10.0.4.152",
        "proto": "UDP",
        "verdict": {
            "action": "pass"
        },
        "dest_port": 5060,
        "pkt_src": "geneve encapsulation",
        "timestamp": "2025-04-02T13:40:10.695086+0000",
        "direction": "to_client"
    }
}

ANF의 Alert 로그에서 app_proto 필드가 “failed“로 표시되는 경우는 Suricata 엔진이 트래픽을 식별할 수 없거나 “bail out” 조건이 발생했을 때입니다. 이때 “bail out” 조건의 경우 다음과 같은 경우를 의미합니다.

  1. 양방향 모두 검사했으나 매칭되는 프로토콜을 찾지 못함
  2. A 방향 검출 실패 & B 방향 트래픽 없는 경우 (예: FTP 데이터 채널)
  3. A 방향 검출 실패 & B 방향 데이터가 너무 적어서 결론을 내리기 어려운 경우

이는 상위 계층 프로토콜(TLS, HTTP, SMTP, SSH 등)의 유효성 검사 실패를 의미하며, 트래픽 Drop 과는 무관합니다.
예를 들어, Suricata는 포트 번호가 아닌 실제 프로토콜 패턴을 분석하여 판단하므로, 포트 443이더라도 TLS 패턴이 없다면 “failed“로 표시될 수 있습니다. 자세한 내용은 하기 Suricata 문서를 참고하시길 바랍니다.

또한 ‘unknown’ 상태는 NetworkFirewall이 애플리케이션 계층 프로토콜을 인식하지 못할 때 발생합니다. 정상적인 L7 연결에서는 Flow log와 Alert log 모두 proto와 app_proto 필드(예: HTTP/TLS)를 포함해야 하지만, Flow log event에 proto:TCP만 존재하고 app_proto:TLS가 보이지 않는다면 이는 Suricata가 해당 트래픽을 인식하지 못했음을 의미합니다. 이러한 현상은 비대칭 라우팅, NACL, Security Group 등의 이슈로 인해 패킷을 재조립하지 못했을 때 발생할 수 있습니다.

보다 자세한 내용은 Suricata 공식 문서와 포럼을 참조하시기 바라며 위와같은 사례가 발생할 경우 서포트 케이스를 통해 도움을 받으실 수 있습니다.

3. UDP 패킷의 established 로깅 조건 알아보기

ANF의 Stateful 엔진을 이용하여 규칙을 생성하다보면 “flow:established“ 와 같은 키워드를 사용하는 경우가 있습니다. “flow:established“ 키워드는 트래픽의 연결 상태를 기반으로 규칙 검사의 순서를 결정하는데 도움을 줄 수 있는데 이 키워드를 UDP 와 함께 사용할 때는 UDP 프로토콜의 특성 상 Flow Established 조건을 만족하기 위한 양방향 패킷이 Stateful 엔진에서 처리되어야 한다는 점에 유의해야 합니다.

즉, UDP와 같은 Stateless 프로토콜의 경우 양방향 트래픽이 모두 관찰되어야 규칙에서 사용된 established 조건에 부합하게 됩니다. 따라서 “flow:established“ 조건을 포함한 Stateless 프로토콜의 규칙이 정상적으로 로깅이 되기 위해서는 In/Out 통신이 모두 ANF 의 Stateful 엔진에서 처리되어야 합니다.

그림. UDP 세션 연결 상태 개념도 (참고 링크)

아래와 같이 Suricata 규칙에서 server에서 client로 전달되는 역방향 규칙을 사용하며 flow:established 키워드를 사용하는 규칙에 의하여 DNS 응답이 탐지가 되는 경우를 살펴보겠습니다.

alert udp any 53 -> any any (flow:established; msg:"ALERT ANY UDP rule, established"; sid:200; rev:1;)
pass udp any 53 -> any any (flow:established; msg:"ALERT ANY UDP rule, established"; sid:201; rev:1;)

아래는 위 Suricata 규칙애 매칭되어 허용된 트래픽에 대한 Alert Log 입니다.

{
    "firewall_name": "FW",
    "availability_zone": "ap-northeast-2a",
    "event_timestamp": "1743612835",
    "event": {
        "dns": {
            "version": 2,
            "answer": {
                "version": 2,
                "type": "answer", 
                "id": 28020,
                "flags": "8180",
                "qr": true,
                "rd": true,
                "ra": true,
                "opcode": 0,
                "rrname": "aws.amazon.com",
                "rrtype": "A",
                "rcode": "NOERROR"
            }
        },
        "tx_id": 1,
        "app_proto": "dns",
        "src_ip": "8.8.8.8",
        "src_port": 53,
        "event_type": "alert",
        "alert": {
            "severity": 3,
            "signature_id": 200,
            "rev": 1,
            "signature": "ALERT ANY UDP rule, established",
            "action": "allowed",
            "category": ""
        },
        "flow_id": 1032449660074532,
        "dest_ip": "10.0.4.152",
        "proto": "UDP",
        "verdict": {
            "action": "pass"
        },
        "dest_port": 33311,
        "pkt_src": "geneve encapsulation",
        "timestamp": "2025-04-02T16:53:55.800921+0000",
        "direction": "to_client" //<--- DNS 쿼리(서버)에서 클라이언트(호스트)로 가는 트래픽을 의미합니다.
    }
}

- dns 필드 내 type : 역방향이므로 DNS query가 아닌 answer으로 기록됩니다.
- src_ip : DNS 응답이 반환된 주소입니다.(google 사용)
- dest_ip : DNS query 출발지입니다.

로그. DNS 응답에 대한 로그 예시

따라서 UDP를 사용할 때 flow:established 키워드가 규칙에 포함되는 경우 양방향 트래픽이 모두 관찰되어야 함을 알 수 있습니다.
이는 만약 순방향 UDP 규칙에 established 옵션이 포함되어 있을 경우 원활한 탐지가 되지 않으며 기본 규칙(drop established)에 의해 평가 될 가능성을 시사합니다.

4. Log 검색

이번에는 ANF 에서 생성하는 다양한 로그를 분석하는 방법에 대해 살펴보려고 합니다. ANF 의 로그는 Amazon CloudWatch Logs 에 저장하거나 Amazon S3 버킷에 저장한 후 분석에 활용할 수 있습니다. 일반적으로 AWS 환경에서 로그를 분석할 때와 마찬가지로 ANF 의 로그분석에서도 CloudWatch 를 활용하는 경우는 상대적으로 짧은 기간의 로그를 분석하거나 별도의 분석 도구 없이 AWS 의 관리 콘솔에서 제공하는 필터 메뉴들을 이용하여 로그를 분석하고자 하는 경우, 그리고 로그를 기반으로 Metric 을 수집하고 경보를 발생하고자 하는 경우에 사용합니다. 그리고 일반적으로, S3 버킷은 저렴한 비용에 로그 파일을 보관하고 동시에 여러 분석 도구에서 데이터를 제공하면서 분석을 수행하고자 하는 경우에 사용합니다.

이 게시물에서는 Amazon Athena 를 이용한 로그 분석과 함께 CloudWatch 로그 그룹에 저장되어 있는 로그를 필터하는 방법에 대해 살펴보도록 하겠습니다.

(1) Amazon Athena 를 이용한 로그 분석

Athena 를 이용하여 ANF 로그를 분석하기 위해서는 먼저 테이블을 생성해야 합니다. 아래와 같이 쿼리문을 작성하여 새로운 테이블을 생성합니다.

그림. ANF Log 분석을 위한 테이블 생성 구문

아래는 Alert Log 와 Flow Log 를 위한 테이블 생성 예시입니다.

## Alert Log 테이블 생성

CREATE EXTERNAL TABLE anf_alert(
  firewall_name string,
  availability_zone string,
  event_timestamp bigint,
  event struct<
    timestamp:string,
    flow_id:bigint,
    event_type:string,
    src_ip:string,
    src_port:int,
    dest_ip:string,
    dest_port:int,
    proto:string,
    app_proto:string,
    alert:struct<
      severity:int,
      signature:string,
      action:string,
      signature_id:int
    >,
    tls:struct<
      sni:string
    >,
    http:struct<
      hostname:string,
      url:string
    >
  >
)
ROW FORMAT SERDE
  'org.openx.data.jsonserde.JsonSerDe'
STORED AS INPUTFORMAT
  'org.apache.hadoop.mapred.TextInputFormat'
OUTPUTFORMAT
  'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
  's3://amzn-s3-demo-bucket/path_to_alert_logs_folder/'
  

## Flow Log 테이블 생성

  CREATE EXTERNAL TABLE anf_flow(
  firewall_name string,
  availability_zone string,
  event_timestamp bigint,
  event struct<
    timestamp:string,
    flow_id:bigint,
    event_type:string,
    src_ip:string,
    src_port:int,
    dest_ip:string,
    dest_port:int,
    proto:string,
    app_proto:string,
    tcp:struct<
    tcp_flags:string
  >,
    netflow:struct<
      pkts:int,
      bytes:bigint,
      start:string,
      finish:string,
      age:int,
      min_ttl:int,
      max_ttl:int,
      tcp_flags:struct<
        syn:boolean,
        fin:boolean,
        rst:boolean,
        psh:boolean,
        ack:boolean,
        urg:boolean
        >
  >
  >
)
ROW FORMAT SERDE
  'org.openx.data.jsonserde.JsonSerDe'
STORED AS INPUTFORMAT
  'org.apache.hadoop.mapred.TextInputFormat'
OUTPUTFORMAT
  'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
  's3://amzn-s3-demo-bucket/path_to_netflow_logs_folder/'

테이블이 완성되었다면 아래와 같이 쿼리문을 작성하여 ANF 로그를 분석할 수 있습니다.

그림. ANF 로그 분석 쿼리문

ANF 로그 분석을 위한 Athena 쿼리문의 다양한 예시는 아래를 참고하시기 바랍니다.

## Alert log 내 signature_id를 사용한 로그 검색 예시

SELECT
  event.timestamp AS Time,
  availability_zone AS AZ,
  event.event_type AS Type,
  event.flow_id AS Flow_ID,
  event.alert.action AS Action,
  event.src_ip AS Src_IP,
  event.src_port AS Src_Port,
  event.dest_ip AS Dst_IP,
  event.dest_port AS Dst_Port,
  event.proto AS Protocol,
  event.tls.sni AS SNI,
  event.http.hostname AS Host,
  event.alert.signature AS Signature
FROM 
  anf_alert
WHERE 
  event.alert.signature_id = 100
LIMIT 10

## Alert log 내 dest_port 및 action을 출발지 IP별로 그룹화하여 로그 검색 예시

SELECT 
    COUNT(*) AS count,
    event.src_ip
FROM anf_alert
WHERE event.dest_port = 443 
    AND event.alert.action = 'allowed'
GROUP BY event.src_ip
ORDER BY count DESC
LIMIT 100

## Flow log 내 flow_id를 사용한 로그 검색 예시

SELECT
  event.timestamp AS Time,
  availability_zone AS AZ,
  event.event_type AS Type,
  event.flow_id AS Flow_ID,
  event.src_ip AS Src_IP,
  event.src_port AS Src_Port,
  event.dest_ip AS Dst_IP,
  event.dest_port AS Dst_Port,
  event.proto AS Protocol,
  event.tcp.tcp_flags AS TCP_flags,
  event.netflow.pkts AS Packets,
  event.netflow.bytes AS Bytes

FROM anf_flow
WHERE event.flow_id = 23711906641119
ORDER BY Time DESC

## 상위 통신량(bytes)을 보이는 출발지 IP TOP 10 검색 예시

SELECT 
    event.src_ip,
    COUNT(*) as connection_count,
    SUM(event.netflow.bytes) as total_bytes,
    SUM(event.netflow.pkts) as total_packets
FROM anf_flow
GROUP BY event.src_ip
ORDER BY total_bytes DESC
LIMIT 10;

## 프로토콜 별 트래픽 분포 분석 검색 예시

SELECT 
    event.app_proto,
    COUNT(*) as connection_count,
    SUM(event.netflow.bytes) as total_bytes,
    AVG(event.netflow.pkts) as avg_packets
FROM anf_flow
WHERE event.app_proto IS NOT NULL
GROUP BY event.app_proto
ORDER BY total_bytes DESC;

## 특정 시간 이상 지속된 연결 검색 예시

SELECT 
    event.src_ip,
    event.dest_ip,
    event.dest_port,
    event.netflow.age as connection_duration,
    event.netflow.bytes,
    event.netflow.pkts
FROM anf_flow
WHERE event.netflow.age > 300 -- 시간초 지정
ORDER BY event.netflow.age DESC;

이러한 테이블 포맷은 각 로그의 구조에 맞게 수정해야 하며 최신 버전 로그의 열을 포함하도록 문을 업데이트해야 할 수 있습니다.
테이블 생성 및 로그 쿼리에 대한 내용은 링크를 참조하시길 바랍니다.

(2) Cloudwatch 로그 그룹 필터

ANF 의 로그 저장소로 CloudWatch 로그 그룹을 선택하였다면 아래와 같이 다양한 필터 옵션을 이용하여 CloudWatch 로그 그룹에 저장되어 있는 로그들을 필터하여 분석을 수행할 수 있습니다.

그림. CloudWatch 로그 그룹 필터

CloudWatch 로그 그룹에 사용할 수 있는 로그 필터의 예시는 아래를 참고하시기 바랍니다.

# 특정 SNI 검색
{$.event.tls.sni = aws.amazon.com}
# 특정 hostname 검색
{$.event.http.hostname = aws.amazon.com}
# 특정 protocol 검색
{$.event.proto = icmp}
# 특정 application layer protocol 검색
{$.event.app_proto = tls}
# 특정 signature/rule Id
{$.event.alert.signature_id = 100}
# 특정 flow Id 검색
{$.event.flow_id = 23711906641119}
# 특정 source port 검색
{$.event.src_port = 58184}
# 특정 source 또는 destination port 검색
{$.event.src_port = 58184 || $.event.dest_port = 80}
# 특정 source 및 destination 쌍 검색 (AND조건)
{ ($.event.src_ip = "10.170.32.252") && ( $.event.dest_ip = "10.170.48.41") }
# 특정 source 또는 destination 쌍 검색 (OR조건)
{ ($.event.src_ip = "10.170.32.252") || ( $.event.dest_ip = "10.170.32.252") }
# 특정 and / or 조건 사용
{ ($.event.src_ip = "10.170.32.252") && ( $.event.dest_ip = "10.170.48.41")  && ($.event.proto = "TCP") && ($.event.dest_port ="80" || $.event.dest_port ="443")}

3. 맺음말

ANF 는 조직의 사용 목적에 따라 다양한 위치에 배포되어 트래픽을 모니터링하고 차단할 수 있습니다. 일반적으로 VPC 에서 아웃바운드로 향하는 트래픽을 제어하기 위해 사용되는 형태를 생각해보면, ANF 는 VPC 와 인터넷 간의 대부분의 트래픽을 감시하고 있다는 것을 의미하기도 합니다. 따라서, ANF 에서 처리되는 트래픽에 대해 로그를 기록하고 이를 기반으로 위협을 찾아내거나 또는 ANF 운영 과정에서 발생할 수 있는 오류 등을 찾아내는 등의 중요성은 아무리 강조해도 지나치지 않다고 볼 수 있을 것입니다.

본 게시물에서는 ANF 의 다양한 로깅 설정과 활용방법, 구조 등에 대해 살펴 보았습니다. ANF 의 로깅 시스템은 복잡하지만, 강력한 기능을 제공하며 방화벽 관리자와 보안 운영팀에게 감사, 규정 준수, 조사 및 보안 태세 개선을 위한 필수적인 데이터를 제공합니다. 따라서, ANF의 로깅 시스템을 효과적으로 활용하기 위해서는 목적지의 활용성과 앞선 요소들을 종합적으로 고려하여 규칙을 설계하고 구현해야 합니다. 특히, 의도한대로 트래픽을처리하고 로그를 기록하기 위해서는 Suricata 엔진의 작동 원리를 이해하고, 다양한 규칙 그룹을 적절히 조합하는 것이 중요합니다. 이를 통해 보안 정책을 정확히 구현하고, 의도하지 않은 트래픽 처리를 방지하시길 바랍니다.

참고자료

Eunsu Shin

Eunsu Shin

신은수 Security Specialist Solutions Architect 는 보안 담당 SA로서 다양한 산업군의 고객들이 AWS 환경에서 수행해야하는 규정 준수 및 인증획득(개인정보보호법, 전자금융감독규정, ISMS-P 인증 등)을 위한 기술적인 도움을 제공해드리고 있습니다. 또한, 고객이 보다 안전하게 AWS 클라우드를 구성하고 운영할 수 있도록 다양한 모범 사례 공유, AWS 보안 서비스 교육 및 기술자문 등의 업무를 수행하고 있습니다.

Janghyun Jo

Janghyun Jo

조장현 Cloud Support Engineer는 현재 다양한 AWS 네트워크 서비스들에 대해 고객 지원 업무를 수행하고 있습니다.