Skip to content

Latest commit

 

History

History
889 lines (681 loc) · 61.6 KB

File metadata and controls

889 lines (681 loc) · 61.6 KB

rc admin

Purpose

The rc admin operation manages the RustFS Admin API, including scanner and storage diagnostics, bounded realtime metrics, KMS inspection and key lifecycle management, cluster information, healing, pools, expansion, decommissioning, rebalance workflows, IAM users, policies, groups, service accounts, per-bucket on-demand migration, site replication, and service control.

rc admin does not implement the MinIO Admin API. MinIO aliases remain available to S3 data commands, but MinIO administrative operations require a MinIO-compatible admin client.

Syntax

rc [GLOBAL OPTIONS] admin <COMMAND>
rc admin account info <ALIAS>
rc admin account passwd <ALIAS> [--current-password-from-env NAME|--current-password-file PATH] [--new-password-from-env NAME|--new-password-file PATH]
rc admin account mfa status <ALIAS>
rc admin account mfa enroll <ALIAS> [--no-qr]
rc admin account mfa activate <ALIAS> [--code CODE|--code-from-env NAME] [--output-file PATH]
rc admin account mfa disable <ALIAS> [--code CODE|--code-from-env NAME] [--password-from-env NAME|--password-file PATH]
rc admin account mfa recovery-codes <ALIAS> [--code CODE|--code-from-env NAME] [--output-file PATH]
rc admin diagnostics <health|cluster|extensions> <ALIAS>
rc admin info <cluster|server|disk|storage> <ALIAS> [OPTIONS]
rc admin scanner status <ALIAS>
rc admin idp openid list <ALIAS>
rc admin idp openid get <ALIAS> <PROVIDER_ID>
rc admin idp openid validate <ALIAS> <PROVIDER_ID> --config-url URL --client-id ID
rc admin idp openid set <ALIAS> <PROVIDER_ID> [OPTIONS]
rc admin idp openid update <ALIAS> <PROVIDER_ID> [OPTIONS]
rc admin idp openid <enable|disable> <ALIAS> <PROVIDER_ID> [--dry-run]
rc admin metrics <ALIAS> [OPTIONS]
rc admin kms status <ALIAS>
rc admin kms configure <ALIAS> <--config-file PATH|--stdin>
rc admin kms reconfigure <ALIAS> <--config-file PATH|--stdin>
rc admin kms start <ALIAS>
rc admin kms restart <ALIAS> --yes
rc admin kms stop <ALIAS> --yes
rc admin kms roundtrip <ALIAS> <BUCKET> [--key-id KEY_ID] --yes
rc admin kms key list <ALIAS> [--limit N] [--marker TOKEN]
rc admin kms key status <ALIAS> [KEY_ID]
rc admin kms key create <ALIAS> [--name NAME] [--description TEXT] [--tag KEY=VALUE]...
rc admin kms key delete <ALIAS> <KEY_ID> [--pending-window-days 7..30] --yes
rc admin kms key delete <ALIAS> <KEY_ID> --immediate --yes --confirm-immediate
rc admin kms key cancel-deletion <ALIAS> <KEY_ID>
rc admin heal <status|start|stop> <ALIAS> [OPTIONS]
rc admin pool <list|status> <ALIAS> [POOL] [OPTIONS]
rc admin expand <start|status|stop> <ALIAS>
rc admin decommission <start|cancel|clear> <ALIAS> <POOL> [OPTIONS]
rc admin decommission status <ALIAS> [POOL] [OPTIONS]
rc admin rebalance <start|status|stop> <ALIAS>
rc admin user <ls|add|info|rm|enable|disable> ...
rc admin user passwd <ALIAS> <ACCESS_KEY> [--password-from-env NAME|--password-file PATH]
rc admin user mfa status <ALIAS> <ACCESS_KEY>
rc admin user mfa reset <ALIAS> <ACCESS_KEY> [--yes]
rc admin policy <ls|create|info|rm|attach|detach|entities> ...
rc admin policy detach <ALIAS> <POLICY>... (--user USER | --group GROUP)
rc admin policy entities <ALIAS> [--user USER]... [--group GROUP]... [--policy POLICY]...
rc admin access-key info <ALIAS> <ACCESS_KEY>
rc admin access-key ls <ALIAS> [--provider builtin|ldap|openid]... [--user USER]... [--all] [OPTIONS]
rc admin group <ls|add|info|rm|enable|disable|add-members|rm-members> ...
rc admin service-account <ls|create|info|rm> ...
rc admin service <restart|stop|freeze|unfreeze> <ALIAS>
rc admin diagnostics client-devnull <ALIAS> [--size <SIZE>] [--timeout <DURATION>] [--concurrency <N>] --yes
rc admin config <get|set|delete|help|history|restore|export|import> ...
rc admin config module-switch <get|set> ...
rc admin bucket-metadata <export|import> <ALIAS> ...
rc admin bucket migration set <ALIAS>/<BUCKET> --provider <s3|aws|minio|rustfs|r2|gcs> [--endpoint URL] --region <R> --source-bucket <B> [OPTIONS] [--dry-run]
rc admin bucket migration <get|rm|status> <ALIAS>/<BUCKET> [--watch [--interval SECONDS]]
rc admin bucket migration backfill start <ALIAS>/<BUCKET> [--prefix P] [--skip-existing always|etag_or_size] [--dry-run]
rc admin bucket migration backfill <cancel|status> <ALIAS>/<BUCKET> [--watch [--interval SECONDS]]
rc admin replicate add <ALIAS> <ALIAS> [<ALIAS>...]
rc admin replicate <info|status> <ALIAS> [OPTIONS]
rc admin replicate edit <ALIAS> --site <DEPLOYMENT_ID|NAME> [EDIT OPTIONS] --yes
rc admin replicate resync <start|cancel> <ALIAS> --site <DEPLOYMENT_ID|NAME> --yes
rc admin replicate resync status <ALIAS> --site <DEPLOYMENT_ID|NAME>
rc admin replicate remove <ALIAS> <--all|--site <NAME>>

Commands

Command Description
account Inspect and manage the identity the alias authenticates as: password and two-factor authentication.
diagnostics Read bounded authenticated snapshots or run explicitly confirmed bounded probes.
info Display cluster, server, or disk information.
scanner Inspect scanner health, freshness, and cycle state.
metrics Query bounded realtime metrics as normalized JSON Lines or raw server records.
kms Inspect KMS state and manage safe native key lifecycle operations.
idp openid Inspect, validate, and safely mutate effective OIDC providers.
heal Start, stop, or inspect healing operations.
pool List pools and inspect pool status.
expand Manage post-expansion data rebalancing. Alias: scale.
decommission Manage server pool decommissioning. Alias: decom.
rebalance Manage post-expansion rebalancing.
user Manage IAM users, including password resets and break-glass two-factor clearing.
policy Manage IAM policies and attachments.
access-key Inspect individual or bounded pages of secret-free access-key metadata.
group Manage IAM groups and group membership.
service-account Manage service accounts.
iam Export or import bounded, versioned IAM archives.
service Control the server process: restart, stop, freeze, unfreeze.
config Inspect, plan, export, and mutate RustFS server configuration.
bucket-metadata Export or import validated per-bucket configuration archives.
bucket migration Configure, inspect, and backfill On-Demand Migration from an external S3-compatible source bucket.
replicate Manage site replication across clusters.

Account and Two-Factor Workflow

rc admin account acts on the identity the alias authenticates as. It never takes a target access key, so it cannot modify another account; managing someone else's credentials is rc admin user passwd and rc admin user mfa.

rc admin account info <alias>
rc admin account passwd <alias> [secret sources]
rc admin account mfa status <alias>
rc admin account mfa enroll <alias> [--no-qr]
rc admin account mfa activate <alias> [--code CODE | --code-from-env NAME] [--output-file PATH]
rc admin account mfa disable <alias> [--code ...] [password sources]
rc admin account mfa recovery-codes <alias> [--code ...] [--output-file PATH]

rc admin user passwd <alias> <access-key> [password sources]
rc admin user mfa status <alias> <access-key>
rc admin user mfa reset <alias> <access-key> [--yes]

Two-factor authentication does not gate rc

rc signs every request with the alias access key. That path is deliberately not gated by two-factor authentication: gating it would break every script the moment a human enabled the second factor on their own account, and it would add no protection, because whoever holds the secret key already has full access without presenting a code. The second factor guards session minting — the interactive console login (AssumeRole) — which rc does not use.

Enabling two-factor authentication therefore never breaks an existing alias or automation. Scripts that do call AssumeRole can pass the factor through STS's own SerialNumber and TokenCode parameters.

Secret and code sources

No command accepts a password on the command line, where it would be captured by shell history and visible in ps. Each password is read from one of:

  • --*-from-env NAME — a named environment variable.
  • --*-file PATH — the first line of a file, up to 4096 bytes. A longer file is reported rather than truncated, so a secret can never be silently shortened into a password nobody knows. The file may be a symlink and may be group- or world-readable, because a Kubernetes projected secret is both.
  • an interactive prompt with echo off, offered only when stdin is a terminal and the output is human-readable.

The SSE-C key file (--sse-c-key-file on the data commands) is stricter: it must be a regular file of exactly 32 bytes with no group or other permission. That key is long-lived encryption material an operator places directly, where a symlink or a readable mode is worth refusing; an account password is neither.

Verification codes additionally accept --code CODE because a TOTP code is valid for at most 90 seconds. --code and --code-from-env are mutually exclusive.

In --json mode, or when stdin is not a terminal, a command that would need to prompt exits with USAGE_ERROR naming the flag to pass instead. No command blocks waiting for input it cannot receive.

QR rendering

The server renders the QR code; rc prints the Unicode block art it returns. There is no QR encoder in the CLI, and the console shows the same symbol from the same source. --no-qr prints only the setup key and the otpauth:// URI, and the QR is skipped automatically when the terminal is narrower than 33 columns, since a wrapped symbol cannot be scanned.

--json output omits the QR entirely — both the SVG and the block art — and carries secret_base32 and otpauth_uri instead.

Recovery codes

Recovery codes are returned in plaintext exactly once, by mfa activate and mfa recovery-codes; the server stores only their hashes and cannot show them again. --output-file PATH writes them with mode 0600 and refuses to overwrite an existing file, because that file may hold the only copy of a previous set. The path is checked before the request is sent: by the time the write runs the server has already rotated, so refusing then would destroy the only copy of the new set as well. If the write fails anyway — a mistyped directory, a full disk — the codes are printed instead of dropped, and the command still exits non-zero to say the file was not written. In --json mode they go to stdout and the error to stderr, so a script gets both. Without --output-file they are printed to stdout.

Each code works once. Generating a new set invalidates the previous one.

Break-glass reset

rc admin user mfa reset clears another identity's second factor, for a user who lost both their authenticator and their recovery codes. It names the target and asks for confirmation; --yes is required in --json mode or when stdin is not a terminal. The account is left protected by its password alone until the user enrols again.

Exit codes

Every other workflow in this reference states how its failures are classified, so these do too. The account and two-factor commands map the server's answer onto the standard codes:

Condition Code
Wrong verification code or recovery code authentication (4)
Wrong account password on mfa disable authentication (4)
Wrong current password on account passwd general (1)
Locked out after repeated wrong codes network (3)
At-rest protection not configured on the server unsupported (7)
Route absent, on a server predating these endpoints not found (5)
Recovery-code output path already occupied conflict (6)
Missing, conflicting, or unprompted flags usage (2)
Already enabled, not enabled, or no pending enrollment general (1)

The two password rows differ because the server answers them differently. mfa disable refuses a wrong password with AccessDenied, which is the authentication class. account passwd answers InvalidRequest instead, and deliberately with the same message its new-password validation uses, so that a caller cannot tell "wrong current password" from "new password rejected" by probing. That lands in general (1). A script that reads 4 as "bad credentials" will not see it for a password change.

The lockout deserves a note, because network (3) usually means "retry". It is retryable here too, but only after the delay the server reports — the code comes from SlowDown, which is the S3 vocabulary's closest analogue to a rate limit. A script that retries immediately will simply be refused again.

A failed --output-file write is the one case where a non-zero exit does not mean nothing happened: the server has already issued the set, so the codes are printed and the exit code reports only that the file was not written.

Root identities

A root identity provisioned from RUSTFS_ACCESS_KEY cannot have its password or username changed at runtime: the value is fixed for the life of the process and also derives the internode RPC secret. rc admin account info reports credentials_source: env and password_mutable: false for such an identity, and the mutation commands fail with a message naming the environment variable. Use a built-in IAM user with the consoleAdmin policy for day-to-day administration.

IAM archive migration

rc admin iam round-trips RustFS users, groups, policies, mappings, and supported service-account metadata through the native RustFS IAM archive routes.

rc admin iam export source --file source-iam.zip
rc admin iam import target --file source-iam.zip --dry-run
rc admin iam import target --file source-iam.zip --conflict overwrite --yes

Exports are normalized to version 1 with deterministic JSON key and ZIP entry ordering. The output is created atomically with owner-only permissions and an existing path is never overwritten. Archives contain IAM credentials required for a round trip, so export to protected storage; archive bytes and server error bodies are never printed.

