uPKI Registration Authority Server
Project description
uPKI RA Server
Registration Authority (RA) Server for the uPKI Public Key Infrastructure system. Provides a complete ACME v2 server implementation for automated certificate management.
Overview
The uPKI RA Server acts as an intermediary between clients and the Certificate Authority (CA), supporting multiple certificate enrollment protocols:
- ACME v2 (RFC 8555) - Automated Certificate Management Environment
- REST API - Traditional CSR-based certificate enrollment
- mTLS Authentication - Certificate-based client authentication
Architecture
graph TB
subgraph "Clients"
ACME[ACME Clients<br/>cert-manager, Traefik]
REST[REST API Clients]
end
subgraph "uPKI RA Server"
direction TB
FastAPI[FastAPI Server]
subgraph "API Routes"
ACME_API[ACME v2<br/>/acme/*]
Public_API[Public REST<br/>/api/v1/*]
Private_API[Private Admin<br/>/api/v1/private/*]
Client_API[Client API<br/>/api/v1/client/*]
end
Storage[(SQLite<br/>ACME Data)]
ZMQ[ZMQ Client]
end
subgraph "uPKI CA Server"
CA[Certificate Authority<br/>Port 5000]
end
ACME -->|HTTPS| FastAPI
REST -->|HTTPS + mTLS| FastAPI
FastAPI --> ACME_API
FastAPI --> Public_API
FastAPI --> Private_API
FastAPI --> Client_API
ACME_API --> Storage
Storage --> SQLite
ZMQ -->|ZMQ| CA
linkStyle 0,1 stroke:#333,stroke-width:2px;
Key Features
- ACME v2 Server — Complete RFC 8555 implementation supporting HTTP-01 and DNS-01 challenge validation
- Multi-Protocol Support — ACME, REST API, and mTLS authentication
- Certificate Lifecycle Management — Enrollment, renewal, and revocation
- Auto-bootstrap — The
startcommand registers the RA with the CA on first boot and starts the server automatically, with no manual intervention - TLS by default (Docker) — The RA serves HTTPS using its own RA certificate, as required by Traefik's built-in ACME client (LEGO)
- Kubernetes Integration — Works with cert-manager as a custom ACME issuer
- Traefik Integration — Direct ACME integration for private networks where Let's Encrypt is not accessible
Requirements
- Python 3.11+
- Poetry (package manager)
- cryptography library
Installation
1. Clone the Repository
git clone https://github.com/circle-rd/upki-ra.git
cd upki-ra
2. Install Dependencies
poetry install
3. Initialize RA
poetry run python ra_server.py init
4. Register with CA
poetry run python ra_server.py register -s <registration_seed>
5. Start the Server
# Default: http://127.0.0.1:8000
poetry run python ra_server.py listen
# Custom bind address and port
poetry run python ra_server.py listen --web-ip 0.0.0.0 --web-port 8443
Alternative: Docker Auto-bootstrap
The start command automates the full lifecycle: it runs register on the first boot (when no ra.crt is present on the data volume), then calls listen. This is the default Docker entrypoint.
# All configuration via environment variables
UPKI_DATA_DIR=/data \
UPKI_CA_HOST=upki-ca \
UPKI_CA_SEED=<seed> \
poetry run python ra_server.py start
Environment Variables
All CLI flags can be overridden by environment variables, which is the recommended approach for Docker and systemd deployments. CLI flags always take precedence over environment variables.
| Variable | Default | Description |
|---|---|---|
UPKI_DATA_DIR |
~/.upki/ra |
Data directory (certs, config, ACME database) |
UPKI_CA_HOST |
127.0.0.1 |
CA server hostname or IP (-i flag) |
UPKI_CA_PORT |
5000 |
CA server ZMQ port (-p flag) |
UPKI_CA_SEED |
— | Registration seed — required for start on first boot |
UPKI_RA_HOST |
127.0.0.1 |
Web server bind address (--web-ip flag) |
UPKI_RA_PORT |
8000 |
Web server port (--web-port flag) |
UPKI_RA_TLS |
true (Docker image) |
Serve HTTPS using the RA certificate |
UPKI_RA_SANS |
upki-ra (Docker image) |
Comma-separated DNS SANs embedded in the RA certificate at first registration |
UPKI_RA_CN |
RA |
Common Name embedded in the RA certificate |
Note on
UPKI_RA_TLSandUPKI_RA_SANS: these are set asENVdefaults in the Docker image (valuestrueandupki-ra). For local/bare-metal deployments both default to their unset values (false/ empty).UPKI_RA_SANSis only used at first registration — changing it after the RA certificate has been issued has no effect.
ACME Server Setup
With cert-manager (Kubernetes)
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: upki-issuer
spec:
acme:
server: https://your-ra-server.com/acme/directory
email: admin@example.com
privateKeySecretRef:
name: upki-account-key
solvers:
- http01:
ingressClassName: traefik
With Traefik (private / air-gapped networks)
uPKI is designed as a drop-in replacement for Let's Encrypt in environments where internet access is unavailable. Traefik's built-in ACME client (LEGO) connects directly to the RA as a custom CA server.
Two prerequisites must be met before Traefik can obtain certificates:
- The RA must serve HTTPS —
UPKI_RA_TLS=true(the default in the Docker image). LEGO requires TLS on the ACME endpoint. - Traefik must trust the internal CA certificate — the RA certificate is signed by the uPKI CA; Traefik's Alpine-based image must have
ca.crtinjected into its trust store before starting.
# traefik.yml (static configuration)
certificatesResolvers:
upki:
acme:
caServer: https://upki-ra:8000/acme/directory
storage: /acme/acme.json
httpChallenge:
entryPoint: web
See Traefik Integration for the full Docker Compose setup, CA certificate injection, DNS resolver configuration, and troubleshooting.
API Endpoints
ACME v2 Endpoints
| Endpoint | Method | Description |
|---|---|---|
/acme/directory |
GET | ACME directory |
/acme/new-nonce |
GET/HEAD | Get new nonce |
/acme/new-account |
POST | Create account |
/acme/new-order |
POST | Create order |
/acme/authz/{id} |
GET | Authorization status |
/acme/challenge/{id}/http-01 |
POST | Validate HTTP-01 challenge |
/acme/challenge/{id}/dns-01 |
POST | Validate DNS-01 challenge |
/.well-known/acme-challenge/{token} |
GET | HTTP-01 challenge response |
/acme/order/{id}/finalize |
POST | Finalize order |
/acme/cert/{id} |
GET | Download certificate |
/acme/revoke-cert |
POST | Revoke certificate |
REST API Endpoints
| Endpoint | Method | Description |
|---|---|---|
/api/v1/health |
GET | Health check |
/api/v1/certify |
POST | Enroll certificate |
/api/v1/certs |
GET | List certificates |
/api/v1/crl |
GET | Get CRL |
/api/v1/profiles |
GET | List profiles |
Project Organization
upki-ra/
├── ra_server.py # Main entry point
├── pyproject.toml # Poetry configuration
├── README.md # This file
├── docs/
│ ├── TRAEFIK_INTEGRATION.md
│ ├── CA_ZMQ_PROTOCOL.md
│ ├── SPECIFICATIONS_RA.md
│ └── SPECIFICATIONS_CA.md
├── upki_ra/
│ ├── __init__.py
│ ├── registration_authority.py # Core RA class
│ ├── core/
│ │ ├── upki_error.py # Exception classes
│ │ └── upki_logger.py # Logging
│ ├── routes/
│ │ ├── acme_api.py # ACME v2 endpoints
│ │ ├── public_api.py # Public REST endpoints
│ │ ├── private_api.py # Admin endpoints
│ │ └── client_api.py # Client endpoints
│ ├── storage/
│ │ ├── abstract.py # Storage interface
│ │ └── sqlite_storage.py # SQLite implementation
│ └── utils/
│ ├── common.py # Utilities
│ ├── tlsauth.py # TLS authentication
│ └── tools.py # ZMQ client & ACME client
└── tests/
├── test_core.py
├── test_utils.py
└── test_routes.py
CA Integration
The RA server communicates with the CA server via ZMQ. For detailed protocol specifications, see the CA ZMQ Protocol Documentation.
graph LR
RA[RA Server<br/>Port 8000] -->|ZMQ| CA[CA Server<br/>Port 5000]
subgraph "RA Data Directory"
Config[config.json]
Keys[ra.key, ra.crt]
CA_Cert[ca.crt]
end
RA --> Config
RA --> Keys
RA --> CA_Cert
Docker Deployment
Minimal Docker Compose
The example below shows the minimal configuration needed to deploy the uPKI stack with Traefik. UPKI_RA_TLS and UPKI_RA_SANS are already set as defaults in the Docker image and do not need to be redeclared unless you want to override them.
services:
upki-ca:
image: ghcr.io/circle-rd/upki-ca:latest
restart: unless-stopped
environment:
UPKI_DATA_DIR: /data
UPKI_CA_SEED: ${PKI_SEED}
volumes:
- upki-ca-data:/data
networks:
- demo-net
healthcheck:
test:
[
"CMD-SHELL",
'python -c ''import socket; s=socket.socket(); s.settimeout(2); s.connect(("127.0.0.1", 5000)); s.close()''',
]
interval: 10s
timeout: 5s
retries: 10
start_period: 10s
upki-ra:
image: ghcr.io/circle-rd/upki-ra:latest
restart: unless-stopped
depends_on:
upki-ca:
condition: service_healthy
environment:
UPKI_DATA_DIR: /data
UPKI_CA_HOST: upki-ca
UPKI_CA_SEED: ${PKI_SEED}
UPKI_RA_HOST: 0.0.0.0
# UPKI_RA_TLS=true and UPKI_RA_SANS=upki-ra are already set in the image
volumes:
- upki-ra-data:/data
networks:
- demo-net
traefik:
image: traefik:v3
restart: unless-stopped
depends_on:
upki-ra:
condition: service_healthy
entrypoint:
- /bin/sh
- -c
- |
cp /ra-data/ca.crt /usr/local/share/ca-certificates/upki-ca.crt
update-ca-certificates
exec traefik
environment:
TRAEFIK_CERTIFICATESRESOLVERS_UPKI_ACME_EMAIL: ${ADMIN_EMAIL}
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- acme:/acme
- ./traefik.yml:/etc/traefik/traefik.yml:ro
- upki-ra-data:/ra-data:ro # Read CA cert from RA data volume
networks:
- demo-net
volumes:
upki-ca-data:
upki-ra-data:
acme:
networks:
demo-net:
See Traefik Integration for the full configuration reference including DNS resolver setup and Traefik service labels.
Development
Running Tests
poetry run pytest tests/
Code Style
poetry run ruff check .
poetry run ruff format .
Related Projects
- uPKI CA Server — Certificate Authority, ZMQ backend for this RA
- 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_ra-0.1.5.tar.gz.
File metadata
- Download URL: upki_ra-0.1.5.tar.gz
- Upload date:
- Size: 43.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
01dcb067b5e3fa3c1cb36bcebc1b60a062e791e4f13d904d3c033c66ee45f04e
|
|
| MD5 |
33b07ba124222f366ec707eef3b7f885
|
|
| BLAKE2b-256 |
c8c802445d2f7ebab0502eae606c3babcfa2de92d8e1453f308b3004069f2589
|
Provenance
The following attestation bundles were made for upki_ra-0.1.5.tar.gz:
Publisher:
publish.yml on circle-rd/upki-ra
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
upki_ra-0.1.5.tar.gz -
Subject digest:
01dcb067b5e3fa3c1cb36bcebc1b60a062e791e4f13d904d3c033c66ee45f04e - Sigstore transparency entry: 1246390724
- Sigstore integration time:
-
Permalink:
circle-rd/upki-ra@fed6dd1e0dc665deffae588b5124aff2cd8cf302 -
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@fed6dd1e0dc665deffae588b5124aff2cd8cf302 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file upki_ra-0.1.5-py3-none-any.whl.
File metadata
- Download URL: upki_ra-0.1.5-py3-none-any.whl
- Upload date:
- Size: 48.0 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 |
2b55290ab8eb45026b1b3ebd836e3bbf69e93cafde9d7029ca2079dcc023884c
|
|
| MD5 |
2468acb95d37fccf5473a897fa6bbb68
|
|
| BLAKE2b-256 |
ee46310355c24a7876c9e08cc2db9b65e8f30c7eb72838d9113da13da16e14f4
|
Provenance
The following attestation bundles were made for upki_ra-0.1.5-py3-none-any.whl:
Publisher:
publish.yml on circle-rd/upki-ra
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
upki_ra-0.1.5-py3-none-any.whl -
Subject digest:
2b55290ab8eb45026b1b3ebd836e3bbf69e93cafde9d7029ca2079dcc023884c - Sigstore transparency entry: 1246390774
- Sigstore integration time:
-
Permalink:
circle-rd/upki-ra@fed6dd1e0dc665deffae588b5124aff2cd8cf302 -
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@fed6dd1e0dc665deffae588b5124aff2cd8cf302 -
Trigger Event:
workflow_dispatch
-
Statement type: