Lambda & CloudWatchEvents & Slack에서 장기적으로 로그인하지 않은 IAM 사용자를 감지 및 통지

개요



AWS를 이용할 때는, 이용자마다 IAM 유저를 작성해, 작업을 진행하고 있다고 생각합니다만, IAM 유저가 어떻게 관리되고 있습니까? 
자신이 근무하고 있는 회사의 사내 기준에서는 정기적으로 계정(AWS라면 IAM 사용자가 됩니다)의 재고를 실시할 필요가 있습니다만, 실제로 각 AWS 계정마다 IAM의 재고를 제대로 관리되어 있을까 하면 솔직히 말해서 미묘하다는 느낌입니다.
IAM 사용자의 재고 기능은 AWS가 제공되지 않았기 때문에 이번에는 파이썬 학습도 겸하고 CloudWatch Events, Lambda, Slack을 사용하여 장기적으로 로그인하지 않은 IAM 사용자를 감지 통지하는 것과 같은 것을 만들어 보았습니다.
아직 파이썬을 공부하기 시작했기 때문에 코드 자체가 깨끗하지는 않지만 조금 여러분과 공유할 수 있으면 좋겠습니다.

사용할 수 있을 때까지의 흐름



Slack의 설정이나 Lambda의 작성 등의 작업이 있습니다만, 특히 어렵지는 않습니다. 아래의 흐름으로 합니다.
1. Slack측 설정(Incoming WebHooks 이용)
2. 로컬 환경에서 코드와 같은 준비 (Lambda에서 Slack으로 보내기 위해 slackweb 사용)
3. Lambda에 코드를 올려 정기적으로 실행하도록 설정
4. 실행 결과 확인

슬랙



Slack의 경우 설정하는 작업이 적습니다.
Custom Integrations Incoming WebHooks을 사용하여 Configurations를 만듭니다.
Lambda에서 보내는 채널 설정이나 Webhook URL을 기록해 두면 됩니다.

이미지적으로는 이런 화면이 됩니다.


로컬 환경에서 코드 준비



slackweb을 작업 디렉토리에 설치합니다. 이 예제에서는 check-iam-users를 작업 디렉토리로 만듭니다.
$ mkdir ~/check-iam-users

$ sudo pip install slackweb -t ./check-iam-users/

$ cd check-iam-users/ && ls
slackweb            slackweb-1.0.5-py2.7.egg-info

check-iam-users에 아래의 lambda용 python 코드의 Webhook 부분에 작성한 Incoming WebHooks URL을 기입해 작성한다.
덧붙여 아래의 예에서는, 90일 이상 로그인하지 않은 유저를 검출·통지하는 예입니다.

lambda_function.py
# -*- coding: utf-8 -*-
from __future__ import print_function
import boto3
import time
import calendar
import slackweb

print('Loading function')

# Webhook
Slack = slackweb.Slack(url="https://hooks.slack.com/services/T0HTZK5S4/******************z5w")

client = boto3.client('iam')

def lambda_handler(event, context):

    # Slack Message Attachments
    Attachments = []

    # 指定した日数以上ログインしていないユーザ
    Users = []

    # 日数を指定
    Days = 90
    Interval = 60 * 60 * 24 * Days
    print(Interval)

    # 現在の時刻を取得
    Now = time.time()
    print(Now)

    UsersList = client.list_users()
    for User in UsersList["Users"]:
        print(User)

        if str(User.get("PasswordLastUsed")) != 'None':
            PasswordLastUsedUnixTime = calendar.timegm(User["PasswordLastUsed"].utctimetuple())
            print(PasswordLastUsedUnixTime)

            if Now - PasswordLastUsedUnixTime > Interval:
                Info = {
                    "UserName" : User['UserName'],
                    "LastLogin" : str(User['PasswordLastUsed'])
                }
                Users.append(Info)
    print('######################')


    if len(Users) != 0:

        Attachments = [
            {"pretext": str(Days) + "日以上、ログインしていないユーザがあります!"}
        ]

        print(Users)
        for User in Users:
            print('######################')
            print(User["UserName"])
            print('######################')
            UserName = User["UserName"]
            PasswordLastUsed = User["LastLogin"]
            Text = "```IAMユーザ: " + UserName + "\n" + \
                    "LastLogin: " + PasswordLastUsed + "```"

            Attachment = {
                "text": Text,
                "color": "danger",
                "mrkdwn_in": ["text"]
            }
            Attachments.append(Attachment)

    else :
        Attachments = [
            {"pretext": "IAMユーザをログイン状況を確認しました.\n" + \
                        str(Days) + "日以上、ログインしていないユーザがありません!"}
        ]

    Slack.notify(attachments = Attachments)


소스 코드 zip화
$ zip -r src.zip lambda_function.py slackweb
  adding: lambda_function.py (deflated 59%)
  adding: slackweb/ (stored 0%)
  adding: slackweb/__init__.py (deflated 4%)
  adding: slackweb/__init__.pyc (deflated 28%)
  adding: slackweb/slackweb.py (deflated 60%)
  adding: slackweb/slackweb.pyc (deflated 54%)

Lambda 만들기



Lambda의 작성에 대해서는, 특히 상세하게 쓸 생각이 없습니다.

실행 결과



동작을 확인하기 위해 Lambda를 테스트하면 이미지 적으로 다음과 같은 messgae가 Slack으로 전송됩니다.

지정한 90일 이상 로그인하지 않은 IAM 사용자가 있는 경우
예약된 이벤트에서 AWS Lambda 사용

지정한 90일 이상 로그인하지 않은 IAM 사용자가 없는 경우


마지막



매우 엉망이지만 Lambda & CloudWatchEvents & Slack에서 장기적으로 로그인하지 않은 IAM 사용자를 감지 및 통지하는 것을 여러분과 공유했습니다.

구조가 대체로 동일합니다만, 다음은 장기적으로 이용되어 있지 않은 AccessKey를 검지·통지하는 것을 소개하고 싶습니다.

좋은 웹페이지 즐겨찾기