uPKI Certificate Authority server
Project description
uPKI CA Server
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
startcommand 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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file upki_ca-0.1.5.tar.gz.
File metadata
- Download URL: upki_ca-0.1.5.tar.gz
- Upload date:
- Size: 40.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d0372cff61a4a84c826c268a84d7b47298afa041e2e486a4a6e7b29c4c2a5389
|
|
| MD5 |
93aa5fef1dad18ff05faf2cea03f2669
|
|
| BLAKE2b-256 |
935fb1de359f51e0e87bafa9c1c4897a916e38c51e85f84c3c0baf3a35b14f7b
|
Provenance
The following attestation bundles were made for upki_ca-0.1.5.tar.gz:
Publisher:
publish.yml on circle-rd/upki-ca
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
upki_ca-0.1.5.tar.gz -
Subject digest:
d0372cff61a4a84c826c268a84d7b47298afa041e2e486a4a6e7b29c4c2a5389 - Sigstore transparency entry: 1246280268
- Sigstore integration time:
-
Permalink:
circle-rd/upki-ca@ea15cf1fa51ebb715808ad552996cbc5706df7ec -
Branch / Tag:
refs/heads/main - Owner: https://github.com/circle-rd
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ea15cf1fa51ebb715808ad552996cbc5706df7ec -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file upki_ca-0.1.5-py3-none-any.whl.
File metadata
- Download URL: upki_ca-0.1.5-py3-none-any.whl
- Upload date:
- Size: 50.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
da97a291b2c5c174b72a141d3dbcbe302266e564463865c92da5038b1d0c6929
|
|
| MD5 |
af88145a7524e2f05308a08e1caa415b
|
|
| BLAKE2b-256 |
2421f1850ea62ebe3a24e121bef701bbaad3fb9f879b9f2fce9ca4346b9fbfad
|
Provenance
The following attestation bundles were made for upki_ca-0.1.5-py3-none-any.whl:
Publisher:
publish.yml on circle-rd/upki-ca
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
upki_ca-0.1.5-py3-none-any.whl -
Subject digest:
da97a291b2c5c174b72a141d3dbcbe302266e564463865c92da5038b1d0c6929 - Sigstore transparency entry: 1246280316
- Sigstore integration time:
-
Permalink:
circle-rd/upki-ca@ea15cf1fa51ebb715808ad552996cbc5706df7ec -
Branch / Tag:
refs/heads/main - Owner: https://github.com/circle-rd
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ea15cf1fa51ebb715808ad552996cbc5706df7ec -
Trigger Event:
workflow_dispatch
-
Statement type: