certman/certman.sh

269 lines
7.8 KiB
Bash
Raw Normal View History

2025-02-28 21:25:33 +01:00
#!/bin/bash
2025-03-03 12:37:55 +01:00
# Exit on any error, treat unset variables as errors, and propagate errors in pipelines
set -euo pipefail
2025-03-03 14:06:31 +01:00
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
2025-03-03 12:37:55 +01:00
exit 1
2025-03-03 14:06:31 +01:00
}
load_env || exit 1
2025-02-28 21:25:33 +01:00
2025-03-03 13:23:13 +01:00
AUTO_MODE="false"
2025-03-03 13:30:15 +01:00
FORCE_UPDATE="false"
FULLCHAIN_PEM="${FULLCHAIN_PEM:-false}"
2025-03-03 13:23:13 +01:00
while [[ $# -gt 0 ]]; do
case $1 in
--silent)
AUTO_MODE="true"
shift
;;
2025-03-03 13:30:15 +01:00
--force)
FORCE_UPDATE="true"
shift
;;
--fullchain-pem)
FULLCHAIN_PEM="true"
shift
;;
2025-03-03 13:23:13 +01:00
*)
shift
;;
esac
done
2025-02-28 21:25:33 +01:00
GREEN='\033[0;32m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
2025-03-03 12:37:55 +01:00
TEMP_DIR=$(mktemp -d)
trap 'rm -rf "$TEMP_DIR"' EXIT
2025-02-28 21:25:33 +01:00
check_requirements() {
2025-03-03 12:37:55 +01:00
local required_commands=("curl" "jq" "openssl")
2025-02-28 21:25:33 +01:00
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
}
validate_api_key() {
local api_key=$1
2025-03-03 12:37:55 +01:00
[[ $api_key =~ ^[A-Za-z0-9_-]{32,}$ ]]
2025-02-28 21:25:33 +01:00
}
setup_directories() {
2025-03-03 12:37:55 +01:00
local dirs=("$CERT_PATH" "$KEY_PATH" "$TEMP_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
2025-02-28 21:25:33 +01:00
}
2025-03-03 12:37:55 +01:00
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_cert_pem="$TEMP_DIR/$domain.cert.pem"
local temp_key_pem="$TEMP_DIR/$domain.key.pem"
2025-02-28 21:25:33 +01:00
2025-03-03 12:37:55 +01:00
echo -e "${BLUE}Processing certificate for $domain${NC}"
2025-02-28 21:25:33 +01:00
# Download certificate
2025-03-03 13:30:15 +01:00
if ! curl -s -fL -o "$temp_cert" -H "X-API-Key: $cert_api_key" \
2025-03-03 12:37:55 +01:00
"https://$CERTWARDEN_SERVER/certwarden/api/v1/download/certificates/$domain"; then
echo -e "${RED}Failed to download certificate for $domain${NC}"
2025-02-28 21:25:33 +01:00
return 1
fi
# Download private key
2025-03-03 13:30:15 +01:00
if ! curl -s -fL -o "$temp_key" -H "X-API-Key: $key_api_key" \
2025-03-03 12:37:55 +01:00
"https://$CERTWARDEN_SERVER/certwarden/api/v1/download/privatekeys/$domain"; then
echo -e "${RED}Failed to download private key for $domain${NC}"
return 1
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
# Create PEM files if requested
if [ "$FULLCHAIN_PEM" = "true" ]; then
cat "$temp_cert" > "$temp_cert_pem"
cat "$temp_key" > "$temp_key_pem"
fi
2025-03-03 12:37:55 +01:00
# Validate certificate and key match
local cert_fingerprint
cert_fingerprint=$(openssl x509 -in "$temp_cert" -noout -pubkey |
openssl pkey -pubin -outform DER 2>/dev/null |
openssl dgst -sha256)
local key_fingerprint
key_fingerprint=$(openssl pkey -in "$temp_key" -pubout -outform DER 2>/dev/null |
openssl dgst -sha256)
if [ "$cert_fingerprint" != "$key_fingerprint" ]; then
echo -e "${RED}Certificate and key do not match for $domain${NC}"
2025-02-28 21:25:33 +01:00
return 1
fi
return 0
}
install_certificate() {
2025-03-03 12:37:55 +01:00
local domain=$1
local final_cert="$CERT_PATH/$domain.crt"
local final_key="$KEY_PATH/$domain.key"
local final_cert_pem="$CERT_PATH/$domain.cert.pem"
local final_key_pem="$KEY_PATH/$domain.key.pem"
2025-03-03 12:37:55 +01:00
local temp_cert="$TEMP_DIR/$domain.crt"
local temp_key="$TEMP_DIR/$domain.key"
local temp_cert_pem="$TEMP_DIR/$domain.cert.pem"
local temp_key_pem="$TEMP_DIR/$domain.key.pem"
2025-03-03 12:37:55 +01:00
local needs_reload=0
# Check if certificate needs updating
2025-03-03 13:30:15 +01:00
if [ "$FORCE_UPDATE" = "true" ]; then
needs_reload=1
elif [ "$FULLCHAIN_PEM" = "true" ] && [ -f "$final_cert_pem" ]; then
if ! cmp -s "$final_cert_pem" "$temp_cert_pem"; then
needs_reload=1
fi
2025-03-03 13:30:15 +01:00
elif [ -f "$final_cert" ]; then
2025-03-03 12:37:55 +01:00
if ! cmp -s "$final_cert" "$temp_cert"; then
needs_reload=1
fi
else
needs_reload=1
fi
2025-02-28 21:25:33 +01:00
2025-03-03 12:37:55 +01:00
# Install new certificate and key
if [ $needs_reload -eq 1 ]; then
if [ "$FULLCHAIN_PEM" = "true" ]; then
if ! cp -f "$temp_cert_pem" "$final_cert_pem" || ! cp -f "$temp_key_pem" "$final_key_pem"; then
echo -e "${RED}Failed to install PEM files for $domain${NC}"
return 1
fi
local files=("$final_cert_pem" "$final_key_pem")
else
if ! cp -f "$temp_cert" "$final_cert" || ! cp -f "$temp_key" "$final_key"; then
echo -e "${RED}Failed to install certificate files for $domain${NC}"
return 1
fi
local files=("$final_cert" "$final_key")
2025-03-03 12:37:55 +01:00
fi
2025-02-28 21:48:08 +01:00
# Set permissions and ownership
for file in "${files[@]}"; do
if ! chown "$CERT_OWNER:$CERT_GROUP" "$file" || \
! chmod "$CERT_PERMISSIONS" "$file"; then
echo -e "${RED}Failed to set permissions for $file${NC}"
return 1
fi
done
2025-03-03 12:37:55 +01:00
echo -e "${GREEN}Certificate updated for $domain${NC}"
2025-02-28 21:25:33 +01:00
return 0
fi
2025-03-03 12:37:55 +01:00
echo -e "${BLUE}Certificate already up to date for $domain${NC}"
return 2
2025-02-28 21:25:33 +01:00
}
2025-03-03 12:37:55 +01:00
process_certificates() {
local service_reloaded=0
local certs_array
certs_array=$(echo "$CERTIFICATES" | jq -c '.[]')
while IFS= read -r cert; do
2025-03-03 13:23:13 +01:00
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')
2025-03-03 12:37:55 +01:00
if download_and_verify_cert "$domain" "$cert_api_key" "$key_api_key"; then
if install_certificate "$domain"; then
service_reloaded=1
2025-02-28 21:48:08 +01:00
fi
2025-03-03 12:37:55 +01:00
fi
done <<< "$certs_array"
# Reload service if needed
if [ $service_reloaded -eq 1 ]; then
echo -e "${BLUE}Reloading $SERVICE_NAME service...${NC}"
if systemctl reload "$SERVICE_NAME"; then
echo -e "${GREEN}Service reloaded successfully${NC}"
2025-02-28 21:48:08 +01:00
else
2025-03-03 12:37:55 +01:00
echo -e "${RED}Failed to reload service${NC}"
return 1
2025-02-28 21:48:08 +01:00
fi
2025-03-03 12:37:55 +01:00
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" ]; then
process_certificates
2025-02-28 21:48:08 +01:00
exit 0
fi
2025-02-28 21:25:33 +01:00
while true; do
2025-03-03 12:37:55 +01:00
echo -e "\n${BLUE}Certificate Management Menu${NC}"
echo "1. Process all certificates"
2025-02-28 21:25:33 +01:00
echo "2. List installed certificates"
echo "3. Check certificate expiration"
2025-03-03 13:35:14 +01:00
echo "4. Force update all certificates"
echo "5. Exit"
2025-02-28 21:48:08 +01:00
2025-03-03 13:35:14 +01:00
read -r -p "Select an option (1-5): " choice
2025-02-28 21:25:33 +01:00
case $choice in
2025-03-03 13:35:14 +01:00
1) FORCE_UPDATE="false"; process_certificates ;;
2025-03-03 12:37:55 +01:00
2) ls -l "$CERT_PATH"/*.crt 2>/dev/null || echo "No certificates found" ;;
3) check_cert_expiration ;;
2025-03-03 13:35:14 +01:00
4) FORCE_UPDATE="true"; process_certificates; FORCE_UPDATE="false" ;;
5) echo -e "${GREEN}Exiting...${NC}"; exit 0 ;;
2025-03-03 12:37:55 +01:00
*) echo -e "${RED}Invalid option${NC}" ;;
2025-02-28 21:25:33 +01:00
esac
done
}
# Script initialization
check_requirements
setup_directories
main_menu