Imports accept --file - for stdin. Files must be regular, non-symlink files with no group or other permissions on Unix, and compressed plus expanded input is bounded to 10 MiB. Every import performs local format validation and a destination conflict preflight. The default --conflict fail stops before mutation; --conflict overwrite must be selected explicitly when replacement is intended. --dry-run validates and reports counts without calling the import route, while a real import additionally requires --yes.

Safe GET exports retry transient network failures up to three times. Import mutations are never retried automatically: a disconnect can leave an unknown outcome, so inspect destination IAM state before retrying. Structured output uses the v3 admin_iam_archive family and reports entity counts only; it never contains secret keys, tokens, credential values, archive contents, or server-provided failure text.

Examples

Show cluster information:

rc admin info cluster local

Read detailed authenticated health observations:

rc admin diagnostics health local

Read the cluster snapshot and extension catalog:

rc admin diagnostics cluster local
rc admin diagnostics extensions local

Inspect scanner health and storage topology:

rc admin scanner status local
rc admin info storage local
rc admin info storage local --metrics

Collect two scanner and disk metric snapshots:

rc --json admin metrics local --scope scanner,disk --samples 2 --interval 3s --by-host --by-disk

Inspect KMS state and manage a key lifecycle:

rc admin kms status local
rc admin kms key list local --limit 100
rc admin kms key status local
rc admin kms configure local --config-file /secure/kms.json
rc admin kms start local
rc admin kms key create local --name archive --description "Archive key" --tag environment=prod
rc admin kms key delete local <KEY_ID> --pending-window-days 7 --yes
rc admin kms key cancel-deletion local <KEY_ID>

Start a deep heal for a prefix:

rc admin heal start local --bucket logs --prefix 2026/ --scan-mode deep

Check global background heal status:

rc admin heal status local

Start and inspect a root recursive manual heal:

rc admin heal start local
rc admin heal status local --client-token <TOKEN_FROM_START>
rc admin heal stop local --client-token <TOKEN_FROM_START>

Check a manual bucket heal task using the client token returned by start:

rc admin heal status local --bucket logs --prefix 2026/ --client-token <TOKEN_FROM_START>

Stop a manual bucket heal task:

rc admin heal stop local --bucket logs --client-token <TOKEN_FROM_START>

Start decommissioning a pool:

rc admin decommission start local '/data/pool1/disk{1...4}'

Check decommissioning status for all pools:

rc admin decommission status local

Check, cancel, or clear decommissioning by pool ID:

rc admin decommission status local 1 --by-id
rc admin decommission cancel local 1 --by-id
rc admin decommission clear local 1 --by-id

Start and inspect post-expansion rebalancing:

rc admin rebalance start local
rc admin rebalance status local
rc admin rebalance stop local

Create a user and attach a policy:

rc admin user add local analyst STRONG_PASSWORD
rc admin policy attach local readonly --user analyst

# Detach several policies from exactly one user.
rc admin policy detach local readonly diagnostics --user analyst

# A comma-separated policy list is accepted too.
rc admin policy detach local readonly,diagnostics --group operations

Inspect policy-to-entity mappings:

# List every policy with its directly attached users and groups.
rc admin policy entities local

# Inspect direct and inherited policies for selected users and groups.
rc admin policy entities local --user analyst --group operations

# Find the users and groups attached to selected policies.
rc --json admin policy entities local --policy readonly --policy diagnostics

Create a service account with a policy file:

rc admin service-account create local SA_ACCESS_KEY SA_SECRET_KEY --policy ./policy.json
rc admin service-account create local SA_ACCESS_KEY SA_SECRET_KEY --user test-user

--user on create sends targetUser so an owner alias can parent the key to another IAM user. Omit it to keep the existing parent-is-the-caller behavior. rc admin service-account ls --user already lists another user's keys.

BREAKING service-account targetUser contract migration

--user on rc admin service-account create is additive and omitted from the request body when unset or empty. Existing creates without --user serialize the same body as before. This PR must be marked BREAKING because docs/reference/rc/admin.md is a protected CLI behavior contract. No JSON schema or config schema_version bump applies.

Link two sites for site replication and check the result:

rc admin replicate add site1 site2
rc admin replicate info site1
rc admin replicate edit site1 --site <DEPLOYMENT_ID> --name edge-eu --yes
rc admin replicate resync start site1 --site edge-eu --yes
rc admin replicate resync status site1 --site edge-eu
rc admin replicate status site1

Gracefully stop or restart a server:

rc admin service stop local
rc admin service restart local

Measure bounded client-to-server upload throughput without storing an object:

rc admin diagnostics client-devnull local --size 8MiB --timeout 30s --concurrency 1 --yes

Behavior

Admin operations use the configured alias to create a RustFS admin client. The credentials behind the alias must have permissions for the requested administrative API. The command accepts aliases with or without a trailing slash.

rc admin diagnostics health, rc admin diagnostics cluster, and rc admin diagnostics extensions perform bounded read-only requests. Each JSON response for these three snapshot commands is limited to 8 MiB. The health command reads the authenticated RustFS health snapshot and is separate from public liveness or readiness probes. Its drive throughput and latency fields are live observations, not active benchmarks, and the command preserves the server's unsupported_probes list instead of claiming mc support diag parity. Cluster output represents snapshot: null as initializing_or_unavailable. Extension diagnostics read schemas and runtime capability summaries only; they never request extension instance configuration.

The diagnostic commands require capability discovery to classify the corresponding route as available. Authentication failures, unsupported routes, malformed JSON, and transport failures retain distinct exit codes.

Observability Workflow

The read-only observability commands target RustFS Admin API v3 routes introduced with the beta.10 diagnostics surface.

Command Description
rc admin scanner status <ALIAS> Classify scanner state as healthy, stale, empty, partial, or disabled and retain current server diagnostic fields.
rc admin info storage <ALIAS> [--metrics] Show backend topology, disk health, and aggregate capacity; optionally include observed drive telemetry.
rc admin metrics <ALIAS> [OPTIONS] Stream bounded realtime metric snapshots.

admin metrics accepts these query and output options:

Option Description
--scope <SCOPES> Comma-separated scopes: scanner, disk, os, batch-jobs, site-resync, network, memory, cpu, rpc, or all.
--samples <1..120> Limit the number of server snapshots. Defaults to 1.
--interval <DURATION> Set the server sampling interval, for example 3s.
--host <HOST> / --disk <PATH> Restrict metrics to selected hosts or disks. Each option may be repeated.
--by-host / --by-disk Request grouped host or disk metrics.
--job-id <ID> / --deployment-id <ID> Restrict batch-job or site-resync metrics.
--metrics-format normalized|raw Emit v3 normalized JSON Lines or bounded raw server JSON records.

Normalized metrics always use one compact v3 JSON object per line, including numeric samples, labels, per-sample timestamps, errors, partial/final markers, and the retained raw snapshot. Raw mode intentionally omits the v3 wrapper. The client rejects responses above 16 MiB, individual records above 1 MiB, and records beyond the requested sample count.

admin info storage --metrics reads only /rustfs/admin/v3/storageinfo after confirming the admin.diagnostics.drive-observations capability. It reports server-observed throughput, latency, utilization, and operation counters; it does not run /v3/speedtest/drive and must not be interpreted as a benchmark. Missing observations are shown as unavailable in human output and null in JSON rather than being fabricated as zero.

Permission failures return the authentication exit code. A missing observability route returns unsupported_feature, allowing automation to distinguish an older RustFS server from missing credentials. Malformed and oversized responses fail without emitting partial normalized records.

IAM Policy-Entity Inspection

rc admin policy entities is a read-only view of the native RustFS /rustfs/admin/v3/idp/builtin/policy-entities route. With no filters it returns policy-to-user/group mappings. Repeated --user, --group, and --policy filters are URL encoded independently, so names containing spaces, slashes, or identity-provider characters are not split or concatenated.

Before sending the IAM request, the CLI requires capability discovery to advertise admin.iam.policy-entities as available. Missing, unknown, disabled, stubbed, and version-gated states fail closed with the unsupported_feature exit code. Permission denial remains an authentication error. Responses are limited to 8 MiB.

JSON output uses schema v3 with the iam_policy_entities family. It includes only the server timestamp, user mappings, inherited group mappings, group mappings, and policy mappings. Unknown response fields are discarded, and secret keys, session tokens, credentials, and raw server error bodies are never included in output.

IAM Policy Detach

rc admin policy detach uses the native RustFS POST /rustfs/admin/v3/idp/builtin/policy/detach mutation. The target must be exactly one --user or --group; policy and entity selectors are validated before capability discovery or mutation traffic. The command fails closed unless the server advertises admin.iam.policy-detach as available.

Detach is idempotent. JSON schema-v3 output uses the iam_policy_detach family and reports the affected entity, the server-reported attached and detached sets, and an unchanged set derived from requested policies that were already detached. A successful retry therefore returns changed: false instead of turning a prior success into an error. Requests are bounded to 512 KiB and responses to 1 MiB; malformed and oversized replies fail without displaying their contents. Authentication denial, missing entities, unsupported routes, validation failures, conflicts, and network failures retain distinct error classes and exit codes.

Bulk Access-Key Inspection

rc admin access-key ls reads RustFS's bulk access-key routes through a typed response model. The default provider is builtin; repeat --provider (or use a comma-separated value) to combine builtin, ldap, and openid scopes. LDAP and OpenID requests are sent only when capability discovery marks their exact provider route available. Missing, disabled, stubbed, unknown, and permission-denied capability states fail closed without probing the route.

Use repeated --user selectors for specific parent identities, no selector for the caller's own identity, or --all for every identity visible to the caller. --all conflicts with --user. --key-type accepts all, users-only, sts, or service-account. At most 1,000 user selectors are accepted; --request-batch-size bounds each request and defaults to 100.

Results are sorted by provider, parent, key type, and access key. --offset and --limit select a deterministic output page; the default limit is 1,000 and the hard limit is 10,000. JSON uses the iam_access_keys output-v3 family and includes total, truncated, and next_offset. Each record contains only the access-key identifier, key type, provider, parent, status, expiration, name, description, and implied-policy flag when RustFS supplied them. Secret keys, session tokens, and unknown server fields are never retained in the public response model.

Provider or selector failures are retained in data.failures. A page with any failure exits non-zero; partial data uses exit code 1, while a uniform all-failed result preserves the specific usage (2), network (3), authorization (4), not-found (5), conflict (6), unsupported (7), or interrupted (130) class.

rc admin access-key ls local --user alice --user bob
rc admin access-key ls local --provider builtin,ldap --all --key-type service-account
rc --json admin access-key ls local --provider openid --all --offset 100 --limit 100

KMS Key Lifecycle Workflow

The KMS commands target the native RustFS beta.10 Admin API. They do not implement the MinIO KMS admin protocol.

Command Description
rc admin kms status <ALIAS> Show not-configured, configured, running, error, or unknown service state plus a non-secret configuration summary.
rc admin kms configure <ALIAS> <--config-file PATH|--stdin> Validate and install an initial Local, Vault KV2, or Vault Transit JSON configuration.
rc admin kms reconfigure <ALIAS> <--config-file PATH|--stdin> Replace configuration through RustFS's native stop, reconfigure, persist, and restart workflow.
rc admin kms start <ALIAS> Start a configured KMS service.
rc admin kms restart <ALIAS> --yes Force a KMS service restart after explicit confirmation.
rc admin kms stop <ALIAS> --yes Stop KMS after explicit confirmation.
rc admin kms roundtrip <ALIAS> <BUCKET> [--key-id KEY_ID] --yes Verify a real SSE-KMS object write/read cycle in an explicit existing bucket, using the configured default key when --key-id is omitted.
rc admin kms key list <ALIAS> [--limit N] [--marker TOKEN] List native RustFS KMS keys with pagination. The limit range is 1..=1000.
rc admin kms key status <ALIAS> [KEY_ID] Show key metadata and lifecycle state. When KEY_ID is omitted, use the configured default key ID.
rc admin kms key create <ALIAS> [--name NAME] [--description TEXT] [--tag KEY=VALUE]... Create a key. Names are sent through RustFS's reserved name tag. Tags reject malformed, duplicate, reserved-name, and control-character input.
rc admin kms key delete <ALIAS> <KEY_ID> [--pending-window-days 7..30] --yes Schedule deletion. The pending window defaults to seven days and --yes is mandatory.
rc admin kms key delete <ALIAS> <KEY_ID> --immediate --yes --confirm-immediate Permanently delete a key with two explicit non-interactive acknowledgements. Immediate deletion cannot be cancelled.
rc admin kms key cancel-deletion <ALIAS> <KEY_ID> Cancel a previously scheduled deletion.

An unconfigured KMS service is a successful status result with state=not-configured; it is not treated as a network failure. Permission failures return the authentication exit code. Missing status or list routes return unsupported_feature, while a missing explicitly requested key returns not_found.

Human output includes service state, backend family, health, default key ID, cache state, and key metadata. JSON output uses the v3 kms family. Configuration responses are normalized instead of passed through: Vault tokens, AppRole secret IDs, local master keys, plaintext data keys, and ciphertext blobs are never part of the KMS inspection output.

