Summary
The RustFS server's add-service-account admin API accepts a targetUser field, which lets an owner/root caller create a service account parented to another IAM user. The Console uses this. rc cannot: neither the CLI nor rc-core ever sends targetUser, so rc admin service-account create can only ever mint a key parented to whatever identity the alias authenticates as.
The result is that a key created in the Console under user test-user and a key created with rc using an admin alias are parented differently, with no way to express the Console's behaviour from the CLI.
Same shape as #261 ("Allow to update the service account policy via CLI since RustFS Console allows").
Reproduction
With alias openprojectx holding the root credentials (root access key rustfs) and an IAM user test-user, two keys created for test-user in the Console and two created with rc:
$ rc admin service-account list openprojectx --user test-user
test-user-ak (parent: test-user) [on] # created in the Console
test-user-ak2 (parent: test-user) [on] # created in the Console
$ rc admin service-account list openprojectx
test-ak (parent: rustfs) [on] # created with rc
test-ak2 (parent: rustfs) [on] # created with rc
test-ak-from-ui (parent: rustfs) [on]
Listing works fine once --user is passed. The gap is creation: rc admin service-account create takes an alias, an access key and a secret key, and exposes --name, --description, --policy, --policy-json and --expiry — but nothing that selects a parent user, so every key it creates is parented to the alias identity (rustfs above). There is no invocation that produces a parent: test-user key.
For contrast, the Console issues GET /rustfs/admin/v3/list-service-accounts?user=test-user and a create carrying "targetUser": "test-user", and both work against this same server.
Why this looks like a gap rather than intended behaviour
The server supports it. add_service_account_parent_within_scope in rustfs/src/admin/handlers/service_account.rs gates the field as:
owner || target_user == req_user || target_user == req_parent_user
so an owner (root credential) may target any existing user, while a non-owner stays confined to its own scope (GHSA-5354). The handler reads create_req.target_user and falls back to cred.access_key only when it is absent.
The docs document it. security-compliance/iam/sts.md lists targetUser in the creation body and notes: "targetUser requires admin privileges; regular users create service accounts for themselves."
The client omits it. targetUser / target_user does not appear anywhere in this repository:
crates/core/src/admin/types.rs:405 — CreateServiceAccountRequest has policy, expiry, name, description, access_key, secret_key, and no target-user field, so the serialized body can never contain one.
crates/cli/src/commands/admin/service_account.rs — CreateArgs has no user flag. ListArgs does have --user (line 46), so listing another user's accounts already works; only creation is missing.
Verified against main @ ef82a1d and published rc-core / rc-s3 0.1.31, rc 0.1.31.
Suggested fix
- Add
pub target_user: Option<String> to CreateServiceAccountRequest, serialized as #[serde(rename = "targetUser", skip_serializing_if = "Option::is_none")] so existing callers are unaffected.
- Add a
--user <USER> flag to CreateArgs and pass it through, mirroring the existing --user on service-account list.
Happy to open a PR if the approach looks right.
Motivation
We build a Kubernetes operator on top of rc-core/rc-s3 that reconciles RustFS buckets, users, policies and access keys. Because targetUser is unreachable from the client, issuing a key for a managed user forces the operator to re-authenticate as that user, which means it must hold the user's password, and every managed user's policy has to grant admin:CreateServiceAccount, admin:ListServiceAccounts and admin:RemoveServiceAccount just so it can manage its own keys. With targetUser the admin credential alone would be sufficient and none of that would be needed.
Summary
The RustFS server's
add-service-accountadmin API accepts atargetUserfield, which lets an owner/root caller create a service account parented to another IAM user. The Console uses this.rccannot: neither the CLI norrc-coreever sendstargetUser, sorc admin service-account createcan only ever mint a key parented to whatever identity the alias authenticates as.The result is that a key created in the Console under user
test-userand a key created withrcusing an admin alias are parented differently, with no way to express the Console's behaviour from the CLI.Same shape as #261 ("Allow to update the service account policy via CLI since RustFS Console allows").
Reproduction
With alias
openprojectxholding the root credentials (root access keyrustfs) and an IAM usertest-user, two keys created fortest-userin the Console and two created withrc:Listing works fine once
--useris passed. The gap is creation:rc admin service-account createtakes an alias, an access key and a secret key, and exposes--name,--description,--policy,--policy-jsonand--expiry— but nothing that selects a parent user, so every key it creates is parented to the alias identity (rustfsabove). There is no invocation that produces aparent: test-userkey.For contrast, the Console issues
GET /rustfs/admin/v3/list-service-accounts?user=test-userand a create carrying"targetUser": "test-user", and both work against this same server.Why this looks like a gap rather than intended behaviour
The server supports it.
add_service_account_parent_within_scopeinrustfs/src/admin/handlers/service_account.rsgates the field as:so an owner (root credential) may target any existing user, while a non-owner stays confined to its own scope (GHSA-5354). The handler reads
create_req.target_userand falls back tocred.access_keyonly when it is absent.The docs document it.
security-compliance/iam/sts.mdliststargetUserin the creation body and notes: "targetUserrequires admin privileges; regular users create service accounts for themselves."The client omits it.
targetUser/target_userdoes not appear anywhere in this repository:crates/core/src/admin/types.rs:405—CreateServiceAccountRequesthaspolicy,expiry,name,description,access_key,secret_key, and no target-user field, so the serialized body can never contain one.crates/cli/src/commands/admin/service_account.rs—CreateArgshas no user flag.ListArgsdoes have--user(line 46), so listing another user's accounts already works; only creation is missing.Verified against
main@ ef82a1d and publishedrc-core/rc-s30.1.31,rc 0.1.31.Suggested fix
pub target_user: Option<String>toCreateServiceAccountRequest, serialized as#[serde(rename = "targetUser", skip_serializing_if = "Option::is_none")]so existing callers are unaffected.--user <USER>flag toCreateArgsand pass it through, mirroring the existing--useronservice-account list.Happy to open a PR if the approach looks right.
Motivation
We build a Kubernetes operator on top of
rc-core/rc-s3that reconciles RustFS buckets, users, policies and access keys. BecausetargetUseris unreachable from the client, issuing a key for a managed user forces the operator to re-authenticate as that user, which means it must hold the user's password, and every managed user's policy has to grantadmin:CreateServiceAccount,admin:ListServiceAccountsandadmin:RemoveServiceAccountjust so it can manage its own keys. WithtargetUserthe admin credential alone would be sufficient and none of that would be needed.