key_mgmt
版本信息
| 项目 | 内容 |
|---|---|
| 组件版本 | 1.140.1 |
| 首发版本 | openUBMC 26.12 |
| 文档作者 | openUBMC 社区 |
| 最后更新 | 2026-10-31 |
1. 组件概述
1.1 组件简介
key_mgmt 为 Master 角色,负责所有域 MK(Master Key)的注册、生成、状态修改、删除等,即生成、更新 KSF 文件。其他使用 KMC 服务的 APP 为 Agent 角色,只对 KSF 文件做读操作,获取 DomainId 和 KeyId 用于加解密。
1.2 解决什么问题
- 为不同业务组件提供密钥域隔离机制,确保个别密钥泄密不会影响全部业务数据安全
- 支持 Master-Agent 架构,实现主从部署场景下的密钥统一管理和安全分发
- 提供 KSF 文件生命周期管理,支持密钥自动更新和密文重加密
1.3 核心功能
- 密钥域管理:为不同组件分配独立的密钥域(Domain),实现密钥集合隔离
- 主密钥生命周期管理:支持 Master Key 的注册、生成、状态修改、删除和自动更新
- KSF 文件管理:管理 KSF(Key Storage File)文件生成、备份和恢复
- 密钥角色管理:区分 Master 和 Agent 角色,Master 拥有全部管理权限,Agent 仅拥有本地域读权限
1.3.1 密钥分层架构
KMC 组件支持多层次密钥架构,上层密钥只用来保护下层密钥,最下层密钥(WK: Work Key)用来保护业务模块应用的机密数据:
- RK(Root Key):根密钥,纯软件环境下由硬编码和文件两部分存储,基于硬件保护根密钥时根密钥直接存储于硬件中
- RMK(Root Master Key):纯软件方式保护根密钥时,由 RK 派生得到,用于加密 Master Key,RK/RMK 封装在根密钥管理模块内部,永不出现在模块之外
- MK(Master Key):主密钥
Master Key按来源分为自动生成和外部导入(注册)两大类: 1)系统随机生成:这类Master Key由KMC内部随机生成,其所属域对应于内部生成域,原则上被封装在Master Key管理模块内部,按需提供密钥访问接口; 2)由业务模块导入:本CBB支持对业务模块导入的Master Key进行管理,其所属域为外部注册域,由业务模块导入的Master Key可以被业务模块直接访问。通常情况下不建议直接访问Master Key,系统可以计算并返回派生密钥(WorkKey),业务模块可输入盐值、迭代次数作为密钥派生运算的参数;
Master Key按使用范围分为本地和共享两大类: 1)本地MK:此类Master Key只能在Master或Agent自身使用,其所属域为本地域,此类主密钥不可以在主从间共享,KMC 3.0起支持本地域 2)共享MK:此类Master Key可以在Master和Agent间共享,其所属域为共享域,KMC 3.0之前版本仅支持共享域(注:KMC V1不支持主从部署,不涉及共享MK,因此无所谓共享或本地划分)
1.3.2 角色权限
组件分 Master 和 Agent 两个角色:
- Master:Master 自身 RootKey 的生成/修改,所有域 MK 的注册/生成/状态修改/删除,Master 自身 KSF 完整性检查和修复
- Agent:Agent 自身 RootKey 的生成/修改,本地域 MK 的注册/生成/状态修改/删除,Agent 自身 KSF 完整性检查和修复
1.3.3 实现流程
1.4 关键术语表
| 术语 | 解释 |
|---|---|
| KSF | Key Storage File,密钥存储文件,用于持久化保存密钥信息 |
| Domain | 密钥作用域,Domain 隔离,为不同 App 分配不同的 Domain,可在 App 间有效隔离密钥集合 |
| KeyId | 密钥 ID,在同一 Domain 内唯一,与 DomainId 共同构成 MK 的唯一身份标识 |
| RK | Root Key,根密钥,纯软件环境下由硬编码和文件两部分存储,基于硬件保护时直接存储于硬件中 |
| RMK | Root Master Key,由 RK 派生得到,用于加密 Master Key |
| MK | Master Key,主密钥,按来源分为自动生成和外部导入(注册)两大类 |
| WK | Work Key,工作密钥,由 MK 派生而来,用于保护业务模块应用的机密数据 |
| KMC | Key Management Center,密钥管理中心,提供密钥加解密和派生运算能力 |
1.5 外部交互边界图
业务组件(Agent)
|
| key_client_lib.lua
v
key_mgmt 服务
|
v
key_mgmt_app.lua
|
+-------------------------+
| |
v v
key_service.lua master_key.lua
| |
+------------+------------+
|
v
KMC 与持久化组件2. API 使用说明与示例
对外发布的 API 为资源协作接口,服务名 bmc.kepler.key_mgmt
2.1 RegisterKey
功能说明
注册新的密钥域,Agent 组件通过此方法向 key_mgmt 注册,获得唯一的 DomainId。
| 属性 | 内容 |
|---|---|
| 接口名 | bmc.kepler.KeyService.Keys |
| 废弃状态 | 正常可用 |
参数说明
| 参数名 | 方向 | 类型 | 描述 | 取值范围 |
|---|---|---|---|---|
| AppName | 输入 | String | 组件名称 | 非空字符串 |
| KsfName | 输入 | String | 主 KSF 文件名 | 非空字符串 |
| KsfBakName | 输入 | String | 备份 KSF 文件名 | 非空字符串 |
| KsfPath | 输入 | String | 主 KSF 存储路径 | 合法目录路径 |
| KsfBakPath | 输入 | String | 备份 KSF 存储路径 | 合法目录路径 |
| OwnerId | 输入 | U32 | 文件所有者 ID | 有效 UID |
| GroupId | 输入 | U32 | 文件所属组 ID | 有效 GID |
返回值与异常
| 返回值 | 含义 | 触发条件 | 处理建议 |
|---|---|---|---|
| DomainId (>0) | 成功 | 正常执行完成 | 无 |
| 0 | 失败 | 参数非法或内部错误 | 检查输入参数是否合法 |
应用场景
业务组件(Agent)在初始化时调用此接口注册密钥域,获取 DomainId 并加载 KSF 文件。
限制条件
此方法仅在 Agent 角色下调用。
2.2 UpdateKey
功能说明
触发所有域的主密钥更新,以异步任务方式执行。
| 属性 | 内容 |
|---|---|
| 接口名 | bmc.kepler.KeyService |
| 废弃状态 | 正常可用 |
参数说明
无参数。
返回值与异常
| 返回值 | 含义 | 触发条件 | 处理建议 |
|---|---|---|---|
| TaskId (>0) | 成功 | 正常执行完成 | 使用 TaskId 查询进度 |
| 0 | 失败 | 服务未就绪 | 检查 key_mgmt 服务状态 |
应用场景
管理员触发密钥更新时调用此方法,系统会逐域更新 MK 并通知各 Agent 组件重新加载 KSF。
限制条件
需要 SecurityMgmt 权限。
2.3 CiphertextUpdated
功能说明
通知密钥管理服务组件已完成密文更新。
| 属性 | 内容 |
|---|---|
| 接口名 | bmc.kepler.KeyService |
| 废弃状态 | 正常可用 |
参数说明
| 参数名 | 方向 | 类型 | 描述 | 取值范围 |
|---|---|---|---|---|
| DomainId | 输入 | U32 | 密钥域 ID | 已注册的 DomainId |
| KeyId | 输入 | U32 | 密钥 ID | 已存在的 KeyId |
返回值与异常
无返回值。
应用场景
Agent 组件完成密文重加密后调用此方法通知 key_mgmt 更新 CiphertextKeyId。
2.4 GetUpdateState
功能说明
查询密钥更新状态。
| 属性 | 内容 |
|---|---|
| 接口名 | bmc.kepler.KeyService |
| 废弃状态 | 正常可用 |
参数说明
无参数。
返回值与异常
| 返回值 | 含义 | 触发条件 |
|---|---|---|
| 0 | 就绪 | 密钥更新已完成 |
| 1 | 更新中 | 密钥更新正在进行 |
| 2 | 已更新 | 所有域密钥已更新,等待 Agent 确认 |
| 3 | 失败 | 密钥更新失败 |
应用场景
Agent 组件查询当前密钥更新状态,判断是否需要重新加载 KSF。
3. 组件扩展案例
3.1 扩展能力概述
key_mgmt 提供客户端库接入机制,支持业务组件(Agent)以插件方式接入密钥管理服务。
3.2 扩展点说明
- 密钥注册扩展:业务组件通过 key_client_lib.lua 注册密钥域,可自定义 KSF 文件路径和权限
3.3 二次开发指导
步骤一:引入客户端库
local KeyClient = require("key_mgmt.key_client_lib")步骤二:构造客户端实例
local key_client = KeyClient.new(
bus,
"SUBJECT_NAME",
function(domain_id, key_id)
print(string.format("密钥已更新: DomainId=%d, KeyId=%d", domain_id, key_id))
end,
"KSF_NAME",
"KSF_BACK_NAME",
{}
)验证方法
- 检查 key_mgmt 服务是否正常运行:
busctl --user tree bmc.kepler.key_mgmt - 调用 RegisterKey 检查返回值是否为有效 DomainId
- 触发 UpdateKey 检查回调是否被正确触发
4. 日志说明
4.1 一键日志收集
| 文件路径 | 内容说明 |
|---|---|
| /var/log/framework.log | key_mgmt 组件日志记录在框架日志中 |
4.2 关键日志信息
| 日志片段 | 日志级别 | 含义解读 | 建议处理动作 |
|---|---|---|---|
init domain %s master key failed during Key Service initialization | ERROR | 服务初始化时域 MK 初始化失败 | 检查该域的 KSF 文件路径配置和磁盘空间 |
kmc initialization failed during Key Service initialization, WsecInitialize failed | ERROR | KMC 核心库初始化失败 | 检查 mc.kmc 库文件是否完整、硬件根密钥是否可用 |
init kmc master failed during Key Service initialization | ERROR | KMC Master 模式初始化失败 | 检查 KSF 文件权限和路径配置 |
init kmc domain failed during Key Service initialization | ERROR | KMC 域初始化失败 | 检查数据库中域数据是否完整 |
init_domain failed for domain_id=%d, err=%s | ERROR | 域初始化失败 | 检查 KSF 文件是否存在及文件锁是否被占用 |
Key Service update domain %d master key failed, err=%s | ERROR | 密钥更新时域 MK 更新失败 | 检查对应域的 KSF 写入权限和磁盘空间 |
Key Service failed to notify master key update | ERROR | 密钥更新后通知 Agent 失败 | 检查 Agent 是否在线,D-Bus 连接是否正常 |
copy datatocheck_bak failed during master key update | ERROR | 密钥更新时备份 datatocheck 失败 | 检查 /data/backup/ksf/ 目录权限和磁盘空间 |
Key Service update the domain %s master key failed, domain id not found | ERROR | 密钥更新失败,域 ID 不存在 | 检查该域是否已注册 |
Key Service import data failed, data is invalid | ERROR | 数据导入失败,数据无效 | 检查 KSF 文件格式是否正确 |
domain %s missing KsfPath...will be removed | WARN | 服务启动时发现域缺少 KSF 路径配置,将被清理 | 如需保留该域,检查数据库中该域的 KSF 路径配置 |
open flock_file failed during master key export ksf | WARN | 导出 KSF 时文件锁打开失败 | 检查 /data/trust/ksf/ 目录权限和锁文件状态 |
backup failed, failed to backup %s to destination path | ERROR | 备份 KSF 文件失败 | 检查 /data/backup/ksf/ 目录权限和磁盘空间 |
recover failed, get preserve config failed | ERROR | 恢复时获取保留配置失败 | 检查数据库连接和配置数据 |
recover failed, domain id is an empty list | ERROR | 恢复时域 ID 列表为空 | 检查备份数据完整性 |
4.3 调试方法
# 开启 key_mgmt 详细日志
busctl --user call bmc.kepler.key_mgmt \
/bmc/kepler/key_mgmt/MicroComponent \
bmc.kepler.MicroComponent.Debug SetDlogLevel a{ss}sy 0 debug 1
# 查看实时日志
tail -f /var/log/framework.log | grep key_mgmt5. 问题定界指南
5.1 典型问题定界
| 现象描述 | 是否为本组件问题 | 判断依据 | 关键证据收集方法 |
|---|---|---|---|
| Agent 无法注册密钥域 | 是 | 检查 RegisterKey 返回值和日志 | 查看框架日志中 RegisterKey 相关日志 |
| 密钥更新失败 | 是 | 检查 UpdateKey 返回的 TaskId 和状态 | 查看框架日志中 UpdateKey 相关日志 |
| KSF 文件读取失败 | 是 | 检查文件权限和路径 | 执行 ls -la /data/trust/ksf/ 检查文件存在性和权限 |
| Agent 未收到密钥更新通知 | 否 | 检查 Agent 是否正确监听属性变更信号 | 检查 Agent 端日志和 key_client_lib 初始化日志 |
| 硬件根密钥不可用 | 否 | 检查 HARDWARE_ROOTKEY_ENABLE 配置 | 确认硬件支持并正确配置 |
5.2 错误码速查表
组件无显式数字错误码
6. 常见问题解答
Q1:kmc解密接口报268错误怎么办?
- 问题描述:查看日志发现kmc解密接口报268错误
- 一句话答案:268错误码代表MK不存在,即该进程中不存在该domainId
- 根因说明:domainId和ksf文件不匹配导致,可能是运行过程中,数据库被破坏,导致domainId被key_mgmt重新匹配;或者由于业务场景没有考虑充分,导致旧密钥被误删,从而加解密失败
- 解决方案:如果是ipmi命令报错,重新设置密码即可;如果是web打不开,日志刷证书解密失败,则重新导入证书;涉及kmc的组件都存在这种情况,可以根据对应业务场景删除相应数据即可,并重新触发加密,即可正常使用;所有涉及kmc的组件都存在这种情况,可以直接彻底地重置kmc数据,删除数据库domainId分配信息,重启key_mgmt,重新导入证书,设置密码等,但是kmc业务面涉及较广,比较难将数据清除干净,不建议使用;多个组件依赖同一个密钥的场景,需要考虑将domain进行拆分,并且兼容降级场景,此时则需要先更新密钥的组件不删除旧domainId
- 适用版本:所有版本
Q2:定位问题时需要持续更新主密钥,如何绕过密钥更新周期检查?
- 问题描述:定位问题时需要绕过密钥更新周期检查
- 一句话答案:使用mdbctl setprop set KeyService_0 bmc.kepler.KeyService LastUpdateTime 1684327765 命令设置密钥更新时间早于当前时间,便可通过更新周期检查
- 适用版本:所有版本
更多常见问题可查看社区文档《key_mgmt密钥管理组件FAQ》