dsh-cloudflare-access

securityinstall failsnpmMIT

Re-validates Cloudflare Access JWTs at the DSH origin so Settings, Credentials, Agent Preset management, and model discovery work from a remote hostname.

下载量 / Downloads
905
测试时间 / Tested
2026-11-07
DSH 版本 / Version
0.2.2-rc.1

Install

dsh plugin --profile web add dsh-cloudflare-access

Sandbox test results

StageResult
1 install✗
2 list—
3 mount—
4 boot—
First error
dsh: initialized profile web at /home/node/.dsh/profiles/web

Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).

README

dsh-cloudflare-access

[English](./README.md)

面向 DeepSeek Harness 的 Cloudflare Access JWT 再验证与远程 privileged 授权。

这是双面 Profile Bundle + Web Client 插件。它不替代 Cloudflare Access。身份仍在 Access。插件在 DSH Origin 再验证 Cf-Access-Jwt-Assertion,使 Settings、Credentials、Agent Preset 管理和模型发现可以在 https://dsh.example.com 这类远程主机名上工作。

不提供登录页、密码库、MFA、会话表或 Cloudflare API 客户端。

插件 2.0.x 对准 DeepSeek Harness 0.1.5-alpha.1。插件 1.0.x 是 DSH 0.1.2 之前那条线(live 验证于 0.1.1-rc.2)。在[兼容性矩阵](#兼容性)更新之前,不要默认其他 DSH 版本可用。

架构

插件运行在 DSH 进程内。它不替代 Cloudflare Access,也不替代 Origin 允许名单。

Internet → Cloudflare Access → Cloudflare Proxy
       → Origin allowlist → reverse proxy → DSH → this plugin

Web Client 只做 capability enablement(connection.isLoopback)。授权裁决留在 Origin 上的 Server。

交互图(切换主题、Guided Views、导出 SVG/PNG):[deployment](./docs/assets/archify/deployment.html)、[request path](./docs/assets/archify/privileged-request.html)、[client vs server](./docs/assets/archify/client-server.html)、[config](./docs/assets/archify/config-precedence.html)。说明见 [docs/diagrams.md](./docs/diagrams.md)。

快速开始

1. 使用 DeepSeek Harness Web profile。用 --trusted-host 钉住公网主机名。

2. 把该 Origin 放到 Cloudflare Access 应用后面。

3. 安装并重启:

dsh plugin --profile web add dsh-cloudflare-access

4. 锁定信任根(生产环境建议如此):

export DSH_CF_ACCESS_TEAM_DOMAIN=https://example.cloudflareaccess.com
export DSH_CF_ACCESS_AUDIENCES=your-access-application-aud

5. 经 Access 打开站点并硬刷新一次,再打开 Settings。Origin 上有效的 Cf-Access-Jwt-Assertion 会代替远程 Host 上的 DSH launch-token Cookie。loopback 仍须使用 dsh web 打印的 ?token= URL。

用 dsh --profile web --dump-config 确认 bundle:应有一层名为 dsh-cloudflare-access,以及插件行 id: cloudflare-access。

安全模型

远程 privileged 请求必须同时通过:

1. DSH 的 Host / Origin / sec-fetch-site 检查(--trusted-host 仍是必须的)。

2. 有效的 Cloudflare Access JWT(签名、iss、aud、过期时间;允许约 30 秒时钟偏差)。

有效 JWT 永远不能授权任意 Host 或 Origin。Loopback(localhost / 127.0.0.1 / ::1)不要求 JWT,因此 SSH Tunnel → localhost → DSH 仍然可用。v2.0 中远程 privileged API 始终要求 JWT。

Origin 应只对 Cloudflare(或等价入口)可达。安装本插件不是把 DSH 挂到公网的理由。详见 [SECURITY.md](./SECURITY.md)。

先做 Host/Origin。有效 JWT 不得把 Host 改写为 loopback。privileged 成功交给原 /api handler(DSH Remote);远程信任主机上有效 Access JWT 同时跳过 DSH launch-token Cookie。缺失或无效 JWT 返回 401/403,且不进入 privileged 业务实现。Loopback 不读 JWT,仍走官方 token/Cookie。

转发 Host、Origin 和 Cf-Access-Jwt-Assertion。不要剥掉 assertion 头。不要信任 CF_Authorization Cookie。

安装

需要 Web profile。包在 npm。

dsh plugin --profile web add dsh-cloudflare-access

未发布的 Git commit:

dsh plugin --profile web add github:Luawig/dsh-cloudflare-access

Git 树已包含预构建的 lib/index.js 和 lib/client.js。github: 安装使用这些产物,不需要 TypeScript 或 esbuild。

重启 DSH。不要手工编辑 $DSH_HOME/profiles/web/cordis.patch.yml,也不要改 DSH 本体。

卸载:

dsh plugin --profile web remove dsh-cloudflare-access

unload 后,本插件的 JWT 包装消失。若运行中的进程仍是旧 fiber,再重启一次。

配置

1. 把 DSH Web origin 放到 Cloudflare Access 应用后面。

2. 复制应用的 Audience(aud)和 team domain,例如 https://example.cloudflareaccess.com(省略 https:// 的主机名也可以)。

3. Cloudflare 会在已认证请求上注入 Cf-Access-Jwt-Assertion。该头是本插件读取的唯一身份。

team domain 规范化为 http(s) origin(路径丢弃)后,推导 issuer 与 JWKS URL:

issuer  = <origin>
JWKS    = <origin>/cdn-cgi/access/certs

不要配置 issuer 或 jwksUrl。支持多个 audience。

生产环境用环境变量钉住 team domain 和 audience。变量一旦存在(即使是空字符串),该字段即锁定,无法从远程 Settings 会话改指向。

变量 · 含义

DSH_CF_ACCESS_TEAM_DOMAIN · Team domain / issuer

DSH_CF_ACCESS_AUDIENCES · 逗号分隔的 audience

DSH_CF_ACCESS_ORDINARY_MODE · off \ · optional \ · required

dsh --profile web --trusted-host dsh.example.com

systemd:

[Service]
Environment=DSH_CF_ACCESS_TEAM_DOMAIN=https://example.cloudflareaccess.com
Environment=DSH_CF_ACCESS_AUDIENCES=your-access-application-aud
Environment=DSH_CF_ACCESS_ORDINARY_MODE=off
ExecStart=/usr/bin/dsh --profile web --trusted-host dsh.example.com

Cordis overlay(仅当对应 env 未设置时使用):

cloudflare:
  teamDomain: https://example.cloudflareaccess.com
  audiences:
    - your-access-application-aud
auth:
  ordinary: off

缺少 teamDomain 或 audiences:插件仍会启动,loopback 不变,远程 privileged API 被拒绝。

普通 API 模式

auth.ordinary 只作用于远程非特权 API,包括 /api/remote.mux。Loopback 忽略它。Host/Origin 始终先执行。

模式 · 无 JWT · 有效 JWT · 无效 JWT

off(默认) · DSH 原策略 · 忽略 · 忽略

optional · DSH 原策略 · 放行 · 拒绝

required · 拒绝 · 放行 · 拒绝

无论该设置如何,远程 privileged API 始终要求有效 JWT。

排障

现象 · 检查

远程 Settings 仍不可用 · Access 必须在站点前面;硬刷新,使 Client 模块在 Settings 之前加载;确认 Cf-Access-Jwt-Assertion 到达 Origin。

Settings UI 从不调用 settings/describe · 本包设置了 dsh.client.immediately: true。若旧 tarball 漏了该项,重新安装。

settings/* 返回 401 · Access header 缺失或未被转发。查反向代理是否转发 Cf-Access-Jwt-Assertion。loopback 仍须打开 dsh web 打印的 ?token= URL。

settings/* 返回 403 · iss/aud/签名/过期无效、插件未配置、Host/Origin 不匹配,或 Origin 时钟偏差超过约 30 秒。

ordinary=required 时事件 WebSocket 失败 · /api/remote.mux 走普通 API 策略。缺 JWT → 401;无效 JWT → 403。

Loopback Settings 坏了 · 卸载插件;loopback 不得要求 JWT。若仍要求,请报 bug。

JWKS / 密钥轮换失败 · Origin 必须能访问 https://<team>/cdn-cgi/access/certs。Cloudflare 轮换密钥后无需改配置。

日志 · 只记录类别(expired、invalid_signature、issuer_mismatch、audience_mismatch、missing_token、jwks_unavailable、unconfigured)。从不记录 token。

本插件不授权 host.pickDirectory 或 host.openPath。部分 native-host UI 仍可能出现。

兼容性

插件 · DSH · 状态

1.0.x · 0.1.1-rc.2(0.1.2 之前) · Live 验证(Web profile,远程 Settings / Credentials)。走 apiProxy + privileged pin。与 DSH 0.1.2+ 不兼容。

2.0.x · 0.

…(truncated)

Rendered from the README published on npm. Formatted only, not edited.

Versions

Published on npm::3,最后更新 2026-09-09

Links

GitHub · Homepage · npm

Same category