Azure CLI与 AWS CLI在 Windows的 TLS握手过程中偶尔失败,错误为ConnectionResetError(10054) / WinError 10054
问题正文
问题描述
在Windows上对任意 az 或 aws 命令,有时能成功,有时会失败,错误信息如下,即使在几秒钟后重试同一条命令,结果也可能不同:
('Connection aborted.', ConnectionResetError(10054, 'An existing connection was forcibly closed by the remote host', None, 10054, None))
完整的回溯信息总是在TLS握手阶段结束:
File "ssl.py", line 1372, in do_handshake
ConnectionResetError: [WinError 10054] An existing connection was forcibly closed by the remote host
...
requests.exceptions.ConnectionError: ('Connection aborted.', ConnectionResetError(10054, ...))
症状
- 同样的
az或aws命令在一次执行中成功,在下一次执行中失败,间隔只有几秒钟 - 切换Wi-Fi网络也无法解决
- 云端服务可访问(某些命令成功),因此身份验证和服务器端配置没有问题
- 错误总是在
ssl.py的do_handshake内发生——发生在TLS协商阶段,而不是之后 - 影响任何在底层使用
urllib3/requests的基于Python的 CLI工具
环境
- Windows 10 / 11
- Azure CLI和/或AWS CLI(任意较新版本)
- 家庭宽带服务提供商(Xfinity、Verizon Fios等)
- 无线网络连接
解决方案
根本原因:本地网络的IPv6不稳定
错误发生在TLS do_handshake 步骤,这意味着TCP连接在SSL协商完成之前就被远端主机重置。这不是Azure/AWS的问题,也不是身份验证问题,也不是你的命令语法的问题。
真正的原因是 你所在的运营商网络中的IPv6不稳定。具体发生的过程如下:
- Azure和 AWS的端点同时支持IPv4和 IPv6
- Windows解析主机名,有时选择IPv6,有时选择IPv4
- 运营商的IPv6路由不稳定,因此在握手中途IPv6连接会被悄无声息地丢弃
- 这导致同一条命令随机成功或失败的现象
这会影响任何使用 urllib3 → requests → Python的 ssl 模块的基于Python的 CLI工具(如Azure CLI、AWS CLI、Hugging Face CLI等),因为重置是在这里暴露的。
在 Xfinity 和 Verizon Fios 的家庭连接上尤其常见,IPv6默认开启,但路由不稳定。
解决办法:在不禁用IPv6的前提下优先使用IPv4(推荐)
这是最简洁的方案。它让Windows在两种选项都可用时偏好IPv4,同时对真正需要IPv6的场景保留IPv6的启用。
步骤1 — 设置前缀策略(无需重启,以管理员身份运行):
powershell
netsh int ipv6 set prefixpolicy ::ffff:0:0/96 46 4
步骤2 — 确保适配器上启用IPv6:
powershell
Enable-NetAdapterBinding -Name "*" -ComponentID ms_tcpip6
步骤3 — 验证:
powershell
Get-NetAdapterBinding -ComponentID ms_tcpip6
你应该在所有适配器上看到 Enabled : True。IPv6现在已启用,但Windows将始终优先尝试IPv4。
如有需要,若要还原前缀策略:
powershell
netsh int ipv6 set prefixpolicy ::ffff:0:0/96 35 4
替代方案:完全禁用IPv6(较简单,但灵活性不足)
如果你根本不需要IPv6,可以将其完全禁用:
powershell
Disable-NetAdapterBinding -Name "*" -ComponentID ms_tcpip6
如要重新启用:
powershell
Enable-NetAdapterBinding -Name "*" -ComponentID ms_tcpip6
为什么有效
[WinError 10054] 代表对端强制关闭了TCP连接。当客户端通过IPv6连接且运营商的IPv6路径出现故障时,云端提供商的负载均衡器会在TCP层重置连接——恰好在TLS握手进行到一半时。偏好IPv4可以完全消除这条代码路径。
该修复适用于Azure CLI、AWS CLI,以及任何使用 urllib3 + requests 的基于Python的工具,因为它们都依赖操作系统进行地址解析和TCP连接设置。
额外:在应用修复期间的重试包装器
Azure CLI:
powershell
$maxRetries = 5
$attempt = 0
do {
$attempt++
Write-Host "Attempt $attempt..."
az webapp config appsettings list `
--name YOUR_APP_NAME `
--resource-group YOUR_RESOURCE_GROUP `
--output table
$success = $LASTEXITCODE -eq 0
if (-not $success) { Start-Sleep -Seconds 2 }
} while (-not $success -and $attempt -lt $maxRetries)
AWS CLI:
powershell
$maxRetries = 5
$attempt = 0
do {
$attempt++
Write-Host "Attempt $attempt..."
aws s3 ls
$success = $LASTEXITCODE -eq 0
if (-not $success) { Start-Sleep -Seconds 2 }
} while (-not $success -and $attempt -lt $maxRetries)