☰
OpenBao PKI UI 引擎(Ember Engine)数据模型与适配器深度解析
2026/9/28 8:50:26 网站建设 项目流程
  • 后端
  • 认证鉴权
  • 密钥管理
  • 密码学

【免费下载链接】openbao

OpenBao is a software solution to manage, store, and distribute sensitive data including secrets, certificates, and keys.

项目地址:https://gitcode.com/GitHub_Trending/op/openbao
点击查看免费下载

OpenBao 的 PKI Secrets Engine 允许安全工程师以远低于传统工作流的成本创建 PKI 证书链。本文将深入剖析 OpenBao 前端仓库中ui/lib/pki这个独立 Ember Engine 的架构设计,重点讲解其数据模型(Model)、适配器(Adapter)与序列化器(Serializer)如何映射 PKI 后端复杂多变的 HTTP 端点,帮助你理解"为何 PKI 数据无法干净地映射到 CRUD 模型",并掌握在 UI 中签发证书、生成根 CA、导入 CA、配置自动 tidy 的完整实现原理。

为什么 PKI 在 UI 层需要一套"非典型"架构

PKI 是出了名的复杂:一次POST请求往往不产生单一实体,而是可能同时创建多个 issuer、key 与 certificate,且响应中部分敏感数据(如私钥、签发 CA 链)只在请求返回时出现一次。这与 Ember Data 惯用的 CRUD 范式(create / read / update / delete 单条记录)并不契合。

因此,OpenBao 前端为 PKI 设计了专门的模型、适配器与序列化器。这些代码并不位于ui/lib/pki引擎内部,而是主应用中(这也是 Ember Engine 的典型用法——引擎通过依赖注入使用主应用中的 Ember Data 层)。ui/lib/pki引擎则负责路由、控制器、组件与模板,构成完整的用户界面。

从目录结构看(ui/lib/pki/addon/routes),PKI 引擎拥有以下核心功能分区:

  • issuers/:根 CA 生成(generate-root)、中间 CA 生成(generate-intermediate)、导入(import)、轮换(rotate-root)、交叉签名(cross-sign)、签发中间证书(sign)
  • certificates/:证书列表与详情
  • keys/:密钥生成(create)与导入(import)
  • roles/:角色的创建、编辑、签发(generate/sign)
  • tidy/:手动 tidy、自动 tidy 配置
  • configuration/:PKI 配置项的创建与编辑

除pki/action之外,其余每个模型在 UI 中都有对应标签页,指向其LIST视图。

pki/action:面向"动作"而非"实体"的操作模型

pki/action模型(ui/app/models/pki/action.js)用于执行各种POST请求。这些请求接收相似的参数,但并不会创建一个单一的 Ember Data 记录;一次动作可能产生多个包含与请求参数不同属性的条目。例如:

  • POST pki/generate/root/:type创建自签名的根 CA 证书(即一个 issuer)与私钥,私钥仅在type = exported时才返回
  • POST pki/issuer/:issuer_ref/sign-intermediate签发证书,并返回仅出现一次的签发 CA 与 CA 链数据

从源码看,模型通过@tracked actionType在不同表单字段之间切换(ui/app/models/pki/action.js),支持的 actionType 包括import、generate-root、generate-csr、sign-intermediate、rotate-root。

适配器:actionType 到端点的映射

pki/action适配器(ui/app/adapters/pki/action.js)的核心逻辑在urlForCreateRecord中,它根据actionType把请求映射到对应端点:

actionType使用 issuer 端点(新式)旧式端点(fallback)
import/issuers/import/bundle/config/ca
generate-root/issuers/generate/root/${type}/root/generate/${type}
generate-csr/issuers/generate/intermediate/${type}/intermediate/generate/${type}
sign-intermediate/issuer/${issuerRef}/sign-intermediate—
rotate-root/root/rotate/${type}—

这里有两个值得注意的设计细节:

  1. 新旧端点并存与能力探测:模型中使用@lazyCapabilities对issuers/import/bundle、issuers/generate/root/:type等新端点做能力探测(ui/app/models/pki/action.js),并通过canImportBundle、canGenerateIssuerRoot、canGenerateIssuerIntermediate、canCrossSign等 getter 决定 UI 是否展示对应操作。如果用户没有新端点的权限,则回退到旧路径。

  2. 请求 ID 作为记录 ID:由于 action 端点不对应单一实体,createRecord在 POST 成功后以result.request_id(或随机 UUID)作为 Ember Data 记录 ID(ui/app/adapters/pki/action.js),并让序列化器根据actionType决定发送哪些属性。

使用pki/action模型的 PKI 工作流包括:根证书生成与轮换、导入 CA 证书与密钥、生成中间 CA CSR、签发中间证书。

关键属性与校验规则

pki/action模型承载了大量表单字段(ui/app/models/pki/action.js),其中最关键的有:

  • type:生成根/中间 CA 时的密钥处理方式,可选exported、internal、existing、kms
  • commonName:必需字段(presence 校验)
  • keyType/keyBits/privateKeyFormat:密钥类型与格式,keyType可选rsa、ed25519、ec、mldsa;privateKeyFormat可选der、pkcs8
  • format:证书输出格式,可选pem、der、pem_bundle,默认pem
  • issuerName/keyName:自定义命名,二者均不能使用保留值default(见模型内自定义校验,ui/app/models/pki/action.js)
  • SAN 系列:altNames(DNS SAN)、ipSans、uriSans、otherSans
  • excludeCnFromSans:将 CN 从 DNS/Email SAN 中排除,适用于 CN 是人工可读标识符而非主机名的场景
  • notBeforeDuration:证书回溯有效期,默认30s,用于纠正各系统间的时钟偏差
  • customTtl/ttl/notAfter:证书有效期(TTL 或具体日期)
  • maxPathLength:路径长度约束,默认-1

生成或签发 CSR 时还会用到csr、caChain、keyId、privateKey、privateKeyType等属性;其中certificate、issuingCa、privateKey等敏感字段被标记为masked: true,在 UI 中脱敏展示。

pki/certificate/base:证书数据模型

pki/certificate/base(ui/app/models/pki/certificate/base.js)用于与证书数据的具体交互。base 模型包含组成证书内容的通用属性,其子类certificate/generate与certificate/sign(ui/app/models/pki/certificate/generate.js、ui/app/models/pki/certificate/sign.js)在此基础上追加属性以完成各自的请求。

base 模型中的属性大致分三类:

  1. 请求参数:commonName、customTtl、excludeCnFromSans、altNames、ipSans、uriSans、otherSans
  2. API 返回内容:caChain、certificate、expiration、issuingCa、privateKey(仅type=exported与/issue返回)、privateKeyType、revocationTime(格式化日期)、serialNumber
  3. 解析结果:parsedCertificate

parsedCertificate:前端证书解析器

parsedCertificate是一个对象,承载由parse-pki-cert.js工具(ui/app/utils/parse-pki-cert.js)返回的全部证书解析数据。

该工具基于asn1js、pkijs与pvutils在浏览器端完成 ASN.1 解码:先把 PEM 字符串剥离-----BEGIN/END CERTIFICATE-----与换行符,转成 DER 后再用 ASN.1 解析为证书对象(ui/app/utils/parse-pki-cert.js)。解析结果包含 Subject 字段、Extensions(含 OID、KeyUsage、SAN 类型等,常量定义在 ui/app/utils/parse-pki-cert-oids.js)、签名位数等。

错误处理约定也很明确:{ can_parse: false }表示外部库无法转换证书;{ parsing_errors: [] }表示证书可转换但存在解析问题——此时 UI 无法进行交叉签名,会提示用户改用 CLI 手动操作。certDisplayFields(certificate、commonName、revocationTime、serialNumber)则定义了证书详情页直接展示的字段(ui/app/models/pki/certificate/base.js)。

此外,模型通过@lazyCapabilities探测revoke端点,canRevoke决定 UI 是否展示吊销操作(ui/app/models/pki/certificate/base.js)。

pki/tidy:手动与自动清理的统一模型

pki/tidy(ui/app/models/pki/tidy.js)用于在不同上下文中管理 tidy 操作。以下三个端点共享几乎相同的参数,唯一的例外是enabled与intervalDuration(仅用于自动 tidy):

  • POST pki/tidy—— 执行一次手动 tidy
  • POST pki/config/auto-tidy—— 设置自动化 tidy 的配置
  • GET pki/config/auto-tidy—— 读取自动 tidy 配置

注意:pki/tidy-status是只读端点,因此不使用 Ember Data 模型。

适配器:手动与自动的分流

pki/tidy适配器(ui/app/adapters/pki/tidy.js)对两类操作做了严格区分:

  • 自动 tidy 配置是唯一持久化的数据,因此findRecord与updateRecord只与/config/auto-tidy端点交互:findRecord走GET,updateRecord走POST。模型 ID 就是后端挂载路径,整个 mount 只有一个持久化的pki/tidy记录。
  • 每次手动 tidy 都是新记录,save()时调用createRecord,且只使用/tidy端点。

适配器还会根据tidyType(auto/manual)抛错来阻止误用:手动模型不能findRecord,自动模型不能createRecord。此外,cancelTidy(backend)提供对POST pki/tidy-cancel的封装,用于取消正在运行的 tidy 操作(ui/app/adapters/pki/tidy.js)。

tidy 参数分组

模型源码将全部 tidy 参数组织为三组(ui/app/models/pki/tidy.js),这正是 UI 表单分组的依据:

Universal operations(通用操作):

  • tidyCertStore:清理证书存储
  • tidyRevokedCerts:从存储中移除所有无效与过期证书
  • tidyRevokedCertIssuerAssociations:清理已吊销证书与 issuer 的关联
  • safetyBuffer:证书被清除前,需超过(本地时钟的)证书过期时间加上该缓冲时长,默认 72 小时
  • pauseDuration:逐张清理证书之间的暂停时长,可释放吊销锁,让其他操作在 tidy 运行期间继续执行

ACME operations(ACME 操作):

  • tidyAcme:清理 ACME 账户、订单与授权
  • acmeAccountSafetyBuffer:无订单账户被标记吊销、以及被标记吊销/停用后保留的时长

Issuer operations(Issuer 操作):

  • tidyExpiredIssuers:在 issuer 安全缓冲时长过后自动移除过期 issuer
  • tidyMoveLegacyCaBundle:将旧版 CA/issuer 捆绑包(来自 Vault 1.11 之前、OpenBao 分叉之前的版本)备份到config/ca_bundle.bak,迁移仅在 issuer 安全缓冲期过后发生
  • issuerSafetyBuffer:issuer 在其 NotAfter 有效期之后应保留的时长,默认 365 天(8760 小时)

自动 tidy 专属参数为enabled(是否启用自动清理,默认false)与intervalDuration(两次自动 tidy 之间的间隔,注意:是从一次操作结束到下一次开始计算)。

CRUD 模型:issuer、role、key

与pki/action不同,以下模型更接近标准 CRUD 模式。

pki/issuer:证书颁发者

