Skip to main content

Enterprise ACME (RFC 8555) server for internal PKI

Project description

ACMEEH

Enterprise ACME (RFC 8555) server for internal PKI

Tests PyPI Python License Codecov Code style: ruff Docker Docker Image Size Docs

Documentation | PyPI | Docker Hub | GitHub


Overview

ACMEEH is a production-ready ACME server built for organizations that need automated certificate management on their internal network. It fully implements RFC 8555 and is compatible with every standards-compliant ACME client — certbot, acme.sh, Caddy, Traefik, Lego, and others.

Plug in your own CA — a local root key, an HSM, HashiCorp Vault, or an upstream ACME provider — and ACMEEH handles the rest: challenge validation, certificate issuance, revocation, CRL distribution, renewal information, and lifecycle hooks.

Built with Python 3.12+, Flask, PostgreSQL, and gunicorn.

Features

  • Pluggable CA Backends — Internal file-based CA, external HTTP API (Vault, EJBCA), PKCS#11 HSM, ACME proxy to upstream CA, or bring your own with ext: plugins. All backends include a circuit breaker for resilience.
  • Challenge Validation — HTTP-01, DNS-01, and TLS-ALPN-01 with configurable timeouts, retries, and background validation workers.
  • Revocation Infrastructure — Built-in CRL generation and ACME Renewal Information (ARI) — each independently toggleable.
  • Admin REST API — Token-authenticated API for user management, audit logs, EAB credentials, identifier allowlists, CSR profiles, certificate search, bulk revocation, and maintenance mode.
  • Hook System — 10 lifecycle events (account registration, order creation, challenge validation, certificate issuance/revocation/delivery, CT submission) with pluggable handlers.
  • Security Controls — Per-endpoint rate limiting, key size and algorithm policies, identifier allowlists, External Account Binding (EAB), CAA enforcement (RFC 8659), CSR validation profiles, and per-account quotas.
  • Prometheus Metrics/metrics endpoint for certificate counts, issuance rates, challenge stats, and CA backend health.
  • Email Notifications — SMTP alerts for certificate expiration with configurable warning days, retry with backoff, and Jinja2 templates.
  • Certificate Transparency — RFC 6962 pre-certificate submission to multiple CT logs with SCT collection.
  • Structured Logging & Audit — JSON and text log formats, audit trail with file/syslog output, and optional webhook export.
  • Background Workers — Daemon threads for challenge validation, certificate expiration checks, nonce/order/challenge cleanup, and data retention — all HA-safe with PostgreSQL advisory locks.

Installation

From PyPI

Linux / macOS:

python3.12 -m venv .venv
source .venv/bin/activate

pip install acmeeh

# Optional: HSM (PKCS#11) support
pip install acmeeh[hsm]

Windows (PowerShell):

python -m venv .venv
.venv\Scripts\Activate.ps1

pip install acmeeh

# Optional: HSM (PKCS#11) support
pip install acmeeh[hsm]

After installation the acmeeh command is available:

acmeeh -c config.yaml --validate-only
acmeeh -c config.yaml --dev

From Source

Linux / macOS:

git clone https://github.com/miichoow/ACMEEH.git
cd ACMEEH

python3.12 -m venv .venv
source .venv/bin/activate

# Install in editable mode (includes all dependencies)
pip install -e ".[dev]"

# Or install dependencies manually
pip install -r requirements.txt

Windows (PowerShell):

git clone https://github.com/miichoow/ACMEEH.git
cd ACMEEH

python -m venv .venv
.venv\Scripts\Activate.ps1

# Install in editable mode (includes all dependencies)
pip install -e ".[dev]"

# Or install dependencies manually
pip install -r requirements.txt

Docker

# 1. Copy the example env file and set your database password
cp docker/.env.example .env
vi .env   # set POSTGRES_PASSWORD

