Harbor 数据库认证(DB Mode)下非管理员用户查看与过滤操作日志的完整验证指南
2026/9/10 5:12:57 网站建设 项目流程

Harbor 数据库认证(DB Mode)下非管理员用户查看与过滤操作日志的完整验证指南

【免费下载链接】harborAn open source trusted cloud native registry project that stores, signs, and scans content.项目地址: https://gitcode.com/GitHub_Trending/ha/harbor

本文基于 Harbor 仓库中的测试用例 4-01-DB-user-view-logs.md 展开,系统性地讲解在auth_mode 为db_auth(本地数据库认证)的 Harbor 环境中,如何验证非管理员用户能否正确查看项目操作日志(审计日志),并逐一验证 push / pull / delete 等操作是否被完整记录、以及日志过滤功能是否按预期工作。读完本文,你将掌握一套可直接复跑的端到端验证流程,并理解 Harbor 审计日志从"记录 → 存储 → 权限过滤 → 查询"的完整链路及其底层源码实现。

测试目标与适用场景

该测试用例属于 Harbor 仓库tests/testcases/Group4-logging(日志功能测试组)的第一个用例,核心目标只有一个:

验证当用户由 Harbor 本地数据库(DB 模式)统一管理时,非管理员用户能够查看其有权限项目的操作日志,且日志可以被正确记录、浏览与过滤。

这个场景在真实生产中非常常见:一个团队把 Harbor 的认证模式配置为本地数据库(auth_mode: db_auth),各项目成员(非系统管理员)需要自行查看自己参与的项目的操作历史,用于排查"谁在什么时候 push / pull / delete 了什么镜像"。系统管理员则可以看到全部审计日志。

说明:Harbor 的认证模式还支持 LDAP / OIDC / UAA 等外部认证。本文用例仅覆盖DB 模式(用户数据存储在 Harbor 本地数据库),这是验证本地用户权限与日志隔离性的基础场景。

前置条件(Environment)

在执行测试前,需要确认以下环境全部就绪:

前置条件说明
Harbor 实例一个正在运行、可访问的 Harbor 实例
认证模式Harbor 配置为本地数据库认证,即auth_mode设为db_auth,用户数据存放在本地数据库
客户端主机一台安装了 Docker CLI(Docker 客户端)的 Linux 主机
用户账号至少一个非管理员用户账号(由本地数据库管理)
项目与镜像项目中存在可 push / pull / delete 的镜像,且该非管理员用户对该项目拥有相应权限(如开发人员或项目管理员)

其中认证模式在 Harbor 安装配置文件(make/harbor.yml.tmpl可查看配置模板)中以auth_mode参数体现,修改后需重新运行make/prepare并重启服务才会生效。

核心验证步骤(Test Steps)

整个验证过程分为六步:登录 → 制造操作 → UI 登录 → 删除镜像 → 查看日志 → 过滤日志。

Step 1:以非管理员用户身份登录 Docker 客户端

在安装了 Docker CLI 的主机上,使用非管理员用户账号登录 Harbor:

docker login <harbor_host>
  • <harbor_host>替换为实际的 Harbor 地址(如192.168.1.10myharbor.example.com);
  • 输入的是非管理员用户的用户名与密码;
  • 该用户必须是某个项目的成员,否则后续将没有可查看的日志项目。

Step 2:执行 push 与 pull 操作制造日志

登录成功后,执行一批docker pushdocker pull命令,向 Harbor 推送镜像并从 Harbor 拉取镜像。例如:

# 为镜像打上 Harbor 仓库标签 docker tag nginx:latest <harbor_host>/<project>/nginx:latest # 推送镜像到 Harbor docker push <harbor_host>/<project>/nginx:latest # 从 Harbor 拉取镜像 docker pull <harbor_host>/<project>/nginx:latest

这些操作是后续验证"日志是否被记录"的核心素材。建议 push 和 pull 各执行若干次,并故意穿插执行,方便后面验证"只过滤 push""只过滤 pull""同时过滤 pull 和 push"等组合条件。

Step 3:以非管理员用户登录 Web UI

打开 Harbor Web 界面,使用与 Step 1 相同的非管理员账号登录。此步骤验证的是:非管理员用户能够正常进入 Harbor 门户并看到自己有权限的项目

Step 4:删除项目中的部分镜像

在 UI 中进入相应项目,删除刚才推送的若干镜像(或镜像的某个 tag)。删除操作同样会进入日志,用于验证delete类型的日志记录与过滤。

Step 5:查看项目日志

在项目页面中打开日志(Logs / 审计日志)视图,此时应能看到此前发生的 push、pull、delete 操作记录。重点核对每条日志的时间与操作内容是否与实际操作一致

Step 6:逐项验证日志过滤条件

测试用例要求使用以下搜索条件逐一过滤日志,并确认过滤结果正确:

过滤组合预期语义
push only只显示 push 操作
pull only只显示 pull 操作
pull and push同时显示 pull 和 push 两类操作
delete only只显示 delete 操作
all显示全部操作,不限制操作类型
push and delete同时显示 push 和 delete 两类操作
不同日期范围(date ranges)按不同的起止时间区间过滤
日期范围 + push时间区间与操作类型组合过滤

每次切换过滤条件后,都应检查返回列表是否只包含符合条件的日志,尤其是组合条件(日期范围 + push),用于验证多个条件同时生效时的过滤逻辑。

预期结果(Expected Outcome)

测试通过的标准如下,缺一不可:

  1. Step 2 与 Step 4 的所有操作都应被记录:push、pull、delete 全部出现在日志中,不存在遗漏;
  2. Step 5 可以正常查看日志:日志列表可见,且每条日志的时间与操作内容正确
  3. Step 6 的过滤功能生效:所有列出的过滤条件都能返回与条件匹配的正确结果。

只有同时满足以上三点,才认为该用例通过,即"DB 模式下非管理员用户查看日志"功能正常。

从源码看审计日志的完整链路

仅仅跑通 UI 还不够,理解底层实现能帮助你在测试不通过时快速定位问题。下面结合本仓库源码说明 Harbor 审计日志从产生到展示的完整链路。

日志数据模型:audit_log 表

审计日志在数据库中对应audit_log表,其 ORM 模型定义在 src/pkg/audit/model/model.go:

type AuditLog struct { ID int64 `orm:"pk;auto;column(id)" json:"id"` ProjectID int64 `orm:"column(project_id)" json:"project_id"` Operation string `orm:"column(operation)" json:"operation"` ResourceType string `orm:"column(resource_type)" json:"resource_type"` Resource string `orm:"column(resource)" json:"resource"` Username string `orm:"column(username)" json:"username"` OpTime time.Time `orm:"column(op_time)" json:"op_time" sort:"default:desc"` } func (a *AuditLog) TableName() string { return "audit_log" }

从字段可以看出每条日志的核心信息:属于哪个项目(project_id)、什么操作(operation,如 push / pull / delete)、操作对象(resourceresource_type)、谁做的(username)、什么时间(op_time。其中op_time默认按降序排序,所以日志列表默认展示最新记录在前——这也是 UI 中"时间倒序"的底层来源。

日志的写入:请求中间件 + 事件通知

操作日志并非由业务代码手动一条条写入,而是通过 HTTP 请求中间件统一捕获。中间件实现位于 src/server/middleware/log/log.go,其核心流程为:

  1. 从请求中提取X-Request-ID、trace ID 等信息附加到日志上下文;
  2. 构造commonevent.Metadata,记录用户名(默认unknown,若已认证则取安全上下文中的用户名)、请求方法(RequestMethod)、请求 URL(RequestURL);
  3. 通过PreCheckMetadata()判断该请求是否属于需要记录审计的操作;
  4. 对需要审计的请求,读取请求体(受common.MaxAuditLogPayloadSize限制,超出则直接返回413 Request Entity Too Large),记录响应码,并通过notification.AddEvent将事件投递到通知系统,最终落库。

同时,审计日志的管理接口定义在 src/pkg/audit/manager.go,提供CountListGetCreateDeletePurge(按保留小时数清理旧日志)等方法。这也是"Step 4 删除镜像后 delete 操作也会被记录"的实现基础——只要请求走了标准中间件链路,就会统一生成审计事件。

日志的查询与权限隔离:非管理员只能看到自己有权访问的项目

这是本用例最关键的验证点:非管理员用户查看日志时,系统如何保证他看不到其他项目的日志?

答案在 API Handler 中:src/server/v2.0/handler/auditlog.go 的checkPermissionAndBuildQuery函数:

  1. 先校验用户已认证(未认证直接返回 401 Unauthorized);
  2. 尝试以系统级权限查询(RequireSystemAccess(ctx, rbac.ActionList, rbac.ResourceAuditLog));
  3. 若用户不是系统管理员,则改为列出该用户参与的所有项目(通过projectCtl.List查询成员关系,同时考虑用户所属用户组GroupIDs);
  4. 对每个项目进一步检查用户是否具备项目级日志查看权限HasProjectPermission(ctx, project.ProjectID, rbac.ActionList, rbac.ResourceLog));
  5. 最终把有权限的项目 ID 集合构造成一个 OrList,作为ProjectID关键词追加到查询条件中——没有权限的项目一条日志都不会返回(如果没有任何有权限的项目,会塞入-1保证查询结果为空)。

对应的 RBAC 资源定义见 src/common/rbac/const.go:项目级资源ResourceLog = Resource("log")(项目日志),系统级资源ResourceAuditLog = Resource("audit-log")(全局审计日志)。而项目角色对日志的权限映射在 src/common/rbac/project/rbac_role.go({Resource: rbac.ResourceLog, Action: rbac.ActionList}),即只有具备对应项目角色的用户才拥有log资源的list动作。

换句话说:本用例的通过条件,本质上是验证"项目成员 → 项目角色 → log 资源 list 权限 → 查询条件注入"这条权限链是否完整生效。

对应的 REST API

日志查询对应的 API 定义在 api/v2.0/swagger.yaml,主要包括:

  • GET /audit-logs:获取用户作为项目管理员成员的项目的近期操作日志,系统管理员可获取全部审计日志(旧版接口,已标记 deprecated);
  • GET /auditlog-exts:获取用户作为项目管理员成员的项目的近期操作日志,或系统管理员获取全部审计日志(扩展字段,包含操作描述与结果);
  • GET /projects/{project_name}/logs:获取指定项目的近期日志(旧版项目级接口,已标记 deprecated);
  • GET /auditlog-exts/events:获取审计日志的全部事件类型。

这些接口均支持q(查询条件)、sortpagepageSize参数,返回X-Total-Count总条数头与Link分页链接——UI 上的日志过滤与分页正是通过q查询参数(如按操作类型、按时间范围组合过滤)实现的,这与 Step 6 中验证的过滤条件一一对应。

过滤条件的实际应用建议

在执行 Step 6 时,以下几点能帮助你更准确地完成验证:

  1. 操作类型维度:先单独验证单一类型(push only / pull only / delete only),确认各类型都被正确标记与过滤;再做组合(pull and push / push and delete),确认多选逻辑为"并集"关系;
  2. 时间维度:先选择一个覆盖全部操作的大时间范围(all),再缩小到一个只覆盖部分操作的窄范围,验证边界时间点上的日志是否被正确包含或排除;
  3. 组合维度:最后验证"日期范围 + push"这类跨维度组合,确认不同类型条件之间是"交集"(AND)关系;
  4. 空结果检查:故意选择一段没有任何操作的时间范围,确认返回空列表且不报错,验证过滤逻辑对空结果的健壮性。

常见问题排查(基于源码线索)

如果测试失败,可以从以下方向入手定位:

  • 日志完全没有记录:检查请求是否经过src/server/middleware/log/log.go的中间件链路,确认请求体大小未超过common.MaxAuditLogPayloadSize(超限会直接返回 413);
  • 非管理员看不到日志:重点检查 src/server/v2.0/handler/auditlog.go 的权限判定逻辑,确认用户的项目角色在 src/common/rbac/project/rbac_role.go 中确实映射了log资源的list权限;
  • 时间/操作内容不正确:对照audit_log表中的op_timeoperationresource字段与 UI 展示是否一致,可借助数据库客户端直接查询audit_log表核对原始数据;
  • 过滤结果不对:确认q查询参数的格式与 src/pkg/audit/manager.go 中Count/List的实现一致,过滤条件最终会转换为 SQL 查询下推到数据库执行。

总结

本用例通过一次完整的端到端验证,覆盖了 Harbor 在DB 认证模式下非管理员用户查看日志的全部关键路径:Docker 客户端的 push / pull、UI 中的镜像删除、日志的查看与八种过滤组合。结合源码可以看到,Harbor 通过请求中间件统一捕获操作事件、以audit_log表持久化,并在 API 层通过"系统级权限 + 项目级log资源list权限"双层校验实现严格的日志隔离——这也是企业生产环境审计合规(谁在何时对哪个镜像做了什么)的基石。

如需进一步扩展验证,可参考仓库中的其他日志相关测试用例(tests/testcases/Group4-logging/目录),并结合 src/pkg/audit 与 src/server/v2.0/handler/auditlog.go 深入理解实现细节。

【免费下载链接】harborAn open source trusted cloud native registry project that stores, signs, and scans content.项目地址: https://gitcode.com/GitHub_Trending/ha/harbor

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

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

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

立即咨询