Skip to main content

uPKI CA Server

License: MIT Python Version Code Style: Ruff PyPI

Certificate Authority (CA) Server for the uPKI Public Key Infrastructure system. Manages the full certificate lifecycle and exposes PKI operations to Registration Authorities over a ZeroMQ protocol.

Overview

The uPKI CA Server is the trust anchor of the uPKI ecosystem. It runs as a persistent background process listening on two dedicated ZMQ ports:

  • Port 5000 — CA operations: certificate signing, renewal, revocation, CRL generation, OCSP checks
  • Port 5001 — RA registration: initial handshake to onboard a new Registration Authority

It is designed to operate standalone or in a containerised stack together with uPKI RA Server and uPKI CLI.

Architecture

graph TB
    subgraph "Clients"
        CLI[uPKI CLI]
        ACME[ACME Clients<br/>cert-manager, Traefik]
    end

    subgraph "uPKI RA Server"
        RA[Registration Authority<br/>Port 8000]
    end

    subgraph "uPKI CA Server"
        direction TB
        CA_OPS[CA Listener<br/>Port 5000]
        RA_REG[Register Listener<br/>Port 5001]

        subgraph "Core"
            Auth[Authority]
            Profiles[Profiles]
        end

        subgraph "Storage"
            FileDB[(TinyDB +<br/>Filesystem)]
        end
    end

    CLI -->|HTTPS + mTLS| RA
    ACME -->|HTTPS| RA

    RA -->|ZMQ REQ/REP| CA_OPS
    RA -->|ZMQ REQ/REP| RA_REG

    CA_OPS --> Auth
    RA_REG --> Auth
    Auth --> Profiles
    Auth --> FileDB

Key Features

  • Certificate Lifecycle — Sign, renew, revoke, and delete certificates via ZMQ commands
  • CRL Management — Generate and serve Certificate Revocation Lists on demand
  • OCSP Checks — Real-time certificate status verification
  • Certificate Profiles — Built-in and custom profiles with configurable key type, validity, extensions, and SANs
  • RA Registration — Seed-based handshake to securely onboard Registration Authorities
  • Import Existing CA — Bootstrap from an existing key/certificate pair (--ca-key / --ca-cert)
  • Docker Auto-bootstrap — Single start command initialises the PKI on first boot then runs both listeners
  • Multiple Storage Backends — File-based storage (default, powered by TinyDB) with a MongoDB interface stub

Requirements

  • Python 3.11+
  • Poetry (package manager)
  • cryptography library

Installation

From PyPI

pip install upki-ca

From Source

git clone https://github.com/circle-rd/upki-ca.git
cd upki-ca
poetry install

Development Installation

poetry install --with dev,lint

CLI Usage

The main entry point is ca_server.py. All commands accept --path <dir> to override the default storage location (~/.upki/ca).

Initialize the PKI

Creates the CA key and certificate on first run. Idempotent on subsequent runs.

# Generate a fresh CA
poetry run python ca_server.py init

# Import an existing CA key and certificate
poetry run python ca_server.py init --ca-key ca.key --ca-cert ca.crt

# Import a password-protected key
poetry run python ca_server.py init --ca-key ca.key --ca-cert ca.crt --ca-password-file /run/secrets/ca_pass

A registration seed is printed on first init. Keep it secure — the RA operator will need it.

Register a Registration Authority

Starts the registration listener (port 5001, clear mode) and waits for the RA to complete the handshake.

poetry run python ca_server.py register

Start the CA Server

Starts the CA listener (port 5000, TLS mode). The RA must already be registered.

# Default: tcp://127.0.0.1:5000
poetry run python ca_server.py listen

# Custom bind address
poetry run python ca_server.py listen --host 0.0.0.0 --port 5000

Auto-bootstrap (Docker / Production)

Initialises the PKI on the first boot (or skips it if already done), then runs both listeners concurrently. This is the default Docker entrypoint.

poetry run python ca_server.py start

Configuration

On first run, ca_server.py init creates ca.config.yml in the storage directory with the following defaults:

company: "Company Name"
domain: "example.com"
host: "127.0.0.1"
port: 5000 # CA listener; registration listener uses port + 1
clients: "register" # all | register | manual
password: null # CA private key password (null = no encryption)
seed: null # RA registration seed (auto-generated if absent)
key_type: "rsa" # rsa | dsa
key_length: 4096
digest: "sha256" # md5 | sha1 | sha256 | sha512
crl_validity: 7 # CRL validity in days

Environment Variables

When running via Docker or systemd, configuration can be injected without editing the config file:

Variable Description
UPKI_DATA_DIR Override the storage path (--path equivalent)
UPKI_CA_SEED Registration seed (used by start on first boot)
UPKI_CA_HOST Bind address for both ZMQ sockets (default 0.0.0.0)
UPKI_CA_KEY_FILE Path to an existing CA private key to import
UPKI_CA_CERT_FILE Path to an existing CA certificate to import

Certificate Profiles

Profiles are stored as YAML files under ~/.upki/ca/profiles/. The following built-in profiles are created automatically at initialisation:

