Installation
This package can be installed with uv (recommended) or pip.
uv (recommended):
uv add 'certified[http]'
To install all optional extras (HTTP client/server support + docs):
uv sync --all-extras
pip:
pip install 'certified[http]'
Command-Line Interface
Two commands are installed with certified: a main interface to certificate
management and microservice startup (certified), and a client for sending
mTLS-authenticated HTTP requests (message).
certified
Usage: certified [OPTIONS] COMMAND [ARGS]...
╭─ Commands ───────────────────────────────────────────────────────────────────╮
│ init Create a new signing and end-entity ID. │
│ add-client Add the client directly to your `known_clients` list. │
│ add-service Add a service directly to your `known_servers` list. │
│ introduce Sign the subject's certificate and print a JSON introduction │
│ to stdout. │
│ add-intro Install an introduction produced by a remote `certified │
│ introduce` call. │
│ set-org Setup this instance as a member of the signing organization. │
│ get-ident Create a json copy of my certificate suitable for sending to a │
│ signing authority. │
│ get-signer Create a json copy of my signing certificate. │
│ serve Run the web server with HTTPS certificate-based trust setup. │
╰──────────────────────────────────────────────────────────────────────────────╯
certified init
Create a new CA signing key and end-entity identity certificate.
The config directory defaults to $VIRTUAL_ENV/etc/certified but can be
overridden with --config or the CERTIFIED_CONFIG environment variable.
Either a person name (positional argument) or --org + --unit must be
provided, along with at least one of --host, --email, or --uri.
Usage: certified init [OPTIONS] [NAME]
Create a new signing and end-entity ID.
╭─ Person Name ──────────────────────────────────────────────────────────────────────────────────╮
│ name [NAME] Note, name parsing into given and surnames and generations, etc. is not │
│ supported. │
│ Examples: - Timothy T. Tester │
╰────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Options ──────────────────────────────────────────────────────────────────────────────────────╮
│ --uid TEXT System user name │
│ --domain TEXT Domain components │
│ (.-separated) │
│ --country TEXT │
│ --state TEXT │
│ --city TEXT │
│ --key-type [ed25519|ed448|secp256r1|secp [default: ed25519] │
│ 384r1|secp521r1|secp256k1] │
│ --overwrite --no-overwrite Overwrite existing config. │
│ [default: no-overwrite] │
│ --config PATH Config file path [default │
│ $VIRTUAL_ENV/etc/certified]. │
│ --help Show this message and exit. │
╰────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Organization Name ────────────────────────────────────────────────────────────────────────────╮
│ --org TEXT If specified, unit must also be present and name cannot be present. │
│ Example: 'Certificate Lab, Inc.'" │
╰────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Organization Unit ────────────────────────────────────────────────────────────────────────────╮
│ --unit TEXT If specified, org must also be present and name cannot be present. │
│ Example: 'Computing Directorate' │
╰────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Example: example@example.org ─────────────────────────────────────────────────────────────────╮
│ --email TEXT email addresses │
╰────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ host names ───────────────────────────────────────────────────────────────────────────────────╮
│ --host TEXT Examples: - "*.example.org" - "example.org" - "éxamplë.org" - │
│ "xn--xampl-9rat.org" - "127.0.0.1" - "::1" - "10.0.0.0/8" - "2001::/16" │
╰────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ uniform resource identifiers ─────────────────────────────────────────────────────────────────╮
│ --uri TEXT Example: https://datatracker.ietf.org/doc/html/rfc3986#section-1.1.2 │
╰────────────────────────────────────────────────────────────────────────────────────────────────╯
certified serve
Run a FastAPI/Starlette ASGI application with mTLS enforced by certified. The server reads its certificate and client trust roots from the config directory.
Usage: certified serve [OPTIONS] APP [URL]
Run the web server with HTTPS certificate-based trust setup.
╭─ Server's ASGI application ──────────────────────────────────────────────────╮
│ * app TEXT Example: path.to.module:attr [required] │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ URL to serve application ───────────────────────────────────────────────────╮
│ url [URL] Example: https://127.0.0.1:8000 │
│ [default: https://0.0.0.0:4433] │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --loki TEXT json file containing url,user,passwd for sending │
│ logs to loki │
│ -v show info-level logs │
│ -vv show debug-level logs │
│ --config PATH Config file path [default │
│ $VIRTUAL_ENV/etc/certified]. │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────╯
certified get-ident / certified get-signer
Export your certificates for sharing with other parties.
get-ident— prints your identity certificate (base64-DER), suitable for sending to a signing authority that will runintroduceon it.get-signer— prints a JSON object{"ca_cert": "..."}containing your CA certificate, suitable for passing toadd-serviceon the other side.
certified introduce / certified add-intro
The recommended workflow for establishing cross-org trust. It resolves the otherwise painful problem of RFC 4514 distinguished-name strings: the signer never types them; the subject never sees them.
How it works:
-
Subject sends their identity certificate to the signer:
certified get-ident > my_cert.b64 # send my_cert.b64 to the signer out-of-band -
Signer verifies the subject is who they claim to be, then runs:
certified introduce my_cert.b64 > intro.json # send intro.json back to the subjectThe JSON response contains:json { "signed_cert": "<base64-DER — subject's cert signed by signer's CA>", "ca_cert": "<base64-DER — signer's CA cert>", "services": {"alias": "https://host:port", ...} // optional }Theservicesfield, if included by the signer, lists service endpoints the subject should be able to reach using the new cross-org identity. -
Subject installs the introduction in one command:
certified add-intro intro.jsonThis automatically: - Saves
id/<signer-RFC4514-name>.crt(the signed PEM chain) - Creates
known_servers/<alias>.yamlfor each entry inservices, pre-populated with the correct CA cert and auth name
No RFC 4514 string handling required.
Usage: certified introduce [OPTIONS] CRT
Sign the subject's certificate and print a JSON introduction to stdout.
...
╭─ Arguments ──────────────────────────────────────────────────────────────────╮
│ * crt PATH Subject's certificate. [required] │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --config PATH Config file path [default $VIRTUAL_ENV/etc/certified]. │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────╯
Usage: certified add-intro [OPTIONS] SIGNATURE
Install an introduction produced by a remote `certified introduce` call.
...
╭─ Arguments ──────────────────────────────────────────────────────────────────╮
│ * signature PATH json signature response containing both │
│ "signed_cert" and "ca_cert". [required] │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --overwrite --no-overwrite Overwrite existing authorization? │
│ [default: no-overwrite] │
│ --config PATH Config file path [default │
│ $VIRTUAL_ENV/etc/certified]. │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────╯
certified add-service
Directly add a known server without the introduction workflow. Useful when you already have the server's CA certificate out-of-band.
The CRT argument accepts a PEM file, a base64-DER string, or a JSON file
with a ca_cert field (the format produced by get-signer or introduce).
The --auth option is for the RFC 4514 distinguished name of an additional
signing authority. The CA cert's own RFC 4514 name is always appended
automatically, so --auth is only needed when the server accepts signatures
from CAs other than the one in CRT.
Tip
Prefer introduce / add-intro for initial setup — it handles the RFC
4514 names and service definitions for you.
Usage: certified add-service [OPTIONS] NAME CRT
Add a service directly to your `known_servers` list.
...
╭─ Arguments ──────────────────────────────────────────────────────────────────╮
│ * name TEXT Service's hostname[:port][/path-prefix]. [required] │
│ * crt PATH Service's public signing certificate (PEM or b64-DER or │
│ json with 'ca-root'). [required] │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --auth TEXT rfc4514 name of an authorizor whose │
│ signature would be recognized for │
│ authenticating to this server. │
│ --overwrite --no-overwrite Overwrite existing server. │
│ [default: no-overwrite] │
│ --config PATH Config file path [default │
│ $VIRTUAL_ENV/etc/certified]. │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────╯
certified add-client
Directly add a known client to known_clients/. Note that end-entity
(non-CA) self-signed certificates cannot be trusted directly by TLS — add a
CA certificate instead to trust all identities it signs.
Usage: certified add-client [OPTIONS] NAME CRT
Add the client directly to your `known_clients` list.
Note that this routine doesn't work for end-entities in practice because
x509 validation rules don't allow self-signed certificates to be clients.
However, you can add a self-signed "root" this way and trust all
certificates granted through it.
╭─ Arguments ──────────────────────────────────────────────────────────────────╮
│ * name TEXT Client's name. [required] │
│ * crt PATH Client's certificate (PEM or b64-DER). [required] │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --overwrite --no-overwrite Overwrite existing client. │
│ [default: no-overwrite] │
│ --config PATH Config file path [default │
│ $VIRTUAL_ENV/etc/certified]. │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────╯
certified set-org
Join an existing organization as a managed member: your self-signed CA is
discarded and replaced by the organization's signed certificate. The org's
CA cert is added to both known_servers/ and known_clients/.
Requires --overwrite. Destructive — removes CA.key, CA.crt,
id/, and CA/ from your config directory.
Usage: certified set-org [OPTIONS] SIGNATURE
Setup this instance as a member of the signing organization.
╭─ Arguments ──────────────────────────────────────────────────────────────────╮
│ * signature PATH json signature response containing both │
│ "signed_cert" and "ca_cert". [required] │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --overwrite --no-overwrite Overwrite existing authorization? │
│ [default: no-overwrite] │
│ --config PATH Config file path [default │
│ $VIRTUAL_ENV/etc/certified]. │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────╯
message
Send an mTLS-authenticated HTTP request from the command line.
Usage: message [OPTIONS] URL [DATA]
Send a json-message to an mTLS-authenticated HTTPS-REST-API.
╭─ Arguments ──────────────────────────────────────────────────────────────────╮
│ * url TEXT Service's Resource URL [default: None] [required] │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ json-formatted message body ────────────────────────────────────────────────╮
│ data [DATA] If present, the message is POST-ed to the URL. │
│ Example: '{"refs": [1,2], "query": "What is 2+2?"}' │
│ [default: None] │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ -X [GET|POST|PUT|DELETE|PATCH] HTTP method [default: None] │
│ -v show info-level logs │
│ -vv show debug-level logs │
│ --config PATH Config file path │
│ --json PATH POST contents of a JSON file │
│ --yaml PATH POST contents of a YAML file (converted to JSON) │
│ --pp / --no-pp Pretty-print JSON output [default: no-pp] │
│ -H TEXT Header (curl-style, e.g. -H "X-Token: ABC") │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────╯