ENGINEER BLOG ENGINEER BLOG
  • 公開日
  • 最終更新日

ALBが自動確保するEIPにタグが付かない問題を、EventBridge + Lambdaで自動解決する

この記事を共有する

目次

はじめに

はじめまして、パーソル&サーバーワークスの松下です!

AWSを中心としたクラウドインフラの構築・運用を担当しています。
最近は日々の運用自動化に力を入れて取り組んでいます。

今回は、インターネット向けALBの作成やスケーリングに伴って確保されることがあるElastic IP アドレス(EIP)にタグが付かない問題を、AWS CloudFormationで自動化して解決した話をします。

何が問題だったのか

インターネット向けのApplication Load Balancer(ALB)では、ALBの作成やスケーリングに伴ってEIPが確保され、ALBのENI(Elastic Network Interface)に割り当てられることがあります。 このとき自動作成されたEIPにはタグが付与されません。

そのため、AWS Security Hub CSPMの「AWS Resource Tagging Standard v1.0.0 - EC2.37」でチェックに引っかかり、アラートが発生してしまいます。

EC2.37で「requiredTagKeys」を指定している場合は、その値に本記事でコピーするタグキーと同じ名前を設定する必要があります。「requiredTagKeys」を指定していない場合は、少なくとも1つのタグキーが付いているかが評価されます。

手動対応の辛さ

対応としては以下の手順が必要でした:

  1. アラート対象のEIPを確認
  2. EIPに関連付けられたENIを特定
  3. ENIに関連付けられたセキュリティグループから対象のALBを判断
  4. ALBのタグ値を確認
  5. EIPに同じタグを手動で付与

新しいEIPが確保されるたびにこの作業が発生するため、自動化したいと考えました。

解決策:Amazon EventBridge + AWS Lambda で自動タグ付け

EIPが確保されたタイミングで自動的にALBの指定タグをコピーする仕組みを作りました。

仕組みの概要

1. Amazon EventBridge
AWS CloudTrail経由で「AllocateAddress」(EIP確保)イベントを検知します。

2. AWS Lambda
以下のロジックを実行します。

  • 確保されたEIPがALB管理(「ServiceManaged: alb」)かどうかを確認
  • 関連付けられたENIのDescriptionからALB名を特定(「ELB app/[alb-name]/[id]」形式)
  • ALBに付与されている指定タグの値を取得
  • 同じタグをEIPにコピー

コピーするタグキーはAWS CloudFormationのパラメーターで指定可能です(デフォルト:「Name」)。

構成図

eip-auto-tag.png

AWS CloudFormationテンプレート

以下のテンプレート1枚でデプロイできます。

eip-auto-tag.yaml(クリックで展開)

AWSTemplateFormatVersion: '2010-09-09'
Description: Auto-tag ALB-managed EIPs with specified tag from parent ALB
Parameters:
  TagKey:
    Type: String
    Default: Name
    Description: ALBからEIPにコピーするタグのキー名
Resources:
  LambdaRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: EipAutoTagPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - ec2:DescribeAddresses
                  - ec2:DescribeNetworkInterfaces
                  - ec2:CreateTags
                Resource: '*'
              - Effect: Allow
                Action:
                  - elasticloadbalancing:DescribeLoadBalancers
                  - elasticloadbalancing:DescribeTags
                Resource: '*'
              - Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource: arn:aws:logs:*:*:*
  TagEipFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: eip-auto-tag-from-alb
      Runtime: python3.12
      Handler: index.handler
      Timeout: 60
      Role: !GetAtt LambdaRole.Arn
      Environment:
        Variables:
          TAG_KEY: !Ref TagKey
      Code:
        ZipFile: |
          import boto3, time, os
          ec2 = boto3.client('ec2')
          elbv2 = boto3.client('elbv2')
          TAG_KEY = os.environ['TAG_KEY']
          def handler(event, context):
              alloc_id = event['detail']['responseElements']['allocationId']
              print(f"New EIP: {alloc_id}")
              for _ in range(6):
                  resp = ec2.describe_addresses(AllocationIds=[alloc_id])
                  addr = resp['Addresses'][0]
                  if addr.get('ServiceManaged') != 'alb':
                      print("Not ALB-managed, skipping")
                      return
                  if addr.get('NetworkInterfaceId'):
                      break
                  time.sleep(5)
              else:
                  raise RuntimeError("ALB-managed EIP is not yet associated; retrying")
              eni_id = addr['NetworkInterfaceId']
              eni = ec2.describe_network_interfaces(NetworkInterfaceIds=[eni_id])
              desc = eni['NetworkInterfaces'][0].get('Description', '')
              if not desc.startswith('ELB app/'):
                  print(f"ENI description not ALB pattern: {desc}")
                  return
              alb_name = desc.split('/')[1]
              albs = elbv2.describe_load_balancers(Names=[alb_name])
              alb_arn = albs['LoadBalancers'][0]['LoadBalancerArn']
              tags_resp = elbv2.describe_tags(ResourceArns=[alb_arn])
              tag_value = None
              for tag in tags_resp['TagDescriptions'][0]['Tags']:
                  if tag['Key'] == TAG_KEY:
                      tag_value = tag['Value']
                      break
              if not tag_value:
                  print(f"ALB {alb_name} has no {TAG_KEY} tag, skipping")
                  return
              ec2.create_tags(Resources=[alloc_id], Tags=[{'Key': TAG_KEY, 'Value': tag_value}])
              print(f"Tagged {alloc_id} with {TAG_KEY}={tag_value}")
  EventRule:
    Type: AWS::Events::Rule
    Properties:
      Name: eip-allocate-detect
      State: ENABLED
      EventPattern:
        source:
          - aws.ec2
        detail-type:
          - AWS API Call via CloudTrail
        detail:
          eventSource:
            - ec2.amazonaws.com
          eventName:
            - AllocateAddress
      Targets:
        - Arn: !GetAtt TagEipFunction.Arn
          Id: TagEipLambda
  LambdaPermission:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !Ref TagEipFunction
      Action: lambda:InvokeFunction
      Principal: events.amazonaws.com
      SourceArn: !GetAtt EventRule.Arn

