news 2026/9/20 13:17:55

pnpr OCI 仓库级作用域令牌认证:`oci.bearerAuth` 配置完全指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
pnpr OCI 仓库级作用域令牌认证:`oci.bearerAuth` 配置完全指南
  • 包管理器
  • 开发工具
  • CLI

【免费下载链接】pnpm

Fast, disk space efficient package manager

项目地址:https://gitcode.com/gh_mirrors/pn/pnpm
点击查看免费下载

导读

本指南围绕 pnpr(pnpm 仓库自带的 OCI 镜像分发服务)新增的oci.bearerAuth配置项展开,讲解如何在 pnpr 的 OCI Distribution 接口上启用 Bearer 令牌认证,让dockerpodmanskopeo等容器客户端通过短时、仓库级作用域(repository-scoped)的凭证访问私有镜像。读完本文,你将掌握该配置的启用方式、令牌的签发与校验流程、权限授予规则、上游 pull-through 场景下的令牌协商机制,以及相关的安全边界与测试验证方法。

一、背景:pnpr 的 OCI 分发面与 Bearer 挑战

pnpr 在pnpr/crates/pnpr/src/server/oci/tokens.rs中实现了一套完整的 OCI token 服务。pnpr 的 OCI 服务面暴露/v2/下的 OCI Distribution API,并同时支持/oci/v2//oci/~<name>/v2/两种寻址方式(见 pnpr README)。

OCI 生态的认证采用Bearer 挑战-响应(challenge-response)模式:当客户端(如dockerpodmanskopeo)访问受保护的资源且未携带有效凭证时,服务端返回401 Unauthorized,并在WWW-Authenticate响应头中给出形如Bearer realm="...",service="..."的挑战;客户端随后携带自己的身份凭证向realm指向的 token 服务换取一个访问令牌,再用该令牌访问真正的资源。

在启用该特性之前,pnpr 的 OCI 面不具备这套令牌协商能力,容器客户端无法使用短时、仓库级作用域的凭证。本特性对应的 changeset 记录在 .changeset/pnpr-oci-scoped-tokens.md 中:设置oci.bearerAuth: true即可让容器客户端使用短时、仓库级作用域的凭证。

二、启用oci.bearerAuth

oci.bearerAuth是 pnpr 配置中oci区块的布尔开关,与镜像字节数限制等参数并列定义。从源码看,其结构体定义在 pnpr/crates/config/src/lib.rs 的OciConfig中:

/// Authentication and byte limits for the OCI distribution surface. #[derive(Debug, Clone, Deserialize)] #[serde(default, rename_all = "camelCase", deny_unknown_fields)] pub struct OciConfig { pub bearer_auth: bool, pub max_blob_bytes: u64, pub max_manifest_bytes: usize, } impl Default for OciConfig { fn default() -> Self { Self { bearer_auth: false, max_blob_bytes: 10 * 1024 * 1024 * 1024, max_manifest_bytes: 4 * 1024 * 1024, } } }

要点:

  • 字段采用 camelCase 序列化rename_all = "camelCase"),因此配置文件中必须写作oci.bearerAuth,而不是oci.bearer_auth
  • 默认值为false,即默认不启用 Bearer 认证,与既有行为保持兼容;
  • 配置结构使用deny_unknown_fields,写入oci区块中未知的字段会导致配置校验失败。

在 pnpr 的 YAML 配置文件中启用方式如下:

oci: bearerAuth: true # 以下为同区块的既有配置,可一并调整 maxBlobBytes: 10737418240 # 单层 blob 上限,默认 10 GiB maxManifestBytes: 4194304 # 单 manifest 上限,默认 4 MiB

在 pnpr README 中,对启用后的行为有明确说明:

Setoci.bearerAuth: trueto offer a Bearer challenge. Clients exchange their pnpr credential at/v2/tokenfor a five-minute token scoped to repositorypull,push, ordeleteactions. The endpoint grants only permitted actions. The parent credential's revocation, read-only flag, and network restrictions remain effective. Anonymous tokens can pull public repositories. Use the samesecret:and registry configuration on all replicas so their tokens interoperate. Scoped tokens cannot access other pnpr APIs or the whole catalog.

三、挑战(challenge)的生成

oci.bearerAuth: true时,任何对 OCI 资源的未授权访问都会得到一个规范的 Bearer 挑战。该逻辑位于challenge()函数(pnpr/crates/pnpr/src/server/oci/tokens.rs):

let realm = format!("{}{base}/token", state.inner.config.http.public_url.trim_end_matches('/')); let mut value = format!(r#"Bearer realm="{realm}",service="pnpr""#);

即服务端生成的挑战格式为:

WWW-Authenticate: Bearer realm="https://<pnpr 公网地址>/<base>/token",service="pnpr",scope="repository:<name>:<actions>"

几点实现细节:

  • realm指向 token 签发端点/v2/token(或对应生态前缀下的 token 端点);
  • service固定为"pnpr",token 签发时也会校验查询参数中的service必须等于pnpr,否则返回BadRequest(“invalid OCI token service”);
  • scope依据请求方法动态推导GET/HEAD请求对应pullDELETE对应pull,push,delete,其余写操作对应pull,push
  • 挑战响应会经过private_no_cache处理,禁止缓存,避免令牌/挑战信息被中间层复用。

如果oci.bearerAuth未开启,则即使收到401,响应中也不会附加WWW-Authenticate头,客户端不会进入令牌协商流程。

四、令牌的签发:/v2/token端点

客户端收到挑战后,携带自己的 pnpr 身份凭证(如Authorization: Basic ...)向realm端点发起令牌请求。issue_token()的完整处理流程(pnpr/crates/pnpr/src/server/oci/tokens.rs)如下:

  1. 开关检查:若oci.bearerAuthfalse,直接返回Unsupported错误(“OCI Bearer authentication is disabled”);
  2. 目标注册表解析:通过addressed_registry()解析请求寻址的 OCI 注册表;
  3. 父凭证校验:从请求头解析身份凭证(token_credentials);若请求携带了凭证但调用方身份为匿名,返回Unauthorized(“invalid credentials”);
  4. 父令牌追溯:若携带的是已签发的 pnpr 令牌,则按其哈希查询父令牌记录,并继承其readonly(只读)标记;
  5. 作用域授予:根据请求查询参数中的scope计算调用方实际被授予的仓库作用域(见下一节);
  6. 签名签发:将 claims(父令牌引用、audience、过期时间、作用域映射)序列化后,用 P-256 ECDSA 私钥签名,输出形如pnpr_oci_<payload>.<signature>的令牌(TOKEN_PREFIX = "pnpr_oci_"),并以 JSON 返回:
{ "token": "pnpr_oci_<payload>.<signature>", "expires_in": 300 }

4.1 短时 TTL 与客户端侧缓存

令牌的 TTL 由常量TTL: u64 = 300决定(5 分钟),每次签发都会返回expires_in: 300。从源码注释可以确认,签发方同时维护了令牌过期时间的取整与安全余量策略:cache_oci_tokenexpires_in会被限制在5..=3600秒,且缓存时预留 5 秒的提前过期余量,避免边缘场景下使用即将过期的令牌。

4.2 签名与防伪造

令牌签名使用p256::ecdsa::SigningKey,其私钥由resolution_cache_secret派生(sha256("pnpr OCI token signing v1\0" + secret))。校验端(decode/verify_claims)会:

  • 校验令牌前缀pnpr_oci_
  • 拒绝长度超过16 * 1024字节的令牌;
  • 用 URL-safe Base64 解码 payload 与签名,使用 P-256 公钥验签;
  • 校验expires是否已过期;
  • 校验oci.bearerAuth是否仍处于开启状态(关闭后旧令牌立即失效)。

由于私钥由secret:配置派生,README 特别强调:所有 replica 应使用相同的secret:与注册表配置,令牌才能互相校验通过

五、仓库级作用域:只能拿到“被授权的最小权限”

这是本特性最核心的设计:令牌携带的不是全局权限,而是一个仓库名到动作集合的映射。令牌 claims 结构如下:

pub struct Claims { pub parent: Option<String>, // 父令牌的哈希引用(用于追溯与撤销) audience: String, // 令牌的 audience(即寻址路径) expires: u64, // 过期时间戳(秒) scopes: BTreeMap<String, Vec<String>>, // 仓库名 -> 动作列表 }

5.1 scope 解析与授予

令牌请求的scope参数遵循 OCI 标准格式repository:<name>:<actions>(动作可逗号分隔多个,如pull,push)。granted_scopesgrant_one_scope的处理逻辑:

  • 未知资源类型直接忽略resource不是repositoryrepository(plugin)的 scope 会被跳过——这保证 pnpr 自己的内部 scope 不会被错误授予;
  • 非法 scope 被丢弃而非拒绝整个请求(与 OCI 协议一致:对不可读仓库的访问以“空授予”应答,而非直接报错);
  • 仓库名必须能解析为合法的 OCI 包名CanonicalPackageName::parse),否则忽略;
  • 单个令牌最多授予 32 个不同仓库,超出返回BadRequest(“too many OCI token scopes”);
  • 每个动作必须通过两次授权authorize(...Action::Access)(可读)是任何动作的前提,之后pull对应Action::Accesspush对应Action::Publishdelete对应Action::Unpublish
  • 只读父令牌的约束:若父令牌携带readonly标记,则非pull动作一律不被授予。

5.2 令牌的使用校验

客户端拿到令牌后访问GET /v2/<name>/manifests/...等资源时,服务端调用Claims::permits(path, method)校验:

  • 令牌的audience必须与请求路径前缀匹配,且后续路径必须形如/v2/...
  • 从路径中解析出端点(manifest、blob、tags、referrers、upload 等),并提取仓库名;
  • 依据方法推导所需动作:GET/HEADpullDELETEdelete,上传会话(含取消)→push
  • 只有请求的仓库确实在scopes中且包含所需动作时才放行。

测试用例token_scopes_ignore_unknown_resources_and_count_distinct_repositories直接验证了这些行为:构造携带多个scope的令牌请求,确认未知资源被忽略、不同仓库被分别计数,且返回的令牌可以按 Bearer 方式用于后续请求。

5.3 令牌边界:不能做什么

README 明确强调令牌的边界:

  • 令牌无法访问 pnpr 的其他 API(如 npm 生态接口);
  • 令牌无法枚举整个 catalogEndpoint::Catalogpermits中直接返回false);
  • 令牌无法扩展到未授予的仓库
  • 父凭证的撤销、只读标记与网络限制始终生效——即如果父凭证被吊销,其后代令牌即使未过期也无法继续使用(decode校验后还需通过authorize阶段)。

