AWS Config Config Rule + SSM Automation으로 WAF Logging 자동으로 활성화 설정

2021.12.10

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

안녕하세요! 클래스메소드 금상원 입니다. 이번 블로그에서는 AWS Config Config Rule + SSM Automation을 이용하여 WAF Logging을 자동으로 활성화 설정 하는법에 대해 소개하도록 하겠습니다.

목표!

AWS Config Rule + SSM Automation로 Logging대상이 S3인 WAF의 Logging을 자동으로 활성화 하자!

IAM Role 생성

IAM Role을 하나 만들어 주기 위해 역활 만들기 버튼을 클릭합니다.

위 의 그림처럼 System Manager를 체크 하고 사용 사례 선택 에서도 System Manager를 선택하고 다음:권한버튼을 클릭 합니다.

정책 필터에 SSM, S3, WAF를 검색하시고

  • AmazonSSMFullAccess
  • AmazonS3FullAccess
  • AWSWAFFullAccess

위의 내용을 클릭하여 추가해 주세요. S3이외의 서비스를 사용하면 다른 서비스도 추가해 주셔야 합니다.

  • AmazonKinesisFullAccess
  • CloudWatchLogsFullAccess

태그는 원하시는 태그만 추가 하시면 됩니다.

역활 이름을 입력 하시고 정책을 확인하시고 역활 만들기 버튼을 클릭해 주세요.

SSM Automation 문서 생성

왼쪽 메뉴에서 자동화 를 클릭합니다.

자동화 생성 버튼을 클릭합니다.

문서 생성 버튼을 클릭합니다.

이름 을 입력하고 편집기 를 클릭한 후, 편집 버튼을 클릭하여 아래의 코드를 복사하여 붙여넣어 줍니다.

description: |
  ### Document name - AWSConfigRemediation-EnableWAFV2Logging

  ## What does this document do?
  This runbook enables logging for an AWS Web Application Firewall (AWS WAFV2) regional and global web access control list (ACL) with the specified Amazon Kinesis Data Firehose (Kinesis Data Firehose) using the [PutLoggingConfiguration](https://docs.aws.amazon.com/waf/latest/APIReference/API_waf_PutLoggingConfiguration.html#API_waf_PutLoggingConfiguration_ResponseSyntax) API.

  ## Input Parameters
  * AutomationAssumeRole: (Required) The Amazon Resource Name (ARN) of the AWS Identity and Access Management (IAM) role that allows Systems Manager Automation to perform the actions on your behalf.
  * LogDestinationConfigs: (Required) The Kinesis Data Firehose ARN that you want to associate with the web ACL.
  * WebAclArn: (Required) ARN of the web ACL for which logging will be enabled.

  ## Output Parameters
  * EnableWAFV2LoggingAndVerify.Output: Success message with HTTP Response from PutLoggingConfiguration, GetLoggingConfiguration API calls or failure exception.
schemaVersion: "0.3"
assumeRole: "{{ AutomationAssumeRole }}"
outputs:
  - EnableWAFV2LoggingAndVerify.Output
parameters:
  AutomationAssumeRole:
    type: String
    description: (Required) The Amazon Resource Name (ARN) of the AWS Identity and Access Management (IAM) role that allows Systems Manager Automation to perform the actions on your behalf.
    allowedPattern: ^arn:(aws[a-zA-Z-]*)?:iam::\d{12}:role/[\w+=,.@/-]+$
  LogDestinationConfigs:
    type: String
    description: (Required) The Kinesis Data Firehose ARN that you want to associate with the web ACL.
  WebAclArn:
    type: String
    description: (Required) ARN of the web ACL for which logging will be enabled.
    allowedPattern: ^arn:(aws[a-zA-Z-]*)?:wafv2:.*
mainSteps:
  - name: EnableWAFV2LoggingAndVerify
    action: "aws:executeScript"
    isEnd: true
    timeoutSeconds: 600
    description: |
      ## EnableWAFV2LoggingAndVerify
      Enables logging for the AWS WAFV2 web ACL and verifies that the logging has the specified configuration.
      ## Outputs
      * Output: Success message with HTTP Response from PutLoggingConfiguration, GetLoggingConfiguration API calls or failure exception.
    inputs:
      Runtime: python3.7
      Handler: enable_wafv2_logging_and_verify
      InputPayload:
        LogDestinationConfigs: "{{ LogDestinationConfigs }}"
        ResourceArn: "{{ WebAclArn }}"
      Script: |-
        import boto3

        def enable_wafv2_logging_and_verify(event, context):

            wafv2_client = boto3.client('wafv2')
            web_acl_arn = event["ResourceArn"]

            # Kinesis Data Firehose
            #firehose_client = boto3.client('firehose')
            #delivery_stream_arn = event["LogDestinationConfigs"]
            #delivery_stream_name = delivery_stream_arn.split("/")[-1]

            #response = firehose_client.describe_delivery_stream(DeliveryStreamName=delivery_stream_name, Limit=1)
            #if response["DeliveryStreamDescription"]["DeliveryStreamARN"] != delivery_stream_arn:
            #    raise Exception("UPDATE FAILED, AMAZON KINESIS DATA FIREHOSE ARN PROVIDED DOESN'T EXISTS.")


            # S3    
            s3 = boto3.resource('s3')
            bucket_arn = event["LogDestinationConfigs"]
            bucket_name = arn2.split(":::")[-1]

            if s3.Bucket(bucket_name).creation_date is None:
                raise Exception("UPDATE FAILED, AMAZON S3 ARN PROVIDED DOESN'T EXISTS.")


            # Watch Logs    
            #watch_logs = boto3.client('logs')
            #watch_logs_arn = event["LogDestinationConfigs"]
            #watch_logs_name = watch_logs_arn.split(":")[-2]



            #response = watch_logs.describe_log_groups(
            #   logGroupNamePrefix = watch_logs_name,
            #   limit=50
            #)

            #if not response['logGroups']:
            #    raise Exception("UPDATE FAILED, AMAZON Watch Logs ARN PROVIDED DOESN'T EXISTS.")

            update_response = wafv2_client.put_logging_configuration(
                LoggingConfiguration={
                    "ResourceArn": web_acl_arn,
                    "LogDestinationConfigs": [
                        bucket_arn,
                    ]
                }
            )
            get_response = wafv2_client.get_logging_configuration(ResourceArn=web_acl_arn)
            if get_response["LoggingConfiguration"]["LogDestinationConfigs"] == [delivery_stream_arn]:
                return {
                    "output": {
                        "Message": "Enable Logging configuration for AWS WAFV2 web ACL is SUCCESSFUL",
                        "HTTPResponsePutAPI": update_response,
                        "HTTPResponseGetAPI": get_response
                        }
                    }
            raise Exception("VERIFICATION FAILED, LOGGING CONFIGURATION FOR AWS WAFV2 IS NOT ENABLED.")
    outputs:
      - Name: Output
        Selector: $.Payload.output
        Type: StringMap

코드를 입력이 왼료 되었으면 자동화 생성 버튼을 클릭해 줍니다.

Config Rule 생성 하기

왼쪽 메뉴에서 규칙 을 클릭합니다.

규칙 추가 를 클릭 합니다.

AWS 관리형 규칙 추가 를 선택하고 AWS 관리형 규칙wafv2-logging-enable 을 검색하여 선택한 후 다음 버튼을 클릭 합니다.

이름 을 입력합니다.

빈도 를 입력하고 파라미터 는 입력을 하셔도 되고 안하셔도 됩니다. 그리고 다음 버튼을 클릭 합니다.

추가된 규칙을 확인하고 규칙 추가 를 클릭하여 생성합니다.

생성된 Config Rule을 선택하고 작업을 클릭하고 문제 해결 관리 를 클릭 합니다.

자동 수정 을 선택하고 재시도 횟수 를 입력하고 수정 작업 세부 정보 를 위에서 만든 문서(WAF_LOGGING_TEST)로 선택합니다.

다음으로는 동시 실행 비율, 오류 발생률 을 입력합니다. 아래의 리소스 ID 파라미터WebAclARN을 선택하고 각각의 파라미터(IAM Role의 ARN, S3의 이름) 을 입력합니다.

각각의 파라미터는 위의 사진 처럼 확인 할 수 있습니다.

위의 사진처럼 미 준수인 WAF의 로깅을 활성화 하는 것을 확인 할 수 있습니다.

코드 설명

베이스 코드는 us-east-1 리전의 SSM Automation에서 기본적으로 제공해주는 AWSConfigRemediation-EnableWAFV2Logging의 코드를 참고했습니다.

베이스 코드

description: |
  ### Document name - AWSConfigRemediation-EnableWAFV2Logging

  ## What does this document do?
  This runbook enables logging for an AWS Web Application Firewall (AWS WAFV2) regional and global web access control list (ACL) with the specified Amazon Kinesis Data Firehose (Kinesis Data Firehose) using the [PutLoggingConfiguration](https://docs.aws.amazon.com/waf/latest/APIReference/API_waf_PutLoggingConfiguration.html#API_waf_PutLoggingConfiguration_ResponseSyntax) API.

  ## Input Parameters
  * AutomationAssumeRole: (Required) The Amazon Resource Name (ARN) of the AWS Identity and Access Management (IAM) role that allows Systems Manager Automation to perform the actions on your behalf.
  * LogDestinationConfigs: (Required) The Kinesis Data Firehose ARN that you want to associate with the web ACL.
  * WebAclArn: (Required) ARN of the web ACL for which logging will be enabled.

  ## Output Parameters
  * EnableWAFV2LoggingAndVerify.Output: Success message with HTTP Response from PutLoggingConfiguration, GetLoggingConfiguration API calls or failure exception.
schemaVersion: "0.3"
assumeRole: "{{ AutomationAssumeRole }}"
outputs:
  - EnableWAFV2LoggingAndVerify.Output
parameters:
  AutomationAssumeRole:
    type: String
    description: (Required) The Amazon Resource Name (ARN) of the AWS Identity and Access Management (IAM) role that allows Systems Manager Automation to perform the actions on your behalf.
    allowedPattern: ^arn:(aws[a-zA-Z-]*)?:iam::\d{12}:role/[\w+=,.@/-]+$
  LogDestinationConfigs:
    type: String
    description: (Required) The Kinesis Data Firehose ARN that you want to associate with the web ACL.
    allowedPattern: ^arn:(aws[a-zA-Z-]*)?:firehose:.*:.*:deliverystream/(aws-waf-logs-.*)$
  WebAclArn:
    type: String
    description: (Required) ARN of the web ACL for which logging will be enabled.
    allowedPattern: ^arn:(aws[a-zA-Z-]*)?:wafv2:.*
mainSteps:
  - name: EnableWAFV2LoggingAndVerify
    action: "aws:executeScript"
    isEnd: true
    timeoutSeconds: 600
    description: |
      ## EnableWAFV2LoggingAndVerify
      Enables logging for the AWS WAFV2 web ACL and verifies that the logging has the specified configuration.
      ## Outputs
      * Output: Success message with HTTP Response from PutLoggingConfiguration, GetLoggingConfiguration API calls or failure exception.
    inputs:
      Runtime: python3.7
      Handler: enable_wafv2_logging_and_verify
      InputPayload:
        LogDestinationConfigs: "{{ LogDestinationConfigs }}"
        ResourceArn: "{{ WebAclArn }}"
      Script: |-
        import boto3

        def enable_wafv2_logging_and_verify(event, context):
            firehose_client = boto3.client('firehose')
            wafv2_client = boto3.client('wafv2')
            web_acl_arn = event["ResourceArn"]
            delivery_stream_arn = event["LogDestinationConfigs"]
            delivery_stream_name = delivery_stream_arn.split("/")[-1]

            response = firehose_client.describe_delivery_stream(DeliveryStreamName=delivery_stream_name, Limit=1)
            if response["DeliveryStreamDescription"]["DeliveryStreamARN"] != delivery_stream_arn:
                raise Exception("UPDATE FAILED, AMAZON KINESIS DATA FIREHOSE ARN PROVIDED DOESN'T EXISTS.")

            update_response = wafv2_client.put_logging_configuration(
                LoggingConfiguration={
                    "ResourceArn": web_acl_arn,
                    "LogDestinationConfigs": [
                        delivery_stream_arn,
                    ]
                }
            )
            get_response = wafv2_client.get_logging_configuration(ResourceArn=web_acl_arn)
            if get_response["LoggingConfiguration"]["LogDestinationConfigs"] == [delivery_stream_arn]:
                return {
                    "output": {
                        "Message": "Enable Logging configuration for AWS WAFV2 web ACL is SUCCESSFUL",
                        "HTTPResponsePutAPI": update_response,
                        "HTTPResponseGetAPI": get_response
                        }
                    }
            raise Exception("VERIFICATION FAILED, LOGGING CONFIGURATION FOR AWS WAFV2 IS NOT ENABLED.")
    outputs:
      - Name: Output
        Selector: $.Payload.output
        Type: StringMap

변경한 부분

베이스 코드의 LogDestinationConfigs 부분에서는 allowedPattern을 사용하여 Kinesis Data Firehose의 ARN을 입력하도록 되어있습니다. S3의 이름 패턴 혹은 Cloud Watch의 ARN의 패턴으로 작성하실려면 이부분을 지우시거나 변경하시면 여러분들이 필요하신 파마미터를 입력받을 수 있습니다.

첫번째 박스

Kinesis Data Firehose의 ARN정보를 받아와서 작업을 처리 하기 위해 firehose_client = boto3.client('firehose'), delivery_stream_arn = event["LogDestinationConfigs"], delivery_stream_name = delivery_stream_arn.split("/")[-1] 의 코드를 사용하고 있습니다.

두번째 박스

Kinesis Data Firehose 가 실제로 존재 하는지를 확인하는 작업을 처리하고 있습니다.

세번째 박스

Kinesis Data Firehose의 ARN정보를 입력 받습니다.
! 여기에서는 무조건 ARN을 입력하셔야 합니다.

WAF의 로깅대상에 설정한 Kinesis Data Firehose의 ARN이 입력 받아온 값과 일치 하는지 확인하는 작업을 처리하고 있습니다.

위에서 설명한 부분의 코드를 변경하시면 S3나 Cloud Watch를 사용 하셔도 자동으로 Logging을 활성화 하실 수 있습니다.

장점 및 단점

장점

  • 1시간 단위로 Config Rule이 검사를 실시하고 Disable을 Enable로 자동으로 변경이 가능합니다.
  • 1시간 단위로 검사를 하기 때문에 처음 실패하여도 다음 변경 작업에서는 성공할 수 있습니다.
  • 한번만 설정하면 계속 사용할 수 있어 운영 / 관리가 편합니다
  • Config Rule에서 검사하고 있는 WAF는 전부 자동으로 Enable로 변경 가능한 대상입니다.

단점

  • 1시간 단위로 검사를 진행하기 때문에 WAF가 생성된 직후 자동으로 Enable로 변경될 때 까지 시간이 걸립니다.
  • WAF의 로그 설정을 Kinesis Data Firehose가 아닌 다른 서비스를 사용하신다면 SSM Automation의 코드를 변경 할 필요가 있습니다.
  • 복수의 로그 설정 / 저장소를 사용하신다면 복수의 Config Rule이 필요로 하게 됩니다.

마무리

이번 블로그에서 Config Rule과 SSM Automation을 이용하여 Logging을 자동으로 활성화 하는 작업을 해보았습니다. 이블로그를 작성한 당시에는 us-east-1에서만 AWSConfigRemediation-EnableWAFV2Logging을 제공 해주고 있고, Kinesis Data Firehose만 사용할 수 있는 코드로 되어있어 추가하고 변경할 부분이 많아 힘드실 수 있지만 제 블로그를 통해 여러분들에게 조금이나마 도움이 되었으면 좋겠습니다.

참고한 자료

wafv2 로깅 지원

AWS Systems Managerオートメーションランブックを利用して非準拠ステータスのAWS Configルールを修復する

AWSConfigRemediation-EnableWAFV2Logging

Enable automatic logging of web ACLs by using AWS Config