Mutation responses use key_create, key_delete, and key_cancel_deletion operations in the v3 kms family. Server error messages are classified into stable permission, missing-key, conflict, unavailable, rejected-request, and malformed-response failures without echoing response bodies. Create and cancellation results deserialize only lifecycle metadata; unknown key-material fields are ignored. These commands do not configure, start, or stop the KMS service and never request or export data keys.

Configuration is never accepted through field-specific command-line flags or positional JSON. Use exactly one of --config-file PATH or --stdin. Input is limited to 1 MiB and must match one strict backend_type request shape: Local, VaultKV2, or VaultTransit. Unknown fields, missing required fields, invalid URLs, relative Local key directories, zero timeout/retry/cache values, insecure production Vault transport, and unsafe Local key-file modes are rejected locally before network access. Vault addresses cannot contain URL credentials, query parameters, or fragments, which prevents hidden secrets from bypassing owned-buffer zeroization. Reconfiguration may use an empty Vault Token value to retain server-stored credentials because RustFS beta.10 defines that sentinel for an existing token; initial configuration may not. AppRole has no equivalent sentinel in beta.10, so both role_id and secret_id remain mandatory and partial credentials are always rejected.

On Unix, --config-file accepts only a regular non-symlink file with no group or other permission bits; mode 0600 is recommended and modes such as 0640 or 0644 are rejected. Standard input has no filesystem permission check and should come from a protected pipe or secret manager. The CLI stores raw input, typed secret fields, serialized request bytes, and the HTTP request body in zeroizing containers. Client errors are static and server response bodies are never copied into diagnostics, so Local master keys, Vault tokens, AppRole IDs, and AppRole secrets are not emitted in debug, human, JSON, or error output.

The v3 lifecycle success operations are configure, reconfigure, start, restart, and stop, each with the resulting service state. Unconfigured start is not_found; permission denial is auth_error; unavailable service/storage is network_error; malformed or rejected responses are general_error; missing lifecycle routes are unsupported_feature. Restart and stop refuse to contact the server unless --yes is present.

kms roundtrip refuses to run without --yes. It generates exactly 4 KiB of random test content internally, writes one randomly named temporary object with explicit SSE-KMS headers, reads and compares the decrypted bytes without creating or reporting a digest, and always attempts permanent deletion even when write, read, or verification fails. The read is bounded to 4 KiB. Application-owned plaintext buffers are zeroized; the temporary object name, plaintext, ciphertext, digest, and generated key material never appear in debug, human, JSON, or error output. A successful v3 result reports only bucket, key_id, passed, cleanup_passed, and write/read/cleanup/total milliseconds. Cleanup failure is a distinct error, and a primary failure explicitly reports when cleanup also failed.

kms key status describes native RustFS key lifecycle metadata. It does not claim compatibility with the mc admin kms key status encryption/decryption probe. The round-trip diagnostic uses only the S3 object API and does not call an Admin API key-generation route. RustFS beta.10 has no direct decrypt-test Admin API or KMS-specific metrics route/selector contract, so rc does not offer KMS-specific metrics and intentionally does not expose the legacy generate-data-key response because that response contains plaintext data-key material.

OIDC Administration

These commands target RustFS's native typed OIDC routes. They do not use LDAP compatibility configuration or browser login endpoints:

Command Behavior
rc admin idp openid list <ALIAS> List all effective persisted and environment-managed providers.
rc admin idp openid get <ALIAS> <PROVIDER_ID> Select one exact provider from the server's typed configuration list.
rc admin idp openid validate <ALIAS> <PROVIDER_ID> --config-url URL --client-id ID Run live discovery validation without saving or changing server configuration.
rc admin idp openid set <ALIAS> <PROVIDER_ID> [OPTIONS] Create a provider or update an existing provider after GET-and-merge and discovery preflight.
rc admin idp openid update <ALIAS> <PROVIDER_ID> [OPTIONS] Update an existing provider and fail if it does not exist.
rc admin idp openid enable <ALIAS> <PROVIDER_ID> [--dry-run] Enable a persisted provider while preserving every other field.
rc admin idp openid disable <ALIAS> <PROVIDER_ID> [--dry-run] Disable a persisted provider while preserving every other field.
rc admin idp openid delete <ALIAS> <PROVIDER_ID> [--yes] Display a secret-free provider summary, confirm, and delete one persisted provider. Use --yes for automation.

Provider output includes only the server's client_secret_configured boolean. Client-secret values are never accepted as command-line literals, sent in validation requests, or included in human/JSON output. A replacement must use --client-secret-stdin or --client-secret-file <PATH> together with --replace-client-secret. Secret files must be regular files, must not be symbolic links, and on Unix must grant no group or other permissions. Omitting a secret preserves the server-side value.

Every mutation first reads the current effective provider, rejects environment-managed or otherwise non-editable providers, merges only explicitly supplied options, and runs the native validation endpoint. --dry-run performs GET and validation and emits the same deterministic, redacted change list without issuing PUT. Successful changes explicitly report restart_required; multiple providers are addressed independently by exact provider ID.

Remote text is terminal-sanitized, response bodies are bounded, and unknown or incomplete provider or mutation shapes fail closed. Missing/unsupported routes use the unsupported_feature exit code, permission failures use the authentication exit code, a missing exact provider uses not_found, conflicts use the conflict exit code, and locally invalid URLs use the usage exit code.

JSON output uses schema v3 family oidc with operations list, get, validate, set, update, enable, disable, and delete. A delete reads the exact provider before mutation, refuses environment-managed or otherwise non-editable providers, and requires an interactive confirmation or --yes in non-interactive/JSON mode. A repeated delete returns deterministic not_found without issuing DELETE. Validation supports repeated --scope and --other-audience options, optional --issuer, claim-name overrides, and --redirect-uri --static-redirect. Mutation fields use the same options, while --clear-issuer, --clear-redirect-uri, --replace-other-audiences, and the paired boolean flags express explicit resets. Scopes must include openid; URLs must be absolute HTTP(S) URLs. RustFS still applies its server-side outbound URL safety policy before performing discovery.

rc admin heal status <ALIAS> reports aggregate background heal status. Manual heals started with rc admin heal start are token-scoped tasks; the start output includes a client token. Root recursive tasks are inspected or stopped with --client-token, while bucket or prefix tasks additionally pass --bucket and optional --prefix.

Diagnostics Workflow

rc admin diagnostics client-devnull measures bounded client-to-server ingress throughput by sending zero-filled request bodies to the RustFS devnull endpoint. The server consumes the bytes without creating an object. The command requires credentials with HealthInfoAdminAction permission.

rc admin diagnostics client-devnull <ALIAS> \
  [--size <SIZE>] \
  [--timeout <DURATION>] \
  [--concurrency <N>] \
  --yes
Option Default Limits and behavior
--size <SIZE> 8MiB Bytes sent by each request. The value must be greater than zero; binary byte units such as MiB are accepted. size × concurrency must not exceed 64MiB.
--timeout <DURATION> 30s Overall active-probe timeout. Use whole seconds from 1s through 60s.
--concurrency <N> 1 Number of simultaneous requests, from 1 through 4.
--yes none Required confirmation because the command deliberately generates network load.

The client checks RustFS diagnostic capabilities before starting the upload and fails closed unless discovery explicitly reports the non-stub admin.diagnostics.client-devnull capability. Unknown server versions, missing capability data, and advertised placeholder implementations are rejected without sending an active probe.

Every successful request must return a measured response with the exact kind client-devnull, measured: true, an rx_bytes value equal to the bytes sent by that request, and present, finite, positive duration and aggregate-write-throughput measurements. Each active-probe response body is limited to 64 KiB. Placeholder responses, oversized or incomplete measurements, non-finite or non-positive measurements, and byte-count mismatches are reported as unsupported rather than as successful results.

A successful result reports requested_bytes, received_bytes, concurrency, elapsed_seconds, and aggregate_throughput_bytes_per_second; human output presents the same values with readable units. Requested and received byte counts are aggregate values across all concurrent requests, and aggregate throughput is calculated from received bytes over client-observed elapsed time.

The active upload is attempted once per concurrent lane and is never retried. Reaching the timeout or pressing Ctrl-C cancels the in-flight requests and stops further body generation; Ctrl-C returns the interrupted exit status. The command does not run object read/write, server-to-client, network mesh, site, drive, or netperf probes, and it does not persist diagnostic payloads.

Heal Workflow

rc admin heal manages cluster healing operations.

Command Description
rc admin heal status <ALIAS> Show aggregate background heal status.
rc admin heal status <ALIAS> --client-token <TOKEN> Show a token-scoped root recursive manual heal task.
rc admin heal status <ALIAS> --bucket <BUCKET> [--prefix <PREFIX>] --client-token <TOKEN> Show a token-scoped manual heal task.
rc admin heal start <ALIAS> [OPTIONS] Start a manual heal operation.
rc admin heal stop <ALIAS> Stop the global background heal operation.
rc admin heal stop <ALIAS> --client-token <TOKEN> Stop a token-scoped root recursive manual heal task.
rc admin heal stop <ALIAS> --bucket <BUCKET> [--prefix <PREFIX>] --client-token <TOKEN> Stop a token-scoped manual heal task.

heal start accepts these operation options:

Option Description
-b, --bucket <BUCKET> Heal a single bucket. Omit this option to recursively heal all buckets.
-p, --prefix <PREFIX> Limit a bucket heal to an object prefix.
--scan-mode normal|deep Select the scan mode. Defaults to normal.
--remove Remove dangling objects or parts found by the heal scan.
--recreate Recreate missing data.
--dry-run Report what would be healed without applying changes.

All manual heals are token-scoped. Save the clientToken returned by heal start; the token is required to inspect or stop the task. Root recursive tasks use the token alone, while bucket and prefix tasks also require their original target options.

Decommission Workflow

rc admin decommission retires server pools from a cluster. The POOL argument can be a pool command line, comma-separated pool command lines, or a zero-based pool ID when --by-id is set.

Command Description
rc admin decommission start <ALIAS> <POOL> [--by-id] Start decommissioning one or more pools.
rc admin decommission status <ALIAS> [POOL] [--by-id] Show decommissioning status for all pools or one pool.
rc admin decommission cancel <ALIAS> <POOL> [--by-id] Cancel decommissioning for a pool.
rc admin decommission clear <ALIAS> <POOL> [--by-id] Clear failed or canceled decommissioning metadata for a pool.

Use rc admin pool list <ALIAS> or rc admin pool status <ALIAS> to find pool IDs and pool command lines before starting a decommission.

Rebalance Workflow

rc admin rebalance manages post-expansion data movement after server pools are added to a deployment.

Command Description
rc admin rebalance start <ALIAS> Start a cluster rebalance operation.
rc admin rebalance status <ALIAS> Show cluster-wide and per-pool rebalance status.
rc admin rebalance stop <ALIAS> Stop a running rebalance operation.

rc admin expand is an alias-oriented workflow for the same post-expansion rebalance step. The expand command is also available as scale.

Service Control Workflow

rc admin service controls the server process behind an alias.

Command Description
rc admin service restart <ALIAS> Request a graceful shutdown for restart. The supervising process manager (systemd, Kubernetes) is responsible for relaunching the binary.
rc admin service stop <ALIAS> Request a graceful shutdown.
rc admin service freeze <ALIAS> Set the service freeze flag. Currently advisory: the server records the flag but does not yet gate request admission on it.
rc admin service unfreeze <ALIAS> Clear the service freeze flag.

The server response reports whether the action was accepted and whether it is effective on the current build. RustFS has no in-process supervisor, so restart and stop both perform a graceful stop; restart relies on the process manager to bring the server back up.

Server Configuration Workflow

rc admin config manages the RustFS server configuration behind an alias. It does not modify the local rc alias configuration.

Command Description
rc admin config get <ALIAS> <SUBSYSTEM[:TARGET]> Read a subsystem or named target. Secret-bearing fields are redacted again by the client before output.
rc admin config set <ALIAS> <SUBSYSTEM[:TARGET]> <KEY=VALUE|KEY=@PATH>... [--dry-run] Consult server help once per subsystem, read the current state, calculate a redacted diff, and apply the directive unless --dry-run is set. KEY=@PATH keeps a value out of process arguments.
rc admin config delete <ALIAS> <SUBSYSTEM[:TARGET]> [KEY...] [--dry-run] Delete selected keys or the complete target after a redacted preflight diff.
rc admin config help <ALIAS> [SUBSYSTEM] [KEY] [--env] Show server-provided subsystem, key, or environment-variable help.
rc admin config history <ALIAS> [--count <N>] List recent history. History data is classified and redacted locally because server records can contain submitted values.
rc admin config restore <ALIAS> <RESTORE_ID> [--dry-run] --yes Preview or apply a history entry as a complete configuration replacement.
rc admin config export <ALIAS> --file <PATH> Create a new, owner-private, redacted configuration file. Existing files are never overwritten.
rc admin config import <ALIAS> --file <PATH> [--dry-run] --yes Validate and preview a complete configuration replacement from a file. Redacted secret placeholders are rejected.
rc admin config module-switch get <ALIAS> Show effective and persisted notification/audit module switches and their sources.
rc admin config module-switch set <ALIAS> [--notify on|off] [--audit on|off] [--dry-run] Update one or both persisted switches. Omitted switches retain their persisted value even when an environment override changes the effective value.

