ばーろぐわにる

SIerからWEB系?インフラエンジニアにジョブチェンジした見習いの備忘録

ALB作成時にパラメータを自動設定するLambda関数つくった

なにこれ

CLBからALBの移行をしてて、結構な数のALBが作成されたのだけどアクセスログやConnection Drainingのタイムアウトを1台づつ設定するのはめんどくさい。そこでALBとTargetGroupが作成されたときCloudWatch Eventsで発火して、Lambda関数で自動設定できる仕組みを作ってみた。今回は以下項目を自動設定してくれるように作成した。

  • 削除保護: 有効化
  • アクセスログ
  • 登録解除の遅延(Connection Draining) : 60秒
    • システムによるだろうけどデフォルト300秒って長くない?

Lambda関数

コード

import boto3
import os
import logging

# constant
timeout           = os.environ.get('CONNECTION_DRAINING_TIMEOUT')
bucket            = os.environ.get('TARGET_S3_BUCKET_NAME')
is_prod_env       = os.environ.get('IS_PRODUCTION_ENV') # Set "True" if production env

# initialize
client  = boto3.client('elbv2')
logger  = logging.getLogger()
logger.setLevel(logging.INFO)


def lambda_handler(event, context):
    event_name = event['detail']['eventName']

    if event_name == 'CreateLoadBalancer':
        if is_prod_env == "True":
            setup_alb_attributes(event)
    elif event_name == 'CreateTargetGroup':
        setup_tg_attributes(event)
    else:
        logger.error("unexpected event: {}".format(event_name))
        return False

    return True


def setup_alb_attributes(event):
    elb_count = len(event['detail']['responseElements']['loadBalancers'])

    for n in range(0, elb_count):

        elb_arn  = event['detail']['responseElements']['loadBalancers'][n]['loadBalancerArn']
        elb_name = event['detail']['responseElements']['loadBalancers'][n]['loadBalancerName']

        try:
            client.modify_load_balancer_attributes(
                LoadBalancerArn = elb_arn ,
                Attributes=[
                    {
                        'Key'  : 'deletion_protection.enabled',
                        'Value': 'true'
                    },
                    {
                        'Key'  : 'access_logs.s3.enabled',
                        'Value': 'true'
                    },
                    {
                        'Key'  : 'access_logs.s3.prefix',
                        'Value': elb_name
                    },
                    {
                        'Key'  : 'access_logs.s3.bucket',
                        'Value': bucket
                    }
                ]
            )
        except Exception as e:
            logger.error("Error: {}".format(e.args))
            return False

    return True


def setup_tg_attributes(event):
    tg_count = len(event['detail']['responseElements']['targetGroups'])

    for n in range(0, tg_count):
        tg_arn = event['detail']['responseElements']['targetGroups'][n]['targetGroupArn']

        try:
            client.modify_target_group_attributes(
                TargetGroupArn = tg_arn ,
                Attributes     = [
                    {
                        'Key'  : 'deregistration_delay.timeout_seconds',
                        'Value': timeout
                    }
                ]
            )
        except Exception as e:
            logger.error("Error: {}".format(e.args))
            return False

    return True

環境変数

f:id:oneal-desu:20190207194026p:plain

補足

  • 削除保護/アクセスログはALB、Connection DrainingはTargetGroupで設定が別れているのでイベント毎で処理も別れてる
  • アクセスログは本番環境以外だったら設定しねーわとかありそうなので環境変数で設定有無を変更できる
  • CloudTrailからイベントの中身をみていると event['detail']['responseElements']['loadBalancers'] は配列できてるので一応forで回してる
  • ALBって書いてるけど多分NLBでも設定できるはず。試してないけど
  • エラー処理は手抜き

CloudWatch Events

f:id:oneal-desu:20190207195423p:plain

感想

CloudWatch EventsでAPIコールでLambda起動のパターンを覚えるとあんなことやこんなことができそうで夢が膨らみます。時間さえあれば。

この規模であればAWSコンソールで直接作れるけど外部モジュール含めて作ろうとするとやっぱり大変そう。Lambdaでゴリゴリ開発するにはAWS SAM or Serverless Frameworkは必須な気がします。本番環境で導入しようとすると権限管理が非常にめんどくさそうだけど。