JumpServer Node.js SDK 实战:通过签名鉴权调用 PAM 账户密钥获取 API
【免费下载链接】jumpserverJumpServer is an open-source Privileged Access Management (PAM) platform that provides DevOps and IT teams with on-demand and secure access to SSH, RDP, Kubernetes, Database and RemoteApp endpoints through a web browser.项目地址: https://gitcode.com/GitHub_Trending/ju/jumpserver
导读
本文基于 JumpServer 开源仓库中 apps/accounts/demos/node 目录下的官方 Node.js 示例(README.ru.md与demo.js),系统讲解如何通过 Node.js 调用 JumpServer 的PAM 账户密钥获取接口(GET /api/v1/accounts/integration-applications/account-secret/)。读完本文,你将掌握该 RESTful 接口的请求参数与返回格式、基于 HMAC-SHA256 的请求签名机制、axios+moment的完整客户端实现,以及后端对应的鉴权与审计原理,可直接在自己的业务系统中安全地拉取资产账户密码。
1. 接口概览
该接口用于按资产名(asset)与账户名(account)获取 JumpServer PAM(特权访问管理)中托管账户的密钥(密码)。它采用标准 RESTful 风格,请求成功后返回 JSON 数据。
请求方式:GET api/v1/accounts/integration-applications/account-secret/
请求参数:
| 参数名 | 类型 | 是否必填 | 说明 |
|---|---|---|---|
| asset | str | 是 | 资产名称(Asset Name) |
| account | str | 是 | 账户名称(Account Name) |
响应示例:
{ "id": "72b0b0aa-ad82-4182-a631-ae4865e8ae0e", "secret": "123456" }其中id为调用方(集成应用)的 ID,secret为查询到的账户密钥明文。值得说明的是,secret是否真正返回还受后端全局配置SECURITY_DISABLE_VIEW_SECRET控制(详见下文第 4 节),因此生产环境下响应中的secret可能为null。
2. 环境要求
运行官方 Node.js 示例需要满足以下依赖(版本以 demo.js 与文档声明为准):
Node.js 16+axios ^1.7.9(发起 HTTP 请求)moment ^2.30.1(生成 RFC 7231 格式的时间戳,用于签名)
安装命令示例:
npm install axios@^1.7.9 moment@^2.30.13. 完整 Node.js 客户端实现解析
官方示例 demo.js 将整个调用封装为一个APIClient类,核心分为配置注入、请求签名与接口调用三部分。
3.1 配置注入:环境变量
客户端通过环境变量注入服务地址与凭据,便于在不同环境(测试/生产)间切换:
const API_URL = process.env.API_URL || "http://127.0.0.1:8080"; const KEY_ID = process.env.API_KEY_ID || "72b0b0aa-ad82-4182-a631-ae4865e8ae0e"; const KEY_SECRET = process.env.API_KEY_SECRET || "6fuSO7P1m4cj8SSlgaYdblOjNAmnxDVD7tr8"; const ORG_ID = process.env.ORG_ID || "00000000-0000-0000-0000-000000000002";| 环境变量 | 默认值 | 含义 |
|---|---|---|
API_URL | http://127.0.0.1:8080 | JumpServer 服务地址(Core) |
API_KEY_ID | 示例 UUID | 在「PAM - 应用管理」中创建应用后生成的 KEY_ID |
API_KEY_SECRET | 示例字符串 | 与应用对应的 KEY_SECRET |
ORG_ID | 00000000-...-0002 | 目标组织 ID |
注意:默认值仅用于本地演示,实际使用必须通过环境变量替换为真实凭据,避免密钥泄露。
3.2 签名机制:HMAC-SHA256
JumpServer 对该类接口使用HTTP Signature(请求签名)认证。signRequest方法完成全部签名工作:
signRequest(method, url, params, headers) { const date = moment().utc().format('ddd, DD MMM YYYY HH:mm:ss [GMT]'); const queryString = Object.keys(params).length ? `?${new URLSearchParams(params).toString()}` : ""; const requestTarget = `${method.toLowerCase()} ${url}${queryString}`; headers['Date'] = date; headers['X-JMS-ORG'] = this.orgId; const signingString = `(request-target): ${requestTarget}\naccept: application/json\ndate: ${date}\nx-jms-org: ${this.orgId}`; const signature = crypto.createHmac('sha256', this.keySecret).update(signingString).digest('base64'); headers['Authorization'] = `Signature keyId="${this.keyId}",algorithm="hmac-sha256",headers="(request-target) accept date x-jms-org",signature="${signature}"`; }关键点拆解:
- 时间戳:使用
moment().utc()生成形如Tue, 09 Sep 2026 03:00:00 GMT的 UTC 时间,同时放入Date请求头,并参与签名串拼装,用于防重放。 - request-target:由
方法小写 + 空格 + 路径 + 查询串构成,签名覆盖了请求目标,防止请求被篡改转发。 - 签名串:按
(request-target)、accept、date、x-jms-org的顺序以换行拼接,headers字段中声明的正是这些被签名覆盖的请求头。 - 算法:
crypto.createHmac('sha256', this.keySecret),即 KEY_SECRET 作为 HMAC 密钥,对签名串做 SHA-256 摘要后 Base64 编码。 - X-JMS-ORG:通过请求头传递组织 ID,签名中也包含该项,保证组织信息不可被中间篡改。
服务端的对应实现可参见 apps/authentication/backends/drf.py 中的ServiceAuthentication(source = 'jms-pam'):它根据请求头中的keyId在IntegrationApplication表中查找id匹配且is_active=True的应用,以其secret作为校验密钥,并通过is_ip_allow对请求来源 IP 与应用的ip_group白名单做校验。
3.3 调用账户密钥接口
async getAccountSecret(asset, account) { const url = `/api/v1/accounts/integration-applications/account-secret/`; const params = { asset: asset, account: account }; const headers = { 'Accept': 'application/json', 'X-Source': 'jms-pam' }; this.signRequest('GET', url, params, headers); try { const response = await axios.get(`${this.apiUrl}${url}`, { headers: headers, params: params, timeout: 10000 }); return response.data; } catch (error) { console.error(`API request failed: ${error}`); return null; } }- 请求头除签名外还携带
X-Source: jms-pam,标识调用来源; - 超时时间设置为 10 秒;
- 调用示例:
client.getAccountSecret("ubuntu_docker", "root"),即查询资产ubuntu_docker上root账户的密码。
完整入口:
(async () => { const client = new APIClient(); const result = await client.getAccountSecret("ubuntu_docker", "root"); console.log(result); })();4. 后端实现原理:接口背后的完整链路
该接口的后端实现位于 apps/accounts/api/account/application.py 的IntegrationApplicationViewSet.get_account_secret,路由在 apps/accounts/urls.py 中注册:
router.register(r'integration-applications', api.IntegrationApplicationViewSet, 'integration-apps')接口处理流程如下:
- 参数校验:使用
IntegrationAccountSecretSerializer校验查询参数(asset、account),不合法直接返回400与错误详情; - 账户查找:将认证后的集成应用作为
service,调用service.get_account(**serializer.data)定位目标账户;找不到时抛出Account not found(JMSException); - 审计留痕:每次查询都会写入
IntegrationApplicationLog,记录来源 IP、服务名、账户与资产信息(apps/audits模块),便于事后追溯; - 密钥返回策略:是否返回明文密码由配置
SECURITY_DISABLE_VIEW_SECRET决定:
secret = None if settings.SECURITY_DISABLE_VIEW_SECRET else account.secret即当该配置开启(禁用查看密钥)时,即使账户存在,secret也会返回None。这是本文开头「响应中的 secret 可能为 null」的根因。
此外,IntegrationApplicationViewSet还提供两个相邻能力:
GET /api/v1/accounts/integration-applications/{id}/secret/(get_once_secret):返回单个应用自身的密钥,且强制要求MFA 二次确认(UserConfirmation.require(ConfirmType.MFA)),权限为accounts.change_integrationapplication;GET /api/v1/accounts/integration-applications/{id}/refresh-secret/(refresh_secret):调用instance.refresh_secret()重新生成应用密钥,用于密钥轮换。
5. 如何获取 API 密钥(FAQ)
Q:如何获得 API 密钥?
A:在 JumpServer 的「PAM - 应用管理」中创建一个应用(Application),即可生成 KEY_ID 与 KEY_SECRET 一对凭据。创建完成后:
- 将
KEY_ID与KEY_SECRET分别注入API_KEY_ID、API_KEY_SECRET环境变量; - 确认该应用处于启用状态(
is_active=True),否则服务端ServiceAuthentication将拒绝认证; - 如应用配置了 IP 白名单(
ip_group),还需确保调用方出口 IP 在白名单内,否则会被is_ip_allow拦截。
如需在自己的业务代码中动态获取这些 SDK 示例,可调用后端暴露的GET /api/v1/accounts/integration-applications/sdks/?language=node接口(get_sdks_info),它会按语言(python/java/go/node/curl)返回对应的 README 与 demo 代码,其中 README 会依据当前语言环境自动选取 apps/accounts/demos/node 下的多语言版本(如README.zh-hans.md、README.en.md、README.ru.md)。
6. 常见问题与排错建议
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
401 Unauthorized | KEY_ID/KEY_SECRET 不匹配、应用未启用、请求签名串与发送的请求不一致 | 核对环境变量;确认时间戳为 UTC GMT 格式;检查headers字段与签名串顺序是否与 demo.js 一致 |
403拒绝 | 来源 IP 不在应用的ip_group白名单内 | 在应用管理中调整 IP 白名单 |
Account not found | 资产名或账户名拼写错误,或账户不属于该资产 | 使用asset的名称(而非地址)查询;在资产列表核对账户 |
secret返回null | 全局配置SECURITY_DISABLE_VIEW_SECRET开启 | 由管理员评估后在系统设置中关闭该配置 |
| 请求超时(10s) | 网络不通或 Core 服务负载高 | 确认API_URL可达;curl命令可先做连通性验证 |
7. 延伸阅读
- 官方 Node.js 示例源码:apps/accounts/demos/node/demo.js
- 接口后端实现:apps/accounts/api/account/application.py
- 路由注册:apps/accounts/urls.py
- 服务端签名认证实现:apps/authentication/backends/drf.py
- 签名认证测试用例:apps/authentication/tests/access_key.py
- 其他语言 SDK 示例:
curl(apps/accounts/demos/curl)、python(apps/accounts/demos/python)、java(apps/accounts/demos/java)、go(apps/accounts/demos/go)
【免费下载链接】jumpserverJumpServer is an open-source Privileged Access Management (PAM) platform that provides DevOps and IT teams with on-demand and secure access to SSH, RDP, Kubernetes, Database and RemoteApp endpoints through a web browser.项目地址: https://gitcode.com/GitHub_Trending/ju/jumpserver
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考