如何用boto3通过资源ID(非ARN)获取AWS资源标签?
仅通过AWS资源ID获取标签的解决方案(无需为每个服务单独创建客户端)
我通过boto3调用CostExplorer的get_cost_and_usage_with_resources方法收集成本统计数据,该方法会返回资源的ID/ARN、使用量及成本信息。现在需要将这些数据与资源标签关联,但Resource Groups Tagging API的get_resources方法仅接受ARN列表,不支持直接传入资源ID(比如EC2卷ID:vol-0053852a4f079axxx),又不想为每个AWS服务单独创建boto3客户端,该如何处理?
尝试过的代码及报错
我直接用资源ID调用get_resources方法,代码如下:
import boto3 tag_client = boto3.client('resourcegroupstaggingapi') def get_resource_tags(resource_arn): response = tag_client.get_resources( ResourceARNList=[resource_arn] ) print(response) get_resource_tags("vol-0e6abc422806b0xxx")
得到报错:
botocore.errorfactory.InvalidParameterException: An error occurred (InvalidParameterException) when calling the GetResources operation: vol-0e6abc422806b0xxx is not a valid AmazonResourceName (ARN)
解决方案:通过资源ID构造ARN后调用Tagging API
AWS资源的ARN有固定格式,只要能从资源ID前缀识别出资源类型,就能拼接出对应的ARN,再用Tagging API获取标签。
1. 核心思路
- 从资源ID前缀判断资源类型(比如
vol-对应EBS卷,i-对应EC2实例) - 结合当前AWS账号ID、资源所在区域,构造符合格式的ARN
- 将构造好的ARN传入
get_resources方法获取标签
2. 实现代码
import boto3 def get_account_id(): """获取当前AWS账号ID""" sts_client = boto3.client('sts') return sts_client.get_caller_identity()['Account'] def get_default_region(): """获取当前boto3会话的默认区域""" session = boto3.Session() return session.region_name def construct_arn(resource_id, resource_region=None): """根据资源ID构造ARN,支持指定资源所在区域""" account_id = get_account_id() region = resource_region or get_default_region() # 根据ID前缀匹配资源类型,可扩展更多资源类型 if resource_id.startswith('vol-'): return f"arn:aws:ec2:{region}:{account_id}:volume/{resource_id}" elif resource_id.startswith('i-'): return f"arn:aws:ec2:{region}:{account_id}:instance/{resource_id}" elif resource_id.startswith('sg-'): return f"arn:aws:ec2:{region}:{account_id}:security-group/{resource_id}" elif resource_id.startswith('s3://'): # S3桶的ARN格式特殊,移除前缀后直接拼接 bucket_name = resource_id.replace('s3://', '') return f"arn:aws:s3:::{bucket_name}" elif resource_id.startswith('rds-'): return f"arn:aws:rds:{region}:{account_id}:db:{resource_id}" elif resource_id.startswith('lambda-'): return f"arn:aws:lambda:{region}:{account_id}:function:{resource_id}" else: raise ValueError(f"无法识别资源ID {resource_id} 的类型,请扩展资源类型判断逻辑") def get_resource_tags(resource_id, resource_region=None): """通过资源ID获取标签""" tag_client = boto3.client('resourcegroupstaggingapi') try: arn = construct_arn(resource_id, resource_region) response = tag_client.get_resources(ResourceARNList=[arn]) # 提取标签字典 if response['ResourceTagMappingList']: return {tag['Key']: tag['Value'] for tag in response['ResourceTagMappingList'][0]['Tags']} return {} except Exception as e: print(f"获取资源 {resource_id} 标签失败: {str(e)}") return {} # 测试:传入EBS卷ID print(get_resource_tags("vol-0e6abc422806b0xxx"))
3. 注意事项
- 区域问题:如果资源不在当前默认区域,需要从CostExplorer的响应中获取资源所在区域(
get_cost_and_usage_with_resources返回结果通常包含Region字段),传入construct_arn的resource_region参数。 - 特殊资源格式:S3桶、CloudFront分发等资源的ARN格式有差异,需要单独处理,可根据需求扩展
construct_arn中的判断逻辑。 - 权限:确保当前IAM角色/用户拥有
sts:GetCallerIdentity(获取账号ID)和tag:GetResources(获取标签)的权限。
内容的提问来源于stack exchange,提问作者Anton Serozhechkin
相关产品推荐
相关产品推荐