# 2. Place your CA root certificate and key
mkdir -p certs
cp /path/to/root.pem     certs/root.pem
cp /path/to/root-key.pem certs/root-key.pem

# 3. Build and start (ACMEEH + PostgreSQL)
docker compose up -d

# 4. Verify
curl http://localhost:8443/livez
curl http://localhost:8443/directory

Build with optional features:

# HSM (PKCS#11) support
docker compose build --build-arg INSTALL_HSM=1

# Gevent async workers
docker compose build --build-arg INSTALL_GEVENT=1

See the Docker documentation for the full reference — environment variables, configuration, common operations, reverse proxy setup, scaling, and troubleshooting.

Dependencies

Core dependencies (installed automatically via pip install acmeeh):

Package Purpose
Flask Web framework
cryptography X.509, JWS, key operations
dnspython DNS-01 challenge validation
Jinja2 Notification email templates
psycopg[binary] PostgreSQL driver
pyConfigKit Configuration management
PyPGKit Database repository layer

Optional:

Package Install with Purpose
python-pkcs11 pip install acmeeh[hsm] HSM backend via PKCS#11
acmeow pip install acmeeh[acme-proxy] ACME proxy CA backend
gunicorn pip install acmeeh[server] Production server (Linux/macOS only)
pytest, pytest-cov pip install acmeeh[dev] Testing and coverage

Quick Start

# Set up PostgreSQL
psql -U postgres -c "CREATE USER acmeeh WITH PASSWORD 'secret';"
psql -U postgres -c "CREATE DATABASE acmeeh OWNER acmeeh;"

# Create config.yaml (see Configuration section below)

# Validate config
acmeeh -c config.yaml --validate-only

# Start development server
DB_PASSWORD=secret acmeeh -c config.yaml --dev

Note: On Windows, gunicorn is not available. Use --dev for the Flask development server, or deploy behind a WSGI server like waitress.

Configuration

ACMEEH uses a single YAML configuration file with 27 settings sections. Only three fields are required:

server:
  external_url: https://acme.example.com

database:
  database: acmeeh
  user: acmeeh
  password: ${DB_PASSWORD}          # env var substitution
  auto_setup: true                  # create tables on first run

ca:
  backend: internal
  internal:
    root_cert_path: /path/to/root-ca.pem
    root_key_path: /path/to/root-ca-key.pem

challenges:
  enabled:
    - http-01

Environment variables are supported via ${VAR} or ${VAR:-default} syntax anywhere in the YAML.

See the full configuration reference for all settings.

CLI Reference

Command Description
acmeeh -c config.yaml Start the server (gunicorn)
acmeeh -c config.yaml --dev Start Flask development server
acmeeh -c config.yaml --validate-only Validate config and exit
acmeeh -c config.yaml db status Check database connectivity
acmeeh -c config.yaml db migrate Run database migrations
acmeeh -c config.yaml ca test-sign Test CA signing with ephemeral CSR
acmeeh -c config.yaml crl rebuild Force CRL rebuild
acmeeh -c config.yaml admin create-user --username admin --email admin@example.com Create admin user
acmeeh -c config.yaml inspect order <id> Inspect an order
acmeeh -c config.yaml inspect certificate <id> Inspect a certificate
acmeeh -c config.yaml inspect account <id> Inspect an account

Global flags: -c/--config (required), --debug, --dev, --validate-only, -v/--version

CA Backends

