onesystems/step-ca-to-e-mail

By onesystems

Updated 10 months ago

Sends a weekly HTML email if step-ca certificates are expired or expiring soon.

Image
Security
Integration & delivery
Monitoring & observability
0

5.4K

onesystems/step-ca-to-e-mail repository overview

Step-CA Expiry Mailer

A tiny container that snapshots your step-ca Badger database, reads certificates via step-badger, and emails an HTML report only when there are expired or soon-to-expire certificates.

  • Uses the same snapshot logic and field parsing as our BookStack sync.
  • Runs on a cron schedule (weekly by default).
  • Works with no-auth SMTP relays (port 25) and authenticated SMTP (STARTTLS 587 or SMTPS 465).
  • Safe to run: mounts your Step-CA DB read-only and snapshots it to /tmp.

Quick Start

1) Build

Place your step-badger_6.5.0 binary in the build context next to the Dockerfile.

docker build -t stepca-expiry-mailer:latest .

✅ You can rename the binary; update COPY in the Dockerfile if you do.

2) Run (no-auth relay on port 25)
docker run -d --name stepca-expiry-mailer \
  -e TZ="Europe/Zurich" \
  -e CRON_SCHEDULE="0 6 * * 1" \
  -e STEP_DB_DIR="/step/db" \
  -e DB_SNAPSHOT="true" \
  -e TMP_BASE="/tmp" \
  -e THRESHOLD_DAYS="30" \
  -e INCLUDE_EXPIRED="true" \
  -e SMTP_HOST="mail-relay.local" \
  -e SMTP_PORT="25" \
  -e SMTP_FROM="[email protected]" \
  -e SMTP_TO="[email protected],[email protected]" \
  -v /path/to/step-ca/db:/step:ro \
  --restart unless-stopped \
  stepca-expiry-mailer:latest
3) Run (authenticated, STARTTLS)
docker run -d --name stepca-expiry-mailer \
  -e SMTP_HOST="smtp.provider.tld" \
  -e SMTP_PORT="587" \
  -e SMTP_STARTTLS="true" \
  -e SMTP_USERNAME="[email protected]" \
  -e SMTP_PASSWORD="supersecret" \
  -e SMTP_FROM="[email protected]" \
  -e SMTP_TO="[email protected]" \
  -v /path/to/step-ca/db:/step:ro \
  --restart unless-stopped \
  stepca-expiry-mailer:latest
4) Docker Compose
services:
  stepca-expiry-mailer:
    image: stepca-expiry-mailer:latest
    environment:
      TZ: Europe/Zurich
      CRON_SCHEDULE: "0 6 * * 1"      # every Monday 06:00
      STEP_DB_DIR: /step/db
      DB_SNAPSHOT: "true"
      TMP_BASE: "/tmp"
      THRESHOLD_DAYS: "30"
      INCLUDE_EXPIRED: "true"
      SMTP_HOST: mail-relay.local
      SMTP_PORT: "25"
      SMTP_FROM: [email protected]
      SMTP_TO: [email protected]
      SMTP_STARTTLS: "false"
      EMAIL_SUBJECT_PREFIX: "[Step-CA]"
      TABLE_TITLE: "Certificates expiring soon"
    volumes:
      - /path/to/step-ca/db:/step:ro
    restart: unless-stopped

How It Works

  1. Snapshot: The container creates a temporary copy of your Badger DB (DB_SNAPSHOT=true). This avoids the Badger directory lock.

  2. Read: It runs step-badger x509Certs <SNAPSHOT> --emit json and parses notBefore/notAfter like the BookStack sync.

  3. Filter: Certificates are included if:

    • days_left <= THRESHOLD_DAYS, or
    • already expired and INCLUDE_EXPIRED=true.
  4. Email: If and only if there are matching entries, it sends a nicely formatted HTML email (plus a plain-text alternative).


Configuration

Required (for email)
  • SMTP_HOST — SMTP server hostname or IP.
  • SMTP_FROM — sender address (e.g., [email protected]).
  • SMTP_TO — comma-separated recipients list.
Common
  • CRON_SCHEDULE — cron syntax for when to run (default: 0 6 * * 1 → Monday 06:00).
  • STEP_DB_DIR — path inside the container to your Step-CA DB root (default: /step/db).
  • DB_SNAPSHOTtrue|false (default: true) — snapshot DB into TMP_BASE before reading.
  • TMP_BASE — base directory for snapshots (default: /tmp).
  • THRESHOLD_DAYS — days left threshold for “soon to expire” (default: 30).
  • INCLUDE_EXPIRED — include already expired certs (default: true).
  • EMAIL_SUBJECT_PREFIX — subject prefix (default: [Step-CA]).
  • TABLE_TITLE — headline shown in the email (default: Certificates expiring soon).
SMTP
  • SMTP_PORT25 (plain/no-auth allowed), 587 (STARTTLS), or 465 (SMTPS).
  • SMTP_STARTTLStrue to use STARTTLS on SMTP_PORT (typically 587).
  • SMTP_USERNAME, SMTP_PASSWORD — set when your SMTP requires auth.
step-badger (advanced)
  • STEP_BADGER_CMD — default /usr/local/bin/step-badger x509Certs
  • STEP_BADGER_ARGS — default --emit json

The image assumes your step-badger has the x509Certs command. If your binary differs, adjust STEP_BADGER_CMD/ARGS.


Permissions & Security

  • The container runs as root by default so it can:

    • read the mounted Badger DB (which is often root-owned),
    • write a private cron file under /app/crontabs.
  • Mount your Step-CA directory read-only: -v /path/to/db:/step:ro.

  • If you must run non-root, grant read+execute on the host to the container UID/GID (ACLs or group membership), then switch USER in the Dockerfile and keep crond -c /app/crontabs.


Troubleshooting

  • Permission denied / Badger lock Ensure the host path is mounted read-only and the container runs as root, or adjust host ACLs if you run non-root. Snapshotting avoids the directory lock.

  • “No parsable certificates with not_after” Means step-badger JSON didn’t include notAfter fields. Make sure you’re using a compatible step-badger build with x509Certs --emit json.

  • No emails arrive Check SMTP_HOST/PORT and whether your relay requires auth or STARTTLS/SMTPS. Use:

    • no-auth internal relay: SMTP_PORT=25, SMTP_STARTTLS=false, no username/password.
    • STARTTLS: SMTP_PORT=587, SMTP_STARTTLS=true.
    • SMTPS: SMTP_PORT=465 (no SMTP_STARTTLS), often requires auth.
  • Cron didn’t run Verify CRON_SCHEDULE syntax and container logs. Cron is started as crond -f -l 8 -c /app/crontabs.



Author


License

MIT License – free for commercial and private use.


Credits

  • step-badger by Smallstep community.
  • This mailer uses the same snapshot & parsing approach as our BookStack sync for step-ca.

Tag summary

Content type

Image

Digest

sha256:5f8fecbc7

Size

23.6 MB

Last updated

10 months ago

docker pull onesystems/step-ca-to-e-mail