mirror of
https://github.com/GrapheneOS/infrastructure.git
synced 2025-06-23 14:14:15 -04:00
migrate to new tlsserver Let's Encrypt profile
We can no longer use OCSP stapling and Must-Staple. These will soon be obsolete once the `shortlived` profile is available for public use since it will provide certificates with a similar lifetime as OCSP responses. In the meantime, we've moved to the `tlsserver` profile stripping legacy features to prepare for the `shortlived` profile which will be identical to `tlsserver` but with a validity period of 6 days. The certificate for SUPL is still temporarily using the classic profile to work around the older generations of end-of-life Snapdragon Pixels not having support for SNI. We can eventually drop support for these devices from the SUPL service to allow us to disable TLSv1.1, DHE and move to the `tlsserver` or `shortlived` profile. The certificate for SMTP is still temporarily using the classic profile to avoid potential compatibility issues with servers supporting TLSv1.2 but still not yet supporting SNI.
This commit is contained in:
parent
a6d1e00d07
commit
90a7780b5e
19 changed files with 28 additions and 775 deletions
1
LICENSE
1
LICENSE
|
@ -1,5 +1,4 @@
|
||||||
Copyright © 2014-2025 GrapheneOS
|
Copyright © 2014-2025 GrapheneOS
|
||||||
Copyright (c) 2017 Tom Wassenberg
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
|
@ -1,676 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
# Unofficial Bash strict mode
|
|
||||||
set \
|
|
||||||
-o errexit \
|
|
||||||
-o errtrace \
|
|
||||||
-o noglob \
|
|
||||||
-o nounset \
|
|
||||||
-o pipefail
|
|
||||||
IFS=$'\n\t'
|
|
||||||
shopt -s inherit_errexit
|
|
||||||
|
|
||||||
determine_colored_output() {
|
|
||||||
declare -gl COLORED_STDOUT COLORED_STDERR
|
|
||||||
readonly GREEN='\033[0;32m'
|
|
||||||
readonly RED='\033[0;31m'
|
|
||||||
readonly COLOR_DEFAULT='\033[0m'
|
|
||||||
|
|
||||||
if [[ -v NO_COLOR || ${TERM-} == dumb ]]; then
|
|
||||||
COLORED_STDOUT=false COLORED_STDERR=false
|
|
||||||
else
|
|
||||||
[[ -t 1 ]] || COLORED_STDOUT=false
|
|
||||||
[[ -t 2 ]] || COLORED_STDERR=false
|
|
||||||
fi
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
exit_with_error() {
|
|
||||||
local error_prefix=error:$'\t\t'
|
|
||||||
|
|
||||||
[[ ${COLORED_STDERR-} != false ]] &&
|
|
||||||
local -r COLORED_ERROR_MSG=${RED}${error_prefix}${*}${COLOR_DEFAULT}
|
|
||||||
|
|
||||||
# We will have closed file descriptor 2 unless verbosity was requested, so we
|
|
||||||
# will try to use FD5 (the FD that stderr was likely redirected to), and
|
|
||||||
# fallback to FD2 if FD5 wasn't opened yet.
|
|
||||||
if [[ -f /dev/fd/5 ]]; then
|
|
||||||
exec >&5
|
|
||||||
else
|
|
||||||
exec >&2
|
|
||||||
fi
|
|
||||||
printf '%b\n' "${COLORED_ERROR_MSG:-${error_prefix}${@}}"
|
|
||||||
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
check_for_dependencies() {
|
|
||||||
if ((BASH_VERSINFO[0] == 4 && BASH_VERSINFO[1] < 3 || BASH_VERSINFO[0] < 4)); then
|
|
||||||
exit_with_error "${0##*/} requires Bash 4.3+."
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! { command -v openssl >&- &&
|
|
||||||
[[ $(openssl version || true) =~ ^OpenSSL\ ([[:digit:]]+)\.([[:digit:]]+) ]] &&
|
|
||||||
((BASH_REMATCH[1] == 1 && BASH_REMATCH[2] >= 1 || BASH_REMATCH[1] > 1)); }; then
|
|
||||||
# shellcheck disable=2016
|
|
||||||
exit_with_error \
|
|
||||||
"${0##*/} requires OpenSSL 1.1.0+," \
|
|
||||||
'but it is not available on $PATH.'
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
parse_cli_options() {
|
|
||||||
local -r cli_options="
|
|
||||||
Usage: ${0} [-c/--certbot-dir DIRECTORY] [-f/--force-update] \\
|
|
||||||
[-h/--help] [-l/--no-color] [-n/--cert-name NAME[,NAME...] \\
|
|
||||||
[-u/--ocsp-responder URL]] [-o/--output-dir DIRECTORY] \\
|
|
||||||
[-q/--quiet|-v/--verbose] [-w/--no-reload-webserver]
|
|
||||||
"
|
|
||||||
|
|
||||||
print_option_error() {
|
|
||||||
local reason=${1} option=${2}
|
|
||||||
shift 2
|
|
||||||
local option_error="${option}: "
|
|
||||||
|
|
||||||
case ${reason} in
|
|
||||||
--conflict)
|
|
||||||
local second_option=${1}
|
|
||||||
shift
|
|
||||||
option_error+="This option cannot be combined with the option ${second_option}."
|
|
||||||
;;
|
|
||||||
--duplicate)
|
|
||||||
option_error+="This option cannot be specified multiple times."
|
|
||||||
;;
|
|
||||||
--unknown)
|
|
||||||
option_error+="Invalid option."
|
|
||||||
;;
|
|
||||||
--value)
|
|
||||||
option_error+="This option requires a value."
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
exit_with_error "${option_error}" "${cli_options}"
|
|
||||||
}
|
|
||||||
|
|
||||||
declare -gl ERROR_ENCOUNTERED
|
|
||||||
|
|
||||||
declare -gi VERBOSITY=${VERBOSITY:-1}
|
|
||||||
|
|
||||||
while ((${#} > 0)); do
|
|
||||||
local parameter=${1}
|
|
||||||
|
|
||||||
case ${parameter} in
|
|
||||||
-[^-]?*)
|
|
||||||
set -- "-${parameter:1:1}" "-${parameter:2}" "${@:2}"
|
|
||||||
;;
|
|
||||||
-c | --certbot-dir | --certbot-dir=?*)
|
|
||||||
if [[ -v CERTBOT_DIR ]]; then
|
|
||||||
print_option_error --duplicate "${parameter}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ${parameter} =~ --certbot-dir=(.+) ]]; then
|
|
||||||
CERTBOT_DIR=${BASH_REMATCH[1]}
|
|
||||||
else
|
|
||||||
if [[ -n ${2-} ]]; then
|
|
||||||
CERTBOT_DIR=${2}
|
|
||||||
shift
|
|
||||||
else
|
|
||||||
print_option_error --value "${parameter}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
CERTBOT_DIR=$(
|
|
||||||
realpath \
|
|
||||||
--canonicalize-missing \
|
|
||||||
--relative-base . \
|
|
||||||
-- "${CERTBOT_DIR}"
|
|
||||||
echo x
|
|
||||||
)
|
|
||||||
CERTBOT_DIR=${CERTBOT_DIR%??}
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-f | --force-update)
|
|
||||||
if [[ ! -v FORCE_UPDATE ]]; then
|
|
||||||
declare -glr FORCE_UPDATE=true
|
|
||||||
fi
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-h | --help)
|
|
||||||
{
|
|
||||||
printf '%s\n' certbot-ocsp-fetcher
|
|
||||||
printf '%s\n' "${cli_options}"
|
|
||||||
local absolute_tool_path
|
|
||||||
absolute_tool_path=$(realpath --no-symlinks -- "${0}")
|
|
||||||
readonly absolute_tool_path
|
|
||||||
cat <<EOSTRING
|
|
||||||
|
|
||||||
certbot-ocsp-fetcher helps you setup OCSP stapling in nginx. The tool primes
|
|
||||||
nginx's OCSP cache to work around nginx's flawed OCSP stapling implementation.
|
|
||||||
The tool does this by fetching and saving OCSP responses for TLS certificates
|
|
||||||
issued with Certbot.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
1. Fetch OCSP responses for all certificates managed by Certbot, and save
|
|
||||||
them in the current working directory. This should usually be run on a
|
|
||||||
schedule, e.g. as a cronjob or systemd timer.
|
|
||||||
|
|
||||||
$ ${0}
|
|
||||||
|
|
||||||
2. Add the path(s) to the resulting OCSP response(s) as the value of the
|
|
||||||
ssl_stapling_file directive in the corresponding vhosts in Nginx. Don't
|
|
||||||
forget to reload Nginx afterwards.
|
|
||||||
|
|
||||||
3. Re-issue all certificates managed by Certbot, to add the OCSP Must-Staple
|
|
||||||
flag to the certs and automatically run certbot-ocsp-fetcher during renewals:
|
|
||||||
|
|
||||||
$ certbot renew --deploy-hook ${absolute_tool_path} --force-renewal --must-staple
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
See the online README for an explanation of all the CLI options:
|
|
||||||
https://github.com/tomwassenberg/certbot-ocsp-fetcher/blob/main/README.md
|
|
||||||
EOSTRING
|
|
||||||
}
|
|
||||||
exit
|
|
||||||
;;
|
|
||||||
-l | --no-color)
|
|
||||||
readonly COLORED_STDOUT=false COLORED_STDERR=false
|
|
||||||
;;
|
|
||||||
-n | --cert-name | --cert-name=?*)
|
|
||||||
if [[ ${parameter} =~ --cert-name=(.+) ]]; then
|
|
||||||
local cert_lineages_value=${BASH_REMATCH[1]}
|
|
||||||
shift
|
|
||||||
else
|
|
||||||
if [[ -n ${2-} ]]; then
|
|
||||||
local cert_lineages_value=${2}
|
|
||||||
shift 2
|
|
||||||
else
|
|
||||||
print_option_error --value "${parameter}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Loop over any lineages passed in the same value of --cert-name.
|
|
||||||
OLDIFS=${IFS}
|
|
||||||
IFS=,
|
|
||||||
declare -Ag CERT_LINEAGES
|
|
||||||
# Check if a hardcoded OCSP responder was specified for this set of
|
|
||||||
# lineages.
|
|
||||||
case ${1-} in
|
|
||||||
-u | --ocsp-responder)
|
|
||||||
if [[ -n ${2-} ]]; then
|
|
||||||
for lineage_name in ${cert_lineages_value}; do
|
|
||||||
CERT_LINEAGES["${lineage_name}"]=${2}
|
|
||||||
done
|
|
||||||
shift
|
|
||||||
else
|
|
||||||
print_option_error --value "${parameter}"
|
|
||||||
fi
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
--ocsp-responder=?*)
|
|
||||||
[[ ${1} =~ --ocsp-responder=(.+) ]]
|
|
||||||
for lineage_name in ${cert_lineages_value}; do
|
|
||||||
CERT_LINEAGES["${lineage_name}"]=${BASH_REMATCH[1]}
|
|
||||||
done
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
# If no OCSP responder was specified, just save the lineage
|
|
||||||
# name as the key, with an empty value.
|
|
||||||
for lineage_name in ${cert_lineages_value}; do
|
|
||||||
CERT_LINEAGES["${lineage_name}"]=
|
|
||||||
done
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
unset lineage_name cert_lineages_value
|
|
||||||
IFS=${OLDIFS}
|
|
||||||
;;
|
|
||||||
-o | --output-dir | --output-dir=?*)
|
|
||||||
if [[ -v OUTPUT_DIR ]]; then
|
|
||||||
print_option_error --duplicate "${parameter}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ${parameter} =~ --output-dir=(.+) ]]; then
|
|
||||||
OUTPUT_DIR=${BASH_REMATCH[1]}
|
|
||||||
else
|
|
||||||
if [[ -n ${2-} ]]; then
|
|
||||||
OUTPUT_DIR=${2}
|
|
||||||
shift
|
|
||||||
else
|
|
||||||
print_option_error --value "${parameter}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
OUTPUT_DIR=$(
|
|
||||||
realpath \
|
|
||||||
--canonicalize-missing \
|
|
||||||
--relative-base . \
|
|
||||||
-- "${OUTPUT_DIR}"
|
|
||||||
echo x
|
|
||||||
)
|
|
||||||
OUTPUT_DIR=${OUTPUT_DIR%??}
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-q | --quiet)
|
|
||||||
if ((VERBOSITY != 1)); then
|
|
||||||
print_option_error --conflict "${parameter}" -v/--verbose
|
|
||||||
else
|
|
||||||
readonly VERBOSITY=0
|
|
||||||
shift
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
-v | --verbose)
|
|
||||||
if ((VERBOSITY == 0)); then
|
|
||||||
print_option_error --conflict "${parameter}" -q/--quiet
|
|
||||||
else
|
|
||||||
VERBOSITY+=1
|
|
||||||
shift
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
-w | --no-reload-webserver)
|
|
||||||
if [[ ! -v RELOAD_WEBSERVER ]]; then
|
|
||||||
declare -glr RELOAD_WEBSERVER=false
|
|
||||||
fi
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
print_option_error --unknown "${parameter}"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
# Respect the common "DEBUG" environment variable if set, unless the --quiet
|
|
||||||
# or --verbose flag has been passed as well.
|
|
||||||
if ((${DEBUG:-0} >= 1)) && ((VERBOSITY == 1)); then
|
|
||||||
# We set VERBOSITY to 0 in case of --quiet, so use the value of $DEBUG
|
|
||||||
# incremented with 1 to match it with $VERBOSITY.
|
|
||||||
VERBOSITY=$((DEBUG + 1))
|
|
||||||
fi
|
|
||||||
|
|
||||||
# When not parsed, the stdout and/or stderr output of all external commands
|
|
||||||
# we call in the script is redirected to file descriptor 3. Depending on the
|
|
||||||
# desired verbosity, we redirect this file descriptor to either stderr or to
|
|
||||||
# /dev/null.
|
|
||||||
if ((VERBOSITY >= 2)); then
|
|
||||||
exec 3>&2
|
|
||||||
else
|
|
||||||
exec 3>/dev/null
|
|
||||||
fi
|
|
||||||
|
|
||||||
# First copy file descriptor 2 to a new FD, so stderr can still be used
|
|
||||||
# (unconditionally) in the exit_with_error function.
|
|
||||||
exec 5>&2
|
|
||||||
if ((VERBOSITY < 1)); then
|
|
||||||
exec 2>/dev/null
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Set output directory if necessary and check if it's writeable
|
|
||||||
prepare_output_dir() {
|
|
||||||
if [[ -v OUTPUT_DIR ]]; then
|
|
||||||
if [[ ! -e ${OUTPUT_DIR} ]]; then
|
|
||||||
# Don't yet fail if it's not possible to create the directory, so we can
|
|
||||||
# exit with a custom error down below
|
|
||||||
mkdir \
|
|
||||||
--parents \
|
|
||||||
-- "${OUTPUT_DIR}" || true
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
# Use $CACHE_DIRECTORY if set (e.g. when run as a systemd service),
|
|
||||||
# otherwise the working directory
|
|
||||||
readonly OUTPUT_DIR=${CACHE_DIRECTORY:-.}
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -w ${OUTPUT_DIR} ]]; then
|
|
||||||
exit_with_error "no write access to output directory (\"${OUTPUT_DIR}\")"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
start_in_correct_mode() {
|
|
||||||
# Create temporary directory to store OCSP staple file,
|
|
||||||
# before having checked the certificate status in the response
|
|
||||||
local temp_output_dir
|
|
||||||
temp_output_dir=$(mktemp --directory)
|
|
||||||
readonly temp_output_dir
|
|
||||||
trap "rm -r -- ""${temp_output_dir}" EXIT
|
|
||||||
|
|
||||||
declare -A lineages_processed
|
|
||||||
|
|
||||||
# These two environment variables are set if this script is invoked by Certbot
|
|
||||||
if [[ ! -v RENEWED_DOMAINS || ! -v RENEWED_LINEAGE ]]; then
|
|
||||||
run_standalone
|
|
||||||
else
|
|
||||||
run_as_deploy_hook
|
|
||||||
fi
|
|
||||||
|
|
||||||
print_and_handle_result
|
|
||||||
}
|
|
||||||
|
|
||||||
# Run in "check one or all certificate lineage(s) managed by Certbot" mode
|
|
||||||
# $1 - Path to temporary output directory
|
|
||||||
run_standalone() {
|
|
||||||
printf >&2 '%s\n\n' "Running in stand-alone mode..."
|
|
||||||
|
|
||||||
readonly CERTBOT_DIR=${CERTBOT_DIR:-/etc/letsencrypt}
|
|
||||||
|
|
||||||
if [[ ! -r ${CERTBOT_DIR} || (-d ${CERTBOT_DIR}/live && ! -r ${CERTBOT_DIR}/live) ]]; then
|
|
||||||
exit_with_error "can't access ${CERTBOT_DIR}/live"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check specific lineage if passed on CLI,
|
|
||||||
# or otherwise all lineages in Certbot's dir
|
|
||||||
if [[ -n ${!CERT_LINEAGES[*]} ]]; then
|
|
||||||
for lineage_name in "${!CERT_LINEAGES[@]}"; do
|
|
||||||
if [[ -r ${CERTBOT_DIR}/live/${lineage_name} ]]; then
|
|
||||||
fetch_ocsp_response \
|
|
||||||
--standalone \
|
|
||||||
"${temp_output_dir}" \
|
|
||||||
"${lineage_name}" \
|
|
||||||
"${CERT_LINEAGES["${lineage_name}"]}"
|
|
||||||
else
|
|
||||||
exit_with_error "can't access ${CERTBOT_DIR}/live/${lineage_name}"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
else
|
|
||||||
set +f
|
|
||||||
shopt -s nullglob
|
|
||||||
for lineage_dir in "${CERTBOT_DIR}"/live/*; do
|
|
||||||
set -f
|
|
||||||
|
|
||||||
# Skip non-directories, like Certbot's README file
|
|
||||||
[[ -d ${lineage_dir} ]] || continue
|
|
||||||
|
|
||||||
fetch_ocsp_response \
|
|
||||||
--standalone "${temp_output_dir}" "${lineage_dir##*/}"
|
|
||||||
done
|
|
||||||
unset lineage_dir
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Run in deploy-hook mode, only processing the passed lineage
|
|
||||||
# $1 - Path to temporary output directory
|
|
||||||
run_as_deploy_hook() {
|
|
||||||
printf >&2 '%s\n\n' "Running as a deploy hook of Certbot..."
|
|
||||||
|
|
||||||
if [[ -v CERTBOT_DIR ]]; then
|
|
||||||
# The directory is already inferred from the environment variable that
|
|
||||||
# Certbot passes
|
|
||||||
exit_with_error \
|
|
||||||
"-c/--certbot-dir cannot be passed" \
|
|
||||||
"when run as Certbot hook"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -v FORCE_UPDATE ]]; then
|
|
||||||
# When run as deploy hook the behavior of this flag is used by default.
|
|
||||||
# Therefore passing this flag would not have any effect.
|
|
||||||
exit_with_error \
|
|
||||||
"-f/--force-update cannot be passed" \
|
|
||||||
"when run as Certbot hook"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -n ${!CERT_LINEAGES[*]} ]]; then
|
|
||||||
# The certificate lineage is already inferred from the environment
|
|
||||||
# variable that Certbot passes
|
|
||||||
exit_with_error "-n/--cert-name cannot be passed when run as Certbot hook"
|
|
||||||
fi
|
|
||||||
|
|
||||||
fetch_ocsp_response \
|
|
||||||
--deploy_hook "${temp_output_dir}" "${RENEWED_LINEAGE##*/}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Check if it's necessary to fetch a new OCSP response
|
|
||||||
check_for_existing_ocsp_staple_file() {
|
|
||||||
[[ -f ${OUTPUT_DIR}/${lineage_name}.der ]] || return 1
|
|
||||||
|
|
||||||
# Validate and verify the existing local OCSP staple file
|
|
||||||
local existing_ocsp_response
|
|
||||||
set +e
|
|
||||||
existing_ocsp_response=$(openssl ocsp \
|
|
||||||
-no_nonce \
|
|
||||||
-issuer "${lineage_dir}/chain.pem" \
|
|
||||||
-cert "${lineage_dir}/cert.pem" \
|
|
||||||
-verify_other "${lineage_dir}/chain.pem" \
|
|
||||||
-respin "${OUTPUT_DIR}/${lineage_name}.der" 2>&3)
|
|
||||||
local -ir existing_ocsp_response_rc=${?}
|
|
||||||
set -e
|
|
||||||
readonly existing_ocsp_response
|
|
||||||
|
|
||||||
((existing_ocsp_response_rc == 0)) || return 1
|
|
||||||
|
|
||||||
for existing_ocsp_response_line in ${existing_ocsp_response}; do
|
|
||||||
if [[ ${existing_ocsp_response_line} =~ ^[[:blank:]]*"This Update: "(.+)$ ]]; then
|
|
||||||
local -r this_update=${BASH_REMATCH[1]}
|
|
||||||
elif [[ ${existing_ocsp_response_line} =~ ^[[:blank:]]*"Next Update: "(.+)$ ]]; then
|
|
||||||
local -r next_update=${BASH_REMATCH[1]}
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
[[ -n ${this_update-} && -n ${next_update-} ]] || return 1
|
|
||||||
|
|
||||||
# Only continue fetching OCSP response if existing response expires within
|
|
||||||
# half of its lifetime.
|
|
||||||
{
|
|
||||||
# The command substitutions here don't respect `set -o errexit`, but in
|
|
||||||
# case any of them fail, the total command still fails unless both
|
|
||||||
# substitutions print an integer. This seems very unlikely to occur, so
|
|
||||||
# let's ignore this.
|
|
||||||
# shellcheck disable=2312
|
|
||||||
local -ri response_lifetime_in_seconds=$(($(date +%s --date "${next_update}") - $(date +%s --date "${this_update}")))
|
|
||||||
|
|
||||||
# `set -o errexit` isn't respected here either, but we default to renewing
|
|
||||||
# the OCSP response, so this is fine.
|
|
||||||
# shellcheck disable=2312
|
|
||||||
(($(date +%s) < $(date +%s --date "${this_update}") + response_lifetime_in_seconds / 2)) || return 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Generate file used by ssl_stapling_file in nginx config of websites
|
|
||||||
# $1 - Whether to run as a deploy hook for Certbot, or standalone
|
|
||||||
# $2 - Path to temporary output directory
|
|
||||||
# $3 - Name of certificate lineage
|
|
||||||
# $4 - OCSP endpoint (if specified on command line)
|
|
||||||
fetch_ocsp_response() {
|
|
||||||
local -r temp_output_dir=${2}
|
|
||||||
local -r lineage_name=${3}
|
|
||||||
|
|
||||||
# This validation should be revisited once
|
|
||||||
# https://github.com/certbot/certbot/issues/6127 is fixed.
|
|
||||||
if [[ ${lineage_name} =~ ($'\n')|($'\t') ]]; then
|
|
||||||
ERROR_ENCOUNTERED=true
|
|
||||||
exit_with_error \
|
|
||||||
"Unsupported characters encountered in the following" \
|
|
||||||
"lineage name: ${lineage_name}$'\n\n'" \
|
|
||||||
"Lineage names with embedded tabs or newlines are not supported," \
|
|
||||||
"because Certbot (as of version 1.18.0) does not have well-defined" \
|
|
||||||
'behavior on handling any "unconventional" lineage names.'
|
|
||||||
fi
|
|
||||||
|
|
||||||
case ${1} in
|
|
||||||
--standalone)
|
|
||||||
local -r lineage_dir=${CERTBOT_DIR}/live/${lineage_name}
|
|
||||||
|
|
||||||
# `set -o errexit` is not respected here, but in case of failure we still
|
|
||||||
# err on the safe side by renewing the OCSP staple file.
|
|
||||||
# shellcheck disable=2310
|
|
||||||
if [[ ${FORCE_UPDATE-} != true ]] &&
|
|
||||||
check_for_existing_ocsp_staple_file; then
|
|
||||||
lineages_processed["${lineage_name}"]="not updated"$'\t'"valid staple file on disk"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
--deploy_hook)
|
|
||||||
local -r lineage_dir=${RENEWED_LINEAGE}
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
return 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
shift 3
|
|
||||||
|
|
||||||
# Verify that the leaf certificate is still valid. If the certificate is
|
|
||||||
# expired, we don't have to request a (new) OCSP response.
|
|
||||||
local cert_expiry_output
|
|
||||||
set +e
|
|
||||||
cert_expiry_output=$(openssl x509 \
|
|
||||||
-in "${lineage_dir}/cert.pem" \
|
|
||||||
-checkend 0 \
|
|
||||||
-noout 2>&3)
|
|
||||||
local -ri cert_expiry_rc=${?}
|
|
||||||
set -e
|
|
||||||
if ((cert_expiry_rc != 0)); then
|
|
||||||
ERROR_ENCOUNTERED=true
|
|
||||||
lineages_processed["${lineage_name}"]="failed to update"
|
|
||||||
if [[ ${cert_expiry_output} == "Certificate will expire" ]]; then
|
|
||||||
lineages_processed["${lineage_name}"]+=$'\t'"leaf certificate expired"
|
|
||||||
fi
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
local ocsp_endpoint
|
|
||||||
if [[ -n ${1-} ]]; then
|
|
||||||
ocsp_endpoint=${1}
|
|
||||||
else
|
|
||||||
ocsp_endpoint=$(openssl x509 \
|
|
||||||
-noout \
|
|
||||||
-ocsp_uri \
|
|
||||||
-in "${lineage_dir}/cert.pem" \
|
|
||||||
2>&3)
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Request, verify and temporarily save the actual OCSP response,
|
|
||||||
# and check whether the certificate status is "good"
|
|
||||||
local ocsp_call_output
|
|
||||||
set +e
|
|
||||||
ocsp_call_output=$(openssl ocsp \
|
|
||||||
-no_nonce \
|
|
||||||
-url "${ocsp_endpoint}" \
|
|
||||||
-issuer "${lineage_dir}/chain.pem" \
|
|
||||||
-cert "${lineage_dir}/cert.pem" \
|
|
||||||
-verify_other "${lineage_dir}/chain.pem" \
|
|
||||||
-respout "${temp_output_dir}/${lineage_name}.der" 2>&3)
|
|
||||||
local -ir ocsp_call_rc=${?}
|
|
||||||
set -e
|
|
||||||
readonly ocsp_call_output=${ocsp_call_output#"${lineage_dir}"/cert.pem: }
|
|
||||||
local -r cert_status=${ocsp_call_output%%$'\n'*}
|
|
||||||
|
|
||||||
if [[ ${ocsp_call_rc} != 0 || ${cert_status} != good ]]; then
|
|
||||||
ERROR_ENCOUNTERED=true
|
|
||||||
|
|
||||||
lineages_processed["${lineage_name}"]="failed to update"
|
|
||||||
if ((VERBOSITY >= 2)); then
|
|
||||||
lineages_processed["${lineage_name}"]+=$'\t'"${ocsp_call_output//[[:space:]]/ }"
|
|
||||||
else
|
|
||||||
lineages_processed["${lineage_name}"]+=$'\t'"${cert_status}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If arrived here status was good, so move OCSP staple file to definitive
|
|
||||||
# folder
|
|
||||||
mv --context "${temp_output_dir}/${lineage_name}.der" "${OUTPUT_DIR}/"
|
|
||||||
|
|
||||||
lineages_processed["${lineage_name}"]=updated
|
|
||||||
}
|
|
||||||
|
|
||||||
print_and_handle_result() {
|
|
||||||
local -r header=LINEAGE$'\t'RESULT$'\t'REASON
|
|
||||||
|
|
||||||
local lineages_processed_marked_up
|
|
||||||
for lineage_name in "${!lineages_processed[@]}"; do
|
|
||||||
lineages_processed_marked_up+=$'\n'"${lineage_name}"$'\t'
|
|
||||||
if [[ ${COLORED_STDOUT-} != false ]]; then
|
|
||||||
if [[ ${lineages_processed["${lineage_name}"]} =~ ^updated ]]; then
|
|
||||||
lineages_processed_marked_up+=${GREEN}
|
|
||||||
elif [[ ${lineages_processed["${lineage_name}"]} =~ ^"failed to update" ]]; then
|
|
||||||
lineages_processed_marked_up+=${RED}
|
|
||||||
fi
|
|
||||||
lineages_processed_marked_up+=${lineages_processed["${lineage_name}"]}${COLOR_DEFAULT}
|
|
||||||
else
|
|
||||||
lineages_processed_marked_up+=${lineages_processed["${lineage_name}"]}
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
unset lineage_name
|
|
||||||
lineages_processed_marked_up=$(sort <<<"${lineages_processed_marked_up-}")
|
|
||||||
readonly lineages_processed_marked_up
|
|
||||||
|
|
||||||
if [[ ${RELOAD_WEBSERVER-} != false ]]; then
|
|
||||||
reload_webserver
|
|
||||||
fi
|
|
||||||
|
|
||||||
local output=${header}${lineages_processed_marked_up-}${nginx_status-}
|
|
||||||
|
|
||||||
if ((VERBOSITY >= 1)); then
|
|
||||||
local output_table
|
|
||||||
# shellcheck disable=2016
|
|
||||||
output_table=$(column \
|
|
||||||
--output-separator $'\t' \
|
|
||||||
--separator $'\t' \
|
|
||||||
--table \
|
|
||||||
<<<"${output}" \
|
|
||||||
2>/dev/null) ||
|
|
||||||
output_table=$(column -s$'\t' -t <<<"${output}" 2>/dev/null) ||
|
|
||||||
local -r column_error=($'\n'
|
|
||||||
'Install the BSD utility `column` for properly formatted output.'
|
|
||||||
'If the version of `column` supports the `--output-separator` flag,'
|
|
||||||
'the output will be formatted as TSV.'
|
|
||||||
$'\n'
|
|
||||||
)
|
|
||||||
readonly output=${output_table:-${output}}
|
|
||||||
unset output_table
|
|
||||||
|
|
||||||
# Extract header to direct it to stderr
|
|
||||||
printf '%s\n' "${output%%$'\n'*}" >&2
|
|
||||||
# Remove header before printing everything else to stdout
|
|
||||||
[[ -n ${!lineages_processed[*]} ]] && printf '%b\n' "${output#*$'\n'}"
|
|
||||||
|
|
||||||
if [[ ${COLORED_STDERR-} != false ]]; then
|
|
||||||
printf %b "${RED}${column_error[*]-}${COLOR_DEFAULT}" >&2
|
|
||||||
else
|
|
||||||
printf %b "${column_error[*]-}" >&2
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
[[ ${ERROR_ENCOUNTERED-} != true ]]
|
|
||||||
}
|
|
||||||
|
|
||||||
reload_webserver() {
|
|
||||||
for lineage_name in "${!lineages_processed[@]}"; do
|
|
||||||
if [[ ${lineages_processed["${lineage_name}"]} == updated ]]; then
|
|
||||||
local nginx_status
|
|
||||||
if nginx -s reload >&3 2>&1; then
|
|
||||||
[[ ${COLORED_STDERR-} != false ]] && nginx_status=${GREEN}
|
|
||||||
# The last line includes a leading space, to workaround the lack of the
|
|
||||||
# `-n` flag in later versions of `column`.
|
|
||||||
nginx_status+=$'\n\n \t'"nginx reloaded"
|
|
||||||
else
|
|
||||||
ERROR_ENCOUNTERED=true
|
|
||||||
[[ ${COLORED_STDERR-} != false ]] && nginx_status=${RED}
|
|
||||||
nginx_status=$'\n\n \t'"nginx not reloaded"$'\t'"unable to reload nginx service, try manually"
|
|
||||||
fi
|
|
||||||
[[ ${COLORED_STDERR-} != false ]] &&
|
|
||||||
readonly nginx_status+=${COLOR_DEFAULT}
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
unset lineage_name
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
check_for_dependencies
|
|
||||||
|
|
||||||
determine_colored_output
|
|
||||||
|
|
||||||
parse_cli_options "${@}"
|
|
||||||
|
|
||||||
prepare_output_dir
|
|
||||||
|
|
||||||
start_in_correct_mode
|
|
||||||
}
|
|
||||||
|
|
||||||
main "${@}"
|
|
|
@ -1,6 +1,6 @@
|
||||||
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
||||||
--key-type ecdsa --reuse-key --must-staple \
|
--key-type ecdsa --reuse-key --preferred-profile tlsserver \
|
||||||
--deploy-hook "certbot-ocsp-fetcher -o /var/cache/certbot-ocsp-fetcher" \
|
--deploy-hook "nginx -s reload" \
|
||||||
--cert-name grapheneos.network \
|
--cert-name grapheneos.network \
|
||||||
-d grapheneos.network \
|
-d grapheneos.network \
|
||||||
-d grapheneos.network \
|
-d grapheneos.network \
|
||||||
|
@ -23,6 +23,6 @@ certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
||||||
|
|
||||||
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
||||||
--key-type rsa --rsa-key-size 3072 --reuse-key \
|
--key-type rsa --rsa-key-size 3072 --reuse-key \
|
||||||
--deploy-hook "certbot-ocsp-fetcher -o /var/cache/certbot-ocsp-fetcher" \
|
--deploy-hook "nginx -s reload" \
|
||||||
--cert-name supl.grapheneos.org \
|
--cert-name supl.grapheneos.org \
|
||||||
-d supl.grapheneos.org
|
-d supl.grapheneos.org
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
||||||
--key-type ecdsa --reuse-key --must-staple \
|
--key-type ecdsa --reuse-key --preferred-profile tlsserver \
|
||||||
--deploy-hook "certbot-ocsp-fetcher -o /var/cache/certbot-ocsp-fetcher" \
|
--deploy-hook "nginx -s reload" \
|
||||||
--cert-name grapheneos.org \
|
--cert-name grapheneos.org \
|
||||||
-d grapheneos.org \
|
-d grapheneos.org \
|
||||||
-d www.grapheneos.org \
|
-d www.grapheneos.org \
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
||||||
--key-type ecdsa --reuse-key --must-staple \
|
--key-type ecdsa --reuse-key --preferred-profile tlsserver \
|
||||||
--deploy-hook "certbot-ocsp-fetcher -o /var/cache/certbot-ocsp-fetcher" \
|
--deploy-hook "nginx -s reload" \
|
||||||
--cert-name ns1.grapheneos.org \
|
--cert-name ns1.grapheneos.org \
|
||||||
-d ns1.grapheneos.org \
|
-d ns1.grapheneos.org \
|
||||||
-d ns1.attestation.app \
|
-d ns1.attestation.app \
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
||||||
--key-type ecdsa --reuse-key --must-staple \
|
--key-type ecdsa --reuse-key --preferred-profile tlsserver \
|
||||||
--deploy-hook "certbot-ocsp-fetcher -o /var/cache/certbot-ocsp-fetcher" \
|
--deploy-hook "nginx -s reload" \
|
||||||
--cert-name ns2.grapheneos.org \
|
--cert-name ns2.grapheneos.org \
|
||||||
-d ns2.grapheneos.org \
|
-d ns2.grapheneos.org \
|
||||||
-d ns2.attestation.app \
|
-d ns2.attestation.app \
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
||||||
--key-type ecdsa --reuse-key --must-staple \
|
--key-type ecdsa --reuse-key --preferred-profile tlsserver \
|
||||||
--deploy-hook "certbot-ocsp-fetcher -o /var/cache/certbot-ocsp-fetcher" \
|
--deploy-hook "nginx -s reload" \
|
||||||
--cert-name releases.grapheneos.org \
|
--cert-name releases.grapheneos.org \
|
||||||
-d releases.grapheneos.org \
|
-d releases.grapheneos.org \
|
||||||
-d apps.grapheneos.org \
|
-d apps.grapheneos.org \
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
||||||
--key-type ecdsa --reuse-key --must-staple \
|
--key-type ecdsa --reuse-key --preferred-profile tlsserver \
|
||||||
--deploy-hook "certbot-ocsp-fetcher -o /var/cache/certbot-ocsp-fetcher" \
|
--deploy-hook "nginx -s reload" \
|
||||||
--cert-name attestation.app \
|
--cert-name attestation.app \
|
||||||
-d attestation.app \
|
-d attestation.app \
|
||||||
-d www.attestation.app
|
-d www.attestation.app
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
||||||
--key-type ecdsa --reuse-key --must-staple \
|
--key-type ecdsa --reuse-key --preferred-profile tlsserver \
|
||||||
--deploy-hook "certbot-ocsp-fetcher -o /var/cache/certbot-ocsp-fetcher" \
|
--deploy-hook "nginx -s reload" \
|
||||||
--cert-name discuss.grapheneos.org \
|
--cert-name discuss.grapheneos.org \
|
||||||
-d discuss.grapheneos.org
|
-d discuss.grapheneos.org
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
||||||
--key-type ecdsa --reuse-key --must-staple \
|
--key-type ecdsa --reuse-key --preferred-profile tlsserver \
|
||||||
--deploy-hook "certbot-ocsp-fetcher -o /var/cache/certbot-ocsp-fetcher" \
|
--deploy-hook "nginx -s reload" \
|
||||||
--cert-name grapheneos.social \
|
--cert-name grapheneos.social \
|
||||||
-d grapheneos.social \
|
-d grapheneos.social \
|
||||||
-d www.grapheneos.social
|
-d www.grapheneos.social
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
||||||
--key-type ecdsa --reuse-key --must-staple \
|
--key-type ecdsa --reuse-key --preferred-profile tlsserver \
|
||||||
--deploy-hook "certbot-ocsp-fetcher -o /var/cache/certbot-ocsp-fetcher" \
|
--deploy-hook "nginx -s reload" \
|
||||||
--cert-name matrix.grapheneos.org \
|
--cert-name matrix.grapheneos.org \
|
||||||
-d matrix.grapheneos.org \
|
-d matrix.grapheneos.org \
|
||||||
-d element.grapheneos.org
|
-d element.grapheneos.org
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
||||||
--key-type ecdsa --reuse-key --must-staple \
|
--key-type ecdsa --reuse-key --preferred-profile tlsserver \
|
||||||
--deploy-hook "certbot-ocsp-fetcher -o /var/cache/certbot-ocsp-fetcher" \
|
--deploy-hook "nginx -s reload" \
|
||||||
--cert-name mta-sts.mail.grapheneos.org \
|
--cert-name mta-sts.mail.grapheneos.org \
|
||||||
-d mail.grapheneos.org \
|
-d mail.grapheneos.org \
|
||||||
-d mail.grapheneos.net \
|
-d mail.grapheneos.net \
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
||||||
--key-type ecdsa --reuse-key --must-staple \
|
--key-type ecdsa --reuse-key --preferred-profile tlsserver \
|
||||||
--deploy-hook "certbot-ocsp-fetcher -o /var/cache/certbot-ocsp-fetcher" \
|
--deploy-hook "nginx -s reload" \
|
||||||
--cert-name ns1.staging.grapheneos.org \
|
--cert-name ns1.staging.grapheneos.org \
|
||||||
-d ns1.staging.grapheneos.org \
|
-d ns1.staging.grapheneos.org \
|
||||||
-d ns2.staging.grapheneos.org \
|
-d ns2.staging.grapheneos.org \
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
||||||
--key-type ecdsa --reuse-key --must-staple \
|
--key-type ecdsa --reuse-key --preferred-profile tlsserver \
|
||||||
--deploy-hook "certbot-ocsp-fetcher -o /var/cache/certbot-ocsp-fetcher" \
|
--deploy-hook "nginx -s reload" \
|
||||||
--cert-name staging.attestation.app \
|
--cert-name staging.attestation.app \
|
||||||
-d staging.attestation.app
|
-d staging.attestation.app
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
|
||||||
--key-type ecdsa --reuse-key --must-staple \
|
--key-type ecdsa --reuse-key --preferred-profile tlsserver \
|
||||||
--deploy-hook "certbot-ocsp-fetcher -o /var/cache/certbot-ocsp-fetcher" \
|
--deploy-hook "nginx -s reload" \
|
||||||
--cert-name staging.grapheneos.org \
|
--cert-name staging.grapheneos.org \
|
||||||
-d staging.grapheneos.org
|
-d staging.grapheneos.org
|
||||||
|
|
|
@ -5,11 +5,8 @@ IgnoreUnowned = etc/modprobe.d/local.conf
|
||||||
IgnoreUnowned = etc/modules-load.d/local.conf
|
IgnoreUnowned = etc/modules-load.d/local.conf
|
||||||
IgnoreUnowned = etc/sysctl.d/local-tcp_wmem.conf
|
IgnoreUnowned = etc/sysctl.d/local-tcp_wmem.conf
|
||||||
IgnoreUnowned = etc/sysctl.d/local.conf
|
IgnoreUnowned = etc/sysctl.d/local.conf
|
||||||
IgnoreUnowned = etc/systemd/system/certbot-ocsp-fetcher.service
|
|
||||||
IgnoreUnowned = etc/systemd/system/certbot-ocsp-fetcher.timer
|
|
||||||
IgnoreUnowned = lost+found
|
IgnoreUnowned = lost+found
|
||||||
IgnoreUnowned = swapfile
|
IgnoreUnowned = swapfile
|
||||||
IgnoreUnowned = usr/local/bin/certbot-ocsp-fetcher
|
|
||||||
|
|
||||||
[PkgIgnoreUnowned]
|
[PkgIgnoreUnowned]
|
||||||
ca-certificates = etc/ca-certificates/extracted
|
ca-certificates = etc/ca-certificates/extracted
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
[Unit]
|
|
||||||
Description=Fetch OCSP responses for all certificates issued with Certbot
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=oneshot
|
|
||||||
|
|
||||||
Restart=on-failure
|
|
||||||
|
|
||||||
CacheDirectory=%N
|
|
||||||
|
|
||||||
User=root
|
|
||||||
Group=root
|
|
||||||
ExecStart=%N --no-reload-webserver
|
|
||||||
ExecStartPost=systemctl reload nginx.service
|
|
||||||
|
|
||||||
RestartSec=5
|
|
||||||
PrivateDevices=true
|
|
||||||
PrivateTmp=yes
|
|
||||||
PrivateUsers=yes
|
|
||||||
PrivateIPC=true
|
|
||||||
|
|
||||||
NoNewPrivileges=true
|
|
||||||
LockPersonality=true
|
|
||||||
|
|
||||||
CapabilityBoundingSet=
|
|
||||||
ProtectHome=yes
|
|
||||||
ProtectControlGroups=true
|
|
||||||
ProtectKernelTunables=true
|
|
||||||
ProtectKernelModules=true
|
|
||||||
ProtectKernelLogs=true
|
|
||||||
ProtectClock=true
|
|
||||||
ProtectProc=invisible
|
|
||||||
ProcSubset=pid
|
|
||||||
ProtectHostname=true
|
|
||||||
RemoveIPC=true
|
|
||||||
|
|
||||||
RestrictAddressFamilies=AF_INET6 AF_INET AF_UNIX
|
|
||||||
MemoryDenyWriteExecute=true
|
|
||||||
RestrictRealtime=true
|
|
||||||
RestrictNamespaces=true
|
|
||||||
RestrictSUIDSGID=true
|
|
||||||
|
|
||||||
DevicePolicy=strict
|
|
||||||
DeviceAllow=/dev/random r
|
|
||||||
DeviceAllow=/dev/urandom r
|
|
||||||
DeviceAllow=/dev/stdin r
|
|
||||||
DeviceAllow=/dev/stdout r
|
|
||||||
DeviceAllow=/dev/null w
|
|
||||||
|
|
||||||
ProtectSystem=strict
|
|
||||||
InaccessiblePaths=/root/
|
|
||||||
ReadOnlyPaths=/etc/letsencrypt
|
|
||||||
UMask=0077
|
|
||||||
|
|
||||||
SystemCallArchitectures=native
|
|
||||||
SystemCallFilter=@system-service
|
|
||||||
SystemCallFilter=~@clock @debug @module @mount @reboot @swap @resources @cpu-emulation @raw-io @obsolete @keyring @privileged
|
|
|
@ -1,10 +0,0 @@
|
||||||
[Unit]
|
|
||||||
Description=Nightly run %N
|
|
||||||
|
|
||||||
[Timer]
|
|
||||||
OnCalendar=*-*-* 01:00:00
|
|
||||||
RandomizedDelaySec=21600
|
|
||||||
Persistent=true
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=timers.target
|
|
|
@ -19,7 +19,7 @@ ProtectKernelModules=true
|
||||||
ProtectKernelTunables=true
|
ProtectKernelTunables=true
|
||||||
ProtectProc=invisible
|
ProtectProc=invisible
|
||||||
ProtectSystem=strict
|
ProtectSystem=strict
|
||||||
ReadWritePaths=/etc/letsencrypt /var/lib/letsencrypt /var/log/letsencrypt -/srv/certbot -/var/cache/certbot-ocsp-fetcher
|
ReadWritePaths=/etc/letsencrypt /var/lib/letsencrypt /var/log/letsencrypt -/srv/certbot
|
||||||
RestrictAddressFamilies=AF_INET AF_INET6
|
RestrictAddressFamilies=AF_INET AF_INET6
|
||||||
RestrictNamespaces=true
|
RestrictNamespaces=true
|
||||||
RestrictRealtime=true
|
RestrictRealtime=true
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue