利用 Python 脚本批量查找并删除指定 IP 的 AWS Lightsail 实例
在 AWS Lightsail 管理中,随着实例数量的增多,我们常常会遇到这样一个问题:
“我知道某个公网 IP 地址,但不知道它关联的是哪台实例。”
或者:
“我有一批老旧的实例只知道 IP,需要一键定位并选择删除。”
如果你逐台在 AWS 控制台中点开每台实例、查看其 IP,效率低下且极易出错。本文将介绍如何通过 Python 脚本,批量查找绑定特定 IP 的实例,并可交互式地选择是否删除。该脚本支持自动遍历多个区域、并发执行、异常处理,并可适应日常运维和资源审计场景。
一、应用场景
-
批量清理使用特定 IP 的老旧实例
-
结合日志系统,从攻击源 IP 快速定位实例
-
故障排查场景下,通过 IP 快速反查服务实例
-
IP 池资源回收后,核查哪些实例仍绑定老 IP
二、技术准备
1. 安装 boto3(AWS Python SDK)
pip install boto3
2. 配置 AWS 凭证
你需要准备一对具有 Lightsail:DeleteInstance
和 Lightsail:GetInstance
权限的 Access Key:
-
AWS_ACCESS_KEY_ID
-
AWS_SECRET_ACCESS_KEY
建议使用 IAM 用户访问密钥,权限不要过大,避免误删其他资源。
📄 三、准备 IP 地址列表
创建一个 ip_list.txt
文件,每行一个目标 IP:
3.122.44.87
54.212.11.100
13.112.22.14
此列表中的 IP 是你想“反查”的 Lightsail 实例。
四、脚本核心逻辑解析
脚本主要包含四个阶段:
1. 并发遍历所有支持的 Lightsail 区域
Lightsail 是按区域划分的服务,实例只能出现在某个区域中,因此我们需要逐个区域去遍历。脚本中使用了 ThreadPoolExecutor
提高并发效率,最多同时运行 15 个线程,快速查找。
2. 分页获取每个区域的所有实例
AWS 的 get_instances()
接口默认返回一页,我们通过 nextPageToken
实现全量分页拉取,避免遗漏任何实例。
3. 对每台实例进行 IP 匹配
匹配逻辑基于实例的 publicIpAddress
字段,若 IP 存在且命中目标列表,即可视为命中。
4. 逐个提示用户确认是否删除
脚本找到目标实例后,会在终端提示你确认是否删除该实例(y
执行删除,其它跳过),确保人为决策参与,避免批量误删。
五、完整脚本源码
import boto3
from concurrent.futures import ThreadPoolExecutor, as_completed# AWS 凭证配置
AWS_ACCESS_KEY_ID = "你的AccessKey"
AWS_SECRET_ACCESS_KEY = "你的SecretKey"# 支持的 Lightsail 区域
lightsail_regions = ["us-east-1", "us-east-2", "us-west-2", "ca-central-1","eu-west-1", "eu-west-2", "eu-central-1","ap-south-1", "ap-northeast-1", "ap-northeast-2","ap-southeast-1", "ap-southeast-2"
]# 读取 IP 列表
with open("ip_list.txt", "r", encoding="utf-8") as f:target_ips = set(line.strip() for line in f if line.strip())found_instances = {} # ip -> (name, region, state)# 分页获取实例
def get_all_instances_in_region(region):instances = []try:client = boto3.client("lightsail",region_name=region,aws_access_key_id=AWS_ACCESS_KEY_ID,aws_secret_access_key=AWS_SECRET_ACCESS_KEY)response = client.get_instances()instances.extend(response.get("instances", []))next_token = response.get("nextPageToken")while next_token:response = client.get_instances(pageToken=next_token)instances.extend(response.get("instances", []))next_token = response.get("nextPageToken")except Exception as e:print(f"[{region}] ❌ 获取实例失败:{e}")return instances# 匹配实例(并发线程任务)
def find_ip_in_region(region):results = []instances = get_all_instances_in_region(region)for ins in instances:ip = ins.get("publicIpAddress")if ip and ip in target_ips:results.append((ip, ins["name"], region, ins["state"]["name"]))return results# 多线程并发查找 IP 对应实例
with ThreadPoolExecutor(max_workers=15) as executor:futures = [executor.submit(find_ip_in_region, region) for region in lightsail_regions]for future in as_completed(futures):matches = future.result()for ip, name, region, state in matches:print(f"\n🔍 找到实例:")print(f" ➤ 实例名:{name}")print(f" ➤ 区域:{region}")print(f" ➤ 状态:{state}")print(f" ➤ IP地址:{ip}")found_instances[ip] = (name, region, state)# 遍历匹配结果,逐个确认是否删除
for ip, (name, region, state) in found_instances.items():choice = input(f"\n⚠️ 是否要删除实例【{name}】(IP: {ip}, 区域: {region})?[y/N]: ").strip().lower()if choice == 'y':try:client = boto3.client("lightsail",region_name=region,aws_access_key_id=AWS_ACCESS_KEY_ID,aws_secret_access_key=AWS_SECRET_ACCESS_KEY)client.delete_instance(instanceName=name)print(f"✅ 实例 {name} 删除成功")except Exception as e:print(f"❌ 删除实例 {name} 失败:{e}")else:print(f"⏭️ 跳过实例 {name}")# 输出未找到的 IP
for ip in target_ips:if ip not in found_instances:print(f"❌ 未找到 IP {ip} 对应的实例")
六、安全注意事项
-
删除操作不可恢复,使用前务必确认 IP 与实例绑定关系准确
-
推荐先执行“只查找”版本脚本,确认命中目标后再启用删除逻辑
-
可将删除部分封装为函数,或加入
--dry-run
模式增强安全性 -
若大批量删除建议加入备份(如自动创建快照)操作