Backstage Auditor 核心服务解析:@backstage/backend-defaults 的审计 API 与实现机制 📅 发布时间:2026/9/13 18:56:22 👁 浏览次数: Backstage Auditor 核心服务解析backstage/backend-defaults 的审计 API 与实现机制【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstagereport-auditor.api.md是 Backstage 仓库中backstage/backend-defaults包 auditor 入口的 API Extractor 报告文件它冻结并声明了 Auditor 核心服务的全部公开 API事件类型、默认实现DefaultAuditorService、服务工厂auditorServiceFactory以及基于独立 Winston 日志器的WinstonRootAuditorService。本篇以该 API 报告为主体骨架结合 auditor 入口源码、单元测试与 核心服务文档 中的配置规范讲解每个导出成员的语义、底层实现、backend.auditor配置项的解析逻辑以及插件侧使用 AuditorService 的完整姿势帮助你在自研后端插件中落地可检索、可分级、可合规的安全审计日志。API 报告中的公开导出总览API 报告 由 API Extractor 自动生成标注Do not edit其作用是在接口发生不兼容变更时提供可 diff 的契约基线。报告中声明的public导出可归为四类类别导出成员作用事件类型AuditorEvent、AuditorEventOptionsTMeta、AuditorEventStatus、AuditorEventActorDetails、AuditorEventRequest描述一条审计事件的结构、创建入参与状态机日志函数AuditorLogFunction审计事件落地到日志系统的回调签名默认实现DefaultAuditorService实现AuditorService接口的核心类服务装配auditorServiceFactory、WinstonRootAuditorService、WinstonRootAuditorServiceOptions分别对应复用现有 logger与独立 Winston logger两种接入方式类型导入关系值得注意AuditorService、AuditorServiceEvent、AuditorServiceEventSeverityLevel、AuthService、HttpAuthService、PluginMetadataService均定义在backstage/backend-plugin-api中backstage/backend-defaults只负责提供实现。也就是说插件依赖注入面向的是接口实现细节由 backend-defaults 提供。事件类型系统AuditorEvent 与其子类型报告中最核心的类型是事件本体与它的状态联合export type AuditorEvent { plugin: string; eventId: string; severityLevel: AuditorServiceEventSeverityLevel; actor: AuditorEventActorDetails; meta?: JsonObject; request?: AuditorEventRequest; } AuditorEventStatus; export type AuditorEventStatus | { status: initiated } | { status: succeeded } | { status: failed; error: Error };AuditorEventStatus是一个可辨识联合discriminated union事件生命周期只有三种状态——initiated操作开始、succeeded成功完成、failed失败并强制携带error: Error。这种结构保证了失败日志一定包含错误对象配合 winston 的errors({ stack: true })格式器可直接输出堆栈。AuditorEventActorDetails记录谁在做actorId用户 entityRef 或服务主体、ip、hostname、userAgent全部为可选字段。AuditorEventRequest只保留url与method两个字段——即原始 Express 请求不会整体入日志只留痕定位信息。AuditorEventOptionsTMeta extends JsonObject是插件侧createEvent的入参形态必填eventId可选severityLevel、request、meta同样与状态联合交叉。在 DefaultAuditorService 的log方法 中可以看到这些字段如何被组装成最终的AuditorEventplugin取自PluginMetadataService.getId()severityLevel缺省为lowactor从请求与凭据中解析meta为空对象时会被规范化为undefined避免在日志里留下无意义的空对象。DefaultAuditorService三段式审计事件与执行者解析DefaultAuditorService实现了AuditorService接口构造方式为静态工厂static create( logFn: AuditorLogFunction, deps: { auth: AuthService; httpAuth: HttpAuthService; plugin: PluginMetadataService; }, ): DefaultAuditorService;它的唯一依赖是一组AuditorLogFunction事件落日志的回调和三个核心服务。核心入口是createEventasync createEvent(options) { await this.log({ ...options, status: initiated }); return { success: async params { /* 合并 meta 后记录 status: succeeded */ }, fail: async params { /* 记录 error 与 status: failed */ }, }; }见 DefaultAuditorService.ts 的 createEvent 实现。其行为有三点关键细节调用即记录createEvent被调用时立即输出第一条initiated日志随后通过返回的success/fail闭包补记终态。一次完整的操作最多产生两条审计日志。meta 渐进合并success/fail的入参可以携带各自的meta会与createEvent时的meta浅合并后者覆盖前者。单元测试 用 use root meta 用例验证了这一点initiated 阶段记录{ initiated: test }succeeded 阶段记录{ initiated, succeeded }failed 阶段记录{ initiated, failed }。失败必含 Errorfail({ error })会把error提升到事件顶层字段与AuditorEventStatus中failed分支的必填约束一致。执行者actor解析逻辑在私有方法getActorId中源码无 HTTP 请求的后台任务使用auth.getOwnServiceCredentials()执行者就是当前服务本身有请求时通过httpAuth.credentials(request)从请求中解析凭据解析失败会抛出ForwardedError(Could not resolve credentials)——即审计不降级身份不明直接让操作失败凭据是用户主体时取principal.userEntityRef是服务主体时取principal.subject否则返回undefined。DefaultAuditorService 测试 用mockServices验证了三种状态落日志的完整字段{ eventId, status, plugin, severityLevel: low, actor: {} }其中actor为空对象正是因为 mock 凭据既非用户也非服务主体时各字段均为undefined。auditorServiceFactory复用现有 logger 的默认装配方式auditorServiceFactory 是 backend-defaults 提供给插件体系的标准服务工厂注册在coreServices.auditor上依赖五个核心服务export const auditorServiceFactory createServiceFactory({ service: coreServices.auditor, deps: { config: coreServices.rootConfig, logger: coreServices.logger, auth: coreServices.auth, httpAuth: coreServices.httpAuth, plugin: coreServices.pluginMetadata, }, factory({ config, logger, plugin, auth, httpAuth }) { const auditLogger logger.child({ isAuditEvent: true }); const severityLogLevelMappings getSeverityLogLevelMappings(config); return DefaultAuditorService.create(event { /* ... */ }, { plugin, auth, httpAuth }); }, });工厂内部有两处设计要点审计日志与业务日志隔离标记通过logger.child({ isAuditEvent: true })派生子日志器所有审计行都会带上isAuditEvent: true字段便于在日志管道中精确过滤审计数据流severity → log level 动态路由根据配置解析出的severityLogLevelMappings用auditLogger[mappings[event.severityLevel]](...)动态调用对应的 winston 级别方法debug/info/warn/error。当事件包含error时即 failed 状态会用除 error 外的其余事件字段创建一个 child logger 再记录避免 Error 对象被当作普通 meta 序列化。日志的 message 固定为${event.plugin}.${event.eventId}形成插件.事件的点号命名空间。WinstonRootAuditorService为审计建立独立日志通道WinstonRootAuditorService提供另一种接入路径不依赖插件体系已有的 logger而是自建一个独立的 winston 日志器适合需要将审计日志写入独立文件、独立传输通道如专用 SIEM 通道的场景。报告与 WinstonRootAuditorService.ts 中定义的选项类型export type WinstonRootAuditorServiceOptions { meta?: JsonObject; format?: Format; transports?: winston.transport[]; };static create(options?)内部通过WinstonLogger.create构建日志器固定注入meta: { service: backstage }与level: info格式器为export const defaultFormatter winston.format.combine( winston.format.timestamp({ format: YYYY-MM-DD HH:mm:ss }), winston.format.errors({ stack: true }), winston.format.splat(), winston.format.json(), );即输出带时间戳、展开错误堆栈的 JSON 行。另有一个公开的auditorFieldFormat作用是在每条日志上追加isAuditEvent: true标记并在create时无条件合入最终 format 链winston.format.combine(auditorFieldFormat, options?.format ?? defaultFormatter)。若传入options.meta会再派生一层 child logger 注入。forPlugin(deps)方法与工厂方式不同其 deps 中多一个config: Config而非loggerforPlugin(deps: { auth: AuthService; config: Config; httpAuth: HttpAuthService; plugin: PluginMetadataService; }): AuditorService { const severityLogLevelMappings getSeverityLogLevelMappings(deps.config); return DefaultAuditorService.create(event { /* 同工厂按 severity 路由级别 */ }, deps); }从源码结构看它本质上是一个根上下文文档示例 展示的标准用法是通过createRootContext()创建一次然后在每个插件的factory里调root.forPlugin(...)得到该插件专属的AuditorService实例既共享底层传输通道又保持插件维度隔离。WinstonRootAuditorService 测试 验证了forPlugin返回的确实是DefaultAuditorService实例且 initiated/succeeded 事件按预期流经内部log方法。backend.auditor.severityLogLevelMappings 配置解析两个实现共用 utils.ts 中的getSeverityLogLevelMappings(config)来解析配置配置根键为backend.auditor读取severityLogLevelMappings下的low/medium/high/critical四个键使用 zod 枚举[debug, info, warn, error]校验每个值缺省默认映射为low: debugmedium/high/critical均为info任一值非法时抛出InputError错误信息会明确指出具体键名、收到的非法值和全部合法取值。对应的app-config.yaml写法可只覆盖单个级别backend: auditor: severityLogLevelMappings: low: debug medium: info high: warn critical: error默认映射的含义是low事件默认落在 debug 级别生产环境通常被日志级别过滤掉而 medium/high/critical 默认都记为 info——如需让高危事件更醒目可将high/critical调至warn/error这正是 核心服务文档 中Severity Log Level Mappings章节给出的用法。插件中使用 AuditorService接口、命名规范与 meta 约定插件侧只依赖backstage/backend-plugin-api的AuditorService接口通过路由选项注入。官方文档 给出的 Express 路由集成示例export async function createRouter(options: RouterOptions): Promiseexpress.Router { const { auditor } options; const router Router(); router.use(express.json()); router.post(/my-endpoint, async (req, res) { const auditorEvent await auditor.createEvent({ eventId: my-endpoint-call, request: req, meta: { // ... metadata about the request }, }); try { // ... process the request await auditorEvent.success(); res.status(200).json({ message: Succeeded! }); } catch (error) { await auditorEvent.fail({ error }); res.status(500).json({ message: Failed! }); throw error; } }); return router; }传入request: req后实现层会自动提取ip、hostname、user-agent进入actororiginalUrl与method进入request字段并从请求凭据解析actorId。命名规范源自核心服务文档并在AuditorEventOptions的eventId文档注释中重申kebab-caseeventId使用如user-login、file-download的形式eventId表逻辑分组如entity-fetch归组所有实体读取操作location-mutate归组所有 location 变更具体动作放meta用meta.queryType、meta.actionType等字段表达组内细分动作例如eventId: entity-fetchmeta: { queryType: by-id }避免与 pluginId 冗余的前缀插件上下文已经由plugin字段单独承载。常用 meta 键约定Key说明格式示例queryType查询类型kebab-case 字符串all、by-id、by-name、by-query、by-refs、ancestry、by-entityactionType变更动作类型kebab-case 字符串create、delete、refreshentityRef实体全引用[kind]:[namespace]/[name]component:default/my-componentlocationRef被操作的 location任意位置引用字符串url:https://example.com/catalog-info.yamluid对象唯一标识任意有效唯一 ID 字符串9a4e740b-e557-427f-b9f2-0d4f092b1c1e典型的写操作审计事件形如{ eventId: entity-mutate, meta: { actionType: delete, uid: some-entity-uid, entityRef: component:default/petstore }, severityLevel: medium }。按 核心服务文档 的指引plugins/catalog-backend的src/service/createRouter.ts是该服务在真实插件中的完整参考实现Catalog 的 Audit Events 文档则示范了如何为一个插件的eventId清单撰写配套文档。选型上应记住审计服务面向安全相关与合规类事件会话管理、数据访问变更、配置变更等一般业务日志仍应走标准LoggerService。小结从 API 契约到可落地的审计能力report-auditor.api.md声明的这组导出构成了 Backstage 后端审计能力的完整闭环AuditorEvent*系列类型约束事件形状与三态状态机DefaultAuditorService负责执行者解析、meta 合并与日志回调auditorServiceFactory与WinstonRootAuditorService分别给出复用现有 logger 并打标isAuditEvent和独立 Winston 通道默认 JSON 格式 时间戳 堆栈展开两种装配路径backend.auditor.severityLogLevelMappings配置则以 zod 校验支撑 severity 到日志级别的灵活路由。理解这层 API 与实现后你可以在任何 Backstage 后端插件中以统一、可过滤、带执行者上下文的格式输出审计事件。【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考