Justin의 개발 로그
article thumbnail

AWS CloudWatch Alarm 을 설정해서 경고가 발생하면 Slack 으로 통지 받는 설정 방법을 정리했습니다.

 

 

1. 준비하기

 

 - Slack WebHook URL 생성 

    > https://<your-team-domain>.slack.com/services/new 에 접속해서 'incomming webhooks' 검색합니다.

    > Add Configuration을 통해서 Webhook URL을 하나 생성합니다. 잘 가지고 있다가 Lambda에서 사용합니다.

 

 

 

 

 

 

 

 

 

 

2. CloudWatch Alarm 생성

 

 - 여러 Metric 중에서 원하는 것을 생성하고 Define Alarm 에서 Actions에 Send notification to 설정을 합니다.

 - Send notification to에는 SNS topic을 선택하면 되는데 기존에 생성된 것이 없는 경우에는 New list를 통해서 생성합니다.

 

 

 - 생성된 SNS topic은 AWS SNS(Simple Notification Service)에서 확인이 가능합니다. 

 - Lambda 설정이 끝나면 해당 Topic에 Subscribe로 추가해야 합니다. (아래에서 다시 다룸)

 

 

 

 

 

 

 

 

3. Lambda 함수 생성 및 설정

 

 - Lambda 함수를 하나 생성합니다. Blueprints 중에서 적절한 것을 선택하면 됩니다. slack으로 검색하면 편리하게 선택 가능합니다.

 

 

 - 선택해서 넘어가면 몇 가지 설정이 있는데요. Role은 없으면 하나 생성하세요. IAM에서 직접 생성하시거나 함수 생성하는 과정에서 Custom으로 생성하시면 됩니다. SNS topic은 CloudWatch에서 알람 생성할 때 생성한 SNS topic을 선택하면됩니다.

 

 

 - 쭉 내려보면 코드가 있고 Environment variables가 있습니다. 코드는 수정할 필요 없고 변수만 채워주면 됩니다. slackChannel은  webhook url 만들 때 선택한 채널 이름을 작성하면 됩니다. kmsEncryptedHookUrl은 webhook url을 암호화해서 입력하면 됩니다.



 

 

AWS Slack Notification 설정

 

암호화 값을 만들려면 키가 필요합니다. 

키를 만든 후에는 aws kms encrypt 명령어를 이용하거나, 아래 이미지처럼 Lamda 설정 화면에서도 암호화 값을 만들 수 있습니다.

둘 중에 편한 방법을 사용하세요.

##처음 한번만 생성하면 됨 (이미 생성했으니 주석 처리)
#aws kms create-key —region ap-northeast-2
{생성된 키 잘 보관할 것}

#한번만 Alias 설정하면 됨
aws kms create-alias --alias-name "alias/pmokey" --target-key-id "a37???7-5291-4???????" --region ap-northeast-2

#암호화
aws kms encrypt --key-id alias/pmokey --plaintext “hooks.slack.com/services/TF?????/BFT????FB5/4MF3q9u7??????”
{
    "CiphertextBlob": "AQI????b3D1xcPxZICOLArr6u/1ZQmcn???????",
    "KeyId": "arn:aws:kms:ap-northeast-2:8062??8???:key/a???68-9d8a-4b??????"
}

slackChannel : #을 제외하고 입력하세요. 위의 캡처는 이름을 잘 못 입력했을 때 캡처한...

kmsEncryptedHookUrl은 https:// 를 제외한 WebHookUrl의 뒷 부분만 입력하세요. 이유는 Lambda 함수의 Python 소스를 보시면 이해 됩니다.

 

 

 

 Lambda 에서 기본 제공하는 Hello World로 테스트

 

테스트 실패

테스트에 사용된 전문을 아래와 같이 CloudWatch 전문에 맞춰야 테스트에 성공함

  
{
  "Records": [
    {
      "EventSource": "aws:sns",
      "EventVersion": "1.0",
      "EventSubscriptionArn": "arn:aws:sns:eu-west-1:000000000000:cloudwatch-alarms:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "Sns": {
        "Type": "Notification",
        "MessageId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
        "TopicArn": "arn:aws:sns:eu-west-1:000000000000:cloudwatch-alarms",
        "Subject": "ALARM: \"Example alarm name\" in EU - Ireland",
        "Message": "{\"AlarmName\":\"Example alarm name\",\"AlarmDescription\":\"Example alarm description.\",\"AWSAccountId\":\"000000000000\",\"NewStateValue\":\"ALARM\",\"NewStateReason\":\"Threshold Crossed: 1 datapoint (10.0) was greater than or equal to the threshold (1.0).\",\"StateChangeTime\":\"2017-01-12T16:30:42.236+0000\",\"Region\":\"EU - Ireland\",\"OldStateValue\":\"OK\",\"Trigger\":{\"MetricName\":\"DeliveryErrors\",\"Namespace\":\"ExampleNamespace\",\"Statistic\":\"SUM\",\"Unit\":null,\"Dimensions\":[],\"Period\":300,\"EvaluationPeriods\":1,\"ComparisonOperator\":\"GreaterThanOrEqualToThreshold\",\"Threshold\":1.0}}",
        "Timestamp": "2017-01-12T16:30:42.318Z",
        "SignatureVersion": "1",
        "Signature": "Cg==",
        "SigningCertUrl": "https://sns.eu-west-1.amazonaws.com/SimpleNotificationService-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.pem",
        "UnsubscribeUrl": "https://sns.eu-west-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:eu-west-1:000000000000:cloudwatch-alarms:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
        "MessageAttributes": {}
      }
    }
  ]
}

 

 

그래도 Test에 실패하면, 복호화 권한이 없기 때문에...

 

Lambda용 Role을 찾아서 아래 권한을 정책에 추가해 준다.

 

더보기

 

 

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "logs:CreateLogGroup",
            "Resource": "arn:aws:logs:ap-northeast-2:806122578816:*"
        },

        {
            "Effect": "Allow",
            "Action": "kms:Decrypt",
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:ap-northeast-2:806122578816:log-group:/aws/lambda/notification2slack4cloudwatch:*"
            ]
        }
    ]
}

 

 

 

 

그래도 안되면....

 

람다 함수 소스를 아래 소스로 변경 후 

람다 환경변수(environment variables)에 WEB_HOOK 값을 셋팅하세요. 

암호화 필요 없고, https://블라블라 넣으시면 됩니다.

즉, FullURL로 셋팅 (Slack WebHookUrl이 소스에 노출되는 단점이 있습니다.)

import boto3
import json
import logging
import os

from base64 import b64decode
from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError


# Change kmsEncryptedHookUrl to HOOK_URL
HOOK_URL = os.environ['HOOK_URL']
# The Slack channel to send a message to stored in the slackChannel environment variable
SLACK_CHANNEL = os.environ['slackChannel']


logger = logging.getLogger()
logger.setLevel(logging.INFO)


def lambda_handler(event, context):
    logger.info("Event: " + str(event))
    message = json.loads(event['Records'][0]['Sns']['Message'])
    logger.info("Message: " + str(message))

    alarm_name = message['AlarmName']
    #old_state = message['OldStateValue']
    new_state = message['NewStateValue']
    reason = message['NewStateReason']

    slack_message = {
        'channel': SLACK_CHANNEL,
        'text': "%s state is now %s: %s" % (alarm_name, new_state, reason)
    }

    req = Request(HOOK_URL, json.dumps(slack_message).encode('utf-8'))
    try:
        response = urlopen(req)
        response.read()
        logger.info("Message posted to %s", slack_message['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)

 

 

Alarm을 받아서 Slack으로 통지하는 Lambda 함수는 준비가 끝났습니다.

CloudWatch 경고를 Lambda로 연결하는 내용은 다음 Post에서 이어서 다루도록 하겠습니다. 

profile

Justin의 개발 로그

@라이프노트

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!