- 公開日
- 最終更新日
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つのタグキーが付いているかが評価されます。
手動対応の辛さ
対応としては以下の手順が必要でした:
- アラート対象のEIPを確認
- EIPに関連付けられたENIを特定
- ENIに関連付けられたセキュリティグループから対象のALBを判断
- ALBのタグ値を確認
- 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」)。
構成図

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」イベントの検知に必要)
処理の流れ(詳細)
- ALBの作成やスケーリングに伴い、EIPが新規確保される
- AWS CloudTrailが「AllocateAddress」APIコールを記録
- Amazon EventBridgeがイベントを検知し、AWS Lambdaを起動
- 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インフラ基盤の構築・運用およびセキュリティガイドラインの策定や管理を担当しています。 オンプレミスからクラウドまで、インフラを幅広い視点で捉えることを大切にしています。 また最近は定型的な手動作業を自動化することにも力を入れており、日々の運用改善に取り組んでいます。