feat: add certificate renewal functionality (#1328)

## Summary

- Add certificate renewal for both client and server certificates
- Allow custom validity period during renewal (prompts user, defaults to
3650 days)
- Show expiry info inline in menus (e.g., "Renew the server certificate
(expires in 3542 days)")
- Regenerate `.ovpn` files after client renewal
- Restart OpenVPN service after server renewal
- Extract reusable helper functions to reduce code duplication
- Add robust input validation and error handling

## New menu option

```
What do you want to do?
   1) Add a new user
   2) Revoke existing user
   3) Renew certificate        ← NEW
   4) Remove OpenVPN
   5) Exit
```

## Renewal submenu

```
What do you want to renew?
   1) Renew a client certificate
   2) Renew the server certificate (expires in 3542 days)
   3) Back to main menu
```

Client list shows expiry for each:
```
Select the existing client certificate you want to renew
     1) alice (expires in 3542 days)
     2) bob (expires in 30 days)
     3) charlie (EXPIRED 5 days ago)
```

## Helper functions added

Extracted common code into reusable functions:
- `getHomeDir()` - home directory detection
- `regenerateCRL()` - CRL regeneration after cert changes
- `generateClientConfig()` - .ovpn file generation  
- `selectClient()` - client listing with optional expiry display
- `getDaysUntilExpiry()` - certificate expiry calculation
- `formatExpiry()` - human-readable expiry formatting

## Test plan

- [x] Client certificate renewal tested in Docker CI
- [x] Server certificate renewal tested in Docker CI
- [x] Certificate validity verified after renewal (~3650 days)
- [x] VPN connectivity tested with renewed certificate

Closes #974 #1002 #1228 #1060
This commit is contained in:
Stanislas
2025-12-09 21:49:19 +01:00
committed by GitHub
parent fb2041d9bb
commit 6b09270347
4 changed files with 475 additions and 81 deletions

8
FAQ.md
View File

@@ -8,6 +8,14 @@ You can, of course, it's even recommended, update the `openvpn` package with you
---
**Q:** How do I renew certificates before they expire?
**A:** Run the script again and select "Renew certificates" from the menu. You can renew either client certificates or the server certificate. The script will show you the current expiration date for each certificate and let you choose a new validity period (default: 3650 days / 10 years).
For client renewals, a new `.ovpn` file will be generated that you need to distribute to the client. For server renewals, the OpenVPN service will need to be restarted (the script will prompt you).
---
**Q:** How do I check for DNS leaks?
**A:** Go to [browserleaks.com](https://browserleaks.com/dns) or [ipleak.net](https://ipleak.net/) (both perform IPv4 and IPv6 check) with your browser. Your IP should not show up (test without and without the VPN). The DNS servers should be the ones you selected during the setup, not your IP address nor your ISP's DNS servers' addresses.

View File

@@ -52,6 +52,7 @@ When OpenVPN is installed, you can run the script again, and you will get the ch
- Add a client
- Remove a client
- Renew certificates (client or server)
- Uninstall OpenVPN
In your home directory, you will have `.ovpn` files. These are the client configuration files. Download them from your server and connect using your favorite OpenVPN client.
@@ -113,6 +114,7 @@ export PASS="1"
## Features
- Installs and configures a ready-to-use OpenVPN server
- Certificate renewal for both client and server certificates
- Uses [official OpenVPN repositories](https://community.openvpn.net/openvpn/wiki/OpenvpnSoftwareRepos) when possible for the latest stable releases
- Iptables rules and forwarding managed in a seamless way
- If needed, the script can cleanly remove OpenVPN, including configuration and iptables rules

View File

@@ -1318,6 +1318,116 @@ verb 3" >>/etc/openvpn/client-template.txt
log_success "If you want to add more clients, you simply need to run this script another time!"
}
# Helper function to get the home directory for storing client configs
function getHomeDir() {
local client="$1"
if [ -e "/home/${client}" ]; then
echo "/home/${client}"
elif [ "${SUDO_USER}" ]; then
if [ "${SUDO_USER}" == "root" ]; then
echo "/root"
else
echo "/home/${SUDO_USER}"
fi
else
echo "/root"
fi
}
# Helper function to regenerate the CRL after certificate changes
function regenerateCRL() {
export EASYRSA_CRL_DAYS=$CRL_VALIDITY_DAYS
run_cmd "Regenerating CRL" ./easyrsa gen-crl
run_cmd "Removing old CRL" rm -f /etc/openvpn/crl.pem
run_cmd "Copying new CRL" cp /etc/openvpn/easy-rsa/pki/crl.pem /etc/openvpn/crl.pem
run_cmd "Setting CRL permissions" chmod 644 /etc/openvpn/crl.pem
}
# Helper function to generate .ovpn client config file
function generateClientConfig() {
local client="$1"
local home_dir="$2"
# Determine if we use tls-auth or tls-crypt
local tls_sig=""
if grep -qs "^tls-crypt" /etc/openvpn/server.conf; then
tls_sig="1"
elif grep -qs "^tls-auth" /etc/openvpn/server.conf; then
tls_sig="2"
fi
# Generate the custom client.ovpn
run_cmd "Creating client config" cp /etc/openvpn/client-template.txt "$home_dir/$client.ovpn"
{
echo "<ca>"
cat "/etc/openvpn/easy-rsa/pki/ca.crt"
echo "</ca>"
echo "<cert>"
awk '/BEGIN/,/END CERTIFICATE/' "/etc/openvpn/easy-rsa/pki/issued/$client.crt"
echo "</cert>"
echo "<key>"
cat "/etc/openvpn/easy-rsa/pki/private/$client.key"
echo "</key>"
case $tls_sig in
1)
echo "<tls-crypt>"
cat /etc/openvpn/tls-crypt.key
echo "</tls-crypt>"
;;
2)
echo "key-direction 1"
echo "<tls-auth>"
cat /etc/openvpn/tls-auth.key
echo "</tls-auth>"
;;
esac
} >>"$home_dir/$client.ovpn"
}
# Helper function to list valid clients and select one
# Arguments: show_expiry (optional, "true" to show expiry info)
# Sets global variables:
# CLIENT - the selected client name
# CLIENTNUMBER - the selected client number (1-based index)
# NUMBEROFCLIENTS - total count of valid clients
function selectClient() {
local show_expiry="${1:-false}"
local client_number
NUMBEROFCLIENTS=$(tail -n +2 /etc/openvpn/easy-rsa/pki/index.txt | grep -c "^V")
if [[ $NUMBEROFCLIENTS == '0' ]]; then
log_fatal "You have no existing clients!"
fi
if [[ $show_expiry == "true" ]]; then
local i=1
while read -r client; do
local client_cert="/etc/openvpn/easy-rsa/pki/issued/$client.crt"
local days
days=$(getDaysUntilExpiry "$client_cert")
local expiry
expiry=$(formatExpiry "$days")
echo " $i) $client $expiry"
((i++))
done < <(tail -n +2 /etc/openvpn/easy-rsa/pki/index.txt | grep "^V" | cut -d '=' -f 2)
else
tail -n +2 /etc/openvpn/easy-rsa/pki/index.txt | grep "^V" | cut -d '=' -f 2 | nl -s ') '
fi
until [[ ${CLIENTNUMBER:-$client_number} -ge 1 && ${CLIENTNUMBER:-$client_number} -le $NUMBEROFCLIENTS ]]; do
if [[ $NUMBEROFCLIENTS == '1' ]]; then
read -rp "Select one client [1]: " client_number
else
read -rp "Select one client [1-$NUMBEROFCLIENTS]: " client_number
fi
done
CLIENTNUMBER="${CLIENTNUMBER:-$client_number}"
CLIENT=$(tail -n +2 /etc/openvpn/easy-rsa/pki/index.txt | grep "^V" | cut -d '=' -f 2 | sed -n "$CLIENTNUMBER"p)
}
function newClient() {
log_header "New Client Setup"
log_prompt "Tell me a name for the client."
@@ -1327,10 +1437,12 @@ function newClient() {
read -rp "Client name: " -e CLIENT
done
if [[ -z $DAYS_VALID ]]; then
if [[ -z $DAYS_VALID ]] || ! [[ $DAYS_VALID =~ ^[0-9]+$ ]] || [[ $DAYS_VALID -lt 1 ]]; then
log_menu ""
log_prompt "How many days should the client certificate be valid for?"
read -rp "Certificate validity (days): " -e -i 3650 DAYS_VALID
until [[ $DAYS_VALID =~ ^[0-9]+$ ]] && [[ $DAYS_VALID -ge 1 ]]; do
read -rp "Certificate validity (days): " -e -i 3650 DAYS_VALID
done
fi
log_menu ""
@@ -1363,59 +1475,9 @@ function newClient() {
log_success "Client $CLIENT added and is valid for $DAYS_VALID days."
fi
# Home directory of the user, where the client configuration will be written
if [ -e "/home/${CLIENT}" ]; then
# if $1 is a user name
homeDir="/home/${CLIENT}"
elif [ "${SUDO_USER}" ]; then
# if not, use SUDO_USER
if [ "${SUDO_USER}" == "root" ]; then
# If running sudo as root
homeDir="/root"
else
homeDir="/home/${SUDO_USER}"
fi
else
# if not SUDO_USER, use /root
homeDir="/root"
fi
# Determine if we use tls-auth or tls-crypt
if grep -qs "^tls-crypt" /etc/openvpn/server.conf; then
TLS_SIG="1"
elif grep -qs "^tls-auth" /etc/openvpn/server.conf; then
TLS_SIG="2"
fi
# Generates the custom client.ovpn
run_cmd "Creating client config" cp /etc/openvpn/client-template.txt "$homeDir/$CLIENT.ovpn"
{
echo "<ca>"
cat "/etc/openvpn/easy-rsa/pki/ca.crt"
echo "</ca>"
echo "<cert>"
awk '/BEGIN/,/END CERTIFICATE/' "/etc/openvpn/easy-rsa/pki/issued/$CLIENT.crt"
echo "</cert>"
echo "<key>"
cat "/etc/openvpn/easy-rsa/pki/private/$CLIENT.key"
echo "</key>"
case $TLS_SIG in
1)
echo "<tls-crypt>"
cat /etc/openvpn/tls-crypt.key
echo "</tls-crypt>"
;;
2)
echo "key-direction 1"
echo "<tls-auth>"
cat /etc/openvpn/tls-auth.key
echo "</tls-auth>"
;;
esac
} >>"$homeDir/$CLIENT.ovpn"
# Generate the .ovpn config file
homeDir=$(getHomeDir "$CLIENT")
generateClientConfig "$CLIENT" "$homeDir"
log_menu ""
log_success "The configuration file has been written to $homeDir/$CLIENT.ovpn."
@@ -1425,30 +1487,14 @@ function newClient() {
}
function revokeClient() {
NUMBEROFCLIENTS=$(tail -n +2 /etc/openvpn/easy-rsa/pki/index.txt | grep -c "^V")
if [[ $NUMBEROFCLIENTS == '0' ]]; then
log_fatal "You have no existing clients!"
fi
log_header "Revoke Client"
log_prompt "Select the existing client certificate you want to revoke"
tail -n +2 /etc/openvpn/easy-rsa/pki/index.txt | grep "^V" | cut -d '=' -f 2 | nl -s ') '
until [[ $CLIENTNUMBER -ge 1 && $CLIENTNUMBER -le $NUMBEROFCLIENTS ]]; do
if [[ $CLIENTNUMBER == '1' ]]; then
read -rp "Select one client [1]: " CLIENTNUMBER
else
read -rp "Select one client [1-$NUMBEROFCLIENTS]: " CLIENTNUMBER
fi
done
CLIENT=$(tail -n +2 /etc/openvpn/easy-rsa/pki/index.txt | grep "^V" | cut -d '=' -f 2 | sed -n "$CLIENTNUMBER"p)
selectClient
cd /etc/openvpn/easy-rsa/ || return
log_info "Revoking certificate for $CLIENT..."
run_cmd "Revoking certificate" ./easyrsa --batch revoke "$CLIENT"
export EASYRSA_CRL_DAYS=$CRL_VALIDITY_DAYS
run_cmd "Regenerating CRL" ./easyrsa gen-crl
run_cmd "Removing old CRL" rm -f /etc/openvpn/crl.pem
run_cmd "Copying new CRL" cp /etc/openvpn/easy-rsa/pki/crl.pem /etc/openvpn/crl.pem
run_cmd "Setting CRL permissions" chmod 644 /etc/openvpn/crl.pem
regenerateCRL
run_cmd "Removing client config from /home" find /home/ -maxdepth 2 -name "$CLIENT.ovpn" -delete
run_cmd "Removing client config from /root" rm -f "/root/$CLIENT.ovpn"
run_cmd "Removing IP assignment" sed -i "/^$CLIENT,.*/d" /etc/openvpn/ipp.txt
@@ -1457,6 +1503,186 @@ function revokeClient() {
log_success "Certificate for client $CLIENT revoked."
}
function renewClient() {
local homeDir days_valid
log_header "Renew Client Certificate"
log_prompt "Select the existing client certificate you want to renew"
selectClient "true"
# Allow user to specify renewal duration (use DAYS_VALID env var for headless mode)
if [[ -z $DAYS_VALID ]] || ! [[ $DAYS_VALID =~ ^[0-9]+$ ]] || [[ $DAYS_VALID -lt 1 ]]; then
log_menu ""
log_prompt "How many days should the renewed certificate be valid for?"
until [[ $days_valid =~ ^[0-9]+$ ]] && [[ $days_valid -ge 1 ]]; do
read -rp "Certificate validity (days): " -e -i 3650 days_valid
done
else
days_valid=$DAYS_VALID
fi
cd /etc/openvpn/easy-rsa/ || return
log_info "Renewing certificate for $CLIENT..."
# Backup the old certificate before renewal
run_cmd "Backing up old certificate" cp "/etc/openvpn/easy-rsa/pki/issued/$CLIENT.crt" "/etc/openvpn/easy-rsa/pki/issued/$CLIENT.crt.bak"
# Renew the certificate (keeps the same private key)
export EASYRSA_CERT_EXPIRE=$days_valid
run_cmd "Renewing certificate" ./easyrsa --batch renew "$CLIENT"
# Revoke the old certificate
run_cmd "Revoking old certificate" ./easyrsa --batch revoke-renewed "$CLIENT"
# Regenerate the CRL
regenerateCRL
# Regenerate the .ovpn file with the new certificate
homeDir=$(getHomeDir "$CLIENT")
generateClientConfig "$CLIENT" "$homeDir"
log_menu ""
log_success "Certificate for client $CLIENT renewed and is valid for $days_valid days."
log_info "The new configuration file has been written to $homeDir/$CLIENT.ovpn."
log_info "Download the new .ovpn file and import it in your OpenVPN client."
}
function renewServer() {
local server_name days_valid
log_header "Renew Server Certificate"
# Get the server name from the config
server_name=$(grep '^cert ' /etc/openvpn/server.conf | cut -d ' ' -f 2 | sed 's/\.crt$//')
if [[ -z "$server_name" ]]; then
log_fatal "Could not determine server certificate name from /etc/openvpn/server.conf"
fi
log_prompt "This will renew the server certificate: $server_name"
log_warn "The OpenVPN service will be restarted after renewal."
if [[ -z $CONTINUE ]]; then
read -rp "Do you want to continue? [y/n]: " -e -i n CONTINUE
fi
if [[ $CONTINUE != "y" ]]; then
log_info "Renewal aborted."
return
fi
# Allow user to specify renewal duration (use DAYS_VALID env var for headless mode)
if [[ -z $DAYS_VALID ]] || ! [[ $DAYS_VALID =~ ^[0-9]+$ ]] || [[ $DAYS_VALID -lt 1 ]]; then
log_menu ""
log_prompt "How many days should the renewed certificate be valid for?"
until [[ $days_valid =~ ^[0-9]+$ ]] && [[ $days_valid -ge 1 ]]; do
read -rp "Certificate validity (days): " -e -i 3650 days_valid
done
else
days_valid=$DAYS_VALID
fi
cd /etc/openvpn/easy-rsa/ || return
log_info "Renewing server certificate..."
# Backup the old certificate before renewal
run_cmd "Backing up old certificate" cp "/etc/openvpn/easy-rsa/pki/issued/$server_name.crt" "/etc/openvpn/easy-rsa/pki/issued/$server_name.crt.bak"
# Renew the certificate (keeps the same private key)
export EASYRSA_CERT_EXPIRE=$days_valid
run_cmd "Renewing certificate" ./easyrsa --batch renew "$server_name"
# Revoke the old certificate
run_cmd "Revoking old certificate" ./easyrsa --batch revoke-renewed "$server_name"
# Regenerate the CRL
regenerateCRL
# Copy the new certificate to /etc/openvpn/
run_cmd "Copying new certificate" cp "/etc/openvpn/easy-rsa/pki/issued/$server_name.crt" /etc/openvpn/
# Restart OpenVPN
log_info "Restarting OpenVPN service..."
if [[ $OS =~ (fedora|arch|centos|oracle) ]]; then
run_cmd "Restarting OpenVPN" systemctl restart openvpn-server@server
elif [[ $OS == "ubuntu" ]] && [[ $VERSION_ID == "16.04" ]]; then
run_cmd "Restarting OpenVPN" systemctl restart openvpn
else
run_cmd "Restarting OpenVPN" systemctl restart openvpn@server
fi
log_success "Server certificate renewed successfully and is valid for $days_valid days."
}
function getDaysUntilExpiry() {
local cert_file="$1"
if [[ -f "$cert_file" ]]; then
local expiry_date
expiry_date=$(openssl x509 -in "$cert_file" -noout -enddate | cut -d= -f2)
local expiry_epoch
expiry_epoch=$(date -d "$expiry_date" +%s 2>/dev/null || date -j -f "%b %d %T %Y %Z" "$expiry_date" +%s 2>/dev/null)
if [[ -z "$expiry_epoch" ]]; then
echo "?"
return
fi
local now_epoch
now_epoch=$(date +%s)
echo $(((expiry_epoch - now_epoch) / 86400))
else
echo "?"
fi
}
function formatExpiry() {
local days="$1"
if [[ "$days" == "?" ]]; then
echo "(unknown expiry)"
elif [[ $days -lt 0 ]]; then
echo "(EXPIRED $((-days)) days ago)"
elif [[ $days -eq 0 ]]; then
echo "(expires today)"
elif [[ $days -eq 1 ]]; then
echo "(expires in 1 day)"
else
echo "(expires in $days days)"
fi
}
function renewMenu() {
local server_name server_cert server_days server_expiry renew_option
log_header "Certificate Renewal"
# Get server certificate expiry for menu display
server_name=$(grep '^cert ' /etc/openvpn/server.conf | cut -d ' ' -f 2 | sed 's/\.crt$//')
if [[ -z "$server_name" ]]; then
server_expiry="(unknown expiry)"
else
server_cert="/etc/openvpn/easy-rsa/pki/issued/$server_name.crt"
server_days=$(getDaysUntilExpiry "$server_cert")
server_expiry=$(formatExpiry "$server_days")
fi
log_menu ""
log_prompt "What do you want to renew?"
log_menu " 1) Renew a client certificate"
log_menu " 2) Renew the server certificate $server_expiry"
log_menu " 3) Back to main menu"
until [[ ${RENEW_OPTION:-$renew_option} =~ ^[1-3]$ ]]; do
read -rp "Select an option [1-3]: " renew_option
done
renew_option="${RENEW_OPTION:-$renew_option}"
case $renew_option in
1)
renewClient
;;
2)
renewServer
;;
3)
manageMenu
;;
esac
}
function removeUnbound() {
# Remove OpenVPN-related config
run_cmd "Removing Unbound include" sed -i '/include: \/etc\/unbound\/openvpn.conf/d' /etc/unbound/unbound.conf
@@ -1584,6 +1810,8 @@ function removeOpenVPN() {
}
function manageMenu() {
local menu_option
log_header "OpenVPN Management"
log_prompt "The git repository is available at: https://github.com/angristan/openvpn-install"
log_success "OpenVPN is already installed."
@@ -1591,13 +1819,15 @@ function manageMenu() {
log_prompt "What do you want to do?"
log_menu " 1) Add a new user"
log_menu " 2) Revoke existing user"
log_menu " 3) Remove OpenVPN"
log_menu " 4) Exit"
until [[ $MENU_OPTION =~ ^[1-4]$ ]]; do
read -rp "Select an option [1-4]: " MENU_OPTION
log_menu " 3) Renew certificate"
log_menu " 4) Remove OpenVPN"
log_menu " 5) Exit"
until [[ ${MENU_OPTION:-$menu_option} =~ ^[1-5]$ ]]; do
read -rp "Select an option [1-5]: " menu_option
done
menu_option="${MENU_OPTION:-$menu_option}"
case $MENU_OPTION in
case $menu_option in
1)
newClient
;;
@@ -1605,9 +1835,12 @@ function manageMenu() {
revokeClient
;;
3)
removeOpenVPN
renewMenu
;;
4)
removeOpenVPN
;;
5)
exit 0
;;
esac
@@ -1617,7 +1850,7 @@ function manageMenu() {
initialCheck
# Check if OpenVPN is already installed
if [[ -e /etc/openvpn/server.conf && $AUTO_INSTALL != "y" ]]; then
if [[ -e /etc/openvpn/server.conf ]]; then
manageMenu
else
installOpenVPN

View File

@@ -92,6 +92,157 @@ cp /root/testclient.ovpn /shared/client.ovpn
sed -i 's/^remote .*/remote openvpn-server 1194/' /shared/client.ovpn
echo "Client config copied to /shared/client.ovpn"
# =====================================================
# Test certificate renewal functionality
# =====================================================
echo ""
echo "=== Testing Certificate Renewal ==="
# Get the original certificate serial number for comparison
ORIG_CERT_SERIAL=$(openssl x509 -in /etc/openvpn/easy-rsa/pki/issued/testclient.crt -noout -serial | cut -d= -f2)
echo "Original client certificate serial: $ORIG_CERT_SERIAL"
# Test client certificate renewal using the script
echo "Testing client certificate renewal..."
RENEW_OUTPUT="/tmp/renew-client-output.log"
(MENU_OPTION=3 RENEW_OPTION=1 CLIENTNUMBER=1 DAYS_VALID=3650 bash /tmp/openvpn-install.sh) 2>&1 | tee "$RENEW_OUTPUT" || true
# Verify renewal succeeded
if grep -q "Certificate for client testclient renewed" "$RENEW_OUTPUT"; then
echo "PASS: Client renewal completed successfully"
else
echo "FAIL: Client renewal did not complete"
cat "$RENEW_OUTPUT"
exit 1
fi
# Verify new certificate has different serial
NEW_CERT_SERIAL=$(openssl x509 -in /etc/openvpn/easy-rsa/pki/issued/testclient.crt -noout -serial | cut -d= -f2)
echo "New client certificate serial: $NEW_CERT_SERIAL"
if [ "$ORIG_CERT_SERIAL" != "$NEW_CERT_SERIAL" ]; then
echo "PASS: Certificate serial changed (renewal created new cert)"
else
echo "FAIL: Certificate serial unchanged"
exit 1
fi
# Verify renewed certificate has correct validity period
# The default is 3650 days, so the cert should be valid for ~10 years from now
CLIENT_CERT_NOT_AFTER=$(openssl x509 -in /etc/openvpn/easy-rsa/pki/issued/testclient.crt -noout -enddate | cut -d= -f2)
CLIENT_CERT_NOT_BEFORE=$(openssl x509 -in /etc/openvpn/easy-rsa/pki/issued/testclient.crt -noout -startdate | cut -d= -f2)
echo "Client certificate valid from: $CLIENT_CERT_NOT_BEFORE"
echo "Client certificate valid until: $CLIENT_CERT_NOT_AFTER"
# Calculate days until expiry (should be close to 3650)
CERT_END_EPOCH=$(date -d "$CLIENT_CERT_NOT_AFTER" +%s 2>/dev/null || date -j -f "%b %d %T %Y %Z" "$CLIENT_CERT_NOT_AFTER" +%s 2>/dev/null)
NOW_EPOCH=$(date +%s)
DAYS_VALID_ACTUAL=$(((CERT_END_EPOCH - NOW_EPOCH) / 86400))
echo "Client certificate validity: $DAYS_VALID_ACTUAL days"
# Should be between 3640 and 3650 days (allowing some tolerance for timing)
if [ "$DAYS_VALID_ACTUAL" -ge 3640 ] && [ "$DAYS_VALID_ACTUAL" -le 3650 ]; then
echo "PASS: Client certificate validity is correct (~3650 days)"
else
echo "FAIL: Client certificate validity is unexpected: $DAYS_VALID_ACTUAL days (expected ~3650)"
exit 1
fi
# Verify new .ovpn file was generated
if [ -f /root/testclient.ovpn ]; then
echo "PASS: New .ovpn file generated"
else
echo "FAIL: .ovpn file not found after renewal"
exit 1
fi
# Verify CRL was updated
if [ -f /etc/openvpn/crl.pem ]; then
echo "PASS: CRL file exists"
else
echo "FAIL: CRL file missing after renewal"
exit 1
fi
# Update shared client config with renewed certificate
cp /root/testclient.ovpn /shared/client.ovpn
sed -i 's/^remote .*/remote openvpn-server 1194/' /shared/client.ovpn
echo "Updated client config with renewed certificate"
echo "=== Client Certificate Renewal Tests PASSED ==="
# =====================================================
# Test server certificate renewal
# =====================================================
echo ""
echo "=== Testing Server Certificate Renewal ==="
# Get server certificate name and original serial
SERVER_NAME=$(grep '^cert ' /etc/openvpn/server.conf | cut -d ' ' -f 2 | sed 's/\.crt$//')
ORIG_SERVER_SERIAL=$(openssl x509 -in "/etc/openvpn/easy-rsa/pki/issued/$SERVER_NAME.crt" -noout -serial | cut -d= -f2)
echo "Server certificate: $SERVER_NAME"
echo "Original server certificate serial: $ORIG_SERVER_SERIAL"
# Test server certificate renewal
echo "Testing server certificate renewal..."
RENEW_SERVER_OUTPUT="/tmp/renew-server-output.log"
(MENU_OPTION=3 RENEW_OPTION=2 CONTINUE=y DAYS_VALID=3650 bash /tmp/openvpn-install.sh) 2>&1 | tee "$RENEW_SERVER_OUTPUT" || true
# Verify renewal succeeded
if grep -q "Server certificate renewed successfully" "$RENEW_SERVER_OUTPUT"; then
echo "PASS: Server renewal completed successfully"
else
echo "FAIL: Server renewal did not complete"
cat "$RENEW_SERVER_OUTPUT"
exit 1
fi
# Verify new certificate has different serial
NEW_SERVER_SERIAL=$(openssl x509 -in "/etc/openvpn/easy-rsa/pki/issued/$SERVER_NAME.crt" -noout -serial | cut -d= -f2)
echo "New server certificate serial: $NEW_SERVER_SERIAL"
if [ "$ORIG_SERVER_SERIAL" != "$NEW_SERVER_SERIAL" ]; then
echo "PASS: Server certificate serial changed (renewal created new cert)"
else
echo "FAIL: Server certificate serial unchanged"
exit 1
fi
# Verify renewed server certificate has correct validity period
SERVER_CERT_NOT_AFTER=$(openssl x509 -in "/etc/openvpn/easy-rsa/pki/issued/$SERVER_NAME.crt" -noout -enddate | cut -d= -f2)
SERVER_CERT_NOT_BEFORE=$(openssl x509 -in "/etc/openvpn/easy-rsa/pki/issued/$SERVER_NAME.crt" -noout -startdate | cut -d= -f2)
echo "Server certificate valid from: $SERVER_CERT_NOT_BEFORE"
echo "Server certificate valid until: $SERVER_CERT_NOT_AFTER"
# Calculate days until expiry (should be close to 3650)
SERVER_END_EPOCH=$(date -d "$SERVER_CERT_NOT_AFTER" +%s 2>/dev/null || date -j -f "%b %d %T %Y %Z" "$SERVER_CERT_NOT_AFTER" +%s 2>/dev/null)
SERVER_DAYS_VALID=$(((SERVER_END_EPOCH - NOW_EPOCH) / 86400))
echo "Server certificate validity: $SERVER_DAYS_VALID days"
if [ "$SERVER_DAYS_VALID" -ge 3640 ] && [ "$SERVER_DAYS_VALID" -le 3650 ]; then
echo "PASS: Server certificate validity is correct (~3650 days)"
else
echo "FAIL: Server certificate validity is unexpected: $SERVER_DAYS_VALID days (expected ~3650)"
exit 1
fi
# Verify the new certificate was copied to /etc/openvpn/
if [ -f "/etc/openvpn/$SERVER_NAME.crt" ]; then
DEPLOYED_SERIAL=$(openssl x509 -in "/etc/openvpn/$SERVER_NAME.crt" -noout -serial | cut -d= -f2)
if [ "$NEW_SERVER_SERIAL" = "$DEPLOYED_SERIAL" ]; then
echo "PASS: New server certificate deployed to /etc/openvpn/"
else
echo "FAIL: Deployed certificate doesn't match renewed certificate"
exit 1
fi
else
echo "FAIL: Server certificate not found in /etc/openvpn/"
exit 1
fi
echo "=== Server Certificate Renewal Tests PASSED ==="
echo ""
echo "=== All Certificate Renewal Tests PASSED ==="
echo ""
# Start OpenVPN server manually (systemd doesn't work in containers)
echo "Starting OpenVPN server..."