All set, delete, import, restore, and module-switch dry runs are client-side and do not send a mutation request. RustFS beta.10 does not expose a revision, ETag, or other optimistic concurrency token for these routes, so rc does not claim atomic compare-and-set protection.

Full imports and restores require --yes. RustFS beta.10 history entries contain the submitted directive rather than a complete pre-change snapshot. The server currently rebuilds its configuration from that directive during restore, which can remove unrelated settings. rc shows this as a complete replacement and warns about the unsafe server behavior tracked in rustfs/backlog#1398; a history restore must not be treated as preservation-safe rollback.

Exports are always redacted because secret values are not a portable client output contract. Replace any required secret values through an approved secret-management workflow before importing; rc rejects the *redacted* placeholder for secret-bearing fields.

Value files are limited to 1 MiB of single-line UTF-8 text. On Unix they must be regular, non-symlink files without group or other permissions; trailing line endings are removed. If server help metadata is incomplete or unavailable, set, delete, and import emit a warning and defer final validation to the mutation endpoint.

Bucket Metadata Archive Workflow

rc admin bucket-metadata exports and imports the per-bucket configuration families supported by the RustFS v3 archive routes: policy, notification, lifecycle, encryption, tagging, quota, object lock, versioning, replication, and replication targets.

Command Description
rc admin bucket-metadata export <ALIAS> --file <PATH> [--bucket <BUCKET>...] [--force] Export all buckets or an explicit selection to a deterministic, owner-private ZIP. The file is created atomically; --force is required to replace an existing path.
rc admin bucket-metadata import <ALIAS> --file <PATH|-> [--bucket <BUCKET>...] --conflict <fail|overwrite|skip> [--dry-run] [--yes] Validate a protected ZIP, compare it with current metadata, and apply the explicit conflict policy. Mutating imports require --yes; dry runs never send a mutation.

Archives are bounded to 100 MiB compressed, 128 MiB expanded, 4,096 entries, and 16 MiB per entry. Entry paths must be exactly <BUCKET>/<SUPPORTED_CONFIG>; duplicate, empty, nested, traversal, and unknown entries fail before mutation. On Unix, file input must be a regular non-symlink file with no group or other permissions. Standard input is available through --file - for an explicitly protected pipeline.

Server exports redact replication-target credentials. The client never prints archive contents and rejects an import whose target metadata contains a missing or redacted secret, because importing it would overwrite a working credential. Supply real target credentials only through a protected archive or standard input.

--conflict fail stops before mutation if any imported config differs from current state. overwrite sends differing configs, while skip removes only conflicting entries from the outgoing archive. Identical entries are never resent. Missing destination buckets remain eligible for the server's create-on-import behavior, while a selected bucket absent from the source archive is a distinct not-found error.

An import is one bounded PUT and is never automatically retried. A transport failure or server error can mean that only part of the archive was applied; inspect every selected bucket before deciding whether to retry. Successful JSON output uses output schema v3 with one admin_operations result per selected bucket.

On-Demand Migration Workflow

rc admin bucket migration manages RustFS On-Demand Migration: a bucket names an external S3-compatible source bucket, a GET that misses locally is served from that source and stored locally in the same pass, and a background backfill job pulls the rest. It is the RustFS equivalent of Cloudflare R2 Sippy or Tigris shadow buckets. The server-side operations guide is docs/operations/on-demand-migration.md in rustfs/rustfs; the wire contract is pinned by the fixtures vendored under crates/core/tests/fixtures/on_demand_migration/.

Every command takes the local bucket as <ALIAS>/<BUCKET>.

Command Description
rc admin bucket migration set <ALIAS>/<BUCKET> --provider <P> [--endpoint URL] --region <R> --source-bucket <B> [--prefix P] [--source-prefix SP] [--access-key AK [--secret-key SK] | --public] [--path-style auto|path|virtual] [--skip-tls-verify] [--ca-cert FILE] [--head proxy|local_only] [--range-get serve_and_backfill|serve_only] [--source-error propagate|not_found] [--no-preserve-etag] [--copy-tags] [--no-events] [--inline-max-bytes N] [--max-concurrent-pulls N] [--dry-run] Validate the configuration, probe the source (HeadBucket plus a one-key listing) and save it. --dry-run sends PUT ...?dry-run=true, which validates and probes without saving.
rc admin bucket migration get <ALIAS>/<BUCKET> Print the saved configuration as a table. Credentials are shown as REDACTED.
rc admin bucket migration rm <ALIAS>/<BUCKET> Remove the configuration. Idempotent; objects already pulled stay in place.
rc admin bucket migration status <ALIAS>/<BUCKET> [--watch] [--interval SECONDS] Print the answering node's runtime status: source-hit ratio, migrated bytes, in-flight and queued pulls, breaker state, request and failure counters, and the last source error.
rc admin bucket migration backfill start <ALIAS>/<BUCKET> [--prefix P] [--skip-existing always|etag_or_size] [--dry-run] Start the background job that walks the source listing and pulls what is missing locally. --dry-run lists and counts without queuing anything.
rc admin bucket migration backfill cancel <ALIAS>/<BUCKET> Ask the running job to stop at its next checkpoint.
rc admin bucket migration backfill status <ALIAS>/<BUCKET> [--watch] [--interval SECONDS] Print the job checkpoint. With --watch, refresh one progress line every --interval seconds (default 2) until the job reaches a terminal state, then print the final checkpoint.

Secret handling

set needs the source secret key whenever --access-key is given. It is taken, in order, from --secret-key, from the RC_ODM_SECRET_KEY environment variable, or from a hidden terminal prompt. Prefer the variable or the prompt: a flag value lands in shell history and in ps output. The prompt is only offered when standard input is a terminal and output is human-readable; with --json or in a script the variable is required and a missing one is a usage error before any request is sent.

The server returns every credential as the placeholder REDACTED, and set replaces the configuration wholesale rather than merging into it. rc therefore refuses the placeholder as a secret: editing an existing configuration means passing the real secret again. --public configures anonymous access and is mutually exclusive with the credential flags.

--endpoint must be scheme://host[:port] with no path, query, fragment or embedded userinfo; it is optional only for --provider aws, where the server derives it from --region. --ca-cert reads a PEM bundle of at most 64 KiB. Arguments are validated before the secret is read, so a typo never costs a prompt.

Output

Human output prints one aligned key/value table per document. status renders served_by_source_ratio exactly as the server reports it: a percentage when present and an em dash (—) when the server returns null, never zero, because a missing ratio and a zero ratio mean different things. --json wraps every result in output schema v3 with type: on_demand_migration and data: {operation, bucket, result}, where result is the server document with credentials redacted. --watch with --json emits one compact record per refresh on stdout; without --json, the backfill progress line is written to stderr so stdout carries only the final document.

Every response field is optional on the client with the server default, so an older server that omits a field still parses, and unknown fields from a newer server are ignored.

Exit codes

Condition Code
Malformed target, missing or conflicting flags, invalid endpoint or CA file, configuration rejected by the server (InvalidArgument), module switch off (OnDemandMigrationDisabled) usage (2)
Source unreachable during the probe (OnDemandMigrationSourceUnreachable), transport failure, 5xx network (3)
Not authorized, or the licence denies the entitlement (AccessDenied) authentication (4)
No configuration (NoSuchConfiguration), no such bucket, no backfill job recorded not found (5)
A backfill job already holds the lease (409 OnDemandMigrationBackfillRunning) conflict (6)
Route family absent (the server predates on-demand migration), or the provider was excluded at build time (501) unsupported (7)

A 404 that does not carry one of the route family's own error codes means the whole feature is missing from the server; rc prints server does not support on-demand migration and exits 7 rather than treating the bucket as unconfigured. Writes are never automatically retried: a set probes the source and a backfill start takes a lease, so a repeated request is a second decision.

Site Replication Workflow

rc admin replicate manages multi-cluster site replication. Peer sites are given as configured alias names; their endpoints and credentials are resolved from the local alias store, so every participating site needs an alias with root credentials before running add.

Command Description
rc admin replicate add <ALIAS> <ALIAS> [<ALIAS>...] Link two or more sites into a site replication cluster. The first alias receives the request.
rc admin replicate info <ALIAS> Show the current site replication configuration.
rc admin replicate edit <ALIAS> --site <DEPLOYMENT_ID|NAME> [EDIT OPTIONS] --yes Read the complete peer document, select one exact peer, apply a bounded edit, and write the peer document back.
rc admin replicate resync start <ALIAS> --site <DEPLOYMENT_ID|NAME> --yes Request a site resync and return the mutation response snapshot.
rc admin replicate resync status <ALIAS> --site <DEPLOYMENT_ID|NAME> Return the last persisted start or cancel snapshot. This is not live worker status.
rc admin replicate resync cancel <ALIAS> --site <DEPLOYMENT_ID|NAME> --yes Request cancellation and return the mutation response snapshot.
rc admin replicate status <ALIAS> [OPTIONS] Show replication status. Without flags the buckets, users, groups, and policies summaries are requested.
rc admin replicate remove <ALIAS> --all Dissolve the entire site replication cluster.
rc admin replicate remove <ALIAS> --site <NAME> Remove one or more named sites. Repeat --site per name.

status accepts these section flags:

Option Description
--buckets Include the bucket replication summary.
--users Include the IAM user replication summary.
--groups Include the IAM group replication summary.
--policies Include the IAM policy replication summary.
--metrics Include replication metrics.

edit accepts these options:

Option Description
--site <DEPLOYMENT_ID|NAME> Select an exact deployment ID first, otherwise a unique exact site name. Partial matching is never used.
--endpoint <URL> Replace the peer endpoint. The value must be an HTTP or HTTPS origin without user information, path, query, or fragment.
--name <NAME> Rename the selected peer, including the local deployment when it is selected by deployment ID.
--skip-tls-verify Set skipTlsVerify=true and clear the custom CA. Conflicts with --verify-tls and --ca-cert.
--verify-tls Set skipTlsVerify=false.
--ca-cert <FILE> Set a certificate-only PEM CA bundle and enable TLS verification. The file is read with a 256 KiB bound.
--clear-ca-cert Set the custom CA to an empty value. Conflicts with --ca-cert.
--yes Confirm the mutating read-modify-write operation. This is required before alias lookup or network access.

At least one edit option must produce an effective semantic change. Endpoint origins are canonicalized for comparison, while an omitted skipTlsVerify is treated as false and an omitted caCertPem is treated as empty. The command rejects a final HTTP peer state when skipTlsVerify=true or a non-empty custom CA remains. This permits an atomic HTTPS-to-HTTP conversion only when the same command clears the active TLS values.

The complete selected peer object is retained privately and sent back with opaque future fields unchanged during the read-modify-write operation, but those fields are never printed. info and edit output use explicit safe projections: service-account access keys, CA contents, opaque future fields, and arbitrary server status strings are never printed. Successful JSON output uses output schema v3 with the admin_operations family. Mutating network failures are reported as non-retryable in JSON because the server outcome may be unknown; inspect info before deciding whether to retry.

resync start and resync cancel require --yes before alias lookup or network access. All three resync commands select a deployment ID first, otherwise a unique exact site name. Their output retains the operation ID, ordered bucket snapshots, and error details. A failed bucket or non-empty error detail produces General exit 1 while still emitting the complete result. A missing persisted snapshot produces Conflict exit 6.

The current RustFS resync status endpoint returns the persisted result of the last successful start or cancel handler invocation; it does not inspect live workers. Every output therefore reports an unknown lifecycle state. Start operations can overlap, cancel is not idempotent, and bucket side effects are not atomic with snapshot persistence. A mutation timeout, malformed success response, or oversized success response has an unknown outcome and must not be retried blindly. See Site Replication Resync Snapshots for response bounds and the complete server limitations.

BREAKING resync contract migration

The resync subcommands are additive and do not change existing command invocations. They use the existing output-v3 admin_operations envelope, so no JSON schema-version migration is required. The protected behavior contract is updated to make snapshot-only semantics explicit: automation must treat result.lifecycle_state as unknown, use result.server_operation only as the persisted operation type, and must not interpret status output as live progress. This PR must be marked BREAKING because it changes the protected CLI behavior contract.

BREAKING output migration

rc admin replicate info --json previously emitted the RustFS server response directly. It now emits an output-v3 admin_operations envelope with changed=false; the safe site configuration is under data.operations[0].result. Scripts must update field access accordingly. serviceAccountAccessKey and caCertPem are intentionally absent, with CA presence represented by hasCustomCA. This PR must be marked BREAKING because the protected CLI behavior contract changes.

Site replication requires bucket versioning support on every site and replicates buckets, objects, IAM users, groups, policies, and service accounts across all linked sites. The server rejects loopback peer endpoints unless the deployment explicitly allows them (RUSTFS_REPLICATION_ALLOW_LOOPBACK_TARGET=true), which is intended for local testing only.

Global options shown in command syntax use the same meaning everywhere:

Option Description
--format auto|human|json Select automatic, human-readable, or JSON output.
--json Emit JSON output where the command supports structured output.
--no-color Disable terminal colors.
--no-progress Disable progress bars.
-q, --quiet Suppress non-error output.
--debug Enable debug logging.