Last active
September 12, 2023 14:57
-
-
Save whereisaaron/d4e94bac59cf01ca213f50756fe1155c to your computer and use it in GitHub Desktop.
Support for automatic restarting for Apache after mod_md renews a certificate and invokes `MDMessageCmd renewed` command
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ... more config ... | |
MDMessageCmd /usr/local/sbin/md_event | |
# ... more config ... |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#-------------------------------------- | |
# Build md_event command | |
#-------------------------------------- | |
FROM gcc:bullseye as build | |
COPY ./md_event.c . | |
RUN gcc md_event.c -o md_event | |
#-------------------------------------- | |
# Apache container | |
#-------------------------------------- | |
FROM ubuntu/apache2:2.4-22.04_beta | |
# ...Configure apache2... | |
COPY --from=build md_event /usr/local/sbin/md_event | |
RUN chmod u+s /usr/local/sbin/md_event | |
COPY ./md_event.sh /usr/local/sbin/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Execute md_event.sh | |
* | |
* 'md_event.sh' is an event handler for apache2 'mod_md' events, | |
* including setting up ACME challenge responses for certificates, | |
* and after renewing certificates. | |
* | |
* This binary simply executes 'md_event.sh' in a fixed location, | |
* passing any command arguments. | |
* | |
* By making the 'md_event' binary compiled from this code 'setuid' | |
* the 'mod_md' bash script will we run as 'root', which enables | |
* the script to restart apache2, enabling it to load any new | |
* or renewed certificiates mod_md has in the 'staging' directory. | |
* | |
* The 'md_event' binary and 'md_event.sh' script must be protected | |
* from tampering or else your attacker will thank you later. | |
* | |
*/ | |
#define _GNU_SOURCE | |
#include <stdio.h> | |
#include <unistd.h> | |
#include <errno.h> | |
const char script_path[] = "/usr/local/sbin/md_event.sh"; | |
int main (int argc, char *argv[]) { | |
// Set uid to 'root' | |
if (setuid(0) != 0) { | |
perror("Failed to change user to root"); | |
return errno; | |
} | |
// Exec the script (using its hash-bang interpretor) | |
execv(script_path, argv); | |
// execv() will only return if an error occurred | |
char *message; | |
asprintf(&message, "Failed to exec %s", script_path); | |
perror(message); | |
return errno; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Log the invocation and effective user id | |
echo "Running as $(id -nu $EUID): md_event.sh $*" | |
# | |
# Restart apache2 gracefully | |
# This enable mod_md to load newly renewed certificate | |
# This script needs to be run as root | |
# | |
# We only care about after a certificate has been renewed | |
if [[ "$1" != "renewed" ]]; then | |
exit 0 | |
fi | |
# Debian default 'nofiles' ulimit is to set 8192 but AWS ECS Fargate hard limit is 4096 | |
# This env var will change command run by '/usr/sbin/apachectl' | |
export APACHE_ULIMIT_MAX_FILES="ulimit -n 4096" | |
echo "Domain '$2' has been renewed, restarting apache2" | |
apache2ctl configtest && apache2ctl graceful | |
result=$? | |
if (( $result == 0 )); then | |
echo "Successful restart of apache2 after renewal of '$2'" | |
else | |
echo "Failed restart of apache2 after renewal of '$2'" | |
fi | |
# No-zero exit will mean mod_md will keeping make this same call again | |
# until zero is returned, which increasing back-off periods. | |
exit $result | |
# end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This utility works with the excellent
mod_md
module for Apachehttpd
that issues and renews TLS certificates using the ACME protocol:https://github.com/icing/mod_md
After a certificate is renewed
mod_md
involved any configuredMDMessageCmd
command with the argumentrenewed
. This code here provides amd_event
binary that can be installed as asetuid
command and will execute amd_event.sh
script that will invoke a graceful restart ofhttpd
, enabling it to load the new certificate.The
Dockerfile
snippet illustrates a multistage container build to build and install this tool.You must also configure
mod_md
to invoke themd_event
command: