본문 바로가기

Python/Boto3

AWS Lambda를 통해 현재 EC2 List를 SES로 받아보기

회사에서 운영을 하다보면, 늘 문서충이 되어야합니다.

 

EC2 서버에 대한 IP, 환경, 이름, Type까지는 기본적으로 항상 조사가 되어야하는 항목들입니다.

이것을 매번하는건 좋지 않을 듯 하여 만들어봤습니다.

 

먼저 SES SMTP 생성 및 인증을 해야합니다. 저는 버지니아리전에서 생성했습니다.

Create My SMTP Credentials를 한 후 기억해주세요

 

 

이제 Email Addresses에서 자신의 이메일을 등록해줍니다.

혹은 메일을 받아야 하는 분들을 등록해 주고, 링크가 가면 인증을 해달라고 말씀해주세요.

 

아까 만든 Credentials를 코드에 그냥 넣어서 좋을것은 없겠죠?

AWS Systems Manager 서비스에서 Parameter Store에 등록해주겠습니다.

이름에는 키 ID, 값에는 그냥 시크릿키 값을 바로 넣어서 사용하도록 하겠습니다.

 

 


 

이제 람다함수에서 SES 메일 전송 및 EC2 Describe에 관한 권한이 있어야합니다.

해당 롤을 만들어서 주겠습니다.

 

슬슬 제가 블로그 운영에 초심을 잃어 권한을 대충넣기 시작했지만..

꼭 필요한 아이들만 찾아서 정책을 만들어서 운영하시기를 권유드립니다.


자, 이제 람다함수를 만들어주도록 하겠습니다.

Pandas, Openpyxl 라이브러리가 필요합니다. 저는 엑셀로 뽑아서 받을것이기 때문이죠

다음 소스를 가지고 레이어를 만들어주겠습니다. 라고 할랬는데, 10MB 까지만 업로드가 가능하네요

참고로 Lambda Layer도 50MB 까지이니 용량이 크게 될 경우 분할해서 레이어를 구성해야 합니다.

여기 >> 구글드라이브 링크에서 다운로드하셔서 아래와 같이 레이어를 만들어주시면 됩니다.

 

 

 

자, 이제 람다 소스코드를 보도록 하겠습니다.

 

import os
import boto3
import smtplib
import datetime
import pandas as pd
from openpyxl import load_workbook
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
from openpyxl.styles import Font, Alignment, Border, Side, PatternFill, Color

def deco_cell(ws, cell, bold, horizon, color):
    box = Border(left=Side(border_style="thin", color='FF000000'),
                 right=Side(border_style="thin", color='FF000000'),
                 top=Side(border_style="thin", color='FF000000'),
                 bottom=Side(border_style="thin", color='FF000000'),
                 diagonal=Side(border_style="thin", color='FF000000'),
                 diagonal_direction=0, outline=Side(border_style="thin", color='FF000000'),
                 vertical=Side(border_style="thin", color='FF000000'),
                 horizontal=Side(border_style="thin", color='FF000000'))

    ws[cell].font = Font(name="맑은 고딕", size=10, bold=bold)
    ws[cell].alignment = Alignment(horizontal=horizon, vertical="center")
    if color != '':
        ws[cell].fill = PatternFill(patternType='solid', fgColor=Color(color))
    ws[cell].border = box

def deco_excel(save_path):
    wb = load_workbook(filename=save_path, read_only=False, data_only=False)
    ws = wb["EC2 List"]

    # ALL
    for each_row in ws.rows:
        for each_row_cell in each_row:
            cell = str(each_row_cell)[6:-1].split('.')[-1]
            if 'A' in cell or 'E' in cell:
                deco_cell(ws, cell, False, 'center', '')
            else:
                deco_cell(ws, cell, False, 'left', '')

    # Header
    for i in range(ord('A'), ord('F')):
        deco_cell(ws, chr(i) + str(1), True, 'center', 'c6e0b4')

    # ALL Width
    ws.column_dimensions['A'].width = 8
    ws.column_dimensions['B'].width = 30
    ws.column_dimensions['C'].width = 9
    ws.column_dimensions['D'].width = 12
    ws.column_dimensions['E'].width = 7.5
    wb.save(save_path)

def GetKey(name):
    ssm = boto3.client('ssm')
    response = ssm.get_parameter(Name=name, WithDecryption=True)
    key = response['Parameter']['Value']
    return key

def ses(RECIPIENT, save_path, year, month):
    SENDER = "phh129@lotte.net"
    SENDERNAME = 'EC2 List'
    # CC = ["phh129@lotte.net", "hyunho129@naver.com"]
    USERNAME_SMTP = "{SES SMTP ID}"
    PASSWORD_SMTP = GetKey('{SES SMTP ID}')

    HOST = "email-smtp.us-east-1.amazonaws.com"
    PORT = 587

    AWS_REGION = "us-east-1"
    SUBJECT = "LAMBDA AWS EC2 List Info"

    ATTACHMENT = save_path

    BODY_TEXT = "LAMBDA AWS EC2 List Info"

    BODY_HTML = """\
    <html>
    <head></head>
    <body>
    <h1> AWS EC2 List </h1>
    <p>멘트멘트멘트.</p><br><br>
    <p>""" + year + "년 " + month + """ 월 EC2 List 레포트 입니다.</p><br><br>
    <p>감사합니다.</p>
    </body>
    </html>
    """

    CHARSET = "UTF-8"
    msg = MIMEMultipart('alternative')
    msg['Subject'] = SUBJECT
    msg['From'] = SENDER
    # msg['CC'] = ", ".join(CC)
    msg['To'] = RECIPIENT

    part1 = MIMEText(BODY_TEXT, 'plain')
    part2 = MIMEText(BODY_HTML, 'html')
    msg.attach(part1)
    msg.attach(part2)
    att = MIMEApplication(open(ATTACHMENT, 'rb').read())
    att.add_header('Content-Disposition', 'attachment', filename=os.path.basename(ATTACHMENT))
    msg.attach(att)
    try:
        server = smtplib.SMTP(HOST, PORT)
        server.ehlo()
        server.starttls()
        server.ehlo()
        server.login(USERNAME_SMTP, PASSWORD_SMTP)
        server.sendmail(SENDER, RECIPIENT, msg.as_string())
        # server.sendmail(SENDER, CC, msg.as_string())
        server.close()
    except Exception as e:
        print("Error: ", e)
    else:
        print("Email sent!")

def lambda_handler(event, context):
    client = boto3.client('ec2', aws_access_key_id=event['access_key_id'], aws_secret_access_key=GetKey(event['access_key_id']))

    records = []
    ec2_list = client.describe_instances()
    for ec2 in ec2_list['Reservations']:
        ec2_info = ec2['Instances'][0]
        name = ''
        env = ''
        for tag in ec2_info['Tags']:
            if tag['Key'] == 'Name':
                name = tag['Value']
            elif tag['Key'] == 'Env':
                env = tag['Value']
        if env == '':
            env = 'TEMP'
        info = {"Ip": ec2_info['PrivateIpAddress'], "Type": ec2_info['InstanceType'], "Name": [name], "Env": [env]}
        records.append(info)

    os.chdir('/tmp')
    Name = []
    Type = []
    IP = []
    Env = []
    save_path = './' + event['account'] + '_EC2_List.xlsx'
    now = datetime.datetime.now()
    year = now.strftime('%Y')
    month = now.strftime('%m')

    if os.path.isfile(save_path):
        os.remove(save_path)

    for record in records:
        if not record['Env']:
            env = 'Empty'
        else:
            env = str(record['Env'][0])
        Name.append(str(record['Name'][0]))
        Type.append(str(record['Type']))
        IP.append(str(record['Ip']))
        Env.append(env)

    df = pd.DataFrame({'Name': Name, 'Type': Type, 'IP': IP, 'Env': Env})
    df = df.sort_values(['Env', 'Type'], ascending=[True, True])
    df = df.reset_index(drop=True)
    df.to_excel(save_path,sheet_name='EC2 List')
    deco_excel(save_path)
    ses(event['send_mail'], save_path, year, month)

 

으 별거없는데 길어서 설명하기 싫지만 해야겠죠

 

deco_cell은 openpyxl에서 엑셀을 색깔이나 폰트 등 수정을 하려면 셀마다 하나하나 스타일을 입혀줘야합니다.

따라서 이 부분을 구성한 것이고, 색깔이나 이러한 부분들은 마음에 안 드실 경우 수정하시면 됩니다.

 

deco_excel은 셀 하나하나 꾸미는 deco_cell을 콜해서 문서 전체를 이쁘게 만들어주는 함수입니다.

이쁘게 만들어야 할 경우 열심히 보시고, 아니라면 크게 보시지 않아도 되는 부분입니다.

 

GetKey함수는 아까 만들었던 Parameter Store에서 값을 가져와서 넣는 부분으로

저는 주로 소스코드에 직접 키값을 넣는게 꺼려질 경우 위와 같이 구성하여서 사용합니다.

 

ses는 boto3 ses메일 보내는 것이기 때문에 다큐먼트 보시면 될 것 같고, CC를 넣으셔야 할 경우 주석을 모두 풀어주세요

 

메인 람다에서는 describe instances를 하여 정보를 가져온 후 리스트에 넣습니다.

해당 리스트를 pandas의 dataframe으로 만들어서 엑셀파일을 /tmp 경로에 만들어 준 후

deco_excel로 이쁘게 만들어서 ses 메일로 보내는것 까지 입니다.

 

크게 어려운 코딩 부분은 없으니 잘 활용해서 사용하시면 되겠습니다.

구성하여 테스트 할 때, 저는 아래와 같이 파라미터를 만들어서 람다를 호출합니다.

{
  "account": "프로젝트 명",
  "access_key_id": "해당 프로젝트 ec2 권한이 있는 IAM Access Key",
  "send_mail": "받는 사람 이메일"
}

다음 포스트에서는 Security Group List를 받아보도록 하겠습니다.