Skip to content

admin service-account create cannot target another user (targetUser unsupported in CLI and rc-core) #340

Description

@CoderYellow

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:405CreateServiceAccountRequest 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.rsCreateArgs 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

  1. Add pub target_user: Option<String> to CreateServiceAccountRequest, serialized as #[serde(rename = "targetUser", skip_serializing_if = "Option::is_none")] so existing callers are unaffected.
  2. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions