S3에 파일이 저장되면 슬랙으로 알림 받기 (with EventBridge, Lambda)

Minseok Kim·2023년 9월 1일
0
post-thumbnail

잠깐 ✋

이 글을 읽기 전에 aws EventBridge에 대한 기본적인 이해가 필요합니다.
잘 모르시는 분들은 먼저 이 포스트를 읽고 와주세요!

S3 이벤트를 default 이벤트 버스로 보내기

aws 상에서 일어나는 거의 대부분의 일들은 management 이벤트로, default 이벤트 버스로 보내집니다.
하지만 S3, Lambda 등의 일부 서비스에서 발생하는 이벤트들은 data 이벤트로 분류되어 default 버스로 보내지지 않습니다.
(management event와 data event의 차이점에 대해 더 알고 싶다면 aws 공식 문서를 읽어보세요)
이 이벤트들을 추적하려면 별도로 설정을 해줘야 합니다.

설정 방법은 다음과 같습니다.
s3 버킷 -> 속성 -> Amazon EventBridge -> 이 버킷의 모든 이벤트에 대해 Amazon EventBridge로 알림 전송 활성화

이 설정을 해주면, 이제 해당 버킷의 모든 이벤트는 default 이벤트 버스로 전송됩니다.

Event Rule을 설정해 원하는 이벤트만 필터링하기

이벤트 버스에 이벤트 룰을 설정해서 버스의 이벤트를 필터링 할 수 있습니다.

만약 S3에 오브젝트가 생성됐다면, 다음과 같은 이벤트가 보내집니다.

{
  "version": "0",
  "id": "17793124-05d4-b198-2fde-7ededc63b103",
  "detail-type": "Object Created",
  "source": "aws.s3",
  "account": "123456789012",
  "time": "2021-11-12T00:00:00Z",
  "region": "ca-central-1",
  "resources": ["arn:aws:s3:::example-bucket"],
  "detail": {
    "version": "0",
    "bucket": {
      "name": "example-bucket"
    },
    "object": {
      "key": "example-key",
      "size": 5,
      "etag": "b1946ac92492d2347c6235b4d2611184",
      "version-id": "IYV3p45BT0ac8hjHg1houSdS1a.Mro8e",
      "sequencer": "00617F08299329D189"
    },
    "request-id": "N4N7GDK58NMKJ12R",
    "requester": "123456789012",
    "source-ip-address": "1.2.3.4",
    "reason": "PutObject"
  }
}

물론 오브젝트가 삭제됐을 때도 이벤트가 보내집니다.

{
  "version": "0",
  "id": "ad1de317-e409-eba2-9552-30113f8d88e3",
  "detail-type": "Object Deleted",
  "source": "aws.s3",
  "account": "123456789012",
  "time": "2021-11-12T00:00:00Z",
  "region": "ca-central-1",
  "resources": ["arn:aws:s3:::example-bucket"],
  "detail": {
    "version": "0",
    "bucket": {
      "name": "example-bucket"
    },
    "object": {
      "key": "example-key",
      "etag": "d41d8cd98f00b204e9800998ecf8427e",
      "version-id": "mtB0cV.jejK63XkRNceanNMC.qXPWLeK",
      "sequencer": "00617B398000000000"
    },
    "request-id": "20EB74C14654DC47",
    "requester": "s3.amazonaws.com",
    "reason": "Lifecycle Expiration",
    "deletion-type": "Delete Marker Created"
  }
}

이 두 이벤트의 가장 큰 차이점은 detail-type 값입니다.
생성됐을 때는 값이 "Object Created" 이고, 삭제됐을 때는 "Object Deleted" 입니다.
우리의 목표는 오브젝트가 생성됐을 때만 슬랙으로 알람을 받는 것이므로 Object Deleted 이벤트는 필터링 해서 걸러줘야 합니다.

이를 위해선 event rule을 다음과 같이 설정합니다.

{
  "source": ["aws.s3"],
  "detail-type": ["Object Created"]
}

간단한 이벤트 정책은 EventBridge 웹 콘솔에서도 작성할 수 있습니다.

위 패턴은 가장 기초적인 패턴이고, 복잡한 요구사항이 있을 땐 아래와 같이 더 복잡한 패턴을 적용할 수 있습니다.

{
    "source": [
        "aws.s3"
    ],
    "detail-type": [
        "Object Created",
        "Object Deleted"
    ],

    "detail": {
        "bucket": {
            "name": [
                "jbarr-public"
            ]
        },
        "object" : {
            "size": [{"numeric" :["<=", 1048576 ] }]
        }
    }
}

이 패턴은 jbarr-public 버킷 안에서 크기가 1Mb 이하의 오브젝트가 생성되거나 삭제되는 이벤트만 선택합니다.
더 복잡한 패턴을 작성하고 싶다면 이 문서를 참고하세요

Event Target

이제 이벤트 패턴까지 모두 작성했고 default 버스에다가 붙여줬습니다.
다음은 이 이벤트를 보낼 타겟을 설정해줘야 합니다.

위 그림에서 볼 수 있듯이 이벤트 타겟은 lambda, Amazon SNS, 기타 엔드포인트 등등 여러가지고 설정할 수 있습니다.

우리는 람다를 사용해서 slack에 메시지를 보내기로 했으므로 람다로 설정해주면 됩니다.

설정을 마치면 아래와 같이 Lambda의 트리거로 EventBridge가 등록된 것을 확인할 수 있습니다.

Lambda 설정

람다는 이벤트 버스로부터 이벤트를 받을 시 자동으로 실행됩니다.
이벤트로부터 메타데이터를 받아와 메시지를 작성하고 slack으로 보내주는 코드는 아래와 같습니다.

import json
import requests
import os

def lambda_handler(event, context):
    # Slack 웹훅 URL 환경 변수에서 가져오기
    webhook_url = os.environ.get("SLACK_WEBHOOK_URL")
    
    if not webhook_url:
        print("Slack Webhook URL not found")
        return {
            'statusCode': 400,
            'body': json.dumps('Slack Webhook URL not found')
        }
    
    # 이벤트에서 필요한 정보 추출
    bucket_name = event['detail']['bucket']['name']
    object_key = event['detail']['object']['key']
    detail_type = event.get('detail-type', '')
    
    # Slack 메시지 초기 설정
    slack_message = {"text": ""}
    
    if detail_type == "Object Created":
        object_size = event['detail']['object']['size']
        slack_message["text"] = "A new object has been created in S3"
        slack_message["attachments"] = [
            {
                "text": f"Bucket Name: {bucket_name}\nObject Key: {object_key}\nObject Size: {object_size} bytes"
            }
        ]
    else:
        slack_message["text"] = "Unknown S3 operation"
    
    # Slack 웹훅을 통해 메시지 전송
    response = requests.post(
        webhook_url, data=json.dumps(slack_message),
        headers={'Content-Type': 'application/json'}
    )
    
    if response.status_code != 200:
        print(f"Failed to send slack message. Status Code: {response.status_code}, Reason: {response.text}")
        
    return {
        'statusCode': 200,
        'body': json.dumps('Slack message sent')
    }

위 코드를 동작시키려면 람다의 환경변수에 SLACK_WEBHOOK_URL을 설정해줘야 하고, requests 모듈을 사용할 수 있도록 lambda layer를 추가해줘야 합니다.
layer를 추가하는 방법은 이 문서를 읽고 따라하시면 됩니다.
(주의할 점이 있는데, 레이어에 등록할 zip 파일의 이름은 반드시 python.zip 이어야 합니다. 그렇지 않으면 lambda에서 인식을 못합니다.)
slack webhook url을 만드는 방법은 이 문서를 참고하세요

동작 확인

위의 모든 과정을 따라하면, 지정한 버킷에 오브젝트를 등록할 시 아래와 같이 메시지가 전송됩니다.

aws event alert라는 이름과 이미지는 제가 별도의 설정을 통해 변경한 것 입니다.

정리

지금까지 EventBridge와 Lambda를 사용해 S3에 객체가 저장됐을 때 슬랙으로 알림을 받는 법을 알아봤습니다.
EventBridge는 s3뿐만 아닌 다른 aws 이벤트도 쉽게 추적할 수 있으므로 잘 알아두면 좋은 도구인 것 같습니다.

읽어주셔서 감사합니다.

0개의 댓글