如何用Python和BOTO3跨关联AWS账号扮演角色列出设备及IP
跨AWS账号获取资源IP地址的Python+Boto3实现方案
我来帮你搞定这个跨账号拉取设备IP的需求!核心思路就是先通过角色切换获取目标账号的临时凭证,再用这些凭证调用对应AWS服务的API提取IP信息,下面一步步给你拆解:
一、先搞定跨账号角色的信任配置
首先得确保每个目标AWS账号里都有一个可被你的发起账号扮演的IAM角色,这个角色需要:
- 信任策略里允许你的发起账号的ARN(或者IAM用户/角色ARN)来扮演它
- 权限策略里至少包含
ec2:DescribeInstances、elasticloadbalancing:DescribeLoadBalancers、elasticloadbalancing:DescribeTargetGroups这些必要权限(根据你要拉的资源类型调整)
比如目标账号角色的信任策略可以写成这样:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::发起账号ID:root" // 或者更细粒度的IAM用户/角色ARN }, "Action": "sts:AssumeRole" } ] }
二、编写角色切换的通用函数
用Boto3的sts客户端来获取临时凭证,之后用这个凭证创建对应服务的客户端:
import boto3 def assume_role(target_account_id, role_name): """获取目标账号的临时凭证,返回可用于创建客户端的session""" sts_client = boto3.client('sts') role_arn = f"arn:aws:iam::{target_account_id}:role/{role_name}" try: response = sts_client.assume_role( RoleArn=role_arn, RoleSessionName="CrossAccountIPCollector" ) # 创建带临时凭证的session session = boto3.Session( aws_access_key_id=response['Credentials']['AccessKeyId'], aws_secret_access_key=response['Credentials']['SecretAccessKey'], aws_session_token=response['Credentials']['SessionToken'] ) return session except Exception as e: print(f"切换到账号{target_account_id}的角色{role_name}失败: {str(e)}") return None
三、针对不同资源类型提取IP
接下来针对你关心的资源(EC2、ELB等)写具体的IP获取逻辑:
1. EC2实例的公网/内网IP
def get_ec2_ips(session): """获取EC2实例的IP信息""" ec2_client = session.client('ec2') ec2_ips = [] # 处理分页,避免资源过多漏取 paginator = ec2_client.get_paginator('describe_instances') for page in paginator.paginate(): for reservation in page['Reservations']: for instance in reservation['Instances']: ec2_ips.append({ "resource_type": "EC2", "instance_id": instance['InstanceId'], "private_ip": instance.get('PrivateIpAddress'), "public_ip": instance.get('PublicIpAddress'), "instance_name": next((tag['Value'] for tag in instance.get('Tags', []) if tag['Key'] == 'Name'), '无名称') }) return ec2_ips
2. 负载均衡器(ELB)的IP
注意ELB分三种类型,处理方式略有不同:
def get_elb_ips(session): """获取各类ELB的IP信息""" elb_client = session.client('elbv2') elb_ips = [] # 获取应用/网络负载均衡器 paginator = elb_client.get_paginator('describe_load_balancers') for page in paginator.paginate(): for lb in page['LoadBalancers']: # 网络LB直接有IP,应用LB需要解析DNS(或者调用describe_target_groups看目标实例,但这里先取DNS和可用区IP) lb_info = { "resource_type": f"ELB-{lb['Type']}", "lb_name": lb['LoadBalancerName'], "lb_dns": lb['DNSName'], "ip_addresses": [] } # 获取LB的IP地址(网络LB会直接返回,应用LB需要通过describe_load_balancer_attributes或者解析DNS) if lb['Type'] == 'network': for addr in lb['AvailabilityZones']: lb_info['ip_addresses'].append(addr['LoadBalancerAddresses'][0]['IpAddress']) elb_ips.append(lb_info) # 兼容经典负载均衡器 classic_elb_client = session.client('elb') classic_paginator = classic_elb_client.get_paginator('describe_load_balancers') for page in classic_paginator.paginate(): for lb in page['LoadBalancerDescriptions']: elb_ips.append({ "resource_type": "ELB-classic", "lb_name": lb['LoadBalancerName'], "lb_dns": lb['DNSName'], "ip_addresses": lb['CanonicalHostedZoneNameID'] # 经典LB需要解析DNS获取IP,这里先记录域名 }) return elb_ips
四、整合起来遍历所有关联账号
把上面的函数整合,批量处理所有目标账号:
def main(): # 替换成你的目标账号列表和对应的角色名称(假设所有账号用同一个角色名,不同的话可以改成字典) target_accounts = [ {"account_id": "123456789012", "role_name": "CrossAccountIPRole"}, {"account_id": "987654321098", "role_name": "CrossAccountIPRole"} ] all_resource_ips = [] for account in target_accounts: session = assume_role(account['account_id'], account['role_name']) if not session: continue print(f"正在获取账号{account['account_id']}的资源IP...") # 拉取EC2 IP ec2_data = get_ec2_ips(session) all_resource_ips.extend(ec2_data) # 拉取ELB IP elb_data = get_elb_ips(session) all_resource_ips.extend(elb_data) # 输出结果,可以保存到文件或者打印 for resource in all_resource_ips: print(resource) if __name__ == "__main__": main()
一些关键注意事项
- 权限问题:目标账号的角色必须有足够的权限去调用对应的Describe接口,不然会报错
- 分页处理:一定要用分页器(
paginator),不然资源多的时候会漏取数据 - DNS解析:应用LB和经典LB的IP是动态的,如果你需要实时IP,可能需要在代码里加DNS解析逻辑(比如用
socket.gethostbyname) - 其他资源:如果还需要RDS、Lambda(虽然Lambda没有固定IP)等资源的IP,可以类似扩展对应的函数
内容的提问来源于stack exchange,提问作者user9877726
相关产品推荐
相关产品推荐

