Skip to main content

tiny-pki

PyPI version Python 3.12+ License: MIT CI

A small private certificate authority for mutual TLS on home and internal networks: issue a CA and its client and server certificates, revoke them with a CRL, hand them to phones as PKCS#12 bundles, and watch for expiry. Built on cryptography 50.0.1 or newer.

It comes in two layers; use either:

  • Library (import tiny_pki): bytes in, bytes out. No filesystem, no global state, no framework. Your application stores the PEMs.
  • CLI (tiny-pki): one-shot commands and a REPL over a CA kept in a directory, for operators running nginx or Mosquitto with mTLS.

What it covers:

  • CA, client and server certificates with RSA (the default) or ECDSA P-256 keys, mixed freely under one CA.
  • Name Constraints, so a stolen CA key cannot impersonate public sites.
  • CRLs with monotonic numbers, and a key-free public/ directory to hand to a sandboxed TLS server.
  • PKCS#12 bundles for phones and browsers, with a legacy mode for old keychains.
  • check, an expiry and revocation monitor with Nagios-style exit codes and JSON output.
  • Rotation without downtime (create client --keep-previous), dry runs for destructive commands, and a store that is safe under concurrent writers.
  • Tab completion for bash, zsh, fish and the REPL.

Consumers: my-tracks (MQTT client certificates, library; my-tracks#1345) and home-warden (nginx mTLS, CLI store; home-warden#49).

Install

The library depends only on cryptography. The command-line tool also needs prompt-toolkit, which comes with the cli extra:

uv add tiny-pki                      # library, or: pip install tiny-pki
pipx install 'tiny-pki[cli]'         # CLI, or: uv tool install 'tiny-pki[cli]'

Without the extra, tiny-pki exits with a message saying how to install it.

Quick start: library

Issue a CA, a client certificate, a server certificate and a CRL, all as PEM bytes:

from datetime import UTC, datetime

from tiny_pki import (
    generate_ca_certificate,
    generate_client_certificate,
    generate_crl,
    generate_pkcs12,
    generate_server_certificate,
    get_certificate_fingerprint,
    get_certificate_serial_number,
)

# Constrain every name type (DNS and IP) your devices use; without
# permitted_subtrees the CA can sign any name, including public sites.
ca_cert, ca_key = generate_ca_certificate("Home CA", key_type="ec-p256", permitted_subtrees=["home", "192.168.0.0/16"])

client_cert, client_key = generate_client_certificate(ca_cert, ca_key, "alice", key_type="ec-p256")
server_cert, server_key = generate_server_certificate(ca_cert, ca_key, "api.home", ["api.home"])
print(get_certificate_fingerprint(client_cert))  # SHA-256, colon-separated hex

# Revoke alice: pass every revoked (serial, revoked_at) pair each time.
serial = get_certificate_serial_number(client_cert)
crl_pem = generate_crl(ca_cert, ca_key, [(serial, datetime.now(UTC))])

# A password-protected bundle for a phone or browser.
p12 = generate_pkcs12(client_cert, client_key, ca_cert, "alice", b"change-me-to-a-long-random-password")

Storing the results, and encrypting the CA key at rest, is up to your application; docs/api.md has the full API and docs/security.md the key-handling advice.

Quick start: CLI

The CLI keeps one CA per directory, given with --store or TINY_PKI_STORE:

export TINY_PKI_STORE=./stores/home-ca
tiny-pki init --cn "Home CA" --permit home --permit 192.168.0.0/16
tiny-pki create server api.home --san api.home --san 192.168.1.10
tiny-pki create client alice
tiny-pki export p12 alice           # prompts for the bundle password
tiny-pki list clients
tiny-pki revoke alice --dry-run     # preview; writes nothing
tiny-pki revoke alice               # republishes public/crl.pem
tiny-pki check                      # exit 0 ok, 1 expiring, 2 expired/revoked/untrusted, 3 error

Run tiny-pki with no command for the REPL, and help COMMAND for any command's flags. Point nginx's ssl_client_certificate at public/ca.crt and ssl_crl at public/crl.pem, reload it after each revoke, and republish the CRL (tiny-pki crl) on a timer: it is valid for 30 days by default.

Documentation

Page Contents
docs/cli.md Every command and flag, plus rotation, nginx and CRL-timer workflows
docs/api.md Library functions, constants, errors and warnings
docs/store.md Store layout, public/, locking, index.json, and the store API
docs/monitoring.md check output, JSON schema, exit codes, cron and systemd recipes
docs/security.md CA key handling, name constraints, choosing a key type, CRL freshness
docs/defaults.md Every default and the reasoning behind it
CHANGELOG.md Release notes
SECURITY.md Reporting a vulnerability

What stays in your app

tiny-pki deliberately does not:

  • Persist anything for library callers; store the PEMs in your database or files.
  • Encrypt keys at rest by itself. The optional tiny_pki.secrets Fernet helpers take a secret you supply; wiring and rotating it are yours (see docs/security.md).
  • Reload nginx, Mosquitto or any other TLS server after a new CRL.
  • Schedule CRL renewal; run tiny-pki crl or generate_crl on a timer.
  • Decide who gets a certificate; authenticating issuance requests is the application's job.

Development

uv sync --group dev
uv run ruff check src tests && uv run ruff format --check src tests
uv run pyright
uv run pytest
uv run tiny-pki --version   # tiny-pki <version> (<commit>)

Contribution rules (stacked PRs, commit style, review flow) are in AGENTS.md.

License

MIT © 2026 Henrique Andrade (GitHub's thehcma); see LICENSE. Code extracted from my-tracks was relicensed MIT by the copyright holder for this shared package.

Release files for tiny-pki 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tiny-pki 0.1.0
File Size Uploaded
tiny_pki-0.1.0.tar.gz 224.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for tiny-pki 0.1.0
File Interpreter ABI Platform
tiny_pki-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 291.7 kB

Release files / tiny_pki-0.1.0.tar.gz

Download URL tiny_pki-0.1.0.tar.gz
Size 224.2 kB
Tags Source
SHA-256 checksum
How to use checksums
335d1df1686c2b3d9286ad83d7ff775a2474c6666c917b2e683aab21823d998d
BLAKE2b-256 checksum
How to use checksums
14b319f810b26fa7a3fbafc2abe7f0b71dc5ec0e8b29452b74c5fe39695613d8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 27, 2026.

Transparency log

Release files / tiny_pki-0.1.0-py3-none-any.whl

Download URL tiny_pki-0.1.0-py3-none-any.whl
Size 67.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d176f57a211788a66a16d7de36878c9800b0b9794c6e6c36b20dcc82f7ba4aa0
BLAKE2b-256 checksum
How to use checksums
a58d70de2d54b0404201e6728eb05648d379605b9730361cda22aa053fc2a843
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 27, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page