step1. github action으로 ecr에 image가 업로드됨
step2. cloudtrail 로그 탐지하여 lambda 실행되어 slack noti
step3. slack noti의 버튼을 클릭하면 api gateway를 호출함
step4. api gateway에 연결되어있는 lambda가 실행됨
앱 추가로 수신 웹훅을 사용하면 보낸 noti의 버튼 요청을 설정하지 못한다.
아래 링크에서 별도로 앱 생성해야한다
생성한 앱에서 웹훅을 추가
해당 앱으로 noti가 발생했고 버튼을 눌렀을때, 어떤동작을 할지 아래 부분에 추가해준다.
import json
import boto3
import os
import urllib3
import logging
# logger setting
logger = logging.getLogger()
logger.setLevel(logging.INFO)
SLACK_CHANNEL = os.environ['slack_channel']
HOOK_URL = os.environ['hook_url']
http = urllib3.PoolManager()
def send_message(message):
data = json.dumps(message).encode('utf-8')
res = http.request(
method='POST',
url=HOOK_URL,
body=data
)
print(res.data, res.status)
def lambda_handler(event, context):
logger.info(json.dumps(event))
iam_event = json.loads(event.get('Records')[0].get('Sns').get('Message'))
# Check if it's an ECR image upload event
if iam_event['detail']['eventName'] == 'PutImage' and ('<ECR image_name>' in iam_event['detail']['requestParameters']['imageTag']) :
# Send notification to Slack with a button to invalidate CloudFront
slack_message = {
"channel":SLACK_CHANNEL,
"text": "New ECR image uploaded!",
"attachments": [
{
"text": "Invalidate CloudFront?",
"callback_id": "<distribution-id>",
"actions": [
{
"name": "invalidate_cloudfront",
"text": "Invalidate CloudFront",
"type": "button",
}
]
}
]
}
send_message(slack_message)
import json
import boto3
import os
import logging
import urllib3
import time
team_id = os.environ['team_id']
channel_id = os.environ['channel_id']
token = os.environ['token']
check_id = os.environ['distribution']
error_message = "Access denied"
cloudfront = boto3.client('cloudfront')
# logger setting
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event, context):
logger.info(json.dumps(event))
distribution_id = event['callback_id']
if check_id != distribution_id:
return {
"statusCode": 403,
"body": error_message
}
if team_id != event['team']['id']:
return {
"statusCode": 403,
"body": error_message
}
if channel_id != event['channel']['id']:
return {
"statusCode": 403,
"body": error_message
}
if token != event['token']:
return {
"statusCode": 403,
"body": error_message
}
try:
response = cloudfront.create_invalidation(
DistributionId=distribution_id,
InvalidationBatch={
'Paths': {
'Quantity': 1,
'Items': [
'/*'
]
},
"CallerReference": str(time.time()).replace(".", ""),
}
)
#print(response)
except Exception as e:
print(f"Failed to invalidate CloudFront: {str(e)}")
return {
"statusCode": 500,
"body": "Failed to invalidate CloudFront"
}
return { "statusCode": 200,
"body": "invalidation initiated successfully!" }
Github action 완료
ECR image upload를 탐지하여 Slack으로 noti
버튼 클릭시 무효화 실행하고 return값으로 noti값이 편집됨