CLI

For edgekms 0.3.0.

The edgekms CLI is a single binary, built for Linux on x86_64 and arm64 and for macOS on Apple silicon. You need it to log in to a tenant from a terminal (SSH, GitHub or OIDC), to manage hosted tenants without the web console, and for the offline break-glass commands, which decrypt and export keys from a root key with no server at all.

With mise

mise use -g github:lokkju/edgekms
edgekms --version

mise picks the release archive for your platform from GitHub. Pin a version with github:lokkju/[email protected].

From a release

Download the archive for your platform from the latest release, with the .sha256 file beside it, check it, and put edgekms on your PATH:

sha256sum -c edgekms-<version>-x86_64-unknown-linux-gnu.tar.gz.sha256   # shasum -a 256 -c on macOS
tar -xzf edgekms-<version>-x86_64-unknown-linux-gnu.tar.gz
install edgekms-<version>-x86_64-unknown-linux-gnu/edgekms ~/.local/bin/
edgekms --version

The archives are named for their Rust target: x86_64-unknown-linux-gnu, aarch64-unknown-linux-gnu and aarch64-apple-darwin.

From source

With a Rust toolchain:

cargo install --git https://github.com/lokkju/edgekms edgekms-cli

The CLI keeps nothing on disk. Every login prints its token on stdout for you to export (VAULT_TOKEN for a tenant, EDGEKMS_CONTROL_TOKEN for the hosted control plane), and root keys are only ever read from stdin, never from a terminal or a flag.

Reference

Generated from the definitions edgekms 0.3.0 is built from. edgekms <command> --help prints the same text.

edgekms

edgekms command line

edgekms <COMMAND>

Subcommands: login, decrypt, export, account, tenant, ops.

edgekms login

Log in to a Worker and print the token on stdout

edgekms login <COMMAND>

Subcommands: ssh, github, oidc.

edgekms login ssh

Sign a challenge with ssh-keygen -Y sign (ssh-agent, FIDO keys included)

edgekms login ssh [OPTIONS] --addr <ADDR> --role <ROLE> --key <KEY>
  • --addr <ADDR> (required): Worker URL; https, or http for loopback only
  • --role <ROLE> (required): The role to log in as, from the deployment's config
  • --key <KEY> (required): The public key file; ssh-keygen finds the private half in ssh-agent. If the agent doesn't hold it, ssh-keygen falls back to the private key file beside it (the same path without .pub) and may prompt for its passphrase
  • --mount <MOUNT> (default ssh): The SSH auth mount name

edgekms login github

GitHub's OAuth device flow: enter a code at github.com, from any browser

edgekms login github [OPTIONS] --addr <ADDR> --role <ROLE> --client-id <CLIENT_ID>
  • --addr <ADDR> (required): Worker URL; https, or http for loopback only
  • --role <ROLE> (required): The role to log in as, from the deployment's config
  • --client-id <CLIENT_ID> (required; env EDGEKMS_GITHUB_CLIENT_ID): The client ID of the deployment's GitHub OAuth App (device flow enabled)
  • --mount <MOUNT> (default github-user): The GitHub user auth mount name

edgekms login oidc

OIDC in a browser: authorization code with PKCE, redirected to 127.0.0.1.

A client secret, for providers that issue one to desktop clients, is read from EDGEKMS_OIDC_CLIENT_SECRET, never from the command line.

edgekms login oidc [OPTIONS] --addr <ADDR> --role <ROLE> --issuer <ISSUER> --client-id <CLIENT_ID>
  • --addr <ADDR> (required): Worker URL; https, or http for loopback only
  • --role <ROLE> (required): The role to log in as, from the deployment's config
  • --mount <MOUNT> (default oidc): The JWT auth mount that trusts this issuer
  • --issuer <ISSUER> (required; env EDGEKMS_OIDC_ISSUER): The issuer URL, as the provider's discovery document names it
  • --client-id <CLIENT_ID> (required; env EDGEKMS_OIDC_CLIENT_ID)
  • --scope <SCOPE> (default openid email): Space-separated scopes; must include openid
  • --port <PORT> (default 8250): Loopback port for the redirect, http://127.0.0.1:<port>/oidc/callback; 0 picks a free one, for providers that accept any loopback port
  • --no-browser: Print the URL without trying to open a browser

edgekms decrypt

Offline: decrypt a ciphertext with the root key read as base64 from stdin

edgekms decrypt --config <CONFIG> --key <KEY> <CIPHERTEXT>
  • --config <CONFIG> (required): The tenant or instance config (JSON) the ciphertext's key is in
  • --key <KEY> (required): The key's name in the config
  • <CIPHERTEXT> (required): The ciphertext, vault:v<version>:...

edgekms export

Offline: print the raw base64 key for one version, root key read as base64 from stdin

edgekms export --config <CONFIG> --key <KEY> --version <VERSION>
  • --config <CONFIG> (required): The tenant or instance config (JSON) the key is in
  • --key <KEY> (required): The key's name in the config

edgekms account