六、上游 pull-through:镜像仓库作为上游时的令牌协商

oci.bearerAuth不仅作用于 hosted(托管)镜像仓库,也深刻影响pull-through 代理场景。pnpr 可以将 Docker Hub、GHCR 等配置为 OCI 上游(见 pnpr README 中的示例):

registries: dockerhub: type: upstream ecosystem: oci url: https://registry-1.docker.io/ public: true defaultRegistry: dockerhub

上游 OCI 拉取的核心实现在 pnpr/crates/upstream/src/oci.rs,其协商流程:

  1. 无凭证首访:pnpr 先不带令牌发起GET/HEAD,若收到401WWW-AuthenticateBearer挑战,则解析挑战;
  2. 解析挑战:仅接受Bearerscheme,且realm/service参数合法(不支持反斜杠转义);
  3. 校验 realmtoken_realm_allowed要求 realm 无用户名/密码/片段,且要么与注册表同源,要么是 Docker Hub →https://auth.docker.io/token这一被明确允许的组合;
  4. 换取令牌:向 realm 发起带servicescope=repository:<name>:pull的请求,凭证(Authorization头)只会在“realm 与注册表不同源但传输安全”时转发;
  5. 缓存令牌:按仓库缓存,expires_in截断到5..=3600秒并预留 5 秒余量,最多缓存 256 个条目,过期条目惰性清理;
  6. 重放与重定向:携带令牌重试请求;对层下载的重定向(如 Docker Hub 的 Cloudflare CDN),仅在oci_download_allowed白名单内的目标(Docker Hub 的三个官方 CDN 源、GHCR 的pkg-containers.githubusercontent.com)才放行。

源码注释明确了两条安全红线:

  • 凭证绝不流向层 CDN 或重定向后的 token 端点with_oci_credentials仅在 URL 与注册表同源且传输安全时才附加凭证);
  • 下游请求者(容器客户端)的凭证也不会被透传给上游——令牌只在 pnpr 与上游之间协商,客户端只会拿到 pnpr 自己签发的 scoped token。

七、安全模型与运维要点

综合源码与 README,使用oci.bearerAuth时需要关注以下安全与运维边界:

关注点说明依据
默认关闭bearer_auth: false,显式开启后才提供 Bearer 挑战OciConfig::default
短时令牌TTL 固定 5 分钟,过期即失效TTL: u64 = 300
仓库级作用域令牌仅含被授予仓库的pull/push/delete动作Claims.scopes
匿名可拉公共仓库匿名令牌可执行pull公共仓库,不可执行写操作grant_action逻辑
父凭证撤销生效父凭证被吊销或只读,后代令牌自动受限parent追溯
多副本一致性所有 replica 需共享同一secret:与注册表配置pnpr README
令牌不越权无法访问其他 pnpr API、无法枚举 catalogpermits()拒绝Endpoint::Catalog
上游凭证不外泄上游协商的凭证不流向层 CDN 与重定向目标oci.rs

