본문 바로가기

AWS

[Lambda] AWS에서 발생하는 Event를 Slack으로 알림 받기

반응형

Account 내에서 IAM User 생성 및 삭제가 발생할 경우 관리자에게 Slack 메시지를 보내는 방법에 대해서 정리하였다.

Slack Message 포매팅 및 전반적으로 수정할 부분이 많지만 처음으로 Slack과의 Message 연동을 한 과정이기 때문에 점차 개선되는 과정을 별도로 정리해볼 예정이다.

 

AWS와 같은 Public Cloud는 모두 API CALL에 의해 동작이 수행되고 감시된다.

⇒ Security Group의 변경, 삭제, 생성은 물론 EC2, RDS, .. 모든 이벤트가 감시된다. 이런 Event가 발생하면 해당 Event 내용을 Lambda로 Trigger하고 Lambda에서 Event를 받아 내용을 Parsing 한 다음에 Slack API를 사용하여 Message를 보낼 수 있다.

 

Slack API를 사용하는 방법은 여러가지가 있다.

  1. HOOK_URL을 받아서 해당 HOOK_URL, CHANNEL로 Message를 POST 하기
  2. SLACK BOT을 발급받아 TOKEN 값으로 인증받은 뒤 특정 CHANNEL ID를 기입하여 POST하거나 Scheduling하여 Bot을 호출하기
  3. SLACK Slash를 활용하여 특정 Event가 발생하면 Slack으로 Message를 보내고 '수락', '거부' 등 REST API를 호출하기 ⇒ 수락을 누르면 어떤 Action을 취할지, 거부를 누르면 어떤 Action을 취할지 정의는 API GATEWAYLAMBDA를 연동하여 간단히 수행할 수 있다.

공부하면 좋은 내용들

JSON 유연하게 다루기

CloudWatch 구독 필터를 걸어 Lambda로 보내기

AWS에서 발생하는 Event들을 어떻게 다룰 수 있는지 이해하기

Requests 등 HTTP Method를 Python에서 다루는 방법

Slack에서 Message 포매팅 이해하고 자유자재로 활용하기

AWS Lambda 좀 더 잘 활용하는 방법 공부하기

 

다양한 패턴들

CloudWatch 경보 → SNS → Lambda

CloudTrail -> CloudWatch Rules → SNS → Lambda

CloudWatch Logs → 구독 필터 → Lambda

 

 

전체적인 과정 정리

 

1. CloudTrail : AWS 상에서 발생하는 모든 API Event를 감시하는 서비스이다.

⇒ AWS와 같은 Public Cloud는 모든 행위가 API CALL에 의해 동작되고 제어된다. 즉, IAM User를 생성하고 삭제하는 행위도 API에 의해 제어됨을 확인할 수 있다.

 

2. CloudWatch Rules : 말 그대로 '규칙'을 정하는 서비스이다.

  1. 특정 Event가 발생할 경우 다른 서비스를 트리거하거나
  2. Cron을 수행하여 다른 서비스를 트리거하거나

를 수행할 수 있다. 여기에서는 CloudTrail에서 발생하는 IAM 이벤트를 감시하여 Lambda를 트리거하도록 해준다.

 

3. Lambda : Serverless 서비스로 별도의 컴퓨팅 리소스 없이 Code만으로 로직을 수행할 수 있도록 도와주는 서비스이다.

⇒ Event가 발생하면 Event 내용을 받아 각각 원하는 내용을 Parsing하고 이를 Slack API를 활용하여 Slack message를 보내주게 된다.

 

주의 사항

IAM은 Global 리소스이기 때문에 버지니아 리전에서 Lambda 및 CloudWatch Rule을 생성해야 한다.

이와 유사하게 CloudFront - ACM 또한 버지니아 리전에서 작업해야 하는 이유가 이 때문이다.

(이를 잊고 Seoul 리전에서 작업했다가 계속 Event가 안오길래 많이 해맸었음)

 

 

과정

1. CloudTrail 추적 활성화

IAM 관련 API 이벤트는 CloudTrail을 통해서만 확인할 수 있다.

 

2. Amazon EventBridge - Rules 생성

 

IAM : CreateUser, DeleteUser 이벤트가 발생하면 Lambda를 호출하도록 하였다.

 

3. Lambda 생성

간단한 Lambda 함수 작성하였음

import boto3
import json
import logging
import os
   
from base64 import b64decode
from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError
   
# Get values from Environments variables
SLACK_CHANNEL = os.environ['SLACK_CHANNEL']
HOOK_URL = os.environ['HOOK_URL']
   
logger = logging.getLogger()
logger.setLevel(logging.INFO)

def send_message(message):

    req = Request(HOOK_URL, data = json.dumps(message).encode('utf-8'))

    try:
        response = urlopen(req)
        response.read()
        logger.info("Message posted to %s", SLACK_CHANNEL)
    except HTTPError as e:
        logger.error("Request failed: %d %s", e.code, e.reason)
    except URLError as e:
        logger.error("Server connection failed: %s", e.reason)

   
def lambda_handler(event, context):

    person_who_ferformed = event['detail']['userIdentity']['userName']      # 누가 행했는지
    event_time = event['detail']['eventTime']                               # 언제 행했는지
    event_name = event['detail']['eventName']                               # 어떤 이벤트인지?
    source_ip = event['detail']['sourceIPAddress']                          # 소스 아이피
    iam_user = event['detail']['requestParameters']['userName']             # 사용자 이름
    
    logger.info("Event        : " + str(event))
    logger.info("SLACK Channel: #" + SLACK_CHANNEL)
    logger.info("HOOK URL     : " + HOOK_URL)

    color = "#eb4034" if event_name.find("delete") >= 0 else "#0c3f7d"

    slack_message = {
        "channel": SLACK_CHANNEL,
        "attachments": [{
            "color": color,
            "blocks": [
            {
                "type": "section",
                "fields": [
                    {
                        "type": "mrkdwn",
                        "text": '*이벤트 이름:*\n' + event_name
                    },
                    {
                        "type": "mrkdwn",
                        "text": '*이벤트 시간:*\n' + event_time
                    }
                ]
            }
            ]
        }],
        "blocks": [
            {
            "type": "section",
            "text": {
                "type": "mrkdwn",
                "text": '소스 IP: *' + source_ip + '*, 수행자: *' + person_who_ferformed + '*\n사용자: *' + iam_user + '* 에게 *' + event_name + '* 이벤트가 발생하였습니다.'
            }
            },
            {
            "type": "divider"
            }
        ]
    }
    
    send_message(slack_message)

 

환경 변수 설정

HOOK_URL, SLACK_CHANNEL을 환경 변수로 등록하고

Python에서는 os 모듈을 활용하여 os.environ.get('#####')등의 형식으로 환경 변수를 가져와주었다.

 

누군가 IAM 계정을 생성하거나 삭제하면 Slack으로 메시지 알림이 오게 된다.

 

 

AWS와 Lambda, Slack을 활용하여 이 외에 여러가지 많은 일들을 수행할 수 있을 것 같다.

 

다음엔 CloudWatch Logs에서 발생하는 특정 Message를 구독 필터를 걸어서 Lambda에서 처리하고 Slack으로 보내는 방법에 대해 정리해볼 예정

 

반응형