mirror of
https://github.com/angristan/openvpn-install.git
synced 2025-12-31 06:57:02 +01:00
fix: support fingerprint mode in client management operations (#1446)
## Summary Fixes fingerprint mode (OpenVPN 2.6+ peer-fingerprint authentication) which was broken for client management operations. ### CI Fix Docker environment variables (`AUTH_MODE`, etc.) weren't being passed to the systemd service running tests. Added `PassEnvironment` directive to fix this. ### Script Fixes In fingerprint mode, `easyrsa self-sign-*` commands don't create/maintain `index.txt`, but several functions depended on it. **Fixed operations:** - `selectClient()`: uses fingerprints from server.conf instead of index.txt - `listClients()`: scans certs in pki/issued/, marks those without fingerprint as revoked - `newClient()`: duplicate check works in fingerprint mode, cleans up revoked cert files for name reuse - `revokeClient()`: removes fingerprint from server.conf, keeps cert for listing - `renewClient()`: uses `self-sign-client` instead of `easyrsa renew` - `renewServer()`: uses `self-sign-server` + regenerates all client configs (they embed server fingerprint) **New helpers:** - `getAuthMode()` - returns "pki" or "fingerprint" - `getClientsFromFingerprints()` - parses client names from server.conf - `clientExistsInFingerprints()` - checks client existence - `getCertExpiry()` - extracts expiry date/days from cert file - `removeCertFiles()` - removes cert/key/req files for regeneration - `extractFingerprint()` - gets SHA256 fingerprint from cert Fixes #1444
This commit is contained in:
@@ -3536,6 +3536,83 @@ function generateClientConfig() {
|
|||||||
} >>"$filepath"
|
} >>"$filepath"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Helper function to get the current auth mode
|
||||||
|
# Returns: "pki" or "fingerprint"
|
||||||
|
function getAuthMode() {
|
||||||
|
if [[ -f /etc/openvpn/server/easy-rsa/AUTH_MODE_GENERATED ]]; then
|
||||||
|
cat /etc/openvpn/server/easy-rsa/AUTH_MODE_GENERATED
|
||||||
|
else
|
||||||
|
echo "pki"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Helper function to get valid client names from server.conf fingerprint block
|
||||||
|
# In fingerprint mode, clients are tracked via comments in the <peer-fingerprint> block
|
||||||
|
# Format in server.conf:
|
||||||
|
# <peer-fingerprint>
|
||||||
|
# # client_name
|
||||||
|
# SHA256:fingerprint
|
||||||
|
# </peer-fingerprint>
|
||||||
|
# Returns: newline-separated list of client names
|
||||||
|
function getClientsFromFingerprints() {
|
||||||
|
local server_conf="/etc/openvpn/server/server.conf"
|
||||||
|
if [[ ! -f "$server_conf" ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
# Extract client names from comments in peer-fingerprint block
|
||||||
|
# Comments are in format "# client_name" on lines before fingerprints
|
||||||
|
sed -n '/<peer-fingerprint>/,/<\/peer-fingerprint>/p' "$server_conf" | grep "^# " | sed 's/^# //'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Helper function to check if a client exists in fingerprint mode
|
||||||
|
# Arguments: client_name
|
||||||
|
# Returns: 0 if exists, 1 if not
|
||||||
|
function clientExistsInFingerprints() {
|
||||||
|
local client_name="$1"
|
||||||
|
getClientsFromFingerprints | grep -qx "$client_name"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Helper function to get certificate expiry info
|
||||||
|
# Arguments: cert_file_path
|
||||||
|
# Outputs: expiry_date|days_remaining (pipe-separated)
|
||||||
|
function getCertExpiry() {
|
||||||
|
local cert_file="$1"
|
||||||
|
local expiry_date="unknown"
|
||||||
|
local days_remaining="null"
|
||||||
|
|
||||||
|
if [[ -f "$cert_file" ]]; then
|
||||||
|
local enddate
|
||||||
|
enddate=$(openssl x509 -enddate -noout -in "$cert_file" 2>/dev/null | cut -d= -f2)
|
||||||
|
if [[ -n "$enddate" ]]; then
|
||||||
|
local expiry_epoch
|
||||||
|
expiry_epoch=$(date -d "$enddate" +%s 2>/dev/null || date -j -f "%b %d %H:%M:%S %Y %Z" "$enddate" +%s 2>/dev/null)
|
||||||
|
if [[ -n "$expiry_epoch" ]]; then
|
||||||
|
expiry_date=$(date -d "@$expiry_epoch" +%Y-%m-%d 2>/dev/null || date -r "$expiry_epoch" +%Y-%m-%d 2>/dev/null)
|
||||||
|
local now_epoch
|
||||||
|
now_epoch=$(date +%s)
|
||||||
|
days_remaining=$(((expiry_epoch - now_epoch) / 86400))
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo "$expiry_date|$days_remaining"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Helper function to remove certificate files for regeneration
|
||||||
|
# Arguments: name (client or server name)
|
||||||
|
# Must be called from easy-rsa directory
|
||||||
|
function removeCertFiles() {
|
||||||
|
local name="$1"
|
||||||
|
rm -f "pki/issued/$name.crt" "pki/private/$name.key" "pki/reqs/$name.req"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Helper function to extract SHA256 fingerprint from certificate
|
||||||
|
# Arguments: cert_file_path
|
||||||
|
# Outputs: fingerprint string or empty on failure
|
||||||
|
function extractFingerprint() {
|
||||||
|
local cert_file="$1"
|
||||||
|
openssl x509 -in "$cert_file" -fingerprint -sha256 -noout 2>/dev/null | cut -d'=' -f2
|
||||||
|
}
|
||||||
|
|
||||||
# Helper function to list valid clients and select one
|
# Helper function to list valid clients and select one
|
||||||
# Arguments: show_expiry (optional, "true" to show expiry info)
|
# Arguments: show_expiry (optional, "true" to show expiry info)
|
||||||
# Sets global variables:
|
# Sets global variables:
|
||||||
@@ -3545,21 +3622,36 @@ function generateClientConfig() {
|
|||||||
function selectClient() {
|
function selectClient() {
|
||||||
local show_expiry="${1:-false}"
|
local show_expiry="${1:-false}"
|
||||||
local client_number
|
local client_number
|
||||||
|
local auth_mode
|
||||||
|
local clients_list
|
||||||
|
|
||||||
|
auth_mode=$(getAuthMode)
|
||||||
|
|
||||||
|
# Get list of valid clients based on auth mode
|
||||||
|
if [[ $auth_mode == "fingerprint" ]]; then
|
||||||
|
# Fingerprint mode: get clients from server.conf peer-fingerprint block
|
||||||
|
clients_list=$(getClientsFromFingerprints)
|
||||||
|
NUMBEROFCLIENTS=$(echo "$clients_list" | grep -c . || echo 0)
|
||||||
|
else
|
||||||
|
# PKI mode: get valid clients from index.txt
|
||||||
|
clients_list=$(tail -n +2 /etc/openvpn/server/easy-rsa/pki/index.txt 2>/dev/null | grep "^V" | cut -d '=' -f 2)
|
||||||
|
NUMBEROFCLIENTS=$(echo "$clients_list" | grep -c . || echo 0)
|
||||||
|
fi
|
||||||
|
|
||||||
NUMBEROFCLIENTS=$(tail -n +2 /etc/openvpn/server/easy-rsa/pki/index.txt | grep -c "^V")
|
|
||||||
if [[ $NUMBEROFCLIENTS == '0' ]]; then
|
if [[ $NUMBEROFCLIENTS == '0' ]]; then
|
||||||
log_fatal "You have no existing clients!"
|
log_fatal "You have no existing clients!"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# If CLIENT is set, validate it exists as a valid client
|
# If CLIENT is set, validate it exists as a valid client
|
||||||
if [[ -n $CLIENT ]]; then
|
if [[ -n $CLIENT ]]; then
|
||||||
if tail -n +2 /etc/openvpn/server/easy-rsa/pki/index.txt | grep "^V" | cut -d '=' -f 2 | grep -qx "$CLIENT"; then
|
if echo "$clients_list" | grep -qx "$CLIENT"; then
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
log_fatal "Client '$CLIENT' not found or not valid"
|
log_fatal "Client '$CLIENT' not found or not valid"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Display client list
|
||||||
if [[ $show_expiry == "true" ]]; then
|
if [[ $show_expiry == "true" ]]; then
|
||||||
local i=1
|
local i=1
|
||||||
while read -r client; do
|
while read -r client; do
|
||||||
@@ -3570,11 +3662,12 @@ function selectClient() {
|
|||||||
expiry=$(formatExpiry "$days")
|
expiry=$(formatExpiry "$days")
|
||||||
echo " $i) $client $expiry"
|
echo " $i) $client $expiry"
|
||||||
((i++))
|
((i++))
|
||||||
done < <(tail -n +2 /etc/openvpn/server/easy-rsa/pki/index.txt | grep "^V" | cut -d '=' -f 2)
|
done <<<"$clients_list"
|
||||||
else
|
else
|
||||||
tail -n +2 /etc/openvpn/server/easy-rsa/pki/index.txt | grep "^V" | cut -d '=' -f 2 | nl -s ') '
|
echo "$clients_list" | nl -s ') '
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Prompt for selection
|
||||||
until [[ ${CLIENTNUMBER:-$client_number} -ge 1 && ${CLIENTNUMBER:-$client_number} -le $NUMBEROFCLIENTS ]]; do
|
until [[ ${CLIENTNUMBER:-$client_number} -ge 1 && ${CLIENTNUMBER:-$client_number} -le $NUMBEROFCLIENTS ]]; do
|
||||||
if [[ $NUMBEROFCLIENTS == '1' ]]; then
|
if [[ $NUMBEROFCLIENTS == '1' ]]; then
|
||||||
read -rp "Select one client [1]: " client_number
|
read -rp "Select one client [1]: " client_number
|
||||||
@@ -3583,7 +3676,7 @@ function selectClient() {
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
CLIENTNUMBER="${CLIENTNUMBER:-$client_number}"
|
CLIENTNUMBER="${CLIENTNUMBER:-$client_number}"
|
||||||
CLIENT=$(tail -n +2 /etc/openvpn/server/easy-rsa/pki/index.txt | grep "^V" | cut -d '=' -f 2 | sed -n "$CLIENTNUMBER"p)
|
CLIENT=$(echo "$clients_list" | sed -n "${CLIENTNUMBER}p")
|
||||||
}
|
}
|
||||||
|
|
||||||
# Escape a string for JSON output
|
# Escape a string for JSON output
|
||||||
@@ -3603,58 +3696,88 @@ function listClients() {
|
|||||||
local cert_dir="/etc/openvpn/server/easy-rsa/pki/issued"
|
local cert_dir="/etc/openvpn/server/easy-rsa/pki/issued"
|
||||||
local number_of_clients
|
local number_of_clients
|
||||||
local format="${OUTPUT_FORMAT:-table}"
|
local format="${OUTPUT_FORMAT:-table}"
|
||||||
|
local auth_mode
|
||||||
|
|
||||||
# Exclude server certificates (CN starting with server_)
|
auth_mode=$(getAuthMode)
|
||||||
number_of_clients=$(tail -n +2 "$index_file" | grep "^[VR]" | grep -cv "/CN=server_")
|
|
||||||
|
|
||||||
if [[ $number_of_clients == '0' ]]; then
|
# Collect client data based on auth mode
|
||||||
if [[ $format == "json" ]]; then
|
|
||||||
echo '{"clients":[]}'
|
|
||||||
else
|
|
||||||
log_warn "You have no existing client certificates!"
|
|
||||||
fi
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Collect client data
|
|
||||||
local clients_data=()
|
local clients_data=()
|
||||||
while read -r line; do
|
|
||||||
local status="${line:0:1}"
|
|
||||||
local client_name
|
|
||||||
client_name=$(echo "$line" | sed 's/.*\/CN=//')
|
|
||||||
|
|
||||||
local status_text
|
if [[ $auth_mode == "fingerprint" ]]; then
|
||||||
if [[ "$status" == "V" ]]; then
|
# Fingerprint mode: get clients from certificates in pki/issued/
|
||||||
status_text="valid"
|
# Valid clients have their fingerprint in server.conf, revoked ones don't
|
||||||
elif [[ "$status" == "R" ]]; then
|
local valid_clients
|
||||||
status_text="revoked"
|
valid_clients=$(getClientsFromFingerprints)
|
||||||
else
|
|
||||||
status_text="unknown"
|
|
||||||
fi
|
|
||||||
|
|
||||||
local cert_file="$cert_dir/$client_name.crt"
|
# Get all client certificates (exclude server certs)
|
||||||
local expiry_date="unknown"
|
local all_clients=()
|
||||||
local days_remaining="null"
|
for cert_file in "$cert_dir"/*.crt; do
|
||||||
|
[[ ! -f "$cert_file" ]] && continue
|
||||||
|
local client_name
|
||||||
|
client_name=$(basename "$cert_file" .crt)
|
||||||
|
# Skip server certificates and backup files
|
||||||
|
[[ "$client_name" == server_* ]] && continue
|
||||||
|
[[ "$client_name" == *.bak ]] && continue
|
||||||
|
all_clients+=("$client_name")
|
||||||
|
done
|
||||||
|
|
||||||
if [[ -f "$cert_file" ]]; then
|
number_of_clients=${#all_clients[@]}
|
||||||
local enddate
|
|
||||||
enddate=$(openssl x509 -enddate -noout -in "$cert_file" 2>/dev/null | cut -d= -f2)
|
|
||||||
|
|
||||||
if [[ -n "$enddate" ]]; then
|
if [[ $number_of_clients == '0' ]]; then
|
||||||
local expiry_epoch
|
if [[ $format == "json" ]]; then
|
||||||
expiry_epoch=$(date -d "$enddate" +%s 2>/dev/null || date -j -f "%b %d %H:%M:%S %Y %Z" "$enddate" +%s 2>/dev/null)
|
echo '{"clients":[]}'
|
||||||
|
else
|
||||||
if [[ -n "$expiry_epoch" ]]; then
|
log_warn "You have no existing client certificates!"
|
||||||
expiry_date=$(date -d "@$expiry_epoch" +%Y-%m-%d 2>/dev/null || date -r "$expiry_epoch" +%Y-%m-%d 2>/dev/null)
|
|
||||||
local now_epoch
|
|
||||||
now_epoch=$(date +%s)
|
|
||||||
days_remaining=$(((expiry_epoch - now_epoch) / 86400))
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
clients_data+=("$client_name|$status_text|$expiry_date|$days_remaining")
|
for client_name in "${all_clients[@]}"; do
|
||||||
done < <(tail -n +2 "$index_file" | grep "^[VR]" | grep -v "/CN=server_" | sort -t$'\t' -k2)
|
[[ -z "$client_name" ]] && continue
|
||||||
|
local status_text
|
||||||
|
# Check if client is in the valid fingerprints list
|
||||||
|
if echo "$valid_clients" | grep -qx "$client_name"; then
|
||||||
|
status_text="valid"
|
||||||
|
else
|
||||||
|
status_text="revoked"
|
||||||
|
fi
|
||||||
|
local expiry_info
|
||||||
|
expiry_info=$(getCertExpiry "$cert_dir/$client_name.crt")
|
||||||
|
clients_data+=("$client_name|$status_text|$expiry_info")
|
||||||
|
done
|
||||||
|
else
|
||||||
|
# PKI mode: get clients from index.txt
|
||||||
|
# Exclude server certificates (CN starting with server_)
|
||||||
|
number_of_clients=$(tail -n +2 "$index_file" 2>/dev/null | grep "^[VR]" | grep -cv "/CN=server_" || echo 0)
|
||||||
|
|
||||||
|
if [[ $number_of_clients == '0' ]]; then
|
||||||
|
if [[ $format == "json" ]]; then
|
||||||
|
echo '{"clients":[]}'
|
||||||
|
else
|
||||||
|
log_warn "You have no existing client certificates!"
|
||||||
|
fi
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
while read -r line; do
|
||||||
|
local status="${line:0:1}"
|
||||||
|
local client_name
|
||||||
|
client_name=$(echo "$line" | sed 's/.*\/CN=//')
|
||||||
|
|
||||||
|
local status_text
|
||||||
|
if [[ "$status" == "V" ]]; then
|
||||||
|
status_text="valid"
|
||||||
|
elif [[ "$status" == "R" ]]; then
|
||||||
|
status_text="revoked"
|
||||||
|
else
|
||||||
|
status_text="unknown"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local expiry_info
|
||||||
|
expiry_info=$(getCertExpiry "$cert_dir/$client_name.crt")
|
||||||
|
clients_data+=("$client_name|$status_text|$expiry_info")
|
||||||
|
done < <(tail -n +2 "$index_file" | grep "^[VR]" | grep -v "/CN=server_" | sort -t$'\t' -k2)
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ $format == "json" ]]; then
|
if [[ $format == "json" ]]; then
|
||||||
# Output JSON
|
# Output JSON
|
||||||
@@ -3830,17 +3953,30 @@ function newClient() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if client already exists
|
# Check if client already exists
|
||||||
if [[ -f pki/index.txt ]]; then
|
local CLIENTEXISTS=0
|
||||||
CLIENTEXISTS=$(tail -n +2 /etc/openvpn/server/easy-rsa/pki/index.txt | grep -E "^V" | grep -c -E "/CN=$CLIENT\$")
|
if [[ $AUTH_MODE == "fingerprint" ]]; then
|
||||||
|
# Fingerprint mode: check server.conf peer-fingerprint block
|
||||||
|
if clientExistsInFingerprints "$CLIENT"; then
|
||||||
|
CLIENTEXISTS=1
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
CLIENTEXISTS=0
|
# PKI mode: check index.txt
|
||||||
|
if [[ -f pki/index.txt ]]; then
|
||||||
|
CLIENTEXISTS=$(tail -n +2 /etc/openvpn/server/easy-rsa/pki/index.txt | grep -E "^V" | grep -c -E "/CN=$CLIENT\$")
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $CLIENTEXISTS != '0' ]]; then
|
if [[ $CLIENTEXISTS != '0' ]]; then
|
||||||
log_error "The specified client CN was already found in easy-rsa, please choose another name."
|
log_error "The specified client CN was already found, please choose another name."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# In fingerprint mode, clean up any revoked cert files so we can reuse the name
|
||||||
|
if [[ $AUTH_MODE == "fingerprint" ]] && [[ -f "pki/issued/$CLIENT.crt" ]]; then
|
||||||
|
log_info "Removing old revoked certificate files for $CLIENT..."
|
||||||
|
removeCertFiles "$CLIENT"
|
||||||
|
fi
|
||||||
|
|
||||||
log_info "Generating client certificate..."
|
log_info "Generating client certificate..."
|
||||||
export EASYRSA_CERT_EXPIRE=$CLIENT_CERT_DURATION_DAYS
|
export EASYRSA_CERT_EXPIRE=$CLIENT_CERT_DURATION_DAYS
|
||||||
|
|
||||||
@@ -3933,20 +4069,13 @@ function revokeClient() {
|
|||||||
regenerateCRL
|
regenerateCRL
|
||||||
run_cmd "Backing up index" cp /etc/openvpn/server/easy-rsa/pki/index.txt{,.bk}
|
run_cmd "Backing up index" cp /etc/openvpn/server/easy-rsa/pki/index.txt{,.bk}
|
||||||
else
|
else
|
||||||
# Fingerprint mode: remove fingerprint from server.conf and delete cert files
|
# Fingerprint mode: remove fingerprint from server.conf
|
||||||
|
# Keep cert files so revoked clients appear in client list
|
||||||
log_info "Removing client fingerprint from server configuration..."
|
log_info "Removing client fingerprint from server configuration..."
|
||||||
|
|
||||||
# Remove comment line and fingerprint line below it from server.conf
|
# Remove comment line and fingerprint line below it from server.conf
|
||||||
sed -i "/^# $CLIENT\$/{N;d;}" /etc/openvpn/server/server.conf
|
sed -i "/^# $CLIENT\$/{N;d;}" /etc/openvpn/server/server.conf
|
||||||
|
|
||||||
# Remove client certificate and key
|
|
||||||
rm -f "pki/issued/$CLIENT.crt" "pki/private/$CLIENT.key"
|
|
||||||
|
|
||||||
# Mark as revoked in index.txt if it exists (for client listing)
|
|
||||||
if [[ -f pki/index.txt ]]; then
|
|
||||||
sed -i "s|^V\(.*\)/CN=$CLIENT\$|R\1/CN=$CLIENT|" pki/index.txt
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Reload OpenVPN to apply fingerprint removal
|
# Reload OpenVPN to apply fingerprint removal
|
||||||
log_info "Reloading OpenVPN to apply fingerprint removal..."
|
log_info "Reloading OpenVPN to apply fingerprint removal..."
|
||||||
if systemctl is-active --quiet openvpn-server@server; then
|
if systemctl is-active --quiet openvpn-server@server; then
|
||||||
@@ -3984,6 +4113,7 @@ function disconnectClient() {
|
|||||||
|
|
||||||
function renewClient() {
|
function renewClient() {
|
||||||
local client_cert_duration_days
|
local client_cert_duration_days
|
||||||
|
local auth_mode
|
||||||
|
|
||||||
log_header "Renew Client Certificate"
|
log_header "Renew Client Certificate"
|
||||||
log_prompt "Select the existing client certificate you want to renew"
|
log_prompt "Select the existing client certificate you want to renew"
|
||||||
@@ -4001,20 +4131,47 @@ function renewClient() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
cd /etc/openvpn/server/easy-rsa/ || return
|
cd /etc/openvpn/server/easy-rsa/ || return
|
||||||
|
auth_mode=$(getAuthMode)
|
||||||
log_info "Renewing certificate for $CLIENT..."
|
log_info "Renewing certificate for $CLIENT..."
|
||||||
|
|
||||||
# Backup the old certificate before renewal
|
# Backup the old certificate before renewal
|
||||||
run_cmd "Backing up old certificate" cp "/etc/openvpn/server/easy-rsa/pki/issued/$CLIENT.crt" "/etc/openvpn/server/easy-rsa/pki/issued/$CLIENT.crt.bak"
|
run_cmd "Backing up old certificate" cp "/etc/openvpn/server/easy-rsa/pki/issued/$CLIENT.crt" "/etc/openvpn/server/easy-rsa/pki/issued/$CLIENT.crt.bak"
|
||||||
|
|
||||||
# Renew the certificate (keeps the same private key)
|
|
||||||
export EASYRSA_CERT_EXPIRE=$client_cert_duration_days
|
export EASYRSA_CERT_EXPIRE=$client_cert_duration_days
|
||||||
run_cmd_fatal "Renewing certificate" ./easyrsa --batch renew "$CLIENT"
|
|
||||||
|
|
||||||
# Revoke the old certificate
|
if [[ $auth_mode == "fingerprint" ]]; then
|
||||||
run_cmd_fatal "Revoking old certificate" ./easyrsa --batch revoke-renewed "$CLIENT"
|
# Fingerprint mode: delete old cert, generate new self-signed, update fingerprint
|
||||||
|
removeCertFiles "$CLIENT"
|
||||||
|
run_cmd_fatal "Generating new certificate" ./easyrsa --batch self-sign-client "$CLIENT" nopass
|
||||||
|
|
||||||
# Regenerate the CRL
|
local new_fingerprint
|
||||||
regenerateCRL
|
new_fingerprint=$(extractFingerprint "pki/issued/$CLIENT.crt")
|
||||||
|
if [[ -z "$new_fingerprint" ]]; then
|
||||||
|
log_fatal "Failed to extract new certificate fingerprint"
|
||||||
|
fi
|
||||||
|
log_info "New fingerprint: $new_fingerprint"
|
||||||
|
|
||||||
|
# Update fingerprint in server.conf (comment line followed by fingerprint)
|
||||||
|
if grep -q "^# $CLIENT\$" /etc/openvpn/server/server.conf; then
|
||||||
|
sed -i "/^# $CLIENT\$/{n;s/.*/$new_fingerprint/}" /etc/openvpn/server/server.conf
|
||||||
|
else
|
||||||
|
log_fatal "Client fingerprint entry not found in server.conf"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Reload OpenVPN to apply new fingerprint
|
||||||
|
if systemctl is-active --quiet openvpn-server@server; then
|
||||||
|
systemctl reload openvpn-server@server 2>/dev/null || systemctl restart openvpn-server@server
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# PKI mode: use easyrsa renew
|
||||||
|
run_cmd_fatal "Renewing certificate" ./easyrsa --batch renew "$CLIENT"
|
||||||
|
|
||||||
|
# Revoke the old certificate
|
||||||
|
run_cmd_fatal "Revoking old certificate" ./easyrsa --batch revoke-renewed "$CLIENT"
|
||||||
|
|
||||||
|
# Regenerate the CRL
|
||||||
|
regenerateCRL
|
||||||
|
fi
|
||||||
|
|
||||||
# Write the .ovpn config file with proper path and permissions
|
# Write the .ovpn config file with proper path and permissions
|
||||||
writeClientConfig "$CLIENT"
|
writeClientConfig "$CLIENT"
|
||||||
@@ -4026,10 +4183,13 @@ function renewClient() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renewServer() {
|
function renewServer() {
|
||||||
local server_name server_cert_duration_days
|
local server_name server_cert_duration_days auth_mode
|
||||||
|
|
||||||
log_header "Renew Server Certificate"
|
log_header "Renew Server Certificate"
|
||||||
|
|
||||||
|
# Determine auth mode
|
||||||
|
auth_mode=$(getAuthMode)
|
||||||
|
|
||||||
# Get the server name from the config (extract basename since path may be relative)
|
# Get the server name from the config (extract basename since path may be relative)
|
||||||
server_name=$(basename "$(grep '^cert ' /etc/openvpn/server/server.conf | cut -d ' ' -f 2)" .crt)
|
server_name=$(basename "$(grep '^cert ' /etc/openvpn/server/server.conf | cut -d ' ' -f 2)" .crt)
|
||||||
if [[ -z "$server_name" ]]; then
|
if [[ -z "$server_name" ]]; then
|
||||||
@@ -4038,6 +4198,9 @@ function renewServer() {
|
|||||||
|
|
||||||
log_prompt "This will renew the server certificate: $server_name"
|
log_prompt "This will renew the server certificate: $server_name"
|
||||||
log_warn "The OpenVPN service will be restarted after renewal."
|
log_warn "The OpenVPN service will be restarted after renewal."
|
||||||
|
if [[ "$auth_mode" == "fingerprint" ]]; then
|
||||||
|
log_warn "All client configurations will be regenerated with the new server fingerprint."
|
||||||
|
fi
|
||||||
if [[ -z $CONTINUE ]]; then
|
if [[ -z $CONTINUE ]]; then
|
||||||
read -rp "Do you want to continue? [y/n]: " -e -i n CONTINUE
|
read -rp "Do you want to continue? [y/n]: " -e -i n CONTINUE
|
||||||
fi
|
fi
|
||||||
@@ -4060,21 +4223,47 @@ function renewServer() {
|
|||||||
cd /etc/openvpn/server/easy-rsa/ || return
|
cd /etc/openvpn/server/easy-rsa/ || return
|
||||||
log_info "Renewing server certificate..."
|
log_info "Renewing server certificate..."
|
||||||
|
|
||||||
# Backup the old certificate before renewal
|
|
||||||
run_cmd "Backing up old certificate" cp "/etc/openvpn/server/easy-rsa/pki/issued/$server_name.crt" "/etc/openvpn/server/easy-rsa/pki/issued/$server_name.crt.bak"
|
|
||||||
|
|
||||||
# Renew the certificate (keeps the same private key)
|
|
||||||
export EASYRSA_CERT_EXPIRE=$server_cert_duration_days
|
export EASYRSA_CERT_EXPIRE=$server_cert_duration_days
|
||||||
run_cmd_fatal "Renewing certificate" ./easyrsa --batch renew "$server_name"
|
|
||||||
|
|
||||||
# Revoke the old certificate
|
if [[ "$auth_mode" == "fingerprint" ]]; then
|
||||||
run_cmd_fatal "Revoking old certificate" ./easyrsa --batch revoke-renewed "$server_name"
|
# Fingerprint mode: delete old cert, generate new self-signed, update fingerprint
|
||||||
|
run_cmd "Backing up old certificate" cp "pki/issued/$server_name.crt" "pki/issued/$server_name.crt.bak"
|
||||||
|
removeCertFiles "$server_name"
|
||||||
|
run_cmd_fatal "Generating new server certificate" ./easyrsa --batch self-sign-server "$server_name" nopass
|
||||||
|
|
||||||
# Regenerate the CRL
|
local new_fingerprint
|
||||||
regenerateCRL
|
new_fingerprint=$(extractFingerprint "pki/issued/$server_name.crt")
|
||||||
|
if [[ -z "$new_fingerprint" ]]; then
|
||||||
|
log_fatal "Failed to extract new server certificate fingerprint"
|
||||||
|
fi
|
||||||
|
echo "$new_fingerprint" >/etc/openvpn/server/server-fingerprint
|
||||||
|
log_info "New server fingerprint: $new_fingerprint"
|
||||||
|
|
||||||
# Copy the new certificate to /etc/openvpn/server/
|
# Copy new cert and key, then regenerate client configs (they embed server fingerprint)
|
||||||
run_cmd_fatal "Copying new certificate" cp "/etc/openvpn/server/easy-rsa/pki/issued/$server_name.crt" /etc/openvpn/server/
|
cp "pki/issued/$server_name.crt" "pki/private/$server_name.key" /etc/openvpn/server/
|
||||||
|
local client
|
||||||
|
for client in $(getClientsFromFingerprints); do
|
||||||
|
[[ -f "pki/issued/$client.crt" ]] && CLIENT="$client" writeClientConfig "$client"
|
||||||
|
done
|
||||||
|
else
|
||||||
|
# PKI mode: use standard easyrsa renew
|
||||||
|
|
||||||
|
# Backup the old certificate before renewal
|
||||||
|
run_cmd "Backing up old certificate" cp "/etc/openvpn/server/easy-rsa/pki/issued/$server_name.crt" "/etc/openvpn/server/easy-rsa/pki/issued/$server_name.crt.bak"
|
||||||
|
|
||||||
|
# Renew the certificate (keeps the same private key)
|
||||||
|
export EASYRSA_CERT_EXPIRE=$server_cert_duration_days
|
||||||
|
run_cmd_fatal "Renewing certificate" ./easyrsa --batch renew "$server_name"
|
||||||
|
|
||||||
|
# Revoke the old certificate
|
||||||
|
run_cmd_fatal "Revoking old certificate" ./easyrsa --batch revoke-renewed "$server_name"
|
||||||
|
|
||||||
|
# Regenerate the CRL
|
||||||
|
regenerateCRL
|
||||||
|
|
||||||
|
# Copy the new certificate to /etc/openvpn/server/
|
||||||
|
run_cmd_fatal "Copying new certificate" cp "/etc/openvpn/server/easy-rsa/pki/issued/$server_name.crt" /etc/openvpn/server/
|
||||||
|
fi
|
||||||
|
|
||||||
# Restart OpenVPN
|
# Restart OpenVPN
|
||||||
log_info "Restarting OpenVPN service..."
|
log_info "Restarting OpenVPN service..."
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ COPY test/validate-output.sh /opt/test/validate-output.sh
|
|||||||
RUN chmod +x /entrypoint.sh /opt/test/validate-output.sh
|
RUN chmod +x /entrypoint.sh /opt/test/validate-output.sh
|
||||||
|
|
||||||
# Create systemd service for the test script
|
# Create systemd service for the test script
|
||||||
|
# PassEnvironment passes Docker env vars (-e) from PID 1 to the service
|
||||||
RUN printf '%s\n' \
|
RUN printf '%s\n' \
|
||||||
'[Unit]' \
|
'[Unit]' \
|
||||||
'Description=OpenVPN Installation Test' \
|
'Description=OpenVPN Installation Test' \
|
||||||
@@ -79,6 +80,7 @@ RUN printf '%s\n' \
|
|||||||
'[Service]' \
|
'[Service]' \
|
||||||
'Type=oneshot' \
|
'Type=oneshot' \
|
||||||
'Environment=HOME=/root' \
|
'Environment=HOME=/root' \
|
||||||
|
'PassEnvironment=AUTH_MODE TLS_SIG TLS_KEY_FILE TLS_VERSION_MIN TLS13_CIPHERSUITES CLIENT_IPV6 VPN_SUBNET_IPV6' \
|
||||||
'WorkingDirectory=/root' \
|
'WorkingDirectory=/root' \
|
||||||
'ExecStart=/entrypoint.sh' \
|
'ExecStart=/entrypoint.sh' \
|
||||||
'RemainAfterExit=yes' \
|
'RemainAfterExit=yes' \
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ if [ "$DUPLICATE_EXIT_CODE" -ne 1 ]; then
|
|||||||
cat "$DUPLICATE_OUTPUT"
|
cat "$DUPLICATE_OUTPUT"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
if grep -q "The specified client CN was already found in easy-rsa" "$DUPLICATE_OUTPUT"; then
|
if grep -q "The specified client CN was already found" "$DUPLICATE_OUTPUT"; then
|
||||||
echo "PASS: Duplicate client name correctly rejected with exit code 1"
|
echo "PASS: Duplicate client name correctly rejected with exit code 1"
|
||||||
else
|
else
|
||||||
echo "FAIL: Expected error message for duplicate client name not found"
|
echo "FAIL: Expected error message for duplicate client name not found"
|
||||||
@@ -538,6 +538,11 @@ done
|
|||||||
# Allow routing to stabilize after renewal restart
|
# Allow routing to stabilize after renewal restart
|
||||||
sleep 3
|
sleep 3
|
||||||
|
|
||||||
|
# Update shared client config after server renewal (fingerprint changed)
|
||||||
|
cp /root/testclient.ovpn /shared/client.ovpn
|
||||||
|
sed -i 's/^remote .*/remote openvpn-server 1194/' /shared/client.ovpn
|
||||||
|
echo "Updated client config with new server fingerprint"
|
||||||
|
|
||||||
# =====================================================
|
# =====================================================
|
||||||
# Verify Unbound DNS resolver (started by systemd via install script)
|
# Verify Unbound DNS resolver (started by systemd via install script)
|
||||||
# =====================================================
|
# =====================================================
|
||||||
|
|||||||
Reference in New Issue
Block a user