Skip to content

rohzb/acmed

Repository files navigation

acmed

⚠️ Early-stage project Expect rough edges, changing interfaces, and incomplete pieces.

Python Tests Docker Build Smoke Test Security Checks Release Pipeline

acmed (ACME Daemon) is an ACME-first broker service for internal infrastructure.

I built it because ACME automation gets awkward fast in segmented networks. HTTP challenges are often not reachable, DNS challenges can require broader permissions than you want to hand out, and many appliances support only part of the ecosystem. The result is usually a pile of one-off scripts and host-specific workarounds.

acmed puts one service in the middle so that policy and request handling live in one place instead of being reinvented per host. It accepts ACME requests, tracks state, applies local authorization/proof rules, and hands issuance work to an adapter.

A key design choice is that acmed does not reimplement issuance tooling. It calls existing tools such as certbot and acme.sh, then focuses on orchestration and policy. Right now the scope is intentionally narrow: ACME-first flow plus controlled backend delegation. The structure leaves room for more broker-like behavior later (for example multiple backends), but that is secondary to keeping the current flow understandable and predictable.

In short, the request path is:

  • client sends ACME request
  • acmed validates and stores it
  • worker resolves policy and proof handling
  • issuer adapter runs the external issuance/challenge flow
  • result is exposed back through normal ACME resources

Prerequisites

  • Python 3.11+ (for source installs and local development)
  • Docker and Docker Compose (for container quick start)

Installation

Choose one of the following installation paths.

From source:

git clone https://github.com/rohzb/acmed.git
cd acmed

python -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install -e .

From GitHub release artifacts:

python -m venv .venv
source .venv/bin/activate
pip install --upgrade pip

# Download wheel/sdist from:
# https://github.com/rohzb/acmed/releases
# Example:
pip install ./acmed-X.Y.Z-py3-none-any.whl

From published Docker image:

docker pull ghcr.io/rohzb/acmed:latest

Published image tags:

  • ghcr.io/rohzb/acmed:latest
  • ghcr.io/rohzb/acmed:X
  • ghcr.io/rohzb/acmed:X.Y
  • ghcr.io/rohzb/acmed:X.Y.Z

Quick start

If you cloned the repository, the easiest way to try acmed is Docker Compose:

cp docker/.env.example docker/.env
cp docker/config/config.allow-all.yml docker/config/config.yml

docker compose -f docker/docker-compose.yml --env-file docker/.env up --build

Warning

config.allow-all.yml is for local development/testing only. Do not use it in production.

To run from the published image directly:

mkdir -p /opt/acmed/config
cp config.example.yml /opt/acmed/config/config.yml

docker run --rm \
  --name acmed \
  -p 8443:8443 \
  -e ACMED_TOKEN_ADMIN='replace-with-random-token' \
  -v /opt/acmed/config/config.yml:/app/config/config.yml:ro \
  ghcr.io/rohzb/acmed:latest

Quick check:

curl http://127.0.0.1:8443/healthz
curl http://127.0.0.1:8443/acme/directory

Configuration is YAML-based around three parts:

  • authorizers: who is allowed
  • proof handlers: how ownership is checked
  • issuer adapters: how certificates are issued

Have a look at config.example.yml for a starting point.

Development

pytest
python -m acmed.main <config.yml>

CI workflows:

  • ci: Python test matrix (3.11 through 3.14) plus package build validation.
  • docker-ci: Docker image build and runtime smoke test (/healthz).
  • security-checks: Trivy (vuln/misconfig) + Gitleaks + TruffleHog security checks.

Docs are under docs/ (start with docs/README.md). Versioning and release policy is defined in docs/reference/versioning.md. Human-facing docs are separate from machine-oriented contracts in docs/models/. Project is MIT licensed (LICENSE).

Releases

Release automation is wired through GitHub Actions on tag push.

Trigger it with an annotated SemVer tag that matches pyproject.toml:

git tag -a vX.Y.Z -m "acmed vX.Y.Z"
git push origin vX.Y.Z

On each vX.Y.Z tag push, CI will:

  • validate tag format and ensure it matches project.version
  • verify CHANGELOG.md contains that version
  • run tests
  • build Python artifacts (sdist and wheel)
  • build and push Docker image tags to GHCR:
    • X.Y.Z
    • X.Y
    • X
    • latest
  • create a GitHub Release with generated notes and attached build artifacts

Feedback and PRs are welcome.

About

ACME broker for segmented/internal networks, centralizing policy checks and delegating issuance to certbot/acme.sh

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors