查看: 110|回复: 0

paramiko批量管理网络设备:SSH并发与分页编码避坑

[复制链接]
发表于 半小时前 | 显示全部楼层 |阅读模式
在中文技术社区里,网络运维自动化一直是个高频话题。日常做设备巡检、配置备份、批量下发NTP/SNMP/AAA,最容易消耗时间的不是复杂技术,而是反复SSH登录、敲命令、等回显、记录结果。paramiko是Python实现的SSHv2协议客户端库,适合把“登录、执行、读取、保存”这套动作代码化、批量化、可重复化。Ansible、Nornir这类工具更像自动挡,paramiko更像手动挡,连接、认证、执行、读取全在自己控制范围内。本文围绕paramiko批量管理网络设备的实践,梳理单台SSH执行、并发采集、配置下发、多厂商差异、编码与分页等常见坑。

一、练手环境和Python环境准备

不建议直接拿生产环境练手,可以用GNS3或eNSP搭实验环境。GNS3可以跑思科IOS路由器和交换机镜像,给设备分配管理IP,宿主机直接SSH访问。原文示例中管理IP为192.168.56.101到192.168.56.105,掩码24位,网关指向192.168.56.1。eNSP适合练华为VRP命令,但不少版本默认不开SSH,需要先配置VTY用户、认证方式和RSA密钥。真实二手设备如思科2960、华为S5700也能练,而且更容易遇到密钥交换算法不匹配、加密算法太弱、设备时间不对导致认证失败等问题。

Python建议用3.8以上版本,paramiko是纯Python写的,底层依赖cryptography和bcrypt,三大平台通常有预编译wheel包。安装命令:
  1. pip install paramiko
复制代码

国内网络可换镜像源:
  1. pip install paramiko -i https://pypi.tuna.tsinghua.edu.cn/simple
复制代码

验证安装:
  1. import paramiko
  2. print(paramiko.__version__)
复制代码

新版本paramiko要求Python 3.6以上。如果还在用Python 2.7,老版本paramiko虽然能跑,但连接新设备时可能因为加密算法支持不足导致握手失败,建议尽早迁移。项目依赖建议用虚拟环境隔离:
  1. python -m venv netauto_env
  2. # Windows激活
  3. netauto_env\Scripts\activate
  4. # Linux/macOS激活
  5. source netauto_env/bin/activate
  6. pip install paramiko
复制代码

二、单台设备SSH执行:先把连接和回显打通

批量操作前,先跑通单台设备。paramiko常用SSHClient,设置AutoAddPolicy自动接受未知主机密钥,生产环境更建议用load_system_host_keys或已知密钥。下面是一个基础执行函数,核心是建立连接、获取交互式shell、发送命令、读取回显、关闭连接:
  1. import paramiko
  2. import time
  3. def exec_command(host, username, password, command, enable_password=None):
  4.     client = paramiko.SSHClient()
  5.     client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  6.     try:
  7.         client.connect(
  8.             hostname=host,
  9.             port=22,
  10.             username=username,
  11.             password=password,
  12.             timeout=10,
  13.             look_for_keys=False,
  14.             allow_agent=False,
  15.             banner_timeout=15,
  16.             auth_timeout=15
  17.         )
  18.         shell = client.invoke_shell()
  19.         time.sleep(1)
  20.         shell.recv(65535)
  21.         shell.send(command + '\n')
  22.         time.sleep(2)
  23.         output = shell.recv(65535).decode('utf-8', errors='ignore')
  24.         return output
  25.     finally:
  26.         client.close()
复制代码

这里有几个关键参数。timeout控制TCP连接超时,banner_timeout控制SSH协议握手阶段超时,auth_timeout控制认证阶段超时。批量执行时如果某个IP不通或SSH服务异常,没有这些超时控制,脚本可能长时间卡住。invoke_shell()拿到的是交互式shell,能模拟真实终端登录,也能处理需要交互的命令;代价是回显需要自己判断命令是否结束。示例里用sleep等待再recv是一种简化做法,更严谨的方式是循环读取,直到输出不再变化或检测到提示符再停止。

认证方式主要有密码认证和密钥认证。密码认证简单,但密码硬编码在脚本里有泄露风险,频繁连接大量设备还可能触发账号锁定。密钥认证可以这样连接:
  1. client = paramiko.SSHClient()
  2. client.connect(
  3.     hostname=host,
  4.     port=22,
  5.     username='admin',
  6.     key_filename='/home/ops/.ssh/id_rsa',
  7.     timeout=10
  8. )
复制代码

密钥认证在批量操作中更安全,脚本里不用放密码。但网络设备端配置更复杂,思科要指定ip ssh pubkey-chain,华为要用rsa peer-public-key导入公钥,不同厂商、不同型号命令有差异。设备规模不大时,密码认证配合环境变量或配置文件读取密码也够用;大规模自动化平台更建议对接密钥管理系统。

三、并发批量采集:线程池和超时隔离

单台跑通后,批量就是读取设备清单并循环调用。串行执行有性能瓶颈,假设单台连接加执行3秒,30台就是90秒。用concurrent.futures线程池可以并发执行:
  1. import paramiko
  2. import time
  3. from concurrent.futures import ThreadPoolExecutor, as_completed
  4. def collect_device_info(device):
  5.     host = device['host']
  6.     username = device['username']
  7.     password = device['password']
  8.     command = device.get('command', 'show version')
  9.     try:
  10.         client = paramiko.SSHClient()
  11.         client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  12.         client.connect(
  13.             hostname=host,
  14.             port=22,
  15.             username=username,
  16.             password=password,
  17.             timeout=10,
  18.             look_for_keys=False,
  19.             allow_agent=False,
  20.             banner_timeout=15,
  21.             auth_timeout=15
  22.         )
  23.         shell = client.invoke_shell()
  24.         time.sleep(1)
  25.         shell.recv(65535)
  26.         shell.send(command + '\n')
  27.         time.sleep(2)
  28.         output = shell.recv(65535).decode('utf-8', errors='ignore')
  29.         client.close()
  30.         return {'host': host, 'status': 'success', 'output': output}
  31.     except Exception as e:
  32.         return {'host': host, 'status': 'failed', 'error': str(e)}
  33. def batch_collect(devices, max_workers=10):
  34.     results = []
  35.     with ThreadPoolExecutor(max_workers=max_workers) as executor:
  36.         future_map = {executor.submit(collect_device_info, dev): dev for dev in devices}
  37.         for future in as_completed(future_map):
  38.             results.append(future.result())
  39.     return results
复制代码

max_workers=10表示最多同时跑10个线程,也就是同时SSH登录10台设备。线程数不是越大越好,要考虑跳板机资源、网络带宽和设备SSH连接数限制。有些老交换机SSH并发数有限,同时登录太多会拒绝新连接。20台以内设备并发数设5到10比较稳妥,上百台可以提高到20到30,但建议分段执行。as_completed是谁先完成谁先返回,不会因为某一台设备卡住而阻塞其他设备采集。

四、批量配置下发:模板、干跑、保存和验证

批量查询是“读”,批量配置下发是“写”,风险级别完全不同。配置下发至少要满足几个条件。第一,设备分组和配置模板分离,不同角色设备下发不同内容。第二,支持干跑模式dry-run,正式执行前生成变更内容供Review。第三,配置下发后自动保存,思科用write memory,华为用save,H3C用save force。第四,配置变更后自动验证,不能只看到命令执行成功就结束。

多厂商混用是常态,思科是show running-config,华为是display current-configuration;思科进特权模式用enable,华为进系统视图用system-view。可以在设备清单里增加vendor字段,按厂商和动作返回命令列表:
  1. def get_commands_by_vendor(vendor, action, params=None):
  2.     if vendor == 'cisco':
  3.         if action == 'backup':
  4.             return ['show running-config']
  5.         elif action == 'save':
  6.             return ['write memory']
  7.         elif action == 'config_ntp':
  8.             return ['configure terminal', 'ntp server ' + params['ntp_server'], 'end', 'write memory']
  9.     elif vendor == 'huawei':
  10.         if action == 'backup':
  11.             return ['display current-configuration']
  12.         elif action == 'save':
  13.             return ['save', 'Y']
  14.         elif action == 'config_ntp':
  15.             return ['system-view', 'ntp-service unicast-server ' + params['ntp_server'], 'return', 'save', 'Y']
  16.     elif vendor == 'h3c':
  17.         if action == 'backup':
  18.             return ['display current-configuration']
  19.         elif action == 'save':
  20.             return ['save force']
