You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Boto3自动标记AWS实例:获取启动者IAM邮箱报错

问题描述

我想要获取启动AWS EC2实例的IAM用户邮箱和账号ID,并用这些信息给实例打标签。目前账号ID能正常获取,但获取IAM用户邮箱时一直报错。
这个Lambda函数由CloudWatch事件规则触发,当实例状态变为running时,会把实例ID传递给Lambda函数。

现有代码
import boto3

def lambda_handler(event, context):
  print(event)
  # 获取事件中的EC2实例ID
  instance_id = event['detail']['instance-id']
  
  # 获取账号ID
  sts_client = boto3.client('sts')
  identity = sts_client.get_caller_identity()
  account_id = identity['Account']
  

  # 给EC2实例打上邮箱和账号ID标签
  ec2 = boto3.client('ec2')
  # 描述实例以获取IAM角色ARN
  response = ec2.describe_instances(InstanceIds=[instance_id])
  iam_role_arn = response['Reservations'][0]['Instances'][0]['IamInstanceProfile']['Arn']
  
  # 获取IAM客户端
  iam = boto3.client('iam')
  
  # 从IAM角色ARN中提取角色名称
  role_name = iam_role_arn.split('/')[1]
  
  # 获取角色详情
  role_details = iam.get_role(RoleName=role_name)
  
  # 从角色详情中获取策略ARN
  policy_arn = role_details['Role']['AssumeRolePolicyDocument']['Statement'][0]['Principal']['AWS'][0]
  
  # 获取策略详情
  policy_details = iam.get_policy(PolicyArn=policy_arn)
  
  # 从策略详情中获取用户ARN
  user_arn = policy_details['Policy']['UserName']
  
  # 获取用户详情
  user_response = iam.get_user(UserName=user_arn)
  
  # 从用户详情中获取用户邮箱
  user_email = user_response['User']['UserName']
  
  ec2.create_tags(
      Resources=[instance_id],
      Tags=[
          {
              'Key': 'Email',
              'Value': email
          },
          {
              'Key': 'AccountID',
              'Value': user_email
          }
      ]
  )
问题分析与修复方案

原代码中的核心错误

  1. 变量引用混乱:打标签时用了未定义的email变量,且AccountID标签错误地使用user_email作为值,应该用获取到的account_id。
  2. IAM用户邮箱逻辑错误:
    • 实例关联角色的信任策略Principal.AWS不一定是IAM用户,可能是账号根用户、其他角色或服务主体,直接取这个作为用户ARN完全错误。
    • get_policy返回的Policy对象不存在UserName字段,这一行必然触发报错。
    • IAM用户的邮箱不会默认出现在get_user结果中,通常需要从用户标签或登录配置中读取。
  3. 获取启动用户的方式错误:通过实例关联角色反推启动用户的逻辑不成立,正确方式是查询CloudTrail记录的RunInstances事件,该事件会记录启动实例的调用者信息。

修正后的代码

以下是调整后的Lambda函数,通过CloudTrail查询启动实例的用户,并从用户标签中提取邮箱(需提前给IAM用户设置Email标签):

import boto3
from datetime import datetime, timedelta

def lambda_handler(event, context):
    print(event)
    instance_id = event['detail']['instance-id']
    
    # 获取账号ID
    sts_client = boto3.client('sts')
    identity = sts_client.get_caller_identity()
    account_id = identity['Account']
    
    # 初始化CloudTrail客户端,查询启动实例的事件
    cloudtrail = boto3.client('cloudtrail')
    start_time = datetime.utcnow() - timedelta(hours=1)
    end_time = datetime.utcnow()
    
    response = cloudtrail.lookup_events(
        LookupAttributes=[
            {'AttributeKey': 'ResourceName', 'AttributeValue': instance_id},
            {'AttributeKey': 'EventName', 'AttributeValue': 'RunInstances'}
        ],
        StartTime=start_time,
        EndTime=end_time,
        MaxResults=1
    )
    
    if not response['Events']:
        print(f"未找到启动实例{instance_id}的RunInstances事件")
        return
    
    # 提取调用者用户名
    caller_arn = response['Events'][0]['Username']
    user_name = caller_arn.split('/')[-1]
    
    # 获取IAM用户详情及标签
    iam = boto3.client('iam')
    user_response = iam.get_user(UserName=user_name)
    user_tags = user_response['User'].get('Tags', [])
    
    # 从标签中获取邮箱,无标签则用用户名作为备选
    user_email = None
    for tag in user_tags:
        if tag['Key'] == 'Email':
            user_email = tag['Value']
            break
    user_email = user_email or user_name
    
    # 给实例打标签
    ec2 = boto3.client('ec2')
    ec2.create_tags(
        Resources=[instance_id],
        Tags=[
            {'Key': 'Email', 'Value': user_email},
            {'Key': 'AccountID', 'Value': account_id}
        ]
    )
    
    print(f"成功给实例{instance_id}打标签:Email={user_email}, AccountID={account_id}")

必要配置说明

  • Lambda权限:需为Lambda角色添加以下权限:
    • sts:GetCallerIdentity
    • cloudtrail:LookupEvents
    • iam:GetUser
    • ec2:CreateTags
  • CloudTrail启用:确保账号已启用CloudTrail,且覆盖实例所在区域
  • IAM用户标签:提前给IAM用户添加Email标签,否则会用用户名作为邮箱备选值

内容的提问来源于stack exchange,提问作者toluwalase adedotun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 16:25:19