Some checks failed
API CI / API Lint (push) Successful in 47s
API CI / API Type Check (push) Failing after 47s
API CI / API Test (push) Successful in 1m0s
API CI / API Build (push) Failing after 50s
API CI / Build Docker Image (push) Has been skipped
Build Crossplane Provider / build (push) Failing after 5m51s
CD Pipeline / Deploy to Staging (push) Failing after 29s
CI Pipeline / Lint and Type Check (push) Failing after 36s
CI Pipeline / Build (push) Has been skipped
CI Pipeline / Test Backend (push) Failing after 1m33s
CI Pipeline / Test Frontend (push) Failing after 30s
CI Pipeline / Security Scan (push) Failing after 1m16s
Crossplane Provider CI / Go Test (push) Failing after 3m23s
Crossplane Provider CI / Go Lint (push) Failing after 7m27s
Crossplane Provider CI / Go Build (push) Failing after 3m27s
Deploy to Staging / Deploy to Staging (push) Failing after 30s
Portal CI / Portal Lint (push) Failing after 21s
Portal CI / Portal Type Check (push) Failing after 21s
Portal CI / Portal Test (push) Failing after 21s
Portal CI / Portal Build (push) Failing after 22s
Test Suite / frontend-tests (push) Failing after 30s
Test Suite / api-tests (push) Failing after 49s
Test Suite / blockchain-tests (push) Failing after 30s
Type Check / type-check (map[directory:. name:root]) (push) Failing after 23s
Type Check / type-check (map[directory:api name:api]) (push) Failing after 21s
Type Check / type-check (map[directory:portal name:portal]) (push) Failing after 19s
Validate Configuration Files / validate (push) Failing after 1m52s
CD Pipeline / Deploy to Production (push) Has been skipped
Co-authored-by: Cursor <cursoragent@cursor.com>
255 lines
6.5 KiB
Bash
Executable File
255 lines
6.5 KiB
Bash
Executable File
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
# Proxmox Certificate Verification Script
|
|
# Verifies ACME certificate installation and validity on Proxmox nodes
|
|
|
|
# Color codes for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Configuration
|
|
NODES=(
|
|
"ml110-01.sankofa.nexus:192.168.11.10"
|
|
"r630-01.sankofa.nexus:192.168.11.11"
|
|
)
|
|
PORT=8006
|
|
WARN_DAYS=30 # Warn if certificate expires in less than 30 days
|
|
|
|
log() {
|
|
echo -e "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $*" >&2
|
|
}
|
|
|
|
info() {
|
|
echo -e "${GREEN}✓${NC} $*"
|
|
}
|
|
|
|
warn() {
|
|
echo -e "${YELLOW}⚠${NC} $*" >&2
|
|
}
|
|
|
|
error() {
|
|
echo -e "${RED}✗${NC} $*" >&2
|
|
}
|
|
|
|
# Check if openssl is available
|
|
check_openssl() {
|
|
if ! command -v openssl &> /dev/null; then
|
|
error "openssl is not installed. Please install openssl to use this script."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Get certificate expiration date
|
|
get_cert_expiry() {
|
|
local hostname=$1
|
|
local ip=$2
|
|
local port=$3
|
|
|
|
# Connect and extract expiration date
|
|
local expiry=$(echo | openssl s_client -connect "${ip}:${port}" -servername "${hostname}" 2>/dev/null | \
|
|
openssl x509 -noout -enddate 2>/dev/null | \
|
|
cut -d= -f2)
|
|
|
|
if [ -z "${expiry}" ]; then
|
|
return 1
|
|
fi
|
|
|
|
echo "${expiry}"
|
|
}
|
|
|
|
# Calculate days until expiration
|
|
days_until_expiry() {
|
|
local expiry_date=$1
|
|
|
|
# Convert expiry date to epoch timestamp
|
|
# Try Linux date format first, then macOS format
|
|
local expiry_epoch
|
|
if expiry_epoch=$(date -d "${expiry_date}" +%s 2>/dev/null); then
|
|
:
|
|
elif expiry_epoch=$(date -j -f "%b %d %H:%M:%S %Y %Z" "${expiry_date}" +%s 2>/dev/null); then
|
|
:
|
|
else
|
|
return 1
|
|
fi
|
|
|
|
local now_epoch=$(date +%s)
|
|
local diff=$((expiry_epoch - now_epoch))
|
|
local days=$((diff / 86400))
|
|
|
|
echo "${days}"
|
|
}
|
|
|
|
# Get certificate issuer
|
|
get_cert_issuer() {
|
|
local hostname=$1
|
|
local ip=$2
|
|
local port=$3
|
|
|
|
local issuer=$(echo | openssl s_client -connect "${ip}:${port}" -servername "${hostname}" 2>/dev/null | \
|
|
openssl x509 -noout -issuer 2>/dev/null | \
|
|
sed 's/issuer=//')
|
|
|
|
echo "${issuer}"
|
|
}
|
|
|
|
# Get certificate subject
|
|
get_cert_subject() {
|
|
local hostname=$1
|
|
local ip=$2
|
|
local port=$3
|
|
|
|
local subject=$(echo | openssl s_client -connect "${ip}:${port}" -servername "${hostname}" 2>/dev/null | \
|
|
openssl x509 -noout -subject 2>/dev/null | \
|
|
sed 's/subject=//')
|
|
|
|
echo "${subject}"
|
|
}
|
|
|
|
# Get certificate SANs (Subject Alternative Names)
|
|
get_cert_sans() {
|
|
local hostname=$1
|
|
local ip=$2
|
|
local port=$3
|
|
|
|
local sans=$(echo | openssl s_client -connect "${ip}:${port}" -servername "${hostname}" 2>/dev/null | \
|
|
openssl x509 -noout -text 2>/dev/null | \
|
|
grep -A1 "Subject Alternative Name" | \
|
|
sed 's/.*DNS://g' | \
|
|
tr ',' '\n' | \
|
|
sed 's/^ *//' | \
|
|
grep -v "^$")
|
|
|
|
echo "${sans}"
|
|
}
|
|
|
|
# Test SSL connection
|
|
test_ssl_connection() {
|
|
local hostname=$1
|
|
local ip=$2
|
|
local port=$3
|
|
|
|
# Test connection and get certificate
|
|
local output=$(echo | openssl s_client -connect "${ip}:${port}" -servername "${hostname}" 2>&1)
|
|
|
|
if echo "${output}" | grep -q "Verify return code: 0"; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Verify certificate for a node
|
|
verify_node_cert() {
|
|
local node_info=$1
|
|
local hostname=$(echo "${node_info}" | cut -d: -f1)
|
|
local ip=$(echo "${node_info}" | cut -d: -f2)
|
|
|
|
log "Checking certificate for ${hostname} (${ip}:${PORT})..."
|
|
|
|
# Test SSL connection
|
|
if ! test_ssl_connection "${hostname}" "${ip}" "${PORT}"; then
|
|
error "SSL connection failed for ${hostname}"
|
|
return 1
|
|
fi
|
|
|
|
info "SSL connection successful"
|
|
|
|
# Get certificate details
|
|
local issuer=$(get_cert_issuer "${hostname}" "${ip}" "${PORT}")
|
|
local subject=$(get_cert_subject "${hostname}" "${ip}" "${PORT}")
|
|
local expiry=$(get_cert_expiry "${hostname}" "${ip}" "${PORT}")
|
|
|
|
if [ -z "${expiry}" ]; then
|
|
error "Could not retrieve certificate expiration for ${hostname}"
|
|
return 1
|
|
fi
|
|
|
|
# Check if certificate is from Let's Encrypt
|
|
if echo "${issuer}" | grep -qi "lets encrypt\|let's encrypt\|letsencrypt"; then
|
|
info "Certificate issuer: Let's Encrypt"
|
|
else
|
|
warn "Certificate issuer: ${issuer}"
|
|
warn "Certificate may not be from Let's Encrypt"
|
|
fi
|
|
|
|
# Display certificate subject
|
|
info "Certificate subject: ${subject}"
|
|
|
|
# Check expiration
|
|
local days=$(days_until_expiry "${expiry}")
|
|
|
|
if [ "${days}" -lt 0 ]; then
|
|
error "Certificate expired ${days#-} days ago!"
|
|
error "Expiration date: ${expiry}"
|
|
return 1
|
|
elif [ "${days}" -lt "${WARN_DAYS}" ]; then
|
|
warn "Certificate expires in ${days} days (${expiry})"
|
|
warn "Renewal should occur automatically, but please monitor"
|
|
else
|
|
info "Certificate expires in ${days} days (${expiry})"
|
|
fi
|
|
|
|
# Get and display SANs
|
|
local sans=$(get_cert_sans "${hostname}" "${ip}" "${PORT}")
|
|
if [ -n "${sans}" ]; then
|
|
info "Certificate SANs:"
|
|
echo "${sans}" | while read -r san; do
|
|
echo " - ${san}"
|
|
done
|
|
fi
|
|
|
|
# Verify hostname matches
|
|
if echo "${subject}" | grep -qi "${hostname}" || echo "${sans}" | grep -qi "${hostname}"; then
|
|
info "Hostname ${hostname} matches certificate"
|
|
else
|
|
warn "Hostname ${hostname} may not match certificate"
|
|
warn "Subject: ${subject}"
|
|
fi
|
|
|
|
echo ""
|
|
return 0
|
|
}
|
|
|
|
# Main verification function
|
|
main() {
|
|
log "Proxmox Certificate Verification Script"
|
|
log "========================================"
|
|
echo ""
|
|
|
|
check_openssl
|
|
|
|
local total_nodes=${#NODES[@]}
|
|
local passed=0
|
|
local failed=0
|
|
|
|
for node_info in "${NODES[@]}"; do
|
|
if verify_node_cert "${node_info}"; then
|
|
((passed++))
|
|
else
|
|
((failed++))
|
|
fi
|
|
done
|
|
|
|
echo ""
|
|
log "========================================"
|
|
log "Verification Summary"
|
|
log "========================================"
|
|
info "Total nodes checked: ${total_nodes}"
|
|
info "Passed: ${passed}"
|
|
if [ "${failed}" -gt 0 ]; then
|
|
error "Failed: ${failed}"
|
|
exit 1
|
|
else
|
|
info "All certificates are valid"
|
|
exit 0
|
|
fi
|
|
}
|
|
|
|
# Run main function
|
|
main "$@"
|
|
|