前提条件

  • ALBにパラメーターで指定したタグキー(デフォルト:Name)のタグが付与されていること
  • AWS CloudTrailで書き込み管理イベントを記録する証跡が有効であること(「AllocateAddress」イベントの検知に必要)

処理の流れ(詳細)

  1. ALBの作成やスケーリングに伴い、EIPが新規確保される
  2. AWS CloudTrailが「AllocateAddress」APIコールを記録
  3. Amazon EventBridgeがイベントを検知し、AWS Lambdaを起動
  4. AWS Lambdaが処理を実行

AWS Lambdaの処理内容は以下です。

  • EIPの情報を取得
  • 「ServiceManaged」が「alb」かを確認し、ALB管理でなければスキップ
  • EIPから関連付けられたENIを確認し、ENIのDescriptionから「ELB app/[alb-name]/[id]」形式でALB名を抽出
  • ALBの指定タグの値を取得
  • EIPにALBと同じタグを付与

注意事項

  • ALB管理以外のEIP(手動確保など)は自動的にスキップされます
  • EIPのENI関連付けに時間がかかる場合に備え、5秒間隔で最大6回確認します
  • 待機中に関連付けが確認できなければ例外を発生させ、AWS Lambdaの非同期再試行に委ねます
  • ALBに指定タグが付いていない場合もスキップされます
  • EIPの作成からタグ付与までには時間差があるため、AWS Security Hub CSPMの評価タイミングによっては一時的に検出結果が発生する可能性があります
  • AWS Lambda関数名(「eip-auto-tag-from-alb」)とAmazon EventBridgeルール名(「eip-allocate-detect」)は固定です。
    必要に応じてデプロイ前にテンプレートの「FunctionName」と「Name」を環境に合わせて変更してください

まとめ

ALBが自動確保するEIPにタグが付かない問題は、AWS Security Hub CSPMのタグ付け標準を有効にしている環境では、継続的な手動対応による運用負荷につながります。Amazon EventBridgeとAWS Lambdaで自動化することで、手動対応を削減し、タグ不足による継続的な検出結果を抑制できます。

AWS CloudFormationテンプレート1枚でデプロイでき、タグキーもパラメーターで指定できます。同じ問題でお困りの方は、環境に合わせて試してみてください。

この記事は私が書きました

松下 千尋

記事一覧

株式会社パーソル&サーバーワークスの松下です! 以前はエンタープライズネットワーク(WAN/LAN)の設計・構築を担当し、 現在はお客様先でAWSインフラ基盤の構築・運用およびセキュリティガイドラインの策定や管理を担当しています。 オンプレミスからクラウドまで、インフラを幅広い視点で捉えることを大切にしています。 また最近は定型的な手動作業を自動化することにも力を入れており、日々の運用改善に取り組んでいます。

松下 千尋

この記事を共有する

クラウドのご相談

CONTACT

クラウド導入や運用でお悩みの方は、お気軽にご相談ください。
専門家がサポートします。

サービス資料ダウンロード

DOWNLOAD

ビジネスをクラウドで加速させる準備はできていますか?
今すぐサービス資料をダウンロードして、詳細をご確認ください。