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/OCSP 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, OCSP responder, 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
gunicorn pip install gunicorn 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 26 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

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-1.0.0.tar.gz (214.1 kB view details)

Uploaded Source

Built Distribution

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

acmeeh-1.0.0-py3-none-any.whl (248.8 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for acmeeh-1.0.0.tar.gz
Algorithm Hash digest
SHA256 2b25becd32159efe4124f238c370844079b4e1bf8c1f285f215bcfde513fdb8d
MD5 8035ea25b5d466d9d7211d659046e660
BLAKE2b-256 1183cfe5b99ba2905b603d936076c20765d39e186e324cc34ce6629a74fb5e24

See more details on using hashes here.

Provenance

The following attestation bundles were made for acmeeh-1.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-1.0.0-py3-none-any.whl.

File metadata

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

File hashes

Hashes for acmeeh-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e24f150ccc621a1459521c32b08147b5fc5842f5b8efd4215b5c9d1621c5883f
MD5 b13e41239d2a9c1d139093c70c4c4186
BLAKE2b-256 1419c7efd0c4f144b7952c785cb5887b586a8b63a63827dc756cd1d1a5ff3b2a

See more details on using hashes here.

Provenance

The following attestation bundles were made for acmeeh-1.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