kc-cli
kc creates, queries, and updates macOS .keychain-db files directly. It does
not call the Security framework, require entitlements, or depend on a running
securityd. The files remain interoperable with Keychain Access and
/usr/bin/security.
The Rust library is keychain-rs. This crate provides
the kc command.
Install
Keychain selection
Every command that accepts --keychain resolves keychains in this order:
- explicit
--keychain KEYCHAINor a command's explicit keychain argument; KC_DEFAULT_KEYCHAIN;keychains.defaultin~/.config/keychain.kdl;login.
Bare names are searched under ~/Library/Keychains and then under configured
search paths. machina therefore resolves to
~/Library/Keychains/machina.keychain-db; system is the system keychain.
Paths containing / are treated as paths.
config show reports both the saved default and the effective default with its
source.
Create and add
Creation always requires an output path or name:
Password items use one assignment grammar:
Supported classes are generic, internet, and appleshare. Friendly field
names and native aliases are interchangeable: account/acct,
service/svce, comment/icmt, and so on. Class-invalid assignments are
errors.
When -w, --secret is absent, the item secret is read from stdin or prompted
for on a terminal.
Identities retain a purpose-built form because their inputs are files:
Certificate and private-key inputs accept PEM or DER by content, regardless of
file extension. Private keys may be PKCS#8 or RSA PKCS#1. PKCS#12/PFX accepts
DER or PEM and has independent --pkcs12-password* inputs.
Get
get is the only item read command. With no predicates it returns all
queryable password, certificate, public-key, private-key, and item-key records.
Predicates are ANDed. The canonical grammar is:
FIELD:VALUE
FIELD:>=VALUE
FIELD[MODIFIERS]:PATTERN
Comparisons are =, !=, <, <=, >, and >=. A value containing % or
_ uses SQL-LIKE semantics: % matches any sequence and _ matches one
character. Backslash escapes a wildcard. [c] is case-insensitive, [d] is
diacritic-insensitive, and [cd] enables both.
Examples:
Dates accept Keychain UTC timestamps (YYYYMMDDhhmmssZ) and RFC 3339 UTC
timestamps. Numeric and boolean fields are compared as their actual types.
Unknown modifiers, malformed comparisons, invalid typed values, and unknown
exact class names are errors.
Projection
-o, --output selects ordered fields:
-u, --distinct emits each projected tuple once while preserving first-seen
order. Deduplication uses typed projected values before text or JSON rendering:
# Unique non-empty service values
# Unique account/service pairs
service:% also matches an empty service; service:_% requires at least one
character. The query language intentionally uses % rather than shell-glob
*.
* emits full record detail. secret decrypts the selected item. More than
one secret requires --all; non-secret queries intentionally allow multiple
rows.
@ref emits opaque, revision-bound item references for mutation pipelines:
|
References carry their keychain and database revision. set validates the
complete stream before changing memory and saves once. A malformed, duplicate,
wrong-keychain, missing, or stale reference aborts the operation without
writing. Human-readable and JSON output are never reparsed as selectors.
Set
set applies assignments to every item matched by --for:
The query must be non-empty. class, record, secret, creation time, and
modification time cannot be changed. Attributes that define a relation's unique
identity are rejected by the library; replacing those means deleting and
adding an item.
Updates are collected first, applied in memory, and saved once. A failure before the save leaves the file unchanged.
Password input
All keychain-password consumers use the same sources:
-E, --password-env [ENV_VAR] default ENV_VAR: KC_PASSWORD
-F, --password-file FILE use - for stdin
--password-gen[=TEMPLATE] creation/change only; default: sha1
-P, --password PASSWORD
--password-policy POLICY alphanumeric|mixed-case|symbol|secure
When no source is set, kc reads the password from stdin or prompts on a
terminal. Environment variables and files avoid exposing secrets in process
arguments. If -P is useful for shell composition, prefer a shell expression:
Access policy and native ACLs
New keychains default to a saved hybrid policy whose direct and native
decision is prompt. Direct secret access therefore requires --interactive;
native ACLs pre-authorize no caller, allowing securityd to show its normal
authorization UI.
extended enforces the kc policy only, native delegates to item ACLs, and
hybrid does both. Keychain-wide policy is projected onto items when they are
written and can be reapplied to existing items. Native Keychain ACLs are still
item-level data; the saved keychain policy is the template and enforcement
model for all items.
For individual legacy operations, kc trust supports:
--trust-requirement PATH=FILE stores the compiled code requirement while the
legacy cdhash remains optional. This preserves Security.framework
interoperability while allowing stronger application identity.
Identity import and export
An explicit output path is recommended for exported secret material. PKCS#12 exports are encrypted with the selected PKCS#12 password.
Other commands
kc info [KEYCHAIN]
kc verify [KEYCHAIN]
kc rm item SELECTOR [--all] [KEYCHAIN]
kc rm identity [-l LABEL | --hash HEX] [KEYCHAIN]
kc cp SELECTOR SOURCE DESTINATION
kc passwd [KEYCHAIN]
kc settings [OPTIONS] [KEYCHAIN]
kc completions SHELL
show, find, and ls were removed in 0.6.0. Their behavior is represented
by get, projections, and an empty query.
Output and exit status
Text is the default. --json is shorthand for --format json;
--format secret emits only secret bytes suitable for a pipeline.
Common exit statuses are stable:
0 success
44 no item matched
45 incorrect keychain password
46 duplicate item
2 command-line or other operational error
Development
The release order is keychain-rs first, then kc-cli.
License
MIT