Replace separate cp and chmod operations with single install commands for certificate, key, and PEM file installation to ensure proper permissions and ownership are set in one operation
288 lines
8.9 KiB
Bash
Executable file
288 lines
8.9 KiB
Bash
Executable file
#!/bin/bash
|
|
|
|
# Exit on any error, treat unset variables as errors, and propagate errors in pipelines
|
|
set -euo pipefail
|
|
|
|
load_env() {
|
|
local paths=(
|
|
"$(pwd)/.env"
|
|
"$(dirname "$(realpath "$0")")/.env"
|
|
"$(dirname "$(realpath "$0")")/.env.$(basename "$(realpath "$0")")"
|
|
"$(dirname "$(readlink "$0")")/.env.$(basename "$0")"
|
|
"/opt/skyfritt-tools-env/.env.$(basename "$0")"
|
|
)
|
|
|
|
for path in "${paths[@]}"; do
|
|
if [[ -f "$path" ]]; then
|
|
source "$path" && return 0
|
|
fi
|
|
done
|
|
|
|
echo "Error: .env file not found in any location" >&2
|
|
exit 1
|
|
}
|
|
|
|
load_env || exit 1
|
|
|
|
AUTO_MODE="false"
|
|
FORCE_UPDATE="false"
|
|
SERVICE_SUPPORTS="${SERVICE_SUPPORTS:-reload}"
|
|
FULLCHAIN_PEM="${FULLCHAIN_PEM:-true}"
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--silent)
|
|
AUTO_MODE="true"
|
|
shift
|
|
;;
|
|
--force)
|
|
FORCE_UPDATE="true"
|
|
shift
|
|
;;
|
|
--disable-pem)
|
|
FULLCHAIN_PEM="false"
|
|
shift
|
|
;;
|
|
--restart)
|
|
SERVICE_SUPPORTS="restart"
|
|
shift
|
|
;;
|
|
*)
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
|
|
GREEN='\033[0;32m'
|
|
RED='\033[0;31m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
TEMP_DIR=$(mktemp -d)
|
|
trap 'rm -rf "$TEMP_DIR"' EXIT
|
|
|
|
check_requirements() {
|
|
local required_commands=("curl" "jq" "openssl")
|
|
for cmd in "${required_commands[@]}"; do
|
|
if ! command -v "$cmd" &> /dev/null; then
|
|
echo -e "${RED}Error: Required command '$cmd' is not installed.${NC}"
|
|
exit 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
setup_directories() {
|
|
local dirs=("$CERT_PATH" "$KEY_PATH")
|
|
for dir in "${dirs[@]}"; do
|
|
if ! mkdir -p "$dir"; then
|
|
echo -e "${RED}Error: Failed to create directory: $dir${NC}"
|
|
exit 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
download_and_verify_cert() {
|
|
local domain=$1
|
|
local cert_api_key=$2
|
|
local key_api_key=$3
|
|
local temp_cert="$TEMP_DIR/$domain.crt"
|
|
local temp_key="$TEMP_DIR/$domain.key"
|
|
local temp_pem="$TEMP_DIR/$domain.pem"
|
|
|
|
echo -e "${BLUE}Processing certificate for $domain${NC}"
|
|
|
|
# Download certificate
|
|
if ! curl -s -fL -o "$temp_cert" -H "X-API-Key: $cert_api_key" \
|
|
"https://$CERTWARDEN_SERVER/certwarden/api/v1/download/certificates/$domain"; then
|
|
echo -e "${RED}Failed to download certificate for $domain${NC}"
|
|
return 1
|
|
fi
|
|
|
|
# Download private key
|
|
if ! curl -s -fL -o "$temp_key" -H "X-API-Key: $key_api_key" \
|
|
"https://$CERTWARDEN_SERVER/certwarden/api/v1/download/privatekeys/$domain"; then
|
|
echo -e "${RED}Failed to download private key for $domain${NC}"
|
|
return 1
|
|
fi
|
|
|
|
# Download fullchain PEM file
|
|
if [ "$FULLCHAIN_PEM" = "true" ]; then
|
|
if ! curl -s -fL -o "$temp_pem" -H "X-API-Key: $cert_api_key.$key_api_key" \
|
|
"https://$CERTWARDEN_SERVER/certwarden/api/v1/download/privatecertchains/$domain"; then
|
|
echo -e "${RED}Failed to download fullchain PEM file for $domain${NC}"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
# Verify files are not empty
|
|
if [ ! -s "$temp_cert" ] || [ ! -s "$temp_key" ]; then
|
|
echo -e "${RED}Downloaded files are empty for $domain${NC}"
|
|
return 1
|
|
fi
|
|
if [ "$FULLCHAIN_PEM" = "true" ] && [ ! -s "$temp_pem" ]; then
|
|
echo -e "${RED}Downloaded PEM file is empty for $domain${NC}"
|
|
return 1
|
|
fi
|
|
|
|
# Validate certificate and key match
|
|
local cert_fingerprint key_fingerprint
|
|
cert_fingerprint=$(openssl x509 -in "$temp_cert" -noout -pubkey |
|
|
openssl pkey -pubin -outform DER |
|
|
openssl dgst -sha256) || true
|
|
key_fingerprint=$(openssl pkey -in "$temp_key" -pubout -outform DER |
|
|
openssl dgst -sha256) || true
|
|
|
|
if [ -z "$cert_fingerprint" ] || [ -z "$key_fingerprint" ]; then
|
|
echo -e "${RED}Failed to extract fingerprints for $domain${NC}"
|
|
return 1
|
|
fi
|
|
|
|
if [ "$cert_fingerprint" != "$key_fingerprint" ]; then
|
|
echo -e "${RED}Certificate and key do not match for $domain${NC}"
|
|
return 1
|
|
fi
|
|
|
|
if [ "$FULLCHAIN_PEM" = "true" ]; then
|
|
local pem_fingerprint
|
|
pem_fingerprint=$(openssl x509 -in "$temp_pem" -noout -pubkey |
|
|
openssl pkey -pubin -outform DER |
|
|
openssl dgst -sha256) || true
|
|
if [ -z "$pem_fingerprint" ]; then
|
|
echo -e "${RED}Failed to extract PEM fingerprint for $domain${NC}"
|
|
return 1
|
|
fi
|
|
if [ "$cert_fingerprint" != "$pem_fingerprint" ]; then
|
|
echo -e "${RED}Certificate and PEM file do not match for $domain${NC}"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
install_certificate() {
|
|
local domain=$1
|
|
local final_cert="$CERT_PATH/$domain.crt"
|
|
local final_key="$KEY_PATH/$domain.key"
|
|
local final_pem="$KEY_PATH/$domain.pem"
|
|
local temp_cert="$TEMP_DIR/$domain.crt"
|
|
local temp_key="$TEMP_DIR/$domain.key"
|
|
local temp_pem="$TEMP_DIR/$domain.pem"
|
|
local needs_reload=0
|
|
|
|
# Check if certificate needs updating
|
|
if [ "$FORCE_UPDATE" = "true" ]; then
|
|
needs_reload=1
|
|
elif [ ! -f "$final_cert" ] || [ ! -f "$final_key" ]; then
|
|
needs_reload=1
|
|
elif ! cmp -s "$final_cert" "$temp_cert" || ! cmp -s "$final_key" "$temp_key"; then
|
|
needs_reload=1
|
|
elif [ "$FULLCHAIN_PEM" = "true" ] && [ -f "$final_pem" ] && ! cmp -s "$final_pem" "$temp_pem"; then
|
|
needs_reload=1
|
|
elif [ "$FULLCHAIN_PEM" = "true" ] && [ ! -f "$final_pem" ]; then
|
|
needs_reload=1
|
|
fi
|
|
|
|
# Install new certificate and key
|
|
if [ $needs_reload -eq 1 ]; then
|
|
if ! install -m "$CERT_PERMISSIONS" -o "$CERT_OWNER" -g "$CERT_GROUP" "$temp_cert" "$final_cert"; then
|
|
echo -e "${RED}Failed to install certificate for $domain${NC}"
|
|
return 1
|
|
fi
|
|
if ! install -m "$KEY_PERMISSIONS" -o "$CERT_OWNER" -g "$CERT_GROUP" "$temp_key" "$final_key"; then
|
|
echo -e "${RED}Failed to install private key for $domain${NC}"
|
|
return 1
|
|
fi
|
|
|
|
if [ "$FULLCHAIN_PEM" = "true" ]; then
|
|
if ! install -m "$KEY_PERMISSIONS" -o "$CERT_OWNER" -g "$CERT_GROUP" "$temp_pem" "$final_pem"; then
|
|
echo -e "${RED}Failed to install PEM file for $domain${NC}"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
echo -e "${GREEN}Certificate updated for $domain${NC}"
|
|
return 0
|
|
fi
|
|
|
|
echo -e "${BLUE}Certificate already up to date for $domain${NC}"
|
|
return 2
|
|
}
|
|
|
|
process_certificates() {
|
|
local service_reloaded=0
|
|
local certs_array
|
|
certs_array=$(echo "$CERTIFICATES" | jq -c '.[]')
|
|
|
|
while IFS= read -r cert; do
|
|
local domain cert_api_key key_api_key
|
|
domain=$(echo "$cert" | jq -r '.domain')
|
|
cert_api_key=$(echo "$cert" | jq -r '.cert_api_key')
|
|
key_api_key=$(echo "$cert" | jq -r '.key_api_key')
|
|
|
|
if download_and_verify_cert "$domain" "$cert_api_key" "$key_api_key"; then
|
|
if install_certificate "$domain"; then
|
|
service_reloaded=1
|
|
fi
|
|
fi
|
|
done <<< "$certs_array"
|
|
|
|
# Reload service if needed
|
|
if [ $service_reloaded -eq 1 ]; then
|
|
if [[ $SERVICE_SUPPORTS = reload ]]; then
|
|
echo -e "${BLUE}Reloading $SERVICE_NAME service...${NC}"
|
|
if systemctl reload "$SERVICE_NAME"; then
|
|
echo -e "${GREEN}Service reloaded successfully${NC}"
|
|
else
|
|
echo -e "${RED}Failed to reload service${NC}"
|
|
return 1
|
|
fi
|
|
elif [[ $SERVICE_SUPPORTS = restart ]]; then
|
|
echo -e "${BLUE}Restarting $SERVICE_NAME service...${NC}"
|
|
if systemctl restart "$SERVICE_NAME"; then
|
|
echo -e "${GREEN}Service restarted successfully${NC}"
|
|
else
|
|
echo -e "${RED}Failed to restart service${NC}"
|
|
return 1
|
|
fi
|
|
fi
|
|
fi
|
|
}
|
|
|
|
check_cert_expiration() {
|
|
echo -e "\n${BLUE}Certificate Expiration Dates:${NC}"
|
|
for cert in "$CERT_PATH"/*.crt; do
|
|
if [ -f "$cert" ]; then
|
|
echo -n "$(basename "$cert"): "
|
|
openssl x509 -enddate -noout -in "$cert"
|
|
fi
|
|
done
|
|
}
|
|
|
|
main_menu() {
|
|
if [ "$AUTO_MODE" = "true" ] || [ "$FORCE_UPDATE" = "true" ]; then
|
|
process_certificates
|
|
exit 0
|
|
fi
|
|
|
|
echo -e "\n${BLUE}Certificate Management Menu${NC}"
|
|
echo "1. Process all certificates"
|
|
echo "2. List installed certificates"
|
|
echo "3. Check certificate expiration"
|
|
echo "4. Force update all certificates"
|
|
|
|
read -r -p "Select an option (1-4): " choice
|
|
|
|
case $choice in
|
|
1) FORCE_UPDATE="false"; process_certificates ;;
|
|
2) ls -l "$CERT_PATH"/*.crt 2>/dev/null || echo "No certificates found" ;;
|
|
3) check_cert_expiration ;;
|
|
4) FORCE_UPDATE="true"; process_certificates; FORCE_UPDATE="false" ;;
|
|
*) echo -e "${RED}Invalid option${NC}" ;;
|
|
esac
|
|
}
|
|
|
|
# Script initialization
|
|
check_requirements
|
|
setup_directories
|
|
main_menu
|