复制代码

这块看起来简单,实际坑很多。NTP命令思科支持ntp server,华为支持ntp-service unicast-server,H3C也支持ntp-service unicast-server,但不同版本、不同型号还有差异。用Netmiko这类基于paramiko二次封装的库可以省去部分多厂商命令映射,但理解paramiko底层执行过程仍然有价值。

配置下发后一定要验证。比如下发NTP后执行show ntp status,检查输出里是否有Synchronized或clock is synchronized,有就标记成功,没有就标记warning交给人工确认。原文提到一个实际案例:设备上配置的NTP服务器地址可达,但设备始终没同步,脚本给出warning,人工排查发现是设备到NTP服务器之间防火墙拦截了123端口。如果脚本只判断“命令执行成功”,这个故障就会被漏掉。

五、实测高频坑:编码、分页、超时和交互

1. 中文设备名和回显乱码。国内设备名、描述信息、SNMP团体名可能是中文。paramiko默认decode('utf-8')不是万能解药,思科老设备可能用ASCII或Latin-1,华为VRP默认GBK的场景也存在。读取回显时用errors='ignore'可避免UnicodeDecodeError导致脚本崩溃。更通用的做法是多重编码尝试:
  1. def smart_decode(data: bytes) -> str:
  2.     for encoding in ('utf-8', 'gbk', 'gb2312', 'latin-1'):
  3.         try:
  4.             return data.decode(encoding)
  5.         except UnicodeDecodeError:
  6.             continue
  7.     return data.decode('utf-8', errors='ignore')
复制代码

原文真实案例是:一台华为S5720交换机设备名为“三层-核心-A”,display version输出里的中文用utf-8解码正常;另一台老版本S5700输出同样中文却用GBK编码,utf-8直接报错。多重编码尝试虽然不优雅,但能覆盖常见设备。

2. 分页输出导致命令“卡死”。很多show命令默认分页显示,比如思科show running-config输出较长时会出现“--More--”,等待用户按空格或回车继续。paramiko的shell.recv()只收了第一屏,你以为命令执行完了,设备其实还在等翻页,后续命令无法正常执行。解法是执行命令前关闭分页。思科在特权模式执行terminal length 0,华为执行screen-length 0 temporary,锐捷执行terminal length 0。推荐在脚本开头统一执行:
  1. # 思科
  2. terminal length 0
  3. # 华为
  4. screen-length 0 temporary
  5. # 锐捷
  6. terminal length 0
复制代码

3. 超时与设备无响应。connect的timeout、banner_timeout、auth_timeout要设置,异常要隔离,单台失败不能影响整批任务。as_completed可以让先完成的设备先返回。原文提到某台设备SSH握手特别慢,如果不加超时控制,串行执行时那一台就能拖慢整个批次。

4. 敏感操作的安全网。配置下发前先备份,先dry-run,再执行;执行后自动保存并验证;验证结果不确定时标记warning交人工判断,而不是强行判定成功或失败。涉及批量改口令、重启端口、清理MAC表项等操作时,更要有回滚和确认机制。

六、项目组织和进阶方向

实际项目中,建议把设备清单、命令模板、采集逻辑、下发逻辑、验证逻辑拆成独立模块。设备清单可以来自Excel、CSV或CMDB接口。采集脚本负责批量读取状态,配置脚本负责按vendor和action生成命令,验证脚本负责检查关键字并汇总结果。

进阶方向上,Netmiko基于paramiko二次封装,自带多厂商命令映射和交互式命令处理;Nornir适合更复杂的并发和资产组织;运维平台则可以把设备操作封装成API。不过给新人的建议仍然是:先会手动登录设备、敲命令、看回显、排查问题,再谈自动化。paramiko适合批量巡检CPU、内存、温度、光功率,批量备份配置文件,批量下发NTP、SNMP、AAA、日志服务器,批量修改口令、重启端口、清理MAC表项等场景。设备数量上到几十上百台,或者操作需要标准化执行时,paramiko脚本的价值就会明显体现出来。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-9-15 11:58 , Processed in 0.020301 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部