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

如何用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:55:41