JumpServer PAM 账号密钥查询 API 实战: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
导读
本文以 JumpServer 仓库内置的 Go 语言 SDK 示例为线索,系统讲解 PAM 资产账号密码(Secret)查询服务的完整集成方案:从 RESTful 接口的请求规范、HMAC-SHA256 签名认证原理,到 Go 代码的逐段实现与常见问题排查。读完本文,你将掌握使用 Go 安全调用 JumpServer 账号密钥接口的完整能力,包括签名请求构造、参数校验、错误处理与结果解析,并能直接复用仓库提供的现成代码。
1. 接口概览:PAM 账号密码查询服务
JumpServer 作为开源特权访问管理(PAM)平台,允许第三方系统(如运维平台、工单系统、自动化脚本)通过 RESTful API 按需获取资产账号的密码,用于自动登录、批量巡检等场景。该能力由IntegrationApplication(集成应用)机制提供:管理员先在 JumpServer 中创建"应用",绑定账号并生成密钥对,第三方服务持密钥调用接口换取账号密码,全程无需把密码明文存储在自己的系统中。
仓库中该功能的核心实现位于:
- 接口视图:apps/accounts/api/account/application.py
- 数据模型:apps/accounts/models/application.py
- 参数校验序列化器:apps/accounts/serializers/account/service.py
- 路由注册:apps/accounts/urls.py(
router.register(r'integration-applications', ...)) - 官方 SDK 示例:Go 版位于 apps/accounts/demos/go/
1.1 接口基本信息
| 项目 | 内容 |
|---|---|
| 请求方式 | GET |
| 接口路径 | api/v1/accounts/integration-applications/account-secret/ |
| 返回格式 | JSON |
| 认证方式 | HTTP Signature(HMAC-SHA256) |
| 请求参数 | asset(资产名称,必填)、account(账号名称,必填) |
响应示例:
{ "id": "72b0b0aa-ad82-4182-a631-ae4865e8ae0e", "secret": "123456" }其中id为发起请求的集成应用(服务)ID,secret为查询到的账号密码明文。
1.2 服务端参数校验:不止 asset 与 account
值得注意的是,从源码看,服务端实际支持的查询参数比原文档列出的两个更丰富。序列化器 IntegrationAccountSecretSerializer 定义了四个可选字段:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| asset | str | 条件必填 | 资产名称 |
| asset_id | UUID | 条件必填 | 资产 ID |
| account | str | 条件必填 | 账号名称 |
| account_id | UUID | 条件必填 | 账号 ID |
校验规则为:account_id一旦提供即直接通过;否则asset/asset_id至少提供一个、account/account_id至少提供一个,否则返回 400 与提示At least one of the following fields must be provided: ...。因此使用asset+account名称组合是最直观的调用方式,而account_id则提供了更精确的定位手段(demo.go 与 jms_pam.go 中均有体现)。
服务端在 get_account_secret 动作中的完整处理流程为:校验参数 → 调用service.get_account(**data)定位账号(对应模型方法 get_account,支持按名称或 ID 组合查询,且账号必须在该应用的accounts绑定列表中)→ 写入审计日志IntegrationApplicationLog→ 依据全局开关SECURITY_DISABLE_VIEW_SECRET决定是否返回密码明文。
2. 环境要求与准备工作
2.1 环境要求
编写 Go 版本 SDK 客户端需要:
- Go 1.16+
- 标准库:
crypto/hmac、crypto/sha256、encoding/base64、net/http - 可选第三方库:
github.com/google/uuid(UUID 校验)、gopkg.in/twindagger/httpsig.v1(HTTP Signature 签名,jms_pam.go 使用)
2.2 获取 API Key(KEY_ID 与 KEY_SECRET)
在 JumpServer 的PAM → 应用管理中创建集成应用,系统会生成一对凭证:
KEY_ID:应用 ID(形如72b0b0aa-ad82-4182-a631-ae4865e8ae0e的 UUID)KEY_SECRET:应用密钥(36 位随机字符串)
创建时需绑定允许访问的账号(模型中的accounts字段),并将来源 IP 加入ip_group白名单(默认['*'],见 IntegrationApplicationSerializer)。密钥可随时在应用中刷新:服务端提供GET api/v1/accounts/integration-applications/{id}/refresh-secret/动作,调用模型方法refresh_secret()重新生成 36 位随机串(application.py)。
2.3 配置项
仓库示例通过环境变量注入配置,均有默认值(demo.go):
| 环境变量 | 默认值 | 说明 |
|---|---|---|
API_URL | http://127.0.0.1:8080 | JumpServer 服务地址 |
API_KEY_ID | 示例 UUID | 应用 ID |
API_KEY_SECRET | 示例密钥 | 应用密钥 |
ORG_ID | 00000000-0000-0000-0000-000000000002 | 组织 ID,通过X-JMS-ORG请求头传递 |
生产环境务必通过环境变量覆盖默认值,切勿使用仓库中的示例凭证。
3. 签名认证:HMAC-SHA256 HTTP Signature
JumpServer 的账号密钥接口采用 HTTP Signature 方案做请求签名,防篡改、防重放。核心思想是:将请求方法、目标路径与若干请求头拼接成待签名字符串,用KEY_SECRET做 HMAC-SHA256 计算,Base64 编码后放入Authorization头。
3.1 签名串构造规则
以 demo.go 为例,签名过程分五步:
第一步:准备参与签名的请求头。示例固定签名以下字段:
(request-target) accept date x-jms-org第二步:构造待签名字符串。每行格式为字段名: 值,行间以换行符拼接:
(request-target): get /api/v1/accounts/integration-applications/account-secret/?asset=ubuntu_docker&account=root accept: application/json date: Mon, 09 Sep 2026 02:12:25 GMT x-jms-org: 00000000-0000-0000-0000-000000000002关键细节:
(request-target)为小写请求方法 + 空格 + 完整 URI(必须包含 query 参数);date使用 RFC 1123 GMT 格式(Go 布局字符串Mon, 02 Jan 2006 15:04:05 GMT);x-jms-org为组织 ID,需与请求头一致。
第三步:计算签名:
mac := hmac.New(sha256.New, []byte(c.KeySecret)) mac.Write([]byte(signatureString)) signatureB64 := base64.StdEncoding.EncodeToString(mac.Sum(nil))第四步:拼装 Authorization 头:
authHeader := fmt.Sprintf( `Signature keyId="%s",algorithm="hmac-sha256",headers="%s",signature="%s"`, c.KeyID, strings.Join(headersList, " "), signatureB64, )headers字段声明参与签名的头列表,服务端据此重建签名串。
第五步:发送请求,同时携带Accept: application/json、Date、X-JMS-ORG、X-Source: jms-pam头(X-Source用于标识调用来源)。
3.2 利用第三方库简化签名
仓库还提供了使用httpsig库的精简实现 jms_pam.go:
func (c *JumpServerPAM) SignRequest(r *http.Request) error { headers := []string{"(request-target)", "date"} signer, err := httpsig.NewRequestSigner(c.KeyID, c.KeySecret, "hmac-sha256") if err != nil { return err } return signer.SignRequest(r, headers, nil) }该版本只需签名(request-target)与date两个字段,库会自动生成Authorization头,代码更简洁;而 demo.go 的手写版本完整展示了签名原理,更适合学习与无外部依赖的场景。
4. Go 代码实战:从最小示例到完整 SDK
4.1 最小可运行示例(demo.go)
demo.go 是开箱即用的完整示例,核心调用逻辑如下:
func (c *APIClient) GetAccountSecret(asset, account string) (map[string]interface{}, error) { u, err := url.Parse(c.APIURL) // ... u.Path = "/api/v1/accounts/integration-applications/account-secret/" q := u.Query() q.Add("asset", asset) q.Add("account", account) u.RawQuery = q.Encode() req, err := http.NewRequest("GET", u.String(), nil) // ... 设置 Accept / X-JMS-ORG / Date / X-Source 头 // ... 按第 3 节构造签名并写入 Authorization 头 resp, err := c.Client.Do(req) // ... if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("API returned non-200 status: %d", resp.StatusCode) } var result map[string]interface{} if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return nil, fmt.Errorf("failed to decode response: %v", err) } return result, nil } func main() { client := NewAPIClient() result, err := client.GetAccountSecret("ubuntu_docker", "root") if err != nil { log.Fatalf("Error: %v", err) } fmt.Printf("Result: %+v\n", result) }运行方式:
cd apps/accounts/demos/go API_URL=http://your-jumpserver:8080 \ API_KEY_ID=your-key-id \ API_KEY_SECRET=your-key-secret \ ORG_ID=your-org-id \ go run demo.go4.2 完整 SDK 封装(jms_pam.go)
jms_pam.go 提供了更工程化的封装,适合集成进大型项目,包含三个核心抽象:
(1)请求对象SecretRequest:封装参数与校验逻辑。NewSecretRequest 接收asset、assetID、account、accountID四个参数,默认Method为 GET;validate 实现服务端同样的校验规则——accountID提供则直接通过(须为合法 UUID),否则要求资产与账号的名称/ID 至少各提供一个,非法 UUID 会返回invalid UUID错误。GetQuery 将非空参数编码进 query。
(2)响应对象Secret:统一结果解析。FromResponse 在状态码为 200 时解码secret并置valid = true;非 200 时将原始错误体原样存入Desc,便于上层展示服务端错误信息(如Account not found)。
(3)客户端JumpServerPAM:通过NewJumpServerPAM(endpoint, keyID, keySecret, orgID)构造(jms_pam.go),orgID为空时默认使用00000000-0000-0000-0000-000000000002;Send方法负责拼接 URL、设置请求头、签名并发送,网络错误同样写入Desc返回而非中断调用。
典型调用示例:
client := NewJumpServerPAM("http://your-jumpserver:8080", keyID, keySecret, "") req, _ := NewSecretRequest("ubuntu_docker", "", "root", "") secret, err := client.Send(req) if err != nil { log.Fatal(err) } fmt.Printf("secret=%s valid=%v\n", secret.Secret, secret.Valid)4.3 与服务端实现对照
客户端 SDK 的行为与服务端源码一一对应:
IntegrationApplicationViewSet.get_account_secret要求RBACPermission权限,即调用方必须是通过X-JMS-ORG指定组织内的有效集成应用(模型 is_authenticated 返回is_active);- 请求成功会写入 IntegrationApplicationLog,记录来源 IP、服务名、账号与资产信息,便于审计追溯;
- 若
settings.SECURITY_DISABLE_VIEW_SECRET开启,接口返回的secret为None——这是全局"禁用查看密钥"策略,调用方需据此调整业务逻辑。
5. 常见问题(FAQ)
Q: API Key 如何获取?
A: 在 JumpServer 的PAM → 应用管理中创建应用,即可生成KEY_ID和KEY_SECRET。创建后需在应用中绑定目标账号,并确保调用方 IP 在ip_group白名单内。
Q: 请求返回 400 "At least one of the following fields must be provided"?
A: 未满足参数组合要求。检查是否提供了asset/asset_id与account/account_id(名称与 ID 组合亦可,但至少各一个)。另外,若传了account_id但格式非法(非 UUID),会提示invalid UUID。
Q: 返回 "Account not found"?
A: 账号不存在,或该账号未绑定到当前集成应用。请确认应用管理中的绑定账号列表,以及asset名称是否与资产名称完全一致。
Q: 签名校验失败(401)?
A: 重点核对三点:date头是否为 RFC 1123 GMT 格式;(request-target)是否包含完整 query 且方法为小写get;headers声明顺序与签名串中头的顺序、取值是否完全一致。建议先对照 demo.sh 用 curl 打通,再用 Go 复现。
Q: 响应中 secret 为 null?
A: JumpServer 开启了全局SECURITY_DISABLE_VIEW_SECRET安全策略,密钥查看被禁用,需要管理员在系统设置中调整。
6. 版本历史(Changelog)
| 版本号 | 变更内容 | 日期 |
|---|---|---|
| 1.0.0 | 初始版本 | 2025-02-11 |
7. 延伸阅读
本主题在仓库中还提供了其他语言的等价示例,可对照阅读:
- Python:apps/accounts/demos/python/demo.py 与 apps/accounts/demos/python/jms_pam/main.py
- Java:apps/accounts/demos/java/demo.java
- Node.js:apps/accounts/demos/node/demo.js
- curl:apps/accounts/demos/curl/demo.sh(最适合先验证签名链路)
各语言示例的 README 与代码文件结构一致,签名规则完全相同,理解了本文的 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),仅供参考