The hosted edgekms service at edgekms.dev: log in to its control plane

edgekms account <COMMAND>

Subcommands: login, ssh-keys, request-invite, logout.

edgekms account login

GitHub's device flow with the hosted edgekms App, or with --ssh a key registered on your account, then print a control token on stdout for export EDGEKMS_CONTROL_TOKEN=.... The token lasts 1800 seconds (30 minutes); tenant export and account ssh-keys add need one under five minutes old. Nothing is saved to disk

edgekms account login [OPTIONS]
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only
  • --client-id <CLIENT_ID>: Your own GitHub App's client id, for a control plane other than api.edgekms.dev. Without it the hosted App's id is used, from EDGEKMS_HOSTED_CLIENT_ID or else from the control plane's /v1/info, and its tokens go only to https://api.edgekms.dev
  • --ssh: Log in without GitHub, with an SSH key registered on your account (see edgekms account ssh-keys): the control plane's challenge is signed through ssh-agent with ssh-keygen -Y sign. Without --key, ssh-agent must hold exactly one Ed25519, sk-ssh-ed25519 or ECDSA P-256 key
  • --key <KEY>: With --ssh, the public key file (ending in .pub) to sign with. ssh-keygen finds the private half in ssh-agent, or falls back to the private key file beside it (the same path without .pub) and may prompt for its passphrase

edgekms account ssh-keys

The SSH keys that can log in to your account with edgekms account login --ssh, for when GitHub is unavailable. Reads the control token from EDGEKMS_CONTROL_TOKEN

edgekms account ssh-keys [OPTIONS] <COMMAND>
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

Subcommands: list, add, remove.

edgekms account ssh-keys list

Print id<TAB>fingerprint<TAB>key_type<TAB>label<TAB>added_ms<TAB>added_via<TAB>last_used_ms for each key (last_used_ms empty for a key that has never logged in), then unverified<TAB><fingerprint> for each key record that failed its integrity check and can't log in

edgekms account ssh-keys list [OPTIONS]
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

edgekms account ssh-keys add

Register a key, proving you hold it with a signature through ssh-agent (ssh-keygen -Y sign -n edgekms-register). Needs a login under five minutes old. The signed challenge names the GitHub account the key goes to, which is printed before signing; a challenge for any account but yours is refused. A registered key can log in, export root keys and add more keys, as your GitHub account can, so prefer a security key (sk-ssh-ed25519), which signs only with a touch, or an agent key added with ssh-add -c, which asks before each signature

edgekms account ssh-keys add [OPTIONS]
  • --key <KEY>: The public key file (ending in .pub). Without it, the one Ed25519, sk-ssh-ed25519 or ECDSA P-256 key ssh-agent holds
  • --label <LABEL>: A label for the key, at most 64 characters. Without it, the key's comment, when that fits
  • --expect-github-id <EXPECT_GITHUB_ID>: The GitHub id of the account the key must go to. Without it, the account EDGEKMS_CONTROL_TOKEN says it is for
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

edgekms account ssh-keys remove

Remove a key, by the id or the SHA256: fingerprint list prints. Every control token it minted stops working

edgekms account ssh-keys remove [OPTIONS] <KEY>
  • <KEY> (required): The key's id or fingerprint
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

edgekms account request-invite

For a GitHub account edgekms.dev doesn't admit yet: GitHub's device flow as for login, then ask for an invite with an optional note on what you'll use edgekms for, or see how an earlier request stands. Nothing is printed on stdout or saved to disk

edgekms account request-invite [OPTIONS]
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only
  • --client-id <CLIENT_ID>: Your own GitHub App's client id, as for login
  • --note <NOTE>: What you'll use edgekms for, at most 500 characters. Without it you're asked, when stdin is a terminal

edgekms account logout

End every control token you hold, the one in EDGEKMS_CONTROL_TOKEN included, before its 1800 seconds are up

edgekms account logout [OPTIONS]
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

edgekms tenant

The hosted edgekms service: manage your tenants. Reads the control token from EDGEKMS_CONTROL_TOKEN (see edgekms account login); a token lasts 1800 seconds

edgekms tenant [OPTIONS] <COMMAND>
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

Subcommands: list, invites, accept, decline, show, create, config, member, export.

edgekms tenant list

List the tenants you are a member of, with your role in each

edgekms tenant list [OPTIONS]
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

edgekms tenant invites

List your pending invites, with the role each offers

edgekms tenant invites [OPTIONS]
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

edgekms tenant accept

Accept a pending invite to a tenant

edgekms tenant accept [OPTIONS] <NAME>
  • <NAME> (required)
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

edgekms tenant decline

Decline a pending invite to a tenant

edgekms tenant decline [OPTIONS] <NAME>
  • <NAME> (required)
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

edgekms tenant show

Print a tenant's details, config, members and pending invites as JSON

edgekms tenant show [OPTIONS] <NAME>
  • <NAME> (required)
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

edgekms tenant create

Create a tenant, optionally from an existing root key. Besides your personal tenant, a tenant you create is named after your GitHub login: <login>-<suffix>

edgekms tenant create [OPTIONS] <NAME>
  • <NAME> (required)
  • --config <CONFIG>: The tenant config, checked locally against the hosted rules before it's sent. The control plane replaces its root_id with the new tenant's unless you import. Without it the control plane writes a default config
  • --import-root-id <IMPORT_ROOT_ID>: Import an existing root key with this root id. The key is read as base64 from stdin (never a terminal), and --config is required
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

edgekms tenant config

Read or replace a tenant's config

edgekms tenant config [OPTIONS] <COMMAND>
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

Subcommands: get, set.

edgekms tenant config get

Print the config JSON on stdout and its version on stderr

edgekms tenant config get [OPTIONS] <NAME>
  • <NAME> (required)
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

edgekms tenant config set

Replace the config with a file, checked locally first

edgekms tenant config set [OPTIONS] <NAME> <FILE>
  • <NAME> (required)
  • <FILE> (required)
  • --if-version <IF_VERSION>: The version being replaced; without it the current version is read first
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

edgekms tenant member

Invite, change or remove a tenant member (owners only)

Also members.

edgekms tenant member [OPTIONS] <COMMAND>
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

Subcommands: add, remove.

edgekms tenant member add

Invite a user by numeric GitHub id, or offer a member the owner role. Nothing changes until they run edgekms tenant accept; only lowering an owner to member applies at once

edgekms tenant member add [OPTIONS] --github-id <GITHUB_ID> <NAME>
  • <NAME> (required)
  • --github-id <GITHUB_ID> (required)
  • --owner: Make them an owner; members are read-only
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

edgekms tenant member remove

Remove a member or withdraw a pending invite; the last owner can't be removed

edgekms tenant member remove [OPTIONS] --github-id <GITHUB_ID> <NAME>
  • <NAME> (required)
  • --github-id <GITHUB_ID> (required)
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

edgekms tenant export

Print a tenant's root key as base64 on stdout (owners only, with a login under five minutes old). Pipe it straight into sops or another encrypted store

edgekms tenant export [OPTIONS] <NAME>
  • <NAME> (required)
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

edgekms ops

The hosted edgekms service, for its operators (OPERATOR_GITHUB_IDS) only. Reads the control token from EDGEKMS_CONTROL_TOKEN

edgekms ops [OPTIONS] <COMMAND>
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

Subcommands: allowlist, tenant, invite-requests.

edgekms ops allowlist

The signup allowlist: the GitHub users who may sign up while SIGNUP_MODE is invite

edgekms ops allowlist [OPTIONS] <COMMAND>
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

Subcommands: add, remove, list.

edgekms ops allowlist add

Let a GitHub user, by numeric id, sign up

edgekms ops allowlist add [OPTIONS] <GITHUB_ID>
  • <GITHUB_ID> (required)
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

edgekms ops allowlist remove

Take a GitHub user off the allowlist. Once they have signed up, they keep logging in while they belong to a tenant

edgekms ops allowlist remove [OPTIONS] <GITHUB_ID>
  • <GITHUB_ID> (required)
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

edgekms ops allowlist list

Print github_id<TAB>added_by<TAB>added_ms for each entry

edgekms ops allowlist list [OPTIONS]
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

edgekms ops tenant

Suspend or resume any tenant, by name

edgekms ops tenant [OPTIONS] <COMMAND>
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

Subcommands: suspend, resume.

edgekms ops tenant suspend

Suspend a tenant: within about 30 seconds its host refuses every request, and its config and members can't change. Its owners can still export the root key

edgekms ops tenant suspend [OPTIONS] <NAME>
  • <NAME> (required)
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

edgekms ops tenant resume

Make a suspended tenant active again

edgekms ops tenant resume [OPTIONS] <NAME>
  • <NAME> (required)
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

edgekms ops invite-requests

Requests for an invite from GitHub users refused while SIGNUP_MODE is invite

edgekms ops invite-requests [OPTIONS] <COMMAND>
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

Subcommands: list, approve, decline, delete.

edgekms ops invite-requests list

Print each request as github_id login status date with its note indented below: every pending one, oldest first, then the 100 most recently decided

edgekms ops invite-requests list [OPTIONS]
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

edgekms ops invite-requests approve

Put the user on the signup allowlist and mark the request approved; their next sign-in creates their personal tenant

edgekms ops invite-requests approve [OPTIONS] <GITHUB_ID>
  • <GITHUB_ID> (required)
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

edgekms ops invite-requests decline

Mark the request declined. They can't ask again until the request is deleted

edgekms ops invite-requests decline [OPTIONS] <GITHUB_ID>
  • <GITHUB_ID> (required)
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only

edgekms ops invite-requests delete

Delete the request, whatever its status. A declined user can then ask again; an approved one stays on the allowlist

edgekms ops invite-requests delete [OPTIONS] <GITHUB_ID>
  • <GITHUB_ID> (required)
  • --api <API> (default https://api.edgekms.dev): The control plane URL; https, or http for loopback only