EventBridge+Step Functions를 활용한 WAF Log 자동화 설정

안건에서 EventBridge와 Step Functions를 활용해서 WAF Log 자동화 설정에 대한 검증을 실시해봤기 때문에 그 과정을 블로그로 정리해 봤습니다.
2021.12.14

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

안녕하세요 클래스메소드 김재욱(Kim Jaewook) 입니다. 안건에서 EventBridge와 Step Functions를 활용해서 WAF Log 자동화 설정에 대한 검증을 실시해봤기 때문에 그 과정을 블로그로 정리해 봤습니다.

EventBridge와 Step Functions에 대한 내용은 아래 블로그를 참고해 주세요

WAF Log를 자동화 설정하는 과정은 다음과 같습니다.

  • Step Functions 생성
  • EventBridge 규칙 생성
  • WAF 생성 후 테스트

Step Functions 생성

먼저 Step Functions에서「상태 머신 생성」버튼을 클릭합니다.

「시각적으로 워크플로 설계」를 선택하고 유형은「Express」를 선택합니다. 유형의 경유 아래「결정을 위한 도움말」을 클릭하면 각 유형에 대한 설명이 나옵니다. 오래 실행되고, 내구성이 있는 워크플로를 원한다면 표준을, 대용량 이벤트처리의 워크플로를 원한다면 Express를 선택하면 됩니다. 보다 자세한 내용은 아래 링크를 참고해 주세요.

Standard vs. Express Workflows

이제 워크플로를 설계할 수 있습니다. 검색창에「put waf」를 검색하고「PutLoggingConfiguration」을 드래그해서 오른쪽으로 끌어옵니다. 이런식으로 간단하게 워크플로를 설계할 수 있습니다. 먼저「PutLoggingConfiguration」의 경우 WAF의 Log를 설정할 수 있는 API 입니다.

{
  "LoggingConfiguration": {
    "LogDestinationConfigs": [
      "S3 or CloudWatch or Kinesis ARN"
    ],
    "ResourceArn.$": "$.aRN"
  }
}

그리고 API 파라미터에 위와 같이 자동으로 코드가 생성됩니다. 먼저 S3에 로그를 저장할 경우 LogDestinationConfigs에 S3의 ARN을 입력하면 됩니다. ResourceArn의 경우 EventBridge로 부터 전달 받은 WAF의 ARN을 입력할 생각이기 때문에「$.aRN」을 입력합니다.

여기서 ResourceArn을 「ResourceArn.$": "$.aRN」의 형태로 수정할 필요가 있는데, ResourceArn에 $를 붙히지 않으면 EventBridge로 부터 파라미터 값을 받아올 수 없기 때문에 주의가 필요합니다.

「PutLoggingConfiguration」에 대한 Request Syntax, Request Parameters의 정보는 아래 링크를 참고해 주세요.

PutLoggingConfiguration

이제 다음으로 넘어가서 상테 시스템을 설정합니다. 먼저 목적에 맞게 적절하게 이름을 입력하고 권한의 경우 새 역할 생성을 선택합니다.

이어서 로깅을 설정합니다. Step Functions에서 상태 머신이 실행 됐을 때 이벤트 로그를 CloudWatch에 저장는데, 여기서 로그 수준을 ALL, ERROR, FATAL, OFF 중 하나로 선택합니다.

모든 이벤트에 대해 로깅을 활성화 하고 싶으면 ALL을, 오류에 대해서만 활성화 하고 싶으면 ERROR을, 심각한 오류 수준에 대해서만 활성화 하고 싶으면 FATAL을, 비활성화 하고 싶으면 OFF를 선택하면 됩니다. 그리고 상태 머신 생성을 끝마칩니다.

생성이 끝나면 IAM에 권한을 추가해야 한다는 메시지가 나옵니다. 「IAM에서 역할 편집」을 클릭합니다.

「정책 연결」을 선택합니다.

WAF를 검색하고「AWSWAFFullAccess」를 선택하고 정책을 연결하면 Step Functions에서의 설정은 끝납니다.

EventBridge 규칙 생성

이어서 EventBridge로 들어와서 규칙 탭에서「규칙 생성」버튼을 클릭합니다.

규칙 이름은 현재 사용 목적에 맞게 적어줍니다.

{
  "source": ["aws.wafv2"],
  "detail-type": ["AWS API Call via CloudTrail"],
  "detail": {
    "eventSource": ["wafv2.amazonaws.com"],
    "eventName": ["CreateWebACL"]
  }
}

패턴 정의에서「사용자 지정 패턴」을 선택하고 위 코드를 복사해서 붙여넣습니다.

CloudTrail에서 CreateWebACL라는 이벤트 Log가 찍히면 EventBridge가 실행되는 코드입니다.

대상은 Step Functions를 선택하고 조금 전 생성한 상태 시스템을 선택합니다.

입력 구성은「일치하는 이벤트의 일부」를 선택하고 $.detail.responseElements.summary 파라미터 값을 넘겨줍니다.

CloudTrail에서 CreateWebACL 이벤트 Log를 살펴보면 responseElemets.summary의 형태로 WAF에 대한 정보가 담겨져 있는 것을 볼 수 있습니다. 여기서 WAF에 대한 정보는 $.detail.responseElements.summary의 형태로 가져올 수 있기 때문에 Step Functions로 $.detail.responseElements.summary를 넘겨줍니다.

이제 생성을 끝마치고 이벤트 규칙으로 돌아와서 조금 전 생성한 규칙 상태가 Enabled로 되어있는지 확인합니다.

WAF Log 자동화 테스트

이제 도쿄 리전에서 WAF를 생성해서 테스트를 진행 하겠습니다.

유저 설정에 맞게 적절하게 WAF를 생성합니다.

그리고 WAF에서「Logging and metrics」탭을 클릭해서 확인해 보면 Disable에서 Enabled로 바뀐 것을 확인할 수 있습니다.

CloudTrail에서 확인해 보면 CreateWebACL 이벤트가 기록되고 PutLoggingConfiguration 이벤트가 기록된 것을 볼 수 있습니다.

Step Functions의 로그도 확인해 보면, 조금 전 생성한 WAF의 arn이 전달되서 Log 설정을 하고 있는 것을 볼 수 있습니다.

장점

  • WAF Log 설정을 빨리 할 수 있다.(3~5초 정도 걸림)
  • 간단하게 구축할 수 있다.(Step Functions, EventBridge에 대해 이해하고 있다면 간단하게 구축 가능)
  • 추가적인 소프트웨어 설치, 관리, 운영이 필요 없다.(오버헤드 감소)
  • 코드가 짧아진다.(실제로 Lambda만을 이용해서 WAF Log 설정을 할 때와 비교해 보면 코드가 상당히 간결하다)
  • 이벤트에 대해 거의 리얼 타임을 제공

단점

  • 이미 만들어진 WAF는 Log 설정을 할 수 없다.(EventBridge가 생성된 이후 부터 CreateWebACL 이벤트를 체크하기 때문)
  • 사람에 따라 다르겠지만 EventBridge와 Step Functions를 이해하는 데 시간이 조금 걸릴수도 있다.(자료가 적기도 함)
  • CloudFront에서 WAF를 사용할 생각이라면, us-east-1에 Cloud Trail 이벤트 기록이 남기 때문에 Event Bridge, Step Functions를 us-east-1에 생성해야 하며, WAF 또 한 CloudFront에 맞춰서 Global (CloudFront)에 생성해야 한다.

참고