[AWS]EC2のタグ付けLambdaをServerlessFrameworkで実装してみた


TL;DR

  • 検証環境など複数メンバーで利用していると、管理者不明のリソースが発生することがある。
  • LambdaでEC2起動時にタグ付けする解決策が一般的だと思うが、
    複数の環境/リージョンがあると都度登録するのも面倒。
  • ServerlessFramework を使って誰でも簡単に実装できるようにした。

※本稿ではServerlessFrameworkの導入手順は触れていないので
 導入方法は公式ドキュメントを参照してください。

1. Lambda関数の準備

  • 起動者の情報をタグ付けするLambda関数ファイル(コードは後述)を用意します。
  • 今回はIAMユーザーとAssumeRoleしているユーザーに対応させています。
handler.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import boto3
import logging
import os

# set the simple logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
region = os.environ['AWS_REGION']
account = os.environ['AWS_ACCOUNT']


def ec2_tagging(event, context):
    logger.info(event)

# Requestor Check
    userType = event['detail']['userIdentity']['type']
    if userType == 'IAMUser':
        Owner = event['detail']['userIdentity']['userName']
    elif userType == 'AssumedRole':
        roleID = event['detail']['userIdentity']['sessionContext']['sessionIssuer']['userName']
        Owner = (event['detail']['userIdentity']['arn'].replace("arn:aws:sts::" + str(account) + ":assumed-role/"+str(roleID)+"/", ""))
    logger.info("Owner: " + Owner)

# Target Resource Check
    instanceIDs = event['detail']['responseElements']['instancesSet']['items']
    logger.info(instanceIDs)
    instance_count = len(instanceIDs)
    try:
        for i in range(0, instance_count):
            instanceID = instanceIDs[i]['instanceId']
            logger.info("target: " + str(instanceID))
            ec2 = boto3.client('ec2')
            r = ec2.create_tags(
                Resources=[instanceID],
                Tags=[
                   {
                        'Key': 'Owner',
                        'Value': Owner
                    },
                ]
            )
    except Exception as e:
        logger.error("error: " + str(e))

2. Lambda実行用のIAM Role作成

  • Lambda実行に必要となる下記権限を有するIAMロールを準備します。
    • CloudwachLogへのログ書き込みの権限
    • EC2にタグを付与する権限
  {
      "Version": "2012-10-17",
      "Statement": [
          {
              "Action": [
                  "logs:CreateLogStream",
                  "logs:PutLogEvents"
              ],
              "Resource": [
                  "arn:aws:logs:*"
              ],
              "Effect": "Allow"
          },
          {
              "Action": [
                  "ec2:CreateTags"
              ],
              "Resource": [
                  "*"
              ],
              "Effect": "Allow"
          }
      ]
  }

3. serverless.ymlの作成

  • serverless.ymlでLambda関数の設定を定義しています。
  • Lambda関数ファイルがあるディレクトリにserverless.yml(内容は後述)を配置します。
  • 環境に応じて修正が必要なパラメータはcustomブロックにまとめましたので、
    AWS AccountIDやリージョン、手順2で作成したIAMロール名等を修正してください。
serverless.yml
service: ${self:custom.service}

provider:
  name: aws
  runtime: python3.6
  stage: ${opt:stage, self:custom.defaultStage}
  region: ${opt:region, self:custom.defaultRegion}
  memorySize: 128
  timeout: 60
  role: arn:aws:iam::${self:custom.account}:role/${self:custom.iam}
  environment:
    AWS_ACCOUNT: ${self:custom.account}

custom:
  account: hoge        ## AWS AccountIDを入力してください。
  defaultStage: dev
  defaultRegion: fuga  ## Regionを入力してください。(e.g.ap-northeast-1)
  description: EC2 Auto Tagging Function
  service: Ec2AutoTag
  iam: piyo            ## Lambdaを実行するIAM Role名を入力してください。

functions:
  Ec2AutoTag:
    name: ${self:custom.service}
    handler: handler.ec2_tagging
    description: ${self:custom.description}
    events:
      - cloudwatchEvent:
          event:
            source:
              - "aws.ec2"
            detail-type:
              - "AWS API Call via CloudTrail"
            detail:
              eventSource:
                - "ec2.amazonaws.com"
              eventName:
                - "RunInstances"

4. deploy

Lambda関数ファイルがあるディレクトリにてデプロイコマンド sls deployを実行するだけです。

$ ls -l
total 8
-rw-rw-r-- 1 ubuntu ubuntu 1453 Aug 29 02:56 handler.py
-rw-rw-r-- 1 ubuntu ubuntu 1012 Aug 29 03:00 serverless.yml
$
$ sls deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
.....
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service .zip file to S3 (774 B)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
...................
Serverless: Stack update finished...
Service Information
service: Ec2AutoTag
stage: dev
region: ap-northeast-1
stack: Ec2AutoTag-dev
api keys:
  None
endpoints:
  None
functions:
  Ec2AutoTag: Ec2AutoTag-dev-Ec2AutoTag

5. 確認

インスタンスを起動してみて、起動者のユーザー名が付与されることを確認できました。

6. 最後に

  • ServerlessFrameworkでLambdaの登録は簡単にできる。
  • StackSetに対応していれば、マルチリージョンに一度にデプロイできて、
    より便利に使えそう。(これから調査)

参考