Profile Type Default Validity Key Usage
ca sslCA 10 years keyCertSign, cRLSign
ra sslCA 1 year digitalSignature, keyEncipherment
server server 60 days serverAuth
webapp server 60 days serverAuth, clientAuth
laptop user 30 days clientAuth, emailProtection
user user 30 days clientAuth
admin user 1 year clientAuth

Custom profiles can be added by dropping a YAML file in the profiles/ directory.

Docker Deployment

Using Docker Run

docker run -d \
  --name upki-ca \
  -p 5000:5000 \
  -p 5001:5001 \
  -v upki_data:/data \
  -e UPKI_DATA_DIR=/data \
  -e UPKI_CA_SEED=<your-seed> \
  ghcr.io/circle-rd/upki-ca:latest

Using Docker Compose

services:
  upki-ca:
    image: ghcr.io/circle-rd/upki-ca:latest
    ports:
      - "5000:5000"
      - "5001:5001"
    volumes:
      - upki_data:/data
    environment:
      UPKI_DATA_DIR: /data
      UPKI_CA_SEED: ${CA_SEED}
    restart: unless-stopped

volumes:
  upki_data:

Build from Source

docker build -t upki-ca:latest .

Project Organization

upki-ca/
├── ca_server.py              # Main entry point (CLI)
├── pyproject.toml            # Poetry configuration
├── Dockerfile                # Docker image definition
├── docs/
│   ├── CA_ZMQ_PROTOCOL.md   # ZMQ protocol specification
│   └── SPECIFICATIONS_CA.md # CA specifications
├── upki_ca/
│   ├── ca/
│   │   ├── authority.py      # Core CA singleton (sign, revoke, renew…)
│   │   ├── cert_request.py   # CSR parsing and validation
│   │   ├── private_key.py    # Private key generation / import
│   │   └── public_cert.py    # Certificate building and serialisation
│   ├── connectors/
│   │   ├── listener.py       # Base ZMQ REP socket
│   │   ├── zmq_listener.py   # CA operations dispatcher (port 5000)
│   │   └── zmq_register.py   # RA registration handler (port 5001)
│   ├── core/
│   │   ├── common.py         # Base class with shared utilities
│   │   ├── options.py        # Allowed values, profiles, durations
│   │   ├── upki_error.py     # Custom exception hierarchy
│   │   ├── upki_logger.py    # Logging setup
│   │   └── validators.py     # Input validation (DN fields, SANs…)
│   ├── storage/
│   │   ├── abstract_storage.py # Storage interface
│   │   ├── file_storage.py     # TinyDB + filesystem (default)
│   │   └── mongo_storage.py    # MongoDB stub (not yet implemented)
│   └── utils/
│       ├── config.py           # YAML config loader / writer
│       └── profiles.py         # Profile management
└── tests/
    ├── test_00_common.py
    ├── test_10_config.py
    ├── test_10_validators.py
    ├── test_20_ca_server.py
    ├── test_20_profiles.py
    └── test_100_pki_functional.py

CA ZMQ Operations

The CA exposes the following commands on port 5000. See docs/CA_ZMQ_PROTOCOL.md for the full message format.

Command Description
get_ca Retrieve the CA certificate
get_crl Retrieve the current CRL
generate_crl Force CRL regeneration
generate Generate a key pair and sign a cert
sign Sign an external CSR
renew Renew an existing certificate
revoke Revoke a certificate
unrevoke Remove a certificate from the CRL
delete Delete a certificate record
view Retrieve certificate details
ocsp_check Check the revocation status of a cert

Development

Running Tests

poetry run pytest tests/

Code Style

poetry run ruff check .
poetry run ruff format .

Related Projects

  • uPKI RA Server — Registration Authority, bridges clients to this CA
  • uPKI CLI — Client application for certificate enrolment and renewal

License

MIT License

Release files for upki-ca 0.1.5

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

Source distribution (sdist)

Source distribution for upki-ca 0.1.5
File Size Uploaded
upki_ca-0.1.5.tar.gz 40.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for upki-ca 0.1.5
File Interpreter ABI Platform
upki_ca-0.1.5-py3-none-any.whl Python 3 none any Details

Total release size: 91.6 kB

Release files / upki_ca-0.1.5.tar.gz

Download URL upki_ca-0.1.5.tar.gz
Size 40.8 kB
Tags Source
SHA-256 checksum
How to use checksums
d0372cff61a4a84c826c268a84d7b47298afa041e2e486a4a6e7b29c4c2a5389
BLAKE2b-256 checksum
How to use checksums
935fb1de359f51e0e87bafa9c1c4897a916e38c51e85f84c3c0baf3a35b14f7b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

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 Apr 7, 2026.

Transparency log

Release files / upki_ca-0.1.5-py3-none-any.whl

Download URL upki_ca-0.1.5-py3-none-any.whl
Size 50.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
da97a291b2c5c174b72a141d3dbcbe302266e564463865c92da5038b1d0c6929
BLAKE2b-256 checksum
How to use checksums
2421f1850ea62ebe3a24e121bef701bbaad3fb9f879b9f2fce9ca4346b9fbfad
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

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 Apr 7, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.5 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