Operator-facing reference for the armor binary's subcommands: what each
command reads, what it writes, which credentials and keys it needs, which exit
code it returns, and where the safe-use boundaries are. The one-paragraph
summary in the README stays short; this document is
the per-command contract. Environment variables are referenced by name only —
the full values reference is Configuration.
Every claim here is enforced by the executable parity gate
(scripts/cli-contract-gate.sh) and the smoke tests in
cmd/armor/cli_reference_test.go and
cmd/armor/cli_secret_safety_test.go:
the command list, every flag name, and the documented help output are checked
against the binary's own registry, and the binary is then built and exercised
for the documented behaviors — the help and version paths exit 0 with the
documented output, unknown subcommands, undefined flags, missing required
flags, and stray positional arguments exit 2, the commands that need
credentials fail with exit 1 without them, client-config accepts exactly
the documented tools and prints their configuration to stdout, migrate -json keeps stdout to JSON only, and every ARMOR_* variable named here is
read by the implementation. The secret-safety tests plant distinctive MEK
and token values through every documented key source (-mek, -mek-file,
ARMOR_MEK, ARMOR_ADMIN_TOKEN), drive the documented failure paths, and
pin that the binary never echoes a credential value into stdout or stderr —
so this page cannot silently drift from the code.
This reference describes the source-tree command contract. It does not certify
the behavior of an arbitrary published image or deployment. armor verify and
armor decrypt have repository tests for fingerprinted wrapped DEKs and v3
multipart manifests/sidecars, while named-key reads, wrapped-DEK decoding in
DR inputs, multipart sidecar preservation, SigV4, presigned GET, and range
performance still need release-image or live evidence for the exact rollout.
Run the focused command against the pinned image and record its result before
calling an operator workflow complete. The canonical status and limitation
register is release-status.md.
armorwith no subcommand runsserve— the container entry point relies on this default.armor --help(also-h,-help) prints the top-level command table and exits 0.armor helpdoes the same.armor <cmd> --helpprints that command's summary and its flags and exits 0 without running the command.armor --version(also-v) prints the version line and exits 0.- An unknown subcommand prints the command table to stderr and exits 2.
- An undefined or malformed flag prints the subcommand's usage to stderr and exits 2 without running the command.
- Every command that takes arguments rejects unexpected positional arguments
with exit 2;
helpdeliberately ignores them (asked-for help is never an error).
Exit-code conventions used by every command:
| Code | Meaning |
|---|---|
| 0 | Success (for check, warnings still exit 0) |
| 1 | The requested work failed: missing credentials or keys, unreadable input, network or HTTP failure, corrupted objects |
| 2 | Usage error: unknown subcommand, undefined flag, missing required flag, unexpected positional argument |
Two credential conventions recur across the offline commands:
- MEK sources, tried in this order:
-mek(hex, 64 chars),-mek-file(path to a file holding the hex),-escrow(see below), then theARMOR_MEKenvironment variable where the command supports the fallback. - Escrow file (
-escrow): a self-contained JSON recovery package withmek, amek_ringarray of{mek, fingerprint}entries, and ab2object (region,endpoint,access_key,secret_key,bucket,cf_domain). Loading it exports the B2 fields into the process environment, so one file arms both the keys and the backend. It is the only multi-key input the CLI has. Format and provisioning: Disaster Recovery.
Run the ARMOR S3-compatible server. This is the default command.
- Inputs: no flags; the entire configuration is environmental
(
ARMOR_LISTENfor the S3 API,ARMOR_ADMIN_LISTENfor the admin API, plus backend, encryption, and authentication variables — Configuration). - Outputs: structured JSON logs on stdout; the S3 API on
ARMOR_LISTEN; the admin API onARMOR_ADMIN_LISTEN. - Exit codes: 0 after a clean shutdown on SIGINT/SIGTERM (in-flight requests are drained with a 60-second cap); 1 when configuration loading, server construction, or listener binding fails; 2 on unexpected positional arguments.
- Credentials/keys: the full deployment set —
ARMOR_MEK, backend credentials, client credentials, andARMOR_ADMIN_TOKEN(without it the key-management and migration admin endpoints stay disabled, fail-closed). - Safe use: the S3 listener deliberately sets no read/write deadlines so
multi-gigabyte multipart transfers survive; front it with something that
tolerates long requests. Keep the admin listener off public interfaces
(loopback or tailnet) — it controls keys and migration. Restarting with the
same
ARMOR_MEKis what keeps existing objects readable.
Run a local instance for trying ARMOR with a filesystem backend and generated
dashboard credentials. With -dir, its MEK persists in a private file so data
survives a restart; without -dir, it uses a disposable temporary directory
and in-memory key.
| Flag | Meaning |
|---|---|
-dir |
Directory for the filesystem backend (default: a temp directory removed on exit) |
-mek-file |
File for the persistent MEK (default: <dir>/.armor-demo-mek when -dir is set; relative custom paths are resolved inside -dir) |
-listen |
S3 API listen address (default 127.0.0.1:9000) |
-admin-listen |
Admin API listen address (default 127.0.0.1:9001) |
- Inputs: the flags above; everything else is fixed by the command
(backend
filesystem, bucketdemo-bucket, access keyarmor, secret keyarmor-demo-secret), except dashboard username/password and admin token, which can be supplied throughARMOR_DASHBOARD_USER,ARMOR_DASHBOARD_PASS, andARMOR_ADMIN_TOKEN. - Outputs: JSON startup logs include the listen addresses, dashboard URL, dashboard credentials, admin token, and S3 credentials. A ready-to-paste AWS CLI configuration follows as a plain-text block on stdout.
- Exit codes: 0 on shutdown; 1 on setup failure (temp directory, config); 2 on unexpected positional arguments.
- Credentials/keys: none required — the command generates the dashboard credentials and admin token if they are not supplied, then prints them. The MEK is generated on first use and saved with mode 0600 when a persistent MEK file is selected.
- Safe use: never point real clients at a demo. The dashboard and admin credentials are printed to the terminal. Back up the MEK file with the demo data; losing it makes the stored objects unreadable.
Verify a deployment's live configuration and connectivity. Read-only.
- Inputs:
--jsonoptionally switches probe output to one newline-delimited JSON object per probe (name,status,detail) on stdout. Without it, output remains human-readable. Both modes load the same configuration the server would (config.Load), so run it inside the container or with the deployment's environment. - Probes:
config(required fields, credentials present),backend(bucket reachable),cloudflare(ranged GET of the newest<prefix>.armor/canary/object through the Cloudflare domain, reportingCF-Cache-Statusand latency),mek(unwraps that canary's wrapped DEK with the configured MEK),fingerprint(scans objects under.armor/and fails when any object names a MEK fingerprint absent from the active key and ring — the retire gate). - Outputs: a redacted configuration dump to stderr (bucket and key
identifiers render as fingerprints); without
--json, one[PASS|WARN|FAIL] probe: messageline per probe on stdout; with--json, one{"name":"...","status":"...","detail":"..."}object per probe on stdout; a final verdict line remains on stderr. - Exit codes: 0 all probes pass (warnings still pass); 1 when a probe fails or the configuration itself fails to load; 2 on an undefined flag or unexpected positional argument.
- Credentials/keys: the deployment's own environment:
ARMOR_MEK, backend credentials, and the rest of Configuration. Thecloudflareandmekprobes need canary objects (the server writes them continuously) and only WARN when none exist. - Safe use: read-only — safe against production at any time. A FAIL on
fingerprintmeans objects exist that a future rotation would orphan; add the named fingerprints to the ring before retiring keys.
MEK rotation is an admin API operation, not a CLI command. Follow the
key-ring runbook: configure and escrow the new
active MEK first, then send POST /admin/key/rotate with an empty body.
The endpoint rejects a supplied MEK body with HTTP 400.
Decrypt one ARMOR-encrypted object offline — break-glass recovery with no running server. Reads single-PUT envelopes (any envelope version) and multipart objects (headerless ciphertext plus HMAC sidecar) through the same format rules as the server's read path. A successful repository test is not a substitute for a DR drill against the published image and its escrow package.
| Flag | Meaning |
|---|---|
-mek |
Master encryption key as hex (32 bytes / 64 chars) |
-mek-file |
File holding the MEK hex |
-mek-ring |
MEK ring: comma-separated fingerprint:key entries (16-hex fingerprint : 64-hex MEK — the same grammar restore-verifier takes), or @file holding the same list. Bare fingerprints (the old form) still parse for one release but carry no key material, so they can never unwrap |
-mek-env |
Allow the ARMOR_MEK environment fallback when no MEK flag is set (default true) |
-escrow |
Escrow JSON file: MEK, ring, and B2 credentials in one package |
-input |
The object: a b2://bucket/key URL or a local file path |
-b2-bucket |
Bucket when -input names only a key |
-b2-region |
B2 region (overrides ARMOR_B2_REGION) |
-b2-endpoint |
B2 S3 endpoint (overrides ARMOR_B2_ENDPOINT) |
-b2-prefix |
ADR-001 prefix the bucket stores objects under (default ARMOR_PREFIX); locates the multipart HMAC sidecar |
-key-id |
Expected x-amz-meta-armor-key-id for multi-key buckets |
-wrapped-dek |
Base64 wrapped DEK — required for local single-PUT files (the x-amz-meta-armor-wrapped-dek metadata value) |
-sidecar |
JSON HMAC sidecar file for a local multipart object |
-iv |
Object IV as hex (16 bytes) — required for a local multipart object (it has no header to read one from) |
-envelope-version |
Envelope version (1, 2, or 3) for local multipart sidecars lacking a version field (default 1); -version is a deprecated alias that still works and prints a pointer |
-output |
Write plaintext here instead of stdout |
-verbose |
Verbose progress on stderr; -v is a deprecated alias that still works and prints a pointer (the top-level armor -v still prints the version) |
-read-concurrency |
Maximum concurrent ranged reads (default ARMOR_READ_CONCURRENCY or 16) |
- Inputs: one object, from B2 (
-input b2://bucket/key, or-input+-b2-bucket) or the local filesystem. B2 reads need the backend environment:ARMOR_B2_REGION,ARMOR_B2_ENDPOINT,ARMOR_B2_ACCESS_KEY_ID,ARMOR_B2_SECRET_ACCESS_KEY(optionalARMOR_CF_DOMAIN) — or an-escrowfile, which exports them. Access and secret keys have no command-line flags on purpose. - Outputs: the plaintext on stdout, or to
-output(created mode 0644). Verbose diagnostics go to stderr. - Exit codes: 0 decrypted and integrity-checked; 1 on any failure — MEK or escrow load, missing/unparseable input, backend error, wrong MEK, HMAC or plaintext-SHA verification failure, output write error; 2 on unexpected positional arguments.
- Credentials/keys: the object's MEK (or the ring entry matching its
fingerprint, from escrow). A fingerprinted wrapped DEK
(
v2:<fingerprint>:<base64>) selects its key by fingerprint; legacy values trial-unwrap against the active key and then the ring. - Safe use: this is the command that turns ciphertext into plaintext —
redirect stdout to a file rather than letting it scroll into a terminal or a
captured session log, and tighten
-output's permissions if the content is sensitive. Prefer-mek-fileorARMOR_MEKover-mek: a command-line key lands in shell history andps. An escrow file is every secret at once — keep it mode 600 and delete it after the recovery. Integrity: single-PUT objects are checked against the header's whole-object SHA-256; multipart objects declare no whole-object digest (ADR-003 gap), so per-block HMACs are the guarantee there.
Audit stored objects for corruption: unwrap each object's DEK, decrypt, and check per-block HMACs and digests — the same checks the server's read path performs, without a running server.
| Flag | Meaning |
|---|---|
-bucket |
Bucket to verify (required) |
-mek |
Master encryption key as hex |
-mek-file |
File holding the MEK hex |
-escrow |
Escrow JSON file — the only way to verify objects written under ring keys other than the active one |
-output |
Write the JSON report here (default stdout) |
-verbose |
Verbose output on stderr; -v is a deprecated alias that still works and prints a pointer |
-prefix |
Only verify keys under this prefix |
-keys-file |
Verify exactly these keys: a JSON array or one key per line (# comments allowed) |
-since |
Skip objects modified before this time (RFC3339 or YYYY-MM-DD) |
-quick |
Verify envelope header and DEK unwrap only — skip downloading and HMAC-checking object bodies |
-concurrency |
Concurrent verifications (default 10) |
-b2-prefix |
ADR-001 prefix the bucket stores objects under (default ARMOR_PREFIX) |
- Inputs: B2 credentials and the keys to check. Backend environment:
ARMOR_B2_REGION,ARMOR_B2_ENDPOINT,ARMOR_B2_ACCESS_KEY_ID,ARMOR_B2_SECRET_ACCESS_KEY— or an-escrowfile, which supplies both the credentials and any ring keys. Key selection: the whole bucket by default, narrowed by-prefix,-keys-file, or-since. The internal.armor/namespace and*.armor-manifestsidecars are skipped; multipart objects whose B2 head carries no metadata resolve it from their ADR-016 manifest. - Outputs: a JSON report (bucket, prefix, totals, and one row per object:
status
OK/CORRUPTED/ERROR, error, details, size, modification time, duration), on stdout or-output. Progress and every failure line with its reason go to stderr. Rows are sorted by key so two runs diff cleanly. - Exit codes: 0 every object verified OK; 1 when any object is CORRUPTED
or ERROR, when zero keys were selected, or when the MEK, keys file,
-sincevalue, backend, or report write fails; 2 when-bucketis missing or positional arguments were passed. - Credentials/keys: at minimum the active MEK. Fingerprinted wrapped DEKs select their key by fingerprint (active key first, then the escrow ring); an object naming a fingerprint this run did not bring is an ERROR row (keying gap — the object may be fine), not a corruption verdict.
- Safe use: read-only against the bucket. Full mode downloads every
selected object in its entirety — on a large bucket that is real egress and
hours; scope with
-prefix/-keys-file/-since, or sweep first with-quick(envelope + DEK only). SIGINT stops scheduling new work and still writes the report for what completed. CORRUPTED means assessed-and-damaged (HMAC mismatch, broken envelope, unparseable wrapped DEK); ERROR means the object could not be assessed at all. Continuous verification — the same checks on a schedule — is the restore verifier (deployment guide).
Drive the server's format migration: re-encrypt objects written in legacy
envelope versions to the server's configured write format, under fresh
per-object keys. The CLI is a thin client of the admin API
(POST/GET /admin/format/migrate); the server performs the migration.
| Flag | Meaning |
|---|---|
-admin-url |
Admin API endpoint (required), e.g. http://127.0.0.1:9001 |
-dry-run |
Verify objects could be migrated without changing anything |
-target |
Target format version (v3 or 3); must match the server's configured write version |
-include |
Comma-separated source versions to migrate (default: v2 for a v3 target, v1 for a v2 target) |
-concurrency |
Concurrent workers (default: the server's own default) |
-watch |
Poll progress every 2 seconds until the migration completes |
-json |
Print the completion report as JSON on stdout |
- Inputs: the admin URL and a bearer token:
ARMOR_ADMIN_TOKENis required — the server disables its migration endpoints without it. - Outputs: progress and the human-readable summary (including the
per-dimension classification report: source layout, size bucket, key
fingerprint, outcome) on stderr. With
-json, the server's final state document goes to stdout and progress lines move to stderr, so stdout carries nothing but JSON. - Exit codes: 0 when the migration was accepted or completed without
failures (a
-watchpoll that finds no migration in progress also exits 0); 1 whenARMOR_ADMIN_TOKENis unset, an HTTP request fails, the response cannot be parsed, the watch fails, or the migration completed with failed objects; 2 on a missing-admin-urlor unexpected positional arguments. - Credentials/keys:
ARMOR_ADMIN_TOKENonly. The MEK never travels through this command — the server holds it. - Safe use: this mutates objects (re-encryption in place). Always start
with
-dry-runand read its classification report; checkARMOR_FORMAT_VERSIONon the server before choosing-target. Point-admin-urlat the admin listener, never the public S3 listener. The operator procedure — safety gates, monitoring, failure triage, and evidence requirements — is the Format Migration Runbook; the full per-format technical detail: V3 Migration Reference; rotation context: Key Rotation Runbook.
Print known-good, copy-pasteable configuration for a common S3-compatible tool: endpoint, path-style addressing, region placeholder, credential variable names, and the multipart contract currently in force for the deployment's write format.
| Flag | Meaning |
|---|---|
-for |
Tool to generate for (required): aws-cli, rclone, boto3, duckdb, litestream, barman |
-endpoint |
ARMOR endpoint URL (required), e.g. http://localhost:9000 |
-bucket |
Bucket name to include in the examples |
-credential |
Named credential to reference in the output comments |
- Inputs: the flags above, plus the deployment's
ARMOR_*environment when available: the write format decides whether the emitted multipart block describes the v2 uniform-part-size contract or v3's no-contract rule. When the environment is missing, the command warns on stderr and assumes v3. - Outputs: the configuration text on stdout; warnings on stderr.
- Exit codes: 0; 2 for a missing
-for/-endpoint, an unknown tool, or unexpected positional arguments. - Credentials/keys: none — the command never reads a credential and only
ever prints variable names or
YOUR_ACCESS_KEY_ID-style placeholders. - Safe use: read-only. Fill the credential placeholders from your provisioning workflow — never paste real values into the generated file and commit it. Per-client behavior notes and the tested matrix: Multipart Client-Compatibility; walkthroughs: Connection Guide.
Print build and version information.
| Flag | Meaning |
|---|---|
-json |
Print a single-line JSON object instead of the text line |
- Inputs: none.
armor --versionandarmor -v(handled before subcommand dispatch) print the same text line. With-json, the reportedformat_write_versionhonorsARMOR_FORMAT_VERSION(2 or 3) exactly as the server's configuration does. - Outputs:
armor <version> (go<goversion>, <os>/<arch>)on stdout, or the JSON object (app,version,go,os,arch,format_write_version, plus VCScommit/dirtywhen stamped). - Exit codes: 0; 2 on unexpected positional arguments or an invalid
ARMOR_FORMAT_VERSION; 1 if JSON rendering fails (not expected in practice). - Credentials/keys: none.
- Safe use: none needed — no network, no filesystem, no secrets.
Print the top-level help: the command table with one-line summaries and the per-command help hint.
- Inputs: none; extra arguments are ignored — asked-for help is never an error.
- Outputs: the help text on stdout.
- Exit codes: always 0.
- Credentials/keys: none.
- Safe use: none needed. For a specific command's flags, run
armor <cmd> --help.