Files
a-share-analysis/docs/deployment/tailscale-tdx-development.md

378 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Tailscale + SSH 隧道访问 TDX 开发手册
## 1. 用途与适用边界
本手册用于 Mac 本地开发期间,按需访问家中 Windows 上仅监听回环地址的 TDX HTTP 接口。链路只用于真实字段核验和只读冒烟,不是生产采集、数据上报或公网部署方案。
```text
Mac 本地程序
-> 127.0.0.1:17710
-> SSH 本地端口转发
-> Tailscale 私有网络
-> Windows OpenSSH
-> Windows 127.0.0.1:17709
-> TDX
```
日常开发默认使用仓库内固定样本。只有需要验证 TDX 真实协议和字段时才启动本隧道;Windows 离线不得阻塞普通开发、测试或构建。
## 2. 安全边界
- 不在路由器上开放或转发 SSH、RDP、`17709`、`17710` 等端口。
- TDX 继续只监听 Windows `127.0.0.1:17709`,不得改为 `0.0.0.0`。
- SSH 使用独立 Ed25519 密钥,不在脚本、仓库、文档或远程 URL 中保存密码和私钥。
- Mac 转发端口只绑定 `127.0.0.1:17710`,不得绑定局域网或所有网卡。
- 真实返回只用于只读验证。日志和测试报告必须脱敏,不保存家庭网络信息、登录信息或无关原始载荷。
- 开发隧道不连接生产数据库、不承担生产采集,也不证明数据源具备商业展示或再分发授权。
文档中的值均为占位符:
- `<WINDOWS_TAILSCALE_HOST>`:Windows 的 Tailscale MagicDNS 名称或 Tailscale IP。
- `<WINDOWS_SSH_USER>`:用于 SSH 登录的 Windows 用户。
- `<MAC_TAILSCALE_IP>`:Mac 的 Tailscale IP,仅在收紧防火墙来源时使用。
## 3. 首次建立 Tailscale 网络
### 3.1 Mac
1. 从 Tailscale 官方渠道安装客户端。
2. 登录项目使用的同一个 Tailnet。
3. 确认菜单栏中的 Tailscale 状态为已连接。
4. 在终端检查本机和节点列表:
```bash
tailscale ip -4
tailscale status
```
### 3.2 Windows
1. 从 Tailscale 官方渠道安装客户端。
2. 登录与 Mac 相同的 Tailnet。
3. 确认 Windows 节点在 Tailscale 管理后台和 Mac 的 `tailscale status` 中均为在线。
4. 在 Windows PowerShell 中检查地址和状态:
```powershell
tailscale ip -4
tailscale status
```
### 3.3 私网连通验证
在 Mac 执行:
```bash
tailscale ping <WINDOWS_TAILSCALE_HOST>
```
只有 Tailscale ping 成功后再排查 SSH。不要用公网 IP 替换占位符,也不要为排障临时开放路由器端口。
## 4. 配置 Windows OpenSSH Server
以下命令在 Windows 管理员 PowerShell 中执行。
### 4.1 安装并启动服务
```powershell
Get-WindowsCapability -Online | Where-Object Name -Like 'OpenSSH.Server*'
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Start-Service sshd
Set-Service -Name sshd -StartupType Automatic
Get-Service sshd
```
如果 OpenSSH Server 已安装,`Add-WindowsCapability` 可以跳过。`Get-Service sshd` 应显示服务正在运行且启动类型为自动。
检查端口监听:
```powershell
Get-NetTCPConnection -LocalPort 22 -State Listen
```
### 4.2 确认防火墙规则
OpenSSH 安装通常会创建入站规则。先检查,不要重复创建同名规则:
```powershell
Get-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -ErrorAction SilentlyContinue
```
首次联调可以保留系统创建的 SSH 规则;链路确认后按第 11 节限制为 Tailscale 来源。不得新增公网端口映射。
## 5. 配置 SSH 密钥登录
### 5.1 在 Mac 生成项目专用密钥
```bash
ssh-keygen -t ed25519 -a 100 -f ~/.ssh/tdx_windows -C "tdx-windows-development"
chmod 600 ~/.ssh/tdx_windows
chmod 644 ~/.ssh/tdx_windows.pub
pbcopy < ~/.ssh/tdx_windows.pub
```
私钥 `~/.ssh/tdx_windows` 只保留在 Mac,不发送给 Windows,也不提交仓库。建议为私钥设置口令,并由 macOS 钥匙串或 `ssh-agent` 管理。
### 5.2 Windows 管理员账户
Windows OpenSSH 默认从 `C:\ProgramData\ssh\administrators_authorized_keys` 读取管理员公钥。必须先创建文件,再设置 ACL;否则 `icacls` 会报“系统找不到指定的文件”。
在管理员 PowerShell 中执行,按提示粘贴刚复制的单行公钥:
```powershell
$authorizedKeys = "$env:ProgramData\ssh\administrators_authorized_keys"
New-Item -ItemType Directory -Force -Path (Split-Path $authorizedKeys)
if (-not (Test-Path $authorizedKeys)) {
New-Item -ItemType File -Path $authorizedKeys
}
$publicKey = Read-Host '粘贴 Mac 的单行 SSH 公钥'
if (-not (Get-Content $authorizedKeys | Where-Object { $_ -eq $publicKey })) {
Add-Content -Path $authorizedKeys -Value $publicKey -Encoding ascii
}
icacls $authorizedKeys /inheritance:r
icacls $authorizedKeys /grant "*S-1-5-18:F" "*S-1-5-32-544:F"
Restart-Service sshd
```
`S-1-5-18` 是 SYSTEM,`S-1-5-32-544` 是本地 Administrators 组。使用 SID 可以避免中文 Windows 的组名本地化问题。
### 5.3 Windows 非管理员账户
非管理员账户使用用户目录下的 `authorized_keys`。在该登录用户自己的 PowerShell 中执行:
```powershell
$sshDirectory = "$env:USERPROFILE\.ssh"
$authorizedKeys = "$sshDirectory\authorized_keys"
New-Item -ItemType Directory -Force -Path $sshDirectory
if (-not (Test-Path $authorizedKeys)) {
New-Item -ItemType File -Path $authorizedKeys
}
$publicKey = Read-Host '粘贴 Mac 的单行 SSH 公钥'
if (-not (Get-Content $authorizedKeys | Where-Object { $_ -eq $publicKey })) {
Add-Content -Path $authorizedKeys -Value $publicKey -Encoding ascii
}
icacls $authorizedKeys /inheritance:r
icacls $authorizedKeys /grant "$($env:USERNAME):F"
Restart-Service sshd
```
管理员和非管理员两种方式只选与实际账户匹配的一种。若修改了 `C:\ProgramData\ssh\sshd_config`,先执行 `sshd -t` 校验,再重启服务。
## 6. 配置 Mac SSH 别名
编辑 Mac 的 `~/.ssh/config`,加入:
```sshconfig
Host tdx-windows
HostName <WINDOWS_TAILSCALE_HOST>
User <WINDOWS_SSH_USER>
IdentityFile ~/.ssh/tdx_windows
IdentitiesOnly yes
ServerAliveInterval 30
ServerAliveCountMax 3
ExitOnForwardFailure yes
LocalForward 127.0.0.1:17710 127.0.0.1:17709
```
然后修正权限:
```bash
chmod 700 ~/.ssh
chmod 600 ~/.ssh/config ~/.ssh/tdx_windows
```
首次连接先验证密钥登录:
先在 Windows 管理员 PowerShell 查看主机公钥指纹:
```powershell
ssh-keygen -lf "$env:ProgramData\ssh\ssh_host_ed25519_key.pub"
```
再在 Mac 连接,并确认首次连接提示的 Ed25519 指纹与 Windows 输出一致:
```bash
ssh -v tdx-windows
```
预期可以直接登录,或只要求输入私钥口令。若仍要求 Windows 账户密码,重点检查公钥文件位置、ACL、登录账户是否属于 Administrators,以及 SSH 调试输出中实际使用的密钥。
## 7. 启动和停止隧道
### 7.1 前台运行
适合首次验证,按 `Ctrl+C` 停止:
```bash
ssh -N tdx-windows
```
### 7.2 后台运行
使用独立控制套接字启动,便于精确停止本项目隧道:
```bash
ssh -fN -M -S ~/.ssh/tdx-windows-control tdx-windows
ssh -S ~/.ssh/tdx-windows-control -O check tdx-windows
```
停止后台隧道:
```bash
ssh -S ~/.ssh/tdx-windows-control -O exit tdx-windows
```
如果控制套接字残留但进程已不存在,先确认 `17710` 没有监听,再删除该单个套接字文件。不要用宽泛的 `pkill ssh`,以免终止其他 SSH 会话。
## 8. 验证 TDX 链路
### 8.1 Windows 本机验证
先确认 TDX 客户端已启动、已登录,接口监听 `127.0.0.1:17709`:
```powershell
Get-NetTCPConnection -LocalAddress 127.0.0.1 -LocalPort 17709 -State Listen
```
端口没有监听时,应先恢复 TDX 客户端;SSH 和 Tailscale 无法替代 TDX 服务本身。
### 8.2 Mac 端口验证
隧道启动后在 Mac 执行:
```bash
nc -vz 127.0.0.1 17710
lsof -nP -iTCP:17710 -sTCP:LISTEN
```
`17710` 的监听进程应为本次 SSH 隧道,不应是其他应用。
### 8.3 只读 HTTP 冒烟
```bash
curl --fail-with-body --silent --show-error \
--connect-timeout 3 \
--max-time 10 \
-H 'Content-Type: application/json' \
-X POST 'http://127.0.0.1:17710/' \
--data '{"id":1,"method":"get_market_data","params":{"stock_list":["600519.SH"],"count":5,"dividend_type":"none","period":"1d"}}'
```
链路验收条件:HTTP 返回成功,且 TDX 业务响应中的错误码表示成功。只验证少量公开行情,不调用交易、账户、自选、写入或大批量接口。
## 9. 外网场景验证
在真正离开家庭网络前,使用 Mac 手机热点或其他外部网络完成一次演练:
1. 确认 Windows 保持开机、联网,Tailscale 和 `sshd` 在线,TDX 已启动并登录。
2. Mac 切换到外部网络后重新连接 Tailscale。
3. 执行 `tailscale ping <WINDOWS_TAILSCALE_HOST>`。
4. 执行 `ssh -N tdx-windows` 并保持终端运行。
5. 依次执行 `nc` 和只读 `curl` 冒烟。
6. 停止隧道,确认 `127.0.0.1:17710` 不再监听。
如果外网演练失败,日常开发继续使用固定样本。不要临时开放公网 SSH、RDP 或 TDX 端口。
## 10. Windows 无人值守准备
当前链路是开发辅助,不承诺生产级 7x24 可用性。为了减少外出后无法联调的概率,可在 Windows 上做以下准备:
- 将虚拟机配置为宿主机启动后自动启动,并确认异常关机后的恢复策略。
- 保持 Tailscale 与 `sshd` 服务自动启动,重启后通过另一台 Tailnet 设备验证在线状态。
- 接通电源时禁用自动睡眠:
```powershell
powercfg /change standby-timeout-ac 0
```
- 明确 TDX 是否需要交互式桌面登录、验证码或人工确认。需要人工登录时,不得把它描述为无人值守服务。
- 安排 Windows 更新和虚拟机重启窗口;更新后重新验证 Tailscale、SSH、TDX 监听和只读请求。
- 不为自动启动把 Windows 密码、TDX 凭据或 SSH 私钥写入仓库和普通脚本。
## 11. 收紧访问范围
链路验证通过后,在 Tailscale 管理后台将访问规则限制为指定开发身份或 Mac 到 Windows SSH 端口。具体策略应以当前 Tailnet 的身份和标签设计为准,不在仓库保存真实账户和地址。
还可在 Windows 中新增一条仅允许 Mac Tailscale IP 访问 SSH 的规则。先确认 Tailscale 网卡名称,再创建规则:
```powershell
Get-NetAdapter | Where-Object InterfaceDescription -Match 'Tailscale'
New-NetFirewallRule `
-DisplayName 'OpenSSH Server - Tailscale Mac Only' `
-Direction Inbound `
-Action Allow `
-Protocol TCP `
-LocalPort 22 `
-RemoteAddress '<MAC_TAILSCALE_IP>' `
-InterfaceAlias 'Tailscale'
```
新规则必须在外网场景实测通过后,才能禁用范围更宽的旧 SSH 规则。若实际网卡别名不是 `Tailscale`,使用 `Get-NetAdapter` 显示的名称,不凭猜测修改。
## 12. 故障排查
### Tailscale ping 不通
- 检查两端是否登录同一个 Tailnet、节点是否过期、Windows 是否睡眠或断网。
- 检查 Tailnet ACL 或设备审批状态。
- 不要先排查 TDX;此时底层私网尚未连通。
### SSH 连接超时或拒绝
- Windows 执行 `Get-Service sshd` 和 `Get-NetTCPConnection -LocalPort 22 -State Listen`。
- 检查 Windows 防火墙和 Tailscale 访问规则。
- Mac 执行 `ssh -vvv tdx-windows`,确认目标是 Tailscale 地址而非家庭公网地址。
### SSH 仍要求 Windows 密码
- 确认 `IdentityFile` 指向 `~/.ssh/tdx_windows`,并检查 `ssh -vvv` 是否提供了该密钥。
- 管理员账户确认文件是 `C:\ProgramData\ssh\administrators_authorized_keys`;非管理员账户确认文件是用户目录下的 `.ssh\authorized_keys`。
- 确认公钥为完整单行文本,文件已先创建,ACL 没有继承无关权限。
- 执行 `sshd -t` 检查配置,再执行 `Restart-Service sshd`。
### Mac 的 `17710` 无法监听
- 查看 SSH 前台错误;`ExitOnForwardFailure yes` 会在端口冲突或转发失败时直接退出。
- 执行 `lsof -nP -iTCP:17710 -sTCP:LISTEN` 查找占用者。
- 不要把本地端口改成 `0.0.0.0`;需要换端口时同步修改本机开发配置,并保持回环绑定。
### 端口可连但 HTTP 失败
- 在 Windows 本机确认 TDX `127.0.0.1:17709` 正在监听。
- 确认 TDX 客户端已登录且当前版本仍支持目标方法。
- 使用最小只读请求检查 HTTP 状态、TDX 错误码和响应时间,不把协议错误误判为网络错误。
### 外出后 Windows 不在线
- 无法远程唤醒或恢复交互式 TDX 登录时,切回固定样本继续开发。
- 不通过新增公网暴露、共享密码或关闭防火墙绕过问题。
- 待公网部署需求明确后,另立功能实现生产级采集器、心跳、补传和远程运维。
## 13. 日常操作速查
开始真实 TDX 联调:
```bash
tailscale ping <WINDOWS_TAILSCALE_HOST>
ssh -fN -M -S ~/.ssh/tdx-windows-control tdx-windows
ssh -S ~/.ssh/tdx-windows-control -O check tdx-windows
nc -vz 127.0.0.1 17710
```
结束联调:
```bash
ssh -S ~/.ssh/tdx-windows-control -O exit tdx-windows
lsof -nP -iTCP:17710 -sTCP:LISTEN
```
最后一条命令无输出表示本地转发已经停止。
## 14. 后续 Provider 接入约束
- 平台配置只能引用 Mac 回环地址 `127.0.0.1:17710`,不得保存家庭网络地址。
- 真实 TDX Provider 必须显式启用;默认仍为确定性的固定样本 Provider。
- Provider 必须限制请求超时、响应体大小、股票数量和并发,并输出来源、采集时间、交易日期、协议版本、追踪 ID 和陈旧状态。
- TDX 原始字段仅在 Adapter 内转换,上层市场概览、规则分析和 AI 分析只依赖版本化内部契约。
- 隧道中断必须返回明确的不可用或陈旧状态,不能把固定样本伪装成实时行情。
- Windows 采集器、公网接收 API、多目标推送、补传队列和无人值守运维继续延期,实施时单独立项并重新进行安全、性能和合规评估。