Backend Description
internal Sign with a root CA key stored as PEM files on disk
external Delegate signing to a remote HTTP API (e.g., HashiCorp Vault, EJBCA)
hsm Sign using a Hardware Security Module via PKCS#11
acme_proxy Proxy to an upstream ACME CA (e.g., Let's Encrypt)
ext:<path> Load a custom backend class (e.g., ext:mycompany.pki.VaultBackend)

All backends support a circuit breaker that prevents cascading failures on repeated signing errors.

See the CA backends documentation for detailed setup instructions.

Challenge Types

Type Validation
http-01 HTTP request to http://{domain}/.well-known/acme-challenge/{token} on port 80
dns-01 DNS TXT record query at _acme-challenge.{domain}
tls-alpn-01 TLS connection to port 443 with ALPN protocol acme-tls/1

For the acme_proxy backend, set challenges.auto_accept: true to auto-accept all downstream challenges (real validation happens upstream).

Custom challenge validators can be added as plugins.

Architecture

ACME Clients (certbot, acme.sh, Caddy, ...)
                    │
             HTTPS / RFC 8555
                    │
    ┌───────────────────────────────┐
    │         Flask API Layer       │
    │  directory, nonce, account,   │
    │  order, authz, challenge,     │
    │  certificate, key-change      │
    ├───────────────────────────────┤
    │        Service Layer          │
    │  AccountService, OrderService │
    │  ChallengeService, CertSvc    │
    ├──────────┬────────────────────┤
    │Repository│    CA Backend      │
    │  Layer   │ internal/external/ │
    │(PyPGKit) │ hsm/acme_proxy/    │
    │          │ ext:custom         │
    ├──────────┴────────────────────┤
    │     DI Container (context.py) │
    └───────────────┬───────────────┘
                    │
             PostgreSQL 14+

Testing

If installed with pip install -e ".[dev]", pytest is already available and PYTHONPATH is handled automatically.

Linux / macOS:

# Run all tests
pytest

# Run a specific test
pytest tests/test_config.py::test_name -v

# Run with coverage
pytest --cov=acmeeh --cov-report=html

Windows (PowerShell):

# Run all tests
pytest

# Run a specific test
pytest tests\test_config.py::test_name -v

# Run with coverage
pytest --cov=acmeeh --cov-report=html

If you installed dependencies manually (without pip install -e .), prefix commands with PYTHONPATH=src on Linux or set it on Windows:

# Linux / macOS
PYTHONPATH=src python -m pytest tests/
# Windows (PowerShell)
$env:PYTHONPATH = "src"; python -m pytest tests/

Documentation

Full documentation is available in the docs/ folder (Sphinx/reStructuredText, compatible with Read the Docs):

To build the docs locally:

pip install -r docs/requirements.txt
sphinx-build -b html docs docs/_build/html

License

Apache License 2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

acmeeh-2.0.0.tar.gz (243.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

acmeeh-2.0.0-py3-none-any.whl (278.3 kB view details)

Uploaded Python 3

File details

Details for the file acmeeh-2.0.0.tar.gz.

File metadata

  • Download URL: acmeeh-2.0.0.tar.gz
  • Upload date:
  • Size: 243.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for acmeeh-2.0.0.tar.gz
Algorithm Hash digest
SHA256 3dc55bed639252aeb9ea4d0e3d647f903ff835f1f9485f0f9c896cd2a06e3dec
MD5 00d34ef04a6fb89de3e598fc93c7f91c
BLAKE2b-256 d4492c933b967d7453edd11739b82f6d1f14a5e7dc53b0e8ee1041961f7cc6fa

See more details on using hashes here.

Provenance

The following attestation bundles were made for acmeeh-2.0.0.tar.gz:

Publisher: publish.yml on miichoow/ACMEEH

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file acmeeh-2.0.0-py3-none-any.whl.

File metadata

  • Download URL: acmeeh-2.0.0-py3-none-any.whl
  • Upload date:
  • Size: 278.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for acmeeh-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 84a7dea3c18ca2dd612d534095c6cabb934ef44df04daeeaff0ac33b75e50417
MD5 2922350b8ed36d7370cba79d535a9e82
BLAKE2b-256 be7cfe02e7134d38eb6c0fd42c0a8c20b1d59b186b3bfdba061d556147404da6

See more details on using hashes here.

Provenance

The following attestation bundles were made for acmeeh-2.0.0-py3-none-any.whl:

Publisher: publish.yml on miichoow/ACMEEH

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page