1. 项目概述与核心价值如果你在 Kubernetes 集群里跑过一些需要网络匿名性或者特殊网络访问的应用比如网络爬虫、安全测试工具或者只是想低调地对外提供一个服务那你肯定琢磨过怎么把 Tor 网络集成进来。传统做法是手动在 Pod 里跑个 Tor 客户端或者用 Sidecar 模式但配置管理、密钥分发、高可用这些事搞起来特别琐碎而且和 K8s 的原生声明式管理风格格格不入。tor-controller这个项目就是为了解决这个痛点而生的。它本质上是一个 Kubernetes Operator通过自定义资源定义CRD让你能用管理Deployment、Service一样熟悉的方式去声明和管理 Tor 守护进程、洋葱服务甚至是高可用的洋葱服务集群。简单来说tor-controller把 Tor 网络的复杂配置抽象成了几个简单的 YAML 资源。你想跑一个 SOCKS5 代理让集群内应用通过 Tor 访问外网写一个Tor资源。你想把集群里的一个 Web 服务以.onion地址的形式发布到 Tor 网络写一个OnionService资源。你需要这个洋葱服务能扛住流量有负载均衡那就用OnionBalancedService。Operator 会负责在背后拉起对应的 Pod生成并管理密钥配置 Tor 守护进程并持续监控和维护这些服务的状态。这大大降低了在 K8s 生态中使用 Tor 的技术门槛和运维成本让开发者能更专注于业务逻辑本身。2. 架构设计与核心组件解析tor-controller的架构清晰体现了 Kubernetes Operator 的设计哲学扩展 API监听事件调和状态。它不是一个单体应用而是由控制器镜像和一系列功能镜像共同协作完成的。2.1 核心 CRD 资源模型项目定义了三种核心的 Custom Resource这也是用户直接交互的接口Tor: 用于部署一个独立的 Tor 守护进程实例。你可以把它想象成一个专用的 SOCKS5 代理 Pod。通过这个资源你可以配置 Tor 的连接方式直接连接、使用网桥、控制端口、指标端口等。它生成的 Service 可以被集群内其他 Pod 引用作为其出站流量的代理。OnionService: 用于创建一个 Tor 隐藏服务Hidden Service也就是我们常说的洋葱服务。它会创建一个包含 Tor 守护进程和一个小型管理容器的 Pod。这个管理容器负责监听 K8s API当OnionService对象的配置如后端服务地址发生变化时动态生成新的 Tor 配置文件并通知 Tor 进程重载。该资源的核心是将一个集群内的 Service比如你的 Web 应用映射到一个.onion地址上。OnionBalancedService: 这是实现高可用洋葱服务的关键。它基于OnionBalance项目创建一个前端负载均衡器和多个后端OnionService实例。用户访问一个统一的.onion地址请求会被前端负载均衡器分发到后端的某个实例上。这解决了单点故障问题并能提供更好的服务可用性和潜在的负载均衡能力。这三种资源都支持命名空间隔离符合多租户场景下的安全需求。2.2 控制器与工作负载镜像分工理解镜像分工对排查问题很有帮助tor-controller镜像: 这是 Operator 的大脑包含了基于kubebuilder框架编写的控制器逻辑。它持续监听上述三种 CRD 资源的事件创建、更新、删除并根据资源描述去创建或更新对应的 Deployment、Service、Secret 等 K8s 原生资源。它本身不运行 Tor。tor-daemon镜像: 这是 Tor 网络的核心客户端/中继/服务端程序。它由bugfest/tor-docker项目从源码编译确保了版本可控和特定功能的启用如反 DoS 的 PoW 保护。Tor资源和OnionService的 Pod 中运行的都是这个镜像。tor-daemon-manager镜像: 这是一个辅助 Sidecar 容器与tor-daemon共同运行在OnionService的 Pod 中。它的职责是作为“配置热加载器”监听 K8s 中对应OnionService对象的变化动态生成torrc配置文件并通过控制端口通知tor-daemon重新加载配置从而实现洋葱服务后端目标的动态更新而无需重启 Tor 进程。tor-onionbalance-manager镜像: 类似地这个镜像运行在OnionBalancedService创建的前端负载均衡器 Pod 中作为 Sidecar 管理onionbalance的配置动态地在后端实例列表变化时更新负载均衡配置。这种将控制平面controller和数据平面daemon, manager分离的设计使得各个组件职责单一更易于维护和升级。2.3 多架构支持与版本管理项目从 v0.3.x 开始就支持amd64、arm64、arm多架构镜像这对于在树莓派ARM或混合架构的 K8s 集群上部署非常友好。通过 GitHub Actions 自动化构建多平台镜像并推送到 Quay.io 仓库。版本管理也相当清晰Helm Chart 版本与控制器版本、Tor 守护进程版本有明确的对应关系表格。例如Chart 0.1.17 对应控制器 v0.10.0Tor 版本为 0.4.8.9并集成了 Obfs4 0.0.14 可插拔传输插件。这种透明度让用户在升级前能准确评估影响。注意在升级tor-controller的 Helm Chart 时务必查看版本对照表。如果 Tor 守护进程版本有跨主版本升级如从 0.4.6.x 到 0.4.7.x可能需要关注其配置项的兼容性变化尽管 Operator 会尽力管理但提前测试是稳妥的做法。3. 详细部署与配置实操理论讲完了我们上手部署和配置。这里我会以 Helm 方式为例因为这是管理 K8s 应用的最佳实践。3.1 使用 Helm 部署控制器首先添加仓库并安装控制器。建议创建一个独立的命名空间来管理。# 添加 Helm 仓库 helm repo add bugfest https://bugfest.github.io/tor-controller helm repo update # 安装 tor-controller helm upgrade --install tor-controller bugfest/tor-controller \ --create-namespace \ --namespace tor-controller这条命令会在tor-controller命名空间下安装所有必要的资源CRD、Controller Deployment、RBAC 权限等。安装完成后检查控制器 Pod 是否运行正常kubectl -n tor-controller get pods你应该能看到一个名为tor-controller-xxxxx的 Pod 状态为Running。重要配置项解析 在安装时你可以通过--set参数或自定义values.yaml文件进行配置。一个关键的选项是namespaced。集群范围模式默认控制器可以管理所有命名空间中的 Tor 相关资源。这是最简单的模式。命名空间模式如果你希望控制器只管理特定命名空间例如出于多租户或安全隔离考虑可以在安装时设置--set namespacedtrue。在这种模式下你需要在每个想要使用tor-controller的命名空间中单独部署一份控制器。这对于大型共享集群来说是一种更精细的权限控制方式。3.2 创建第一个洋葱服务假设我们已经在default命名空间有一个简单的 Nginx 服务名为my-webapp端口为80。我们想把它作为洋葱服务暴露出去。步骤一创建 OnionService 资源定义文件my-onion.yamlapiVersion: tor.k8s.torproject.org/v1alpha2 kind: OnionService metadata: name: my-first-onion namespace: default # 确保与后端服务在同一命名空间 spec: version: 3 # 目前只支持 v3这也是默认值可不写 rules: - port: number: 80 # 洋葱服务对外监听的端口 backend: service: name: my-webapp # 你的后端 Kubernetes Service 名称 port: number: 80 # 后端 Service 的端口 # privateKeySecret 字段不填控制器会自动生成随机密钥和地址步骤二应用配置并查看状态kubectl apply -f my-onion.yaml # 查看洋葱服务状态可以使用短名称 onion 或 os kubectl get onionservices # 或 kubectl get onion # 或 kubectl get os # 输出示例 NAME HOSTNAME TARGETCLUSTERIP AGE my-first-onion abcdef1234567890.onion 10.96.123.456 30sHOSTNAME列就是生成的.onion地址。同时控制器会在同一命名空间创建一个名为my-first-onion-tor-secret的 Secret里面保存了该洋葱服务的私钥、公钥和地址。步骤三访问测试你需要使用 Tor 浏览器或者配置了 Tor 代理的客户端如curl通过--socks5-hostname参数来访问这个.onion地址。在集群内部你也可以临时启动一个带有 Tor 客户端的 Pod 来测试kubectl run -it --rm tor-test --imagealpine/curl:latest --restartNever -- sh # 在容器内安装 tor 和 curl如果镜像没有或使用已集成 Tor 的镜像进行测试。 # 假设洋葱地址是 abcdef1234567890.onion # curl -x socks5h://localhost:9050 http://abcdef1234567890.onion3.3 使用自定义密钥固定洋葱地址随机地址适合临时服务。对于长期服务你通常希望有一个固定的、可对外宣传的.onion地址。这就需要使用自己的密钥对。步骤一在本地生成 v3 洋葱服务密钥你需要tor命令行工具。# 创建一个临时目录 mkdir -p /tmp/my-onion-keys cd /tmp/my-onion-keys # 生成 v3 洋葱服务的密钥和主机名文件 tor --hiddenservice-dir . --keygen v3 # 查看生成的文件 ls -la # 会看到 hostname, hs_ed25519_secret_key, hs_ed25519_public_key步骤二创建包含密钥的 Kubernetes Secretkubectl create secret generic my-custom-onion-secret \ --namespace default \ --from-fileprivateKeyFilehs_ed25519_secret_key \ --from-filepublicKeyFilehs_ed25519_public_key \ --from-fileonionAddresshostname步骤三在 OnionService 中引用此 SecretapiVersion: tor.k8s.torproject.org/v1alpha2 kind: OnionService metadata: name: my-fixed-onion namespace: default spec: version: 3 privateKeySecret: name: my-custom-onion-secret # 如果 Secret 中的键名就是标准的 privateKeyFile, publicKeyFile, onionAddress则 key 字段可以省略 rules: - port: number: 80 backend: service: name: my-webapp port: number: 80应用这个 YAML 后你的洋葱服务就会使用你提供的密钥对应固定的.onion地址。实操心得备份好本地生成的hs_ed25519_secret_key文件这是你洋葱服务的“根密钥”丢失它就意味着永久失去了对这个地址的控制权无法在其他地方重建相同的服务。同时确保 Secret 的访问权限RBAC受到严格限制防止密钥泄露。3.4 配置资源限制与节点调度洋葱服务 Pod 默认的资源请求可能较小。在生产环境中你需要根据预期流量进行调整。同时你可能希望将这些 Pod 调度到具有特定标签的节点上。apiVersion: tor.k8s.torproject.org/v1alpha2 kind: OnionService metadata: name: my-prod-onion spec: rules: [...] template: spec: nodeSelector: dedicated: tor-node # 调度到带有此标签的节点 tolerations: - key: dedicated operator: Equal value: tor-node effect: NoSchedule resources: requests: memory: 64Mi cpu: 100m limits: memory: 128Mi cpu: 500mspec.template下的配置会传递到底层管理的 Pod。这里我们指定了节点选择器、容忍度以及容器的资源限制。这对于保证服务稳定性和实现硬件隔离非常有用。3.5 创建高可用洋葱服务对于关键服务单点 Pod 故障会导致服务中断。OnionBalancedService可以解决这个问题。apiVersion: tor.k8s.torproject.org/v1alpha2 kind: OnionBalancedService metadata: name: my-ha-onion spec: replicas: 3 # 创建 3 个后端洋葱服务实例 template: # 每个后端的配置模板与 OnionService 的 spec 类似 spec: version: 3 rules: - port: number: 80 backend: service: name: my-webapp port: number: 80 template: # 后端 Pod 的模板 resources: limits: memory: 128Mi cpu: 250m balancerTemplate: # 前端负载均衡器 Pod 的模板 spec: nodeSelector: dedicated: tor-lb-node torResources: # 负载均衡器 Pod 中 tor 容器的资源 limits: memory: 64Mi cpu: 100m balancerResources: # 负载均衡器 Pod 中 onionbalance 容器的资源 limits: memory: 64Mi cpu: 100m应用后你会得到一个前端负载均衡器 Pod运行tor-daemon和tor-onionbalance-manager。三个后端洋葱服务 Pod运行tor-daemon和tor-daemon-manager。一个统一的.onion地址通过kubectl get onionha查看流量由前端负载均衡器分发给三个后端。注意事项OnionBalance的高可用机制在于多个后端实例。如果前端负载均衡器 Pod 挂了服务依然会中断。因此可以考虑将balancerTemplate配置为使用Deployment虽然当前 CRD 可能默认就是并设置多个副本或者通过 K8s Service 的负载均衡机制来保护前端。不过在 Tor 网络上下文中客户端的连接持久性需要被考虑简单的多副本可能不是最佳方案需要结合OnionBalance自身的健康检查机制来理解。4. 高级功能与集成指南4.1 启用客户端授权认证洋葱服务默认对 Tor 网络上的所有用户开放。为了限制访问可以启用客户端授权。这要求连接方提供特定的密钥对进行认证。步骤一生成客户端授权密钥对这通常在客户端进行。假设你有一个安装了tor的 Linux 环境# 在客户端机器上操作 mkdir -p ~/client-auth cd ~/client-auth # 为名为 myclient 的客户端生成密钥 tor --keygen client --keytype curve25519 --client-name myclient # 这会生成 myclient.auth 和 myclient.auth_private 文件 # myclient.auth 的内容以 descriptor:x25519: 开头需要提供给服务端 cat myclient.auth步骤二在服务端创建包含客户端公钥的 Secret# 假设从客户端获得的公钥是descriptor:x25519:ABCDEFG1234567890... # 将其 Base32 部分ABCDEFG1234567890...存入 Secret kubectl create secret generic my-authorized-client \ --namespace default \ --from-literalpublicKeyABCDEFG1234567890... # 或者直接存储完整的 auth 文件内容 # --from-fileauthKeymyclient.auth步骤三在 OnionService 中引用授权客户端apiVersion: tor.k8s.torproject.org/v1alpha2 kind: OnionService metadata: name: my-private-onion spec: rules: [...] authorizedClients: - name: my-authorized-client # 引用上面创建的 Secret # key: publicKey # 如果 Secret 中存储公钥的键名是 publicKey可省略。如果是其他键名需指定。配置完成后只有拥有对应私钥myclient.auth_private文件的 Tor 客户端才能访问此洋葱服务。4.2 与 Ingress Controller 集成有时你希望同一个服务既能通过洋葱网络访问也能通过常规互联网Clearnet访问或者你想在洋葱服务前面再加一层 HTTP 层面的路由和 TLS 终止。这时可以结合nginx-ingress等 Ingress 控制器。架构思路让OnionService的后端指向nginx-ingress-controller的 Service而不是直接指向你的应用 Service。然后由 Ingress 规则来根据域名或路径将流量路由到不同的后端应用。apiVersion: tor.k8s.torproject.org/v1alpha2 kind: OnionService metadata: name: onion-ingress spec: version: 3 rules: - port: number: 80 backend: service: name: nginx-ingress-nginx-controller # 你的 nginx-ingress Service 名称 port: number: 80 # nginx-ingress 的服务端口然后你照常创建Ingress资源指定host为你洋葱服务的.onion地址或者通配符nginx-ingress就会处理这些进入的 HTTP/HTTPS 请求。你甚至可以在 Ingress 上配置 TLS虽然 Tor 网络内部是加密的但这是在洋葱服务和你的应用之间再加一层加密。警告这种配置将你的服务暴露给了两个网络。你需要确保你的应用本身没有信息泄露风险例如不会在 HTTP 头或内容中泄露内部 IP、真实域名等。同时要仔细考虑安全边界避免洋葱服务成为攻击常规服务的跳板。4.3 配置 Tor 守护进程使用网桥在某些网络环境下直接连接 Tor 网络可能被阻止。此时需要配置网桥Bridge。步骤一获取网桥信息访问 Tor 项目的网桥获取页面请注意遵守当地法律法规和使用条款选择obfs4等可插拔传输协议获取几行类似下面的配置Bridge obfs4 1.2.3.4:12345 ABCDEF123456 cert... iat-mode0步骤二在 Tor 资源中配置apiVersion: tor.k8s.torproject.org/v1alpha2 kind: Tor metadata: name: tor-with-bridges spec: config: | # 启用网桥 UseBridges 1 # 粘贴你获得的网桥配置行 Bridge obfs4 1.2.3.4:12345 ABCDEF123456 cert... iat-mode0 Bridge obfs4 5.6.7.8:54321 GHIJKL789012 cert... iat-mode0 # 其他可选配置例如禁用直接连接 # DisableNetwork 0 ClientTransportPlugin obfs4 exec /usr/local/bin/obfs4proxy # 确保 SOCKS 端口可被集群内访问 SocksPort 0.0.0.0:9050 SocksPolicy accept 10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 SocksPolicy reject *这个Tor实例启动后会使用指定的网桥连接 Tor 网络。集群内其他 Pod 可以通过这个实例的 SOCKS5 代理tor-with-bridges-tor-svc:9050进行匿名访问。4.4 启用监控指标tor-controller从 v0.5.x 开始集成了指标导出器。要启用 Prometheus 监控非常简单apiVersion: tor.k8s.torproject.org/v1alpha2 kind: OnionService metadata: name: my-monitored-onion spec: serviceMonitor: enabled: true # 关键启用 ServiceMonitor rules: [...]前提是你的集群中已经安装了Prometheus Operator并且其能发现ServiceMonitor资源。启用后Tor 守护进程和onionbalance如果适用的指标如流量、连接数、错误率等会被自动抓取。你可以配置 Grafana 仪表盘来可视化这些指标监控洋葱服务的健康状态和性能。5. 故障排查与运维经验即使有了 Operator在实际运维中还是会遇到各种问题。下面是一些常见场景和排查思路。5.1 洋葱服务无法访问这是最常见的问题。可以按照以下步骤排查检查资源状态kubectl get onion onion-name -o yaml查看status字段。如果有错误信息通常会在这里显示。确保status.ready为True。检查 Pod 状态kubectl get pods -l controlleronion-name找到对应的 Tor Pod确保其状态是Running且所有容器就绪READY列为2/2。查看 Pod 日志# 查看管理容器的日志通常包含配置生成和同步信息 kubectl logs pod-name -c manager # 查看 Tor 守护进程的日志包含连接、认证等详细信息 kubectl logs pod-name -c tor在 Tor 日志中搜索Bootstrapped 100%这表示 Tor 客户端已成功连接到网络。如果卡在某个百分比可能是网络问题或网桥配置错误。查看是否有[warn]或[err]级别的日志。检查后端服务确保OnionService中spec.rules[].backend.service指向的 Service 和 Pod 是存在的并且端口正确。可以在集群内直接curl这个 Service 的 ClusterIP 来验证后端应用是否健康。检查密钥 Secret如果使用了自定义密钥检查对应的 Secret 是否存在且数据格式正确。特别是onionAddress文件的内容是否是一个有效的.onion地址。网络策略如果你的集群使用了网络策略NetworkPolicy确保 Tor Pod 可以出站连接到 Tor 网络通常需要允许出站到 TCP 9001, 9030 等端口具体取决于配置并且 Tor Pod 可以被后端服务访问入站。5.2 控制器无法创建资源如果执行kubectl apply后资源一直处于Pending或没有相应 Pod 被创建问题可能出在控制器本身。检查控制器日志kubectl -n tor-controller logs -l app.kubernetes.io/nametor-controller查看是否有权限错误RBAC、镜像拉取失败、或者处理 CRD 时的逻辑错误。检查 RBAC确保控制器有足够的权限在你的目标命名空间中创建Deployment、Service、Secret等资源。如果是命名空间模式部署确保控制器部署在了正确的命名空间。检查 CRD确认 CRD 已成功安装kubectl get crd | grep tor.k8s.torproject.org5.3 性能调优与资源规划内存与 CPUTor 进程在建立大量连接或处理高流量时可能消耗较多 CPU 和内存。对于中高负载的洋葱服务或中继节点建议监控 Pod 的资源使用情况并适当提高spec.template.resources.limits。onionbalance前端负载均衡器本身开销不大。持久化存储默认情况下Tor 的密钥和状态数据存储在 Pod 的临时卷中。Pod 重启后如果使用的是随机密钥会生成新的地址如果使用自定义密钥会从 Secret 重新加载。目前 CRD 不支持持久化卷声明PVC。这意味着对于Tor资源代理用途重启不影响客户端重连即可。对于OnionService如果使用随机密钥重启会导致.onion地址改变这是不可接受的。因此生产环境的洋葱服务务必使用自定义密钥privateKeySecret。对于OnionBalancedService前端和后端实例都应使用自定义密钥并将密钥保存在 Secret 中。节点选择与亲和性将 Tor 相关的 Pod 调度到具有稳定网络和足够资源的专用节点上可以提高服务稳定性。使用nodeSelector、tolerations和affinity进行控制。5.4 升级与回滚升级控制器直接使用 Helm 升级即可。tor-controller的 Deployment 配置了正确的更新策略会滚动更新控制器 Pod。helm repo update helm upgrade tor-controller bugfest/tor-controller -n tor-controller升级 Tor 守护进程版本这需要通过升级tor-controller的 Helm Chart 版本来实现因为 Chart 版本绑定了tor-daemon镜像版本。升级后已有的Tor、OnionService、OnionBalancedService资源需要手动触发一次更新例如通过kubectl edit添加一个注释才能让控制器重建 Pod使用新版本的镜像。在升级前务必在测试环境验证新版本 Tor 的兼容性。回滚如果升级后出现问题可以使用 Helm 进行回滚。helm history tor-controller -n tor-controller helm rollback tor-controller REVISION_NUMBER -n tor-controller5.5 安全最佳实践最小权限原则为控制器配置精确的 RBAC 权限仅授予其管理所需资源Deployment, Service, Secret 等的权限。避免使用cluster-admin。密钥管理洋葱服务的私钥是最高机密。务必使用 Kubernetes Secret 存储并限制其访问权限通过 RBAC。考虑使用外部密钥管理服务如云厂商的 KMS、HashiCorp Vault来加密存储这些 Secret而不是明文存放在 etcd 中。网络隔离使用 Kubernetes 网络策略来限制 Tor Pod 的网络访问。例如只允许 Tor Pod 出站到必要的 Tor 网络端口限制其与集群内其他非必要服务的通信。客户端授权对于需要限制访问的洋葱服务强烈建议启用客户端授权认证而不是完全公开。审计日志确保 Kubernetes API 服务器的审计日志开启并监控对tor.k8s.torproject.org相关资源的创建、修改和删除操作。通过tor-controller我们将 Tor 这一强大的匿名网络工具无缝地集成到了云原生的 Kubernetes 体系中。它通过声明式 API 简化了复杂配置通过 Operator 模式自动化了生命周期管理并通过 CRD 提供了极大的灵活性。从简单的 SOCKS5 代理到高可用的生产级洋葱服务这个项目为在 K8s 中利用 Tor 网络提供了坚实且优雅的解决方案。在实际使用中把握好密钥管理、资源监控和安全配置这几个关键点就能让这项技术为你的应用安全、隐私和网络穿透需求提供可靠的支持。