八、如何验证:测试与实操

8.1 仓库内的自动化验证

pnpr 为 OCI 认证提供了完整的集成测试,是理解该特性的最佳入口:

  • pnpr/crates/pnpr/tests/oci_registry/authorization.rs:覆盖令牌签发、作用域忽略/计数、Bearer 携带请求等核心路径,测试中显式设置config.http.oci.bearer_auth = true
  • pnpr/crates/pnpr/tests/oci_registry/uploads.rs:覆盖携带认证的 blob 上传会话;
  • pnpr/crates/pnpr/tests/oci_registry/behavior.rs:OCI 面的行为级测试;
  • pnpr/crates/config/src/tests/upstream.rs:验证上游auth: type: bearer会转换为Authorization: Bearer <token>头,以及oci.bearerAuth配置的解析。

8.2 手动验证

启用oci.bearerAuth: true后,可用任一容器客户端验证完整协商流程:

# 1. 未携带凭证访问,观察 401 + WWW-Authenticate 挑战头 curl -i https://pnpr.example.com/v2/acme/app/manifests/latest # 2. 携带 pnpr 身份凭证向 realm 换取 scoped token # (realm 由上一步的 WWW-Authenticate 头给出,如 .../v2/token?service=pnpr&scope=repository:acme/app:pull) # 3. 使用 skopeo 完整走一遍 Bearer 协商 skopeo copy docker://pnpr.example.com/acme/app:1.0 oci:./app:1.0

skopeo的等价命令亦见 pnpr README 的 OCI 章节,podmandocker等标准客户端遵循同一 Bearer 流程,无需额外配置即可对接。

九、结语

oci.bearerAuth为 pnpr 的 OCI 分发面补上了标准的 Bearer 令牌认证能力:客户端用一次性、5 分钟有效、仓库级作用域(pull/push/delete)的令牌访问镜像资源,令牌由 P-256 签名防伪造,父凭证的撤销与只读语义全程生效,上游 pull-through 场景下凭证也严格限定在注册表与可信 realm 之间,绝不流向层 CDN。该特性在 .changeset/pnpr-oci-scoped-tokens.md 中标记为@pnpm/pnpr的 minor 变更,源码、配置与集成测试均位于pnpr/目录,可作为深入研读的起点。

  • 包管理器
  • 开发工具
  • CLI

【免费下载链接】pnpm

Fast, disk space efficient package manager

项目地址:https://gitcode.com/gh_mirrors/pn/pnpm
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 13:15:29

毕业论文知识图谱构建:SpringBoot+Vue+Neo4j实战

简介&#xff1a;本资源是一套面向高校计算机专业教师、毕业设计指导者及高年级本科生的毕业论文知识图谱构建与可视化教学原型系统&#xff0c;聚焦教育领域中毕业设计质量监控与技术热点分析的实际需求。系统基于SpringBoot后端与Vue前端实现&#xff0c;集成Neo4j图数据库与…

作者头像 李华
网站建设 2026/9/20 13:15:22

OpenClaw 接 DeepSeek V4 Pro/Flash,Base URL 填 TaoToken

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/20 13:13:10

Dify+Ollama+DeepSeek-r1私有化部署:知识库与智能体实战

简介&#xff1a;面向企业技术团队、运维人员与正在选型大模型私有化方案的开发者&#xff0c;这份幕僚云私有化部署 Dify、Ollama 与 DeepSeek-r1 的资源包&#xff0c;聚焦于在数据不出内网的前提下搭建可用的 LLM 应用服务&#xff0c;解决隐私保护、安全合规与个性化落地问…

作者头像 李华
网站建设 2026/9/20 13:11:25

OpenAL Windows 64位部署指南:从DLL安装到音频开发避坑全解析

简介&#xff1a;面向 Windows 64 位游戏、多媒体与虚拟现实应用开发者的 openAL-windows64&#xff0c;是一份跨平台开源音频接口 OpenAL 的二进制集成包&#xff0c;用于绕开繁琐的源码编译与依赖配置&#xff0c;在工程中直接实现 3D 音频定位、多音源混音、环境回响等能力。…

作者头像 李华