Issuer 由pki/action模型通过导入 CA 或生成根 CA 创建(ui/app/models/pki/issuer.js),本模型负责其 update / read / list:

  • 只读字段:issuerId、isDefault、keyId(默认密钥 ID)、caChain、certificate、serialNumber,以及从证书内容解析出的parsedCertificate、commonName、isRoot、各类 SAN
  • 可更新字段:issuerName、leafNotAfterBehavior(叶子证书有效期超过 issuer 时的处理:err/truncate/permit)、usage(issuing-certificates/crl-signing/ocsp-signing)、manualChain(手动指定证书链,第一个元素必须是当前 issuer 的引用)、revocationSignatureAlgorithm(构建 CRL 时的签名算法,默认留空由 Go 自动选择)、issuingCertificates、crlDistributionPoints、ocspServers
  • 能力探测:canRotateIssuer(根轮换)、canCrossSign(交叉签名)、canSignIntermediate(签发中间 CA)、canConfigure、canDeleteAllIssuers分别对应/root/rotate/*、/intermediate/cross-sign、/issuer/:issuerId/sign-intermediate、/issuer/:issuerId、/root端点的权限(ui/app/models/pki/issuer.js)

pki/role:签发角色

Role 是 PKI 中"策略化签发"的核心实体,支持 create/update、read、list。模型源码将全部配置项组织成清晰的表单分组(ui/app/models/pki/role.js):

  • 默认组:name、issuerRef(指定签发证书的 issuer,默认default,可通过read -field=default pki_int/config/issuers查询)、customTtl、notBeforeDuration(默认30s)、maxTtl(未设置时使用系统最大 lease TTL)、generateLease(签发的证书是否附带 lease)、noStore(不在存储后端保存证书——可提升大批量签发性能,但证书无法枚举或吊销)、addBasicConstraints
  • Domain handling:allowedDomains、allowedDomainsTemplate、allowBareDomains、allowSubdomains、allowGlobDomains、allowWildcardCertificates、allowLocalhost(默认 true)、allowAnyName、enforceHostnames(默认 true)
  • Key parameters:keyType(rsa/ec/ed25519/mldsa/any,默认rsa)、keyBits(默认2048)、signatureBits(仅 RSA 适用,可选0/256/384/512)
  • Key usage:keyUsage(默认['DigitalSignature', 'KeyAgreement', 'KeyEncipherment'])、extKeyUsage、extKeyUsageOids
  • Policy identifiers:policyIdentifiers(OID 列表)
  • SAN Options:allowIpSans(默认 true)、allowedUriSans、allowUriSansTemplate、allowedOtherSans
  • Additional subject fields:allowedUserIds、allowedSerialNumbers(支持 shell 风格 glob,留空则禁止自定义序列号)、requireCn(默认 true)、useCsrCommonName(默认 true)、useCsrSans(默认 true)以及 OU/组织/国家等身份元数据

角色在权限控制上也十分精细:canDelete、canEdit、canRead基于/roles/:id端点;canGenerateCert基于/issue/:id;canSign基于/sign/:id;canSignVerbatim基于/sign-verbatim/:id(ui/app/models/pki/role.js)。

pki/key:密钥管理

pki/key(ui/app/models/pki/key.js)的CREATE有两条路径:

  • generate:生成新密钥,type可选internal(私钥不返回、之后也无法取回)或exported(私钥在响应中返回);keyType可选rsa、ec、ed25519、mldsa
  • import:通过pemBundle导入已有密钥

模型同样包含read/list能力,并通过canRead、canEdit、canDelete、canGenerateKey、canImportKey控制 UI 操作入口(ui/app/models/pki/key.js)。校验规则要求type与keyType必选,且keyName不能是保留值default。

引擎内部:路由、组件与序列化器如何协作

除数据层外,ui/lib/pki引擎还提供了完整的页面组件(ui/lib/pki/addon/components),例如:

  • 配置向导类:pki-configure-create、pki-configuration-edit、pki-generate-root、pki-issuer-generate-root、pki-issuer-import、pki-issuer-generate-intermediate、pki-issuer-rotate-root、pki-issuer-cross-sign
  • 表单组件:pki-role-form、pki-key-form、pki-tidy-form、pki-sign-intermediate-form、pki-import-pem-bundle、pki-key-usage、pki-key-parameters、pki-not-valid-after-form
  • 展示组件:parsed-certificate-info-rows(渲染parsedCertificate的证书信息行)、pki-info-table-rows、pki-overview
  • 状态页:pki-tidy-status、pki-tidy-manual、pki-tidy-auto-settings

路由(ui/lib/pki/addon/routes)与模板(ui/lib/pki/addon/templates)按issuers、certificates、keys、roles、tidy、configuration划分,与各模型的 LIST 视图一一对应。

序列化器(ui/app/serializers/pki)则负责两端工作:一方面把表单属性按目标端点筛选后发送(例如pki/action序列化器按actionType决定发送哪些字段,见 ui/app/adapters/pki/action.js 中serializer.serialize(snapshot, actionType)的调用);另一方面把后端返回的证书内容解析为parsedCertificate,供详情页直接渲染。

小结:一张 PKI 前端数据流全景图

综合来看,OpenBao PKI UI 引擎的数据流可以概括为:

  1. 用户在路由/组件中触发操作(生成根、导入 CA、签发证书、配置 tidy 等);
  2. 对应模型(pki/action负责非 CRUD 动作,pki/issuer、pki/role、pki/key负责 CRUD,pki/tidy统一手动/自动清理)通过@lazyCapabilities探测权限,决定 UI 展示哪些入口;
  3. 适配器根据 actionType / tidyType 将请求映射到正确的端点(ui/app/adapters/pki/action.js、ui/app/adapters/pki/tidy.js);
  4. 序列化器筛选发送字段,后端返回后由parse-pki-cert.js在浏览器端完成 ASN.1 解码,生成parsedCertificate供详情页与交叉签名等高级功能使用。

这套"模型 + 适配器 + 序列化器 + 引擎组件"的分层设计,正是 OpenBao 在前端优雅地消化 PKI 后端复杂 API 的关键所在——它让安全工程师可以在图形界面中完成从根 CA 建立到证书签发、再到自动清理的全生命周期管理,而无需直接面对底层千变万化的 HTTP 端点。

  • 后端
  • 认证鉴权
  • 密钥管理
  • 密码学

【免费下载链接】openbao

OpenBao is a software solution to manage, store, and distribute sensitive data including secrets, certificates, and keys.

项目地址:https://gitcode.com/GitHub_Trending/op/openbao
点击查看免费下载
上一篇:mise shell-alias unset:从全局配置中移除 Shell 别名
下一篇:CPython C API 类型创建改进:非类型基类报错优化与 bases must be types 错误信息

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询