InsightFace Server 信任密钥体系:用 Ed25519 公钥离线校验 MODEL.LICENSE 模型授权
【免费下载链接】insightfaceState-of-the-art 2D and 3D Face Analysis Project项目地址: https://gitcode.com/GitHub_Trending/in/insightface
本文围绕 InsightFace Server 后端中的可信模型授权公钥(server/backend/insightface_server/licensing/trusted_keys/)展开:这个目录存放的是 InsightFace 签发的 Ed25519 公钥,用于在完全离线的环境下校验每个模型包附带的MODEL.LICENSE签名文件。读完本文,你将理解该公钥的密钥指纹如何本地复核、验证器如何从该目录加载并匹配密钥、MODEL.LICENSE的完整字段结构与签名流程,以及"公钥入库、私钥隔离"这一安全边界在源码、测试与容器构建中是如何被强制落地的。
这个目录里有什么
trusted_keys目录只承担一件事:保存 InsightFace 模型授权体系的可信公钥。按 trusted_keys/README.md 的说明:
insightface-model-license-public-ed25519.pem是当前生效(Status: active)的 InsightFace Ed25519 公钥,专门用于离线验证MODEL.LICENSE文件;- 该密钥激活日期为 2026-07-22;
- 公钥 DER 编码的 SHA-256 指纹为
afa29e9508d9ae7a1308974a8f044a49e1d2c8ed7dba6f2a02f66ce0c450181d。
公钥文件本体是一个标准的 PEM 封装的 Ed25519 SubjectPublicKeyInfo:
-----BEGIN PUBLIC KEY----- MCowBQYDK2VwAyEAJyP2ZksitIXEOZX1cOauRUbsnmNvNmEAA5aXvcNUsA8= -----END PUBLIC KEY-----对应的仓库路径为 insightface-model-license-public-ed25519.pem。MCowBQYDK2Vw这一 DER 前缀是 Ed25519 公钥(1 字节参数长度 + 32 字节原始密钥)在 SubjectPublicKeyInfo 中的固定编码特征,因此该指纹实际唯一标识的就是那 32 字节原始公钥。
如何本地复核公钥指纹
README 给出的 SHA-256 指纹是对公钥DER 编码计算的。只要机器上有 OpenSSL,就可以不依赖任何 Python 依赖复算它:
openssl pkey -in server/backend/insightface_server/licensing/trusted_keys/insightface-model-license-public-ed25519.pem \ -pubin -outform DER | sha256sum在本文撰写时按此命令对仓库内文件实际执行,输出与 README 完全一致:
afa29e9508d9ae7a1308974a8f044a49e1d2c8ed7dba6f2a02f66ce0c450181d这就是运维场景下"确认我拿到的公钥就是发布方声明的那把"的标准做法。由于验证是纯本地密码学运算(Ed25519 验签不需要网络、时间戳服务或证书链),InsightFace Server 可以在 air-gapped(无外网)环境中完成模型授权校验,这也是 README 强调 "verify MODEL.LICENSE files offline" 的设计意图。
验证器如何加载 trusted_keys
公钥目录的消费方是 licensing/model_license.py 中的_trusted_keys()函数。它实现了验证器与密钥目录之间的约定:
- 默认目录:未显式传入目录时,使用
Path(__file__).with_name("trusted_keys"),即与本模块同级的trusted_keys目录——因此打包安装insightface_server时,密钥必须随 wheel 一起分发; - 加载规则:对目录下所有
*.pem文件(按文件名排序)逐个用cryptography的serialization.load_pem_public_key解析; - 类型强校验:解析出的密钥若不是
Ed25519PublicKey实例直接抛出ModelLicenseError,防止混入其他算法的公钥; - 空目录即失败:一个
.pem都没有时抛出 "No trusted InsightFace model-license keys found",验证器不会降级为跳过签名校验。
一个细节值得关注:glob("*.pem")之后还有一道if not path.name.startswith(".")过滤。其动机来自 tests/unit/test_model_license.py 中的test_trusted_keys_ignore_macos_appledouble_files:macOS 压缩包会附带._xxx前缀的 AppleDouble 元数据文件,若不过滤,这类文件若以.pem结尾就会被当作密钥加载并在解析阶段炸掉验证流程。该测试把真实仓库公钥复制进临时目录、再塞入一个伪 AppleDouble 文件,断言_trusted_keys只识别出 1 把密钥。
verify_model_license()在签名验证阶段把目录里的所有公钥都作为候选:
for key in keys: try: key.verify(signature, signed) break except InvalidSignature: continue else: raise ModelLicenseError("Model license signature verification failed")从源码结构看,这是为密钥轮换预留的:新旧两把公钥可以短暂同时存在于此目录,旧密钥签发的存量MODEL.LICENSE仍能被新代码验证,直到存量授权过期或续签后移除旧公钥即可。
MODEL.LICENSE 的字段结构与签名方式
trusted_keys 目录是"验签的一端",另一端是被验签的MODEL.LICENSE。model_license.py 定义的格式(LICENSE_VERSION = 1)如下:
| 字段 | 必填 | 约束 |
|---|---|---|
license_version | 是 | 必须等于 1 |
license_id | 是 | 非空字符串,≤256 字符 |
issuer | 是 | 必须精确等于InsightFace |
model_id | 是 | 正则^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$,且必须与当前加载的模型 ID 一致 |
grant | 是 | non-commercial或commercial之一 |
valid_from | 是 | UTC 时间戳(ISO 8601,以Z结尾) |
signature | 是 | 64 字节 Ed25519 签名,base64url 编码(无填充) |
customer/reference/valid_until | 否 | 字符串,≤256 字符;valid_until若存在必须晚于valid_from |
业务规则上还有两条硬约束:grant为commercial时必须提供customer字段(否则视为商业授权无法落实到具体客户,直接拒绝);JSON 解析启用_reject_duplicate_keys,重复字段名会直接报错,避免"后值覆盖前值"的 JSON 注入。
签名对象不是原始文件字节,而是规范化的字段集合:canonical_license_bytes()剔除外signature字段后,用 RFC 8785(JCS,JSON Canonicalization Scheme)序列化再签名。这保证了字段顺序、空白差异不影响验签,同时任何对已签字段(如把non-commercial篡改为commercial)的改动都会导致签名失败。
仓库自带 4 份由该公钥体系签发的默认授权,例如 defaults/buffalo_l/MODEL.LICENSE:
{ "license_version": 1, "license_id": "buffalo_l-public-v1", "issuer": "InsightFace", "model_id": "buffalo_l", "grant": "non-commercial", "valid_from": "2021-09-22T00:00:00Z", "signature": "mkF_zjs_gw5lzWlN6DXlBWPY6ZK7diTGoSORdp33ISLegqxSrL930a--bHEGOOiUO4n-W9kX5qQc6kbEkGnUBQ" }同级的antelopev2、buffalo_m、buffalo_sc三份默认授权位于 licensing/defaults 目录下。测试test_bundled_public_license_verifies_with_active_public_key正是用仓库内置的这份buffalo_l授权 +trusted_keys目录中的公钥完成一次真实验签,断言issuer == "InsightFace"且grant == "non-commercial"——它同时验证了"内置授权与内置公钥确实配对"这一发布一致性。
值得强调的一个设计决策(见 model_license.py 顶部 docstring):授权只绑定逻辑model_id,不绑定 ONNX 文件摘要。这意味着运维方可以把同一模型转成 FP16、INT8、优化后的 ONNX 甚至 TensorRT 引擎而无需重新申请授权;models/packages.py 的模块注释对同一策略做了呼应。
从 CLI 到模型安装的完整校验链
trusted_keys最终服务于 InsightFace Server 的模型安装与运行前检查。整条链路如下:
- 安装时:models/packages.py 的
install_package()在解包模型文件的同时写入MODEL.LICENSE(取自 defaults 目录 中对应模型的内置授权),随后调用verify_model_license(license_path, expected_model_id=package.name);_ensure_model_license()对已存在的授权同样先验签再复用,防止安装目录中的授权文件被中途替换。 - 许可证确认:models_cli.py 在安装前打印
license_notice()("Non-commercial research use only" 等提示);非交互环境必须显式传--accept-license,否则直接报错,避免无人值守安装绕过授权确认。 - 离线复核:
verify子命令调用verify_installed(),内部再次执行verify_model_license(),通过_print_verified_license()打印LICENSE VERIFIED、Issuer、License ID、Model ID、Grant 等public_summary()字段,供脚本化巡检使用。
测试 tests/unit/test_model_license.py 用临时生成的 Ed25519 私钥构造授权,系统性地覆盖了篡改场景:把grant改成commercial会触发 "signature verification failed";model_id与期望不符会触发 "not the active model";issuer非 InsightFace 会被拒绝;valid_until早于当前时间会判定过期;commercial授权缺customer被拒。这些用例就是trusted_keys这套机制"防什么"的精确清单。
公钥入库、私钥隔离的安全边界
README 最后一段定义了该目录的边界纪律:只有公钥可以进入这里;签发用的私钥必须留在仓库根目录、被 Git 忽略的.private/license-issuer/中,且绝不允许进入源码归档或容器镜像。这条策略不是文档口号,而是被容器契约测试强制执行的:tests/docker/test_container_contract.py 断言:
- 仓库根
.dockerignore包含.private/与**/*.pem(注意后者意味着除后端包内随源码发布的 trusted_keys 公钥外,任何散落的 PEM 都不会进镜像——这里的取舍是:私钥从不落库,而公钥必须随insightface_server包发布以保证离线可验签); .gitignore包含.private/。
因此在密钥轮换时的安全动作是:新公钥提交进trusted_keys并更新 README 的激活日期与 DER SHA-256 指纹,旧公钥在存量授权过渡期结束后移除;而签发侧永远只操作.private/license-issuer/下的私钥。
小结
trusted_keys/是 InsightFace Server 离线模型授权体系的信任根:一把(或多把轮换中的)Ed25519 公钥 + README 中可复核的 DER SHA-256 指纹,即可在无网络环境下判定MODEL.LICENSE是否由 InsightFace 合法签发;- 公钥指纹可用一行 OpenSSL 命令本地复算,与 README 声明值
afa29e…181d一致; - 验证器对该目录的读取规则(仅
*.pem、忽略._元数据文件、类型强校验、空目录即失败)由 model_license.py 实现并有对应单元测试; - 私钥与公钥的物理隔离(
.private/license-issuer/vstrusted_keys/)由.gitignore、.dockerignore及容器契约测试共同保证; - 该机制只校验授权的合法性与有效期(签名、issuer、model_id 作用域、grant、时间窗),具体商业/非商业使用条款见 LICENSING.md。
【免费下载链接】insightfaceState-of-the-art 2D and 3D Face Analysis Project项目地址: https://gitcode.com/GitHub_Trending/in/insightface
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考