Concepts

Architecture

How uPKI RA is structured and how it bridges ACME clients with the uPKI CA.

Architecture

Overview

uPKI RA is a FastAPI application that speaks ACME v2 on one side and ZMQ on the other. It is stateful: all ACME objects (accounts, orders, authorizations, certificates) are stored in a local SQLite database.

┌──────────────────────────────────────────────────┐
│                 uPKI RA process                   │
│                                                   │
│  ┌──────────────────────────────────────────┐    │
│  │           FastAPI / uvicorn              │    │
│  │                                          │    │
│  │  /acme/*    (public — RFC 8555)          │    │
│  │  /api/v1/*  (private — mTLS required)   │    │
│  │  /api/client/* (client — mTLS required) │    │
│  │  /api/public/* (public — no auth)       │    │
│  └──────────────┬───────────────────────────┘    │
│                 │                                 │
│  ┌──────────────▼───────────────────────────┐    │
│  │       RegistrationAuthority              │    │
│  │  (ZMQ REQ client → CA port 5000)         │    │
│  └──────────────────────────────────────────┘    │
│                 │                                 │
│  ┌──────────────▼───────────────────────────┐    │
│  │         SQLiteStorage                    │    │
│  │  accounts / orders / authorizations /    │    │
│  │  challenges / certificates               │    │
│  └──────────────────────────────────────────┘    │
└──────────────────────────────────────────────────┘
        ▲                         │
  ACME clients               ZMQ REQ
  (Traefik, etc.)         CA port 5000

Core components

RegistrationAuthority

The main orchestrator (upki_ra/registration_authority.py). Initialises the ZMQ connection to the CA, manages bootstrapping, and exposes the ACME and admin operations to the route handlers.

Route modules

ModulePath prefixAuthDescription
acme_api.py/acme/JWS (ACME)Full ACME v2 protocol
public_api.py/api/v1/public/NoneHealth check, CA cert download
private_api.py/api/v1/mTLSAdmin operations (issue, revoke…)
client_api.py/api/client/mTLSClient-facing certificate operations

SQLite storage

All ACME state lives in a single SQLite database file. Tables mirror ACME objects:

  • accounts — ACME accounts (JWK, contact, status)
  • orders — Certificate orders (identifiers, status, expiry)
  • authorizations — Per-identifier authorizations
  • challenges — HTTP-01/TLS-ALPN-01 challenges
  • certificates — Issued certificate PEM and metadata

ZMQ connector

The RA maintains a persistent zmq.REQ socket to the CA on port 5000. All certificate operations are serialised as JSON and sent synchronously (request–reply).

Data directory layout

/data (UPKI_DATA_DIR)
├── ra.config.yml       # RA configuration
├── ra.crt              # RA TLS certificate
├── ra.key              # RA TLS private key
├── ca.crt              # CA certificate (downloaded from CA on bootstrap)
└── acme.db             # SQLite ACME state

Startup sequence

  1. Parse CLI flags / environment variables
  2. Connect ZMQ REQ socket to CA port 5000
  3. Auto-bootstrap: if no ra.crt found, register with CA port 5001 and obtain a certificate
  4. Configure uvicorn with the RA's TLS certificate (if UPKI_RA_TLS=true)
  5. Mount all route modules on the FastAPI app
  6. Start uvicorn event loop
Copyright © 2026