Concepts
Architecture
How uPKI CA is structured internally and how it communicates with the outside world.
Architecture
Overview
uPKI CA follows a single-process, single-authority model. All external communication happens over ZMQ sockets. There is no HTTP interface, no REST API, and no web UI — by design.
┌─────────────────────────────────────┐
│ uPKI CA process │
│ │
│ ┌──────────┐ ┌──────────────┐ │
│ │ Authority │────▶│ FileStorage │ │
│ └──────────┘ └──────────────┘ │
│ │ │
│ ┌────▼────────────────────────┐ │
│ │ ZMQ REP Listeners │ │
│ │ port 5000 (CA operations) │ │
│ │ port 5001 (RA registration) │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────┘
▲ ▲
uPKI RA / CLI new RA nodes
(ZMQ REQ) (ZMQ REQ)
Core components
Authority
The central singleton class (upki_ca/ca/authority.py). Responsible for:
- Loading/creating the root key pair and self-signed certificate
- Maintaining the certificate store and CRL
- Executing all certificate operations (generate, sign, renew, revoke…)
- Delegating persistence to the configured storage backend
ZmqListener (port 5000)
Handles all ongoing CA operations from registered RA nodes and admin tools:
- Certificate sign / generate / renew / revoke / unrevoke / delete
- CRL generation and retrieval
- Profile listing and inspection
- Admin node management (list_admins, add_admin, remove_admin)
- ACME state synchronisation (acmesync*)
ZmqRegister (port 5001)
Accepts new RA node registrations. This socket is intentionally not protected by mTLS — it uses a shared seed as the authentication mechanism. Once an RA has registered, all further communication goes through port 5000.
Storage backends
| Backend | Status | Use case |
|---|---|---|
FileStorage | Production-ready | Default. TinyDB for metadata, plain files for PEM data. |
MongoStorage | Stub / experimental | Future: centralised multi-CA deployments. |
Data directory layout
/data (UPKI_DATA_DIR)
├── ca.config.yml # CA configuration
├── ca.crt # Root CA certificate (UPKI_CA_CERT_FILE)
├── ca.key # Root CA private key (UPKI_CA_KEY_FILE)
├── crl.pem # Current CRL
├── nodes/ # Node certificates (one subdirectory per CN)
│ └── <cn>/
│ ├── cert.pem
│ └── key.pem
└── db/
├── nodes.json # TinyDB — node metadata
├── certs.json # TinyDB — certificate records
└── admins.json # TinyDB — admin list
Startup sequence
- Load or create root key + certificate from
UPKI_DATA_DIR - Apply configuration from
ca.config.yml - Bind ZMQ REP socket on port 5000
- Bind ZMQ REP socket on port 5001
- Enter event loop — process requests until SIGTERM/SIGINT