- 存储
- 分布式文件系统
- 对象存储
- 云原生
【免费下载链接】cubefs
cloud-native distributed storage
CubeFS 的用户管理机制以 Master 节点的 HTTP 接口为核心,为对象存储(object storage)与 POSIX 文件系统提供统一的身份标识、AK/SK 凭证与权限控制能力。本文基于官方管理 API 文档,结合 master/api_service_user.go、master/user.go 与 proto/user_proto.go 等源码实现,系统讲解用户创建、删除、查询、更新、授权、移除权限与卷所有权转移的全部 API 调用方式、参数含义与底层原理,帮助读者完整掌握 CubeFS 多租户用户体系的运维要点。
用户体系的核心概念
在 CubeFS 中,用户管理服务于对象存储(S3 协议)与 POSIX 文件系统两套访问入口,其核心设计如下:
- 用户 ID 与卷 Owner 强绑定:CubeFS 将卷的
Owner字段视为用户 ID。创建卷时若Owner值为testuser,则该卷会自动归属于用户testuser(体现在用户信息的own_vols列表中)。 - 自动建用户:如果创建卷时不存在与
Owner相同值的用户 ID,Master 会在创建卷的过程中自动创建该用户。 - root 用户自举:集群启动时自动创建 root 用户(type 值为
0x1)。从源码看,master/user.go 中定义了RootUserID = "root"与默认密码DefaultRootPasswd = "CubeFSRoot"。 - 用户类型枚举:proto/user_proto.go 定义了四种
UserType:0x0(invalid,无效)、0x1(root)、0x2(admin,管理员)、0x3(normal,普通用户)。Valid()方法仅接受 root/admin/normal 三种类型,且 API 层拒绝直接创建或修改为 root 类型(见 master/api_service_user.go)。 - AK/SK 凭证:每个用户对应一对对象存储凭证——Access Key(16 位字母数字)与 Secret Key(32 位字母数字),未指定时由系统自动生成。
从 HTTP 路由注册(master/http_server.go)可以看到,用户管理接口均挂在 Master 的 HTTP 服务(默认端口17010)下,路径常量定义于 proto/admin_proto.go(如UserCreate、UserUpdate等)。
创建用户(Create User)
通过 POST 请求向/user/create接口提交 JSON 数据创建用户:
curl -H "Content-Type:application/json" -X POST --data '{"id":"testuser","pwd":"12345","type":3}' "http://10.196.59.198:17010/user/create"创建成功后,该用户即可用于访问集群中的对象存储功能。
::: tip 提示 集群启动时自动创建 root 用户(type 值为0x1),因此 root 用户无需(也不允许)通过该接口重复创建。 :::
参数列表
| 参数 | 类型 | 说明 | 取值范围 | 是否必填 | 默认值 |
|---|---|---|---|---|---|
| id | string | 用户 ID | 由字母、数字和下划线组成,不超过 21 个字符 | 是 | 无 |
| pwd | string | 用户密码 | 无限制 | 否 | CubeFSUser |
| ak | string | 对象存储 Access Key | 由 16 位字母和数字组成 | 否 | 系统自动生成 |
| sk | string | 对象存储 Secret Key | 由 32 位字母和数字组成 | 否 | 系统自动生成 |
| type | int | 用户类型 | 2(管理员)/ 3(普通用户) | 是 | 无 |
源码级校验规则(可参见 master/user.go 的createKey与 master/api_service_user.go):
- 用户 ID 必须匹配
ownerRegexp,即^[A-Za-z][A-Za-z0-9_]{0,20}$(首字符必须为字母,总长度不超过 21 字符),该正则定义于 master/server.go。不匹配时返回ErrInvalidUserID。 - 类型必须合法(
Valid()通过且非 root),否则返回ErrInvalidUserType。 - 密码为空时默认使用
CubeFSUser(常量DefaultUserPassword);密码在存储时经 SHA-1 摘要后保存(encodingPassword,见 master/user.go)。 - AK/SK 为空时通过
util.RandomString随机生成,且会循环检查 AK 在AKStore中的唯一性,避免与既有用户冲突;显式传入的 AK/SK 则需分别满足AKRegexp(^[a-zA-Z0-9]{16}$)与SKRegexp(^[a-zA-Z0-9]{32}$),见 proto/user_proto.go。 - 用户 ID 重复时返回
ErrDuplicateUserID。
删除用户(Delete User)
curl -v "http://10.196.59.198:17010/user/delete?user=testuser"删除集群中指定的用户。
参数列表
| 参数 | 类型 | 说明 |
|---|---|---|
| user | string | 用户 ID |
删除前置约束(见 master/user.go 的deleteKey):删除前会检查该用户是否仍拥有卷(Policy.OwnVols非空则返回ErrOwnVolExists),root 用户不可删除(返回ErrNoPermission),用户不存在返回ErrUserNotExists。删除成功后,Master 会同步从userStore、AKStore以及各卷的volUser索引中移除该用户(removeUserFromAllVol)。
查询用户信息(Query User Information)
查询接口返回用户基本信息,包括用户ID、Access Key、Secret Key、用户拥有的卷列表、其他用户授予的权限列表、用户类型、创建时间等。其中:
policy字段:表示该用户拥有权限的卷及其权限;own_vols:表示 Owner 为该用户的卷;authorized_vols:表示其他用户授权的卷及对应的权限限制。
上述字段对应 proto/user_proto.go 中的UserPolicy结构:OwnVols []string与AuthorizedVols map[string][]string(卷到权限字符串列表的映射)。
按用户 ID 查询
curl -v "http://10.196.59.198:17010/user/info?user=testuser" | python -m json.tool参数列表
| 参数 | 类型 | 说明 |
|---|---|---|
| user | string | 用户 ID |
按 Access Key 查询
curl -v "http://10.196.59.198:17010/user/akInfo?ak=0123456789123456" | python -m json.tool参数列表
| 参数 | 类型 | 说明 |
|---|---|---|
| ak | string | 用户 16 位 Access Key |
按 AK 查询时,Master 先通过AKStore反查AKUser(AK 与用户 ID 的映射),再取出完整用户信息(getKeyInfo,见 master/user.go)。AK 参数还会经AKRegexp校验格式(master/api_service_user.go)。
响应示例
{ "user_id": "testuser", "access_key": "gDcKaBvqky4g8StT", "secret_key": "ZVY5RHlrnOrCjImW9S3MajtYZyxSegcf", "policy": { "own_vols": ["vol1"], "authorized_vols": { "ltptest": [ "perm:builtin:ReadOnly", "perm:custom:PutObjectAction" ] } }, "user_type": 3, "create_time": "2020-05-11 09:25:04" }该响应结构即 proto/user_proto.go 中UserInfo的 JSON 序列化结果。
查询用户列表(Query User List)
curl -v "http://10.196.59.198:17010/user/list?keywords=test" | python -m json.tool查询集群中所有用户 ID 包含指定关键字的用户信息。底层实现遍历userStore,用strings.Contains(userInfo.UserID, keywords)进行子串匹配(getAllUserInfo,见 master/user.go)。
参数列表
| 参数 | 类型 | 说明 |
|---|---|---|
| keywords | string | 在用户 ID 中搜索的关键字 |
更新用户信息(Update User Information)
curl -H "Content-Type:application/json" -X POST --data '{"user_id":"testuser","access_key":"KzuIVYCFqvu0b3Rd","secret_key":"iaawlCchJeeuGSnmFW72J2oDqLlSqvA5","type":3}' "http://10.196.59.198:17010/user/update"更新指定用户 ID 的信息,包括Access Key、Secret Key与用户类型。
参数列表
| 参数 | 类型 | 说明 | 是否必填 |
|---|---|---|---|
| user_id | string | 要更新的用户 ID | 是 |
| access_key | string | 新的 Access Key | 否 |
| secret_key | string | 新的 Secret Key | 否 |
| type | int | 新的用户类型 | 否 |
源码细节(updateKey,见 master/user.go):未修改的用户 ID 返回ErrInvalidUserID;root 用户不允许被修改(ErrNoPermission);新的 AK 会做格式校验与全局唯一性检查(重复返回ErrDuplicateAccessKey);type传入 0 表示不修改类型;更新 AK 时同时维护AKStore映射(先删除旧 AK 条目,再写入新 AK 条目),保证 AK 反查的一致性。测试用例 master/api_service_test.go 展示了通过createKey创建用户并调用transferVol的典型用法。
用户授权(User Authorization)
curl -H "Content-Type:application/json" -X POST --data '{"user_id":"testuser","volume":"vol","policy":["perm:builtin:ReadOnly","perm:custom:PutObjectAction"]}' "http://10.196.59.198:17010/user/updatePolicy"更新指定用户对某个卷的访问权限。policy的取值可以是以下几种形式之一:
- 只读或读写权限,取值为
perm:builtin:ReadOnly或perm:builtin:Writable; - 指定操作的权限,格式为
action:oss:XXX。例如GetObject操作对应的 policy 值为action:oss:GetObject; - 自定义权限,格式为
perm:custom:XXX,其中 XXX 由用户自定义。
指定权限后,该用户在使用对象存储功能时只能在规定的权限范围内访问该卷。
::: danger 警告 如果该用户已拥有对此卷的权限设置,此操作会覆盖原有权限。 :::
参数列表
| 参数 | 类型 | 说明 | 是否必填 |
|---|---|---|---|
| user_id | string | 设置权限的用户 ID | 是 |
| volume | string | 设置权限的卷名称 | 是 |
| policy | string slice | 要设置的权限列表 | 是 |
权限模型与底层实现:
- 权限字符串经由 proto/perm_action.go 中的
ParsePermission/ParseAction解析。内置权限(builtin)匹配正则^perm:builtin:...:(Writable|ReadOnly)$,操作权限(action)匹配^action:((oss:(\w+))|(posix:(\w)+))$,自定义权限匹配^perm:custom:(\w)+$。 AddAuthorizedVol(见 proto/user_proto.go)会过滤掉无法解析的非法权限项后写入AuthorizedVols[volume],因此同一卷的授权是整体覆盖语义。- 更新前会校验卷是否存在(返回
ErrCodeVolNotExists),且不允许对用户自己拥有的卷授权(返回ErrIsOwner,见 master/user.go)。 - 权限判断时,
UserPolicy.IsAuthorized/IsAuthorizedS3(proto/user_proto.go)负责判定用户对卷与具体操作的访问权:owner 默认拥有全部权限;内置Writable权限覆盖写类 S3 API,内置ReadOnly权限则结合WriteS3Api列表(PutObject、DeleteObject、CompleteMultipartUpload等)拒绝写操作。 - 内置权限还映射到具体操作集合
builtinPermissionActionsMap(proto/perm_action.go),例如ReadOnly包含OSSGetObjectAction、OSSListObjectsAction、POSIXReadAction等,Writable在其基础上追加OSSPutObjectAction、OSSUploadPartAction、POSIXWriteAction等。 - 授权成功后还会在卷的用户索引
volUser中登记(addUserToVol),便于按卷反查用户。
移除用户权限(Remove User Permissions)
curl -H "Content-Type:application/json" -X POST --data '{"user_id":"testuser","volume":"vol"}' "http://10.196.59.198:17010/user/removePolicy"移除指定用户对某个卷的全部权限。
参数列表
| 参数 | 类型 | 说明 | 是否必填 |
|---|---|---|---|
| user_id | string | 移除权限的用户 ID | 是 |
| volume | string | 移除权限的卷名称 | 是 |
底层实现调用removePolicy(master/user.go):对用户拥有的卷执行该操作会返回ErrIsOwner;否则从AuthorizedVols中删除该卷条目(RemoveAuthorizedVol),并同步从volUser索引中移除用户与卷的关联。
转移卷(Transfer Volume)
curl -H "Content-Type:application/json" -X POST --data '{"volume":"vol","user_src":"user1","user_dst":"user2","force":true}' "http://10.196.59.198:17010/user/transferVol"转移指定卷的所有权。此操作将指定卷从源用户移除并添加到目标用户,同时将卷结构中的Owner字段值更新为目标用户的用户 ID。
参数列表
| 参数 | 类型 | 说明 | 是否必填 |
|---|---|---|---|
| volume | string | 要转移所有权的卷名称 | 是 |
| user_src | string | 卷的原始属主,必须与卷Owner字段的原值一致 | 是 |
| user_dst | string | 所有权转移的目标用户 ID | 是 |
| force | bool | 是否强制转移卷。设为 true 时,即使user_src与卷Owner字段的值不相等,卷也会被转移到目标用户 | 否 |
源码级执行流程(transferUserVol见 master/api_service_user.go,transferVol见 master/user.go):
- 校验卷存在(不存在返回
ErrCodeVolNotExists)。 - 非
force模式下,若vol.Owner != param.UserSrc,直接返回ErrHaveNoPolicy拒绝转移。 - 调用
transferVol:若源用户确实拥有该卷,先从源用户移除该卷所有权(removeOwnVol),再为目标用户添加该卷所有权(addOwnVol)。 - 更新卷的
Owner字段为目标用户 ID,并通过m.cluster.syncUpdateVol(vol)将卷元数据同步写入 Raft 持久化;若同步失败则回滚Owner并返回ErrPersistenceByRaft。 - 测试用例 master/api_service_test.go 中
createUserWithPolicy即通过transferVol将卷commonVolName的所有权转移给新用户cfs,可作实践参考。
接口速查与运维建议
| 操作 | 方法 | 路径 | 关键参数 |
|---|---|---|---|
| 创建用户 | POST | /user/create | id, pwd, ak, sk, type |
| 删除用户 | GET/POST | /user/delete | user |
| 按 ID 查询 | GET | /user/info | user |
| 按 AK 查询 | GET | /user/akInfo | ak |
| 查询列表 | GET | /user/list | keywords |
| 更新用户 | POST | /user/update | user_id, access_key, secret_key, type |
| 用户授权 | POST | /user/updatePolicy | user_id, volume, policy[] |
| 移除权限 | POST | /user/removePolicy | user_id, volume |
| 转移卷 | POST | /user/transferVol | volume, user_src, user_dst, force |
实际使用时请注意以下几点:
- 所有接口均针对 Master 节点 HTTP 服务(默认
17010端口)发起,路由注册见 master/http_server.go。 - 创建与更新接口仅接受
admin(2)与normal(3)两种类型,root 用户由集群自动创建且不可被删除或降级。 - 用户的密码仅用于本地身份校验(SHA-1 摘要存储),对象存储访问凭证是 AK/SK;AK 是 16 位、SK 是 32 位的字母数字串,也可由调用方显式指定。
- 授权操作对同一卷是整体覆盖语义,追加新权限前请先查询用户当前
authorized_vols,避免误覆盖既有策略。 - 卷所有权转移涉及卷元数据的 Raft 持久化,建议在业务低峰期执行,并确认目标用户已存在;
force=true可用于修复卷 Owner 与实际属主不一致的历史遗留数据。
- 存储
- 分布式文件系统
- 对象存储
- 云原生
【免费下载链接】cubefs
cloud-native distributed storage
相关推荐
CubeFS Master 用户管理 API 完全指南:用户创建、权限授权与卷转交实战
CubeFS Master 用户管理 API 完全指南:用户创建、权限授权与卷转交实战 用户管理是 CubeFS 对象存储(Object Storage)功能的
存储分布式文件系统对象存储云原生CubeFS AuthNode 授权节点完全指南:从 Key 管理到 Master API 鉴权实战
CubeFS AuthNode 授权节点完全指南:从 Key 管理到 Master API 鉴权实战 导读 AuthNode 是 CubeFS 分布式存储系统中
存储分布式文件系统对象存储云原生CubeFS 卷管理实战指南:Master 管理 API 全解析
CubeFS 卷管理实战指南:Master 管理 API 全解析 卷(Volume)是 CubeFS 集群中面向用户的核心存储单元,对应对象存储中的 Bucke
存储分布式文件系统对象存储云原生
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考