Skip to content

Torstein-Eide/Step-certificate-renewal-wrapper-script

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Step certificate renewal wrapper script

  • Credits to: Torstein Eide
  • First created: 2026-01-12
  • License: MIT

intro:

A small, opinionated wrapper around the step CLI for renewing mTLS certificates in a way that plays nicely with systemd.

It consist of 3 parts, pre-check, Cert Renewal and post scripts.

This script is designed to be used from systemd-timers, cron, or service hooks where exit codes actually matter.

It solves a common annoyance:

  • step ca renew exits with code 1 when a certificate does not need renewal.
  • systemd interprets that as a failure.

This wrapper normalizes that behavior so:

  • “Nothing to renew” is treated as systemd success
  • Real errors still fail hard
  • Optional post-renew hooks are executed only when relevant

Features

  • Pre-checks whether renewal is needed
  • Runs step ca renew only when required
  • Normalizes exit codes for systemd compatibility
  • Optional post-renew hook support
  • Verbose logging mode for debugging
  • Sets up systemd-timers and systemd-units.

Not included

  • Installing of Step on server.
  • Installing of Step certificate authority.
  • Creating the certificate in the first place.
  • Coping the certificate to the server.

background:

Do to the way systemd units are setup if the certificate does not need renewal this script will exit early with code 0. Instead of code 1 from the pre-check. This is to avoid systemd treating the non-renewal as an error.

pre-renewal check:

The script checks if the certificate needs renewal using step certificate needs-renewal command. If the certificate does not need renewal, the script exits early with code 0.

Renewal:

If the certificate needs renewal, the script renews it using step ca renew --force command.

Post-renewal scripts:

Any executable scripts in ${BIN_POST_PATH} will be run after a successful renewal to perform additional tasks.

Typical use cases:

  • Reloading or Restarting services that use the certificate
  • Converting certificate formats (e.g., PEM to PKCS12)
  • Importing renewed certificates into application-specific keystores
  • Rebuilding bundles
  • Notifying monitoring systems

It assumes that there only one certificate per machine. if multiple certificates exist per machine,then post-renewal needs be split accordingly. For example by using creating specific post-renewal scripts for each certificate.

This needs to be done since this Step certificate renewal wrapper script try to not exit with error if no renewal is needed. If ExecStartPost or OnSuccess is used in the systemd unit file, it will be executed even if no renewal is needed, which not be desired behavior. if ExcecStartPre is used, the script will exit with code 1 if no renewal is needed, which will be treated as an error by systemd, which not be desired behavior. That results in alert fatigue and unnecessary noice.

use per certificate post-renewal scripts:

For example systemd unit file

In the cert-renewer@.service systemd unit file, you can set the BIN_POST_PATH environment variable like this:

[Service]
...
Environment=BIN_POST_PATH=/etc/step/bin-post-%i

Exit Codes

Code Meaning
0 Success (including “no renewal”)
>=1 Real error (propagated)

Logging:

This script is more chatty when run from command line than when run from systemd. And can be more chatty if VERBOSE_LOG env-variable is set to 1.

Environment variables:

several environment variables are set by systemd. These include:

Variable Default Description
CERT_LOCATION /etc/step/certs/%i.crt Path to the certificate to renew, default by systemd
KEY_LOCATION /etc/step/certs/%i.key Path to the corresponding private key, default by systemd
STEPPATH /usr/bin/step) Path to the step installation

Additional environment variables can be set. These include:

Variable Default Description
VERBOSE_LOG 0 If set to 1, enables verbose logging
SKIP_CHECK 0 If set to 1, skips the pre-renewal check
BIN_POST_PATH /etc/step/bin-post Path to the post-renewal scripts

installation:

  1. git clone the repository to your server:

    git clone https://github.com/yourusername/step-cert-renew.git
  2. Copy the step-renew scripts to your desired location, e.g., /etc/step/bin/step-renew:

    scp -r install.sh bin/  bin-post/ systemd/ ${REMOTE_SERVER}:/etc/step
  3. Configure the systemd timer unit as needed, e.g., adjust the schedule in cert-renewer@.timer.

    sudo nano /etc/step/systemd/cert-renewer@.timer
  4. Run the installation script to install the systemd service and timer units:

    sudo /etc/step/install.sh
  5. Verify that the service and timer units are installed correctly:

    systemctl list-units --type=service 'cert-renewer@*' --no-pager
    systemctl list-timers 'cert-renewer@*' --no-pager
  6. Use systemctl to edit and set environment variables for the service unit as needed:

    sudo systemctl edit cert-renewer@foo.bar.service

    Example of environment variables to set:

    ### Editing /etc/systemd/system/cert-renewer@foo.bar.service.d/override.conf
    ### Anything between here and the comment below will become the contents of the drop-in file
    [Service]
    Environment=BIN_POST_PATH=/etc/step/bin-post-foo.bar
    Environment=HEALTHCHECKSIO_PING_URL=https://hc-ping.com/Super_secret_prodject/Server1-Cert-Renewed
    
    ### Edits below this comment will be discarded

Usage:

This script is intended to be run by systemd as part of a timer unit. It can also be run manually for testing or debugging purposes.

Example command to run manually:

CERT_LOCATION="/etc/step/certs/mycert.crt" \
KEY_LOCATION="/etc/step/certs/mycert.key" \
STEPPATH="/etc/step/bin/step-renew" \
VERBOSE_LOG=1 \
SKIP_CHECK=0 \
/etc/step/bin/step-renew

References:

About

A small, opinionated wrapper around the `step` CLI for renewing mTLS certificates in a way that plays nicely with `systemd`.

Topics

Resources

License

Stars

Watchers

Forks

Contributors

Languages