mirror of
https://github.com/angristan/openvpn-install.git
synced 2025-12-17 17:27:03 +01:00
Merge origin/master into pr-962
This commit is contained in:
12
.github/workflows/docker-test.yml
vendored
12
.github/workflows/docker-test.yml
vendored
@@ -9,7 +9,7 @@ name: Docker Test
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -89,6 +89,15 @@ jobs:
|
||||
name: tls-auth
|
||||
sig: "3"
|
||||
key_file: tls-auth.key
|
||||
# Test firewalld support on Fedora
|
||||
- os:
|
||||
name: fedora-42-firewalld
|
||||
image: fedora:42
|
||||
enable_firewalld: true
|
||||
tls:
|
||||
name: tls-crypt-v2
|
||||
sig: "1"
|
||||
key_file: tls-crypt-v2.key
|
||||
|
||||
name: ${{ matrix.os.name }}
|
||||
steps:
|
||||
@@ -103,6 +112,7 @@ jobs:
|
||||
run: |
|
||||
docker build \
|
||||
--build-arg BASE_IMAGE=${{ matrix.os.image }} \
|
||||
--build-arg ENABLE_FIREWALLD=${{ matrix.os.enable_firewalld && 'y' || 'n' }} \
|
||||
-t openvpn-server \
|
||||
-f test/Dockerfile.server .
|
||||
|
||||
|
||||
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -8,7 +8,7 @@ name: Lint
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
3
.github/workflows/update-easyrsa-hash.yml
vendored
3
.github/workflows/update-easyrsa-hash.yml
vendored
@@ -61,10 +61,13 @@ jobs:
|
||||
|
||||
- name: Commit changes
|
||||
if: env.HASH_CHANGED == 'true'
|
||||
env:
|
||||
PAT: ${{ secrets.PAT }}
|
||||
run: |
|
||||
if ! git diff --quiet openvpn-install.sh; then
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git remote set-url origin "https://x-access-token:${PAT}@github.com/${{ github.repository }}"
|
||||
git add openvpn-install.sh
|
||||
git commit -m "chore: update Easy-RSA SHA256 hash"
|
||||
git push
|
||||
|
||||
4
FAQ.md
4
FAQ.md
@@ -87,9 +87,9 @@ If your client is <2.3.3, remove `tls-version-min 1.2` from your `/etc/openvpn/s
|
||||
|
||||
---
|
||||
|
||||
**Q:** What syctl and iptables changes are made by the script?
|
||||
**Q:** What sysctl and firewall changes are made by the script?
|
||||
|
||||
**A:** Iptables rules are saved at `/etc/iptables/add-openvpn-rules.sh` and `/etc/iptables/rm-openvpn-rules.sh`. They are managed by the service `/etc/systemd/system/iptables-openvpn.service`
|
||||
**A:** If firewalld is active, the script uses `firewall-cmd --permanent` to configure port, masquerade, and rich rules. Otherwise, iptables rules are saved at `/etc/iptables/add-openvpn-rules.sh` and `/etc/iptables/rm-openvpn-rules.sh`, managed by `/etc/systemd/system/iptables-openvpn.service`.
|
||||
|
||||
Sysctl options are at `/etc/sysctl.d/99-openvpn.conf`
|
||||
|
||||
|
||||
36
README.md
36
README.md
@@ -59,7 +59,8 @@ The first time you run it, you'll have to follow the assistant and answer a few
|
||||
When OpenVPN is installed, you can run the script again, and you will get the choice to:
|
||||
|
||||
- Add a client
|
||||
- Remove a client
|
||||
- List client certificates
|
||||
- Revoke a client
|
||||
- Renew certificates (client or server)
|
||||
- Uninstall OpenVPN
|
||||
|
||||
@@ -95,10 +96,11 @@ If you want to customise your installation, you can export them or specify them
|
||||
- `COMPRESSION_ENABLED=n`
|
||||
- `CUSTOMIZE_ENC=n`
|
||||
- `CLIENT=clientname`
|
||||
- `PASS=1`
|
||||
- `PASS=1` (set to `2` for password-protected clients, requires `PASSPHRASE`)
|
||||
- `MULTI_CLIENT=n`
|
||||
- `CLIENT_CERT_DURATION_DAYS=3650`
|
||||
- `SERVER_CERT_DURATION_DAYS=3650`
|
||||
- `NEW_CLIENT=y` (set to `n` to skip client creation after installation)
|
||||
- `CLIENT_FILEPATH=/custom/path/client.ovpn` (optional, overrides default output path)
|
||||
|
||||
The `.ovpn` file is saved to `CLIENT_FILEPATH` if defined, otherwise: the client's home directory if it exists (`/home/$CLIENT`), otherwise `SUDO_USER`'s home, otherwise `/root`.
|
||||
@@ -107,8 +109,6 @@ If the server is behind NAT, you can specify its endpoint with the `ENDPOINT` va
|
||||
|
||||
Other variables can be set depending on your choice (encryption, compression). You can search for them in the `installQuestions()` function of the script.
|
||||
|
||||
Password-protected clients are not supported by the headless installation method since user input is expected by Easy-RSA.
|
||||
|
||||
The headless install is more-or-less idempotent, in that it has been made safe to run multiple times with the same parameters, e.g. by a state provisioner like Ansible/Terraform/Salt/Chef/Puppet. It will only install and regenerate the Easy-RSA PKI if it doesn't already exist, and it will only install OpenVPN and other upstream dependencies if OpenVPN isn't already installed. It will recreate all local config and re-generate the client file on each headless run.
|
||||
|
||||
### Headless User Addition
|
||||
@@ -121,20 +121,42 @@ The following Bash script adds a new user `foo` to an existing OpenVPN configura
|
||||
#!/bin/bash
|
||||
export MENU_OPTION="1"
|
||||
export CLIENT="foo"
|
||||
export PASS="1"
|
||||
export PASS="1" # set to "2" for a password-protected client, and set PASSPHRASE
|
||||
# export CLIENT_FILEPATH="/etc/openvpn/clients/foo.ovpn"
|
||||
./openvpn-install.sh
|
||||
```
|
||||
|
||||
**Note:** When a client name matches a system user (e.g., `foo` and `/home/foo` exists), the script automatically sets proper ownership and permissions on the `.ovpn` file.
|
||||
|
||||
### Headless User Revocation
|
||||
|
||||
It's also possible to automate the revocation of an existing user. The key is to provide the `MENU_OPTION` variable set to `3` along with either `CLIENT` (client name) or `CLIENTNUMBER` (1-based index from the client list).
|
||||
|
||||
The following Bash script revokes the existing user `foo`:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
export MENU_OPTION="3"
|
||||
export CLIENT="foo"
|
||||
./openvpn-install.sh
|
||||
```
|
||||
|
||||
Alternatively, you can use the client number:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
export MENU_OPTION="3"
|
||||
export CLIENTNUMBER="1" # Revokes the first client in the list
|
||||
./openvpn-install.sh
|
||||
```
|
||||
|
||||
## 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
|
||||
- Firewall rules and forwarding managed seamlessly (native firewalld support, iptables fallback)
|
||||
- If needed, the script can cleanly remove OpenVPN, including configuration and firewall rules
|
||||
- Customisable encryption settings, enhanced default settings (see [Security and Encryption](#security-and-encryption) below)
|
||||
- OpenVPN 2.4 features, mainly encryption improvements (see [Security and Encryption](#security-and-encryption) below)
|
||||
- Variety of DNS resolvers to be pushed to the clients
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
# Configuration constants
|
||||
readonly DEFAULT_CERT_VALIDITY_DURATION_DAYS=3650 # 10 years
|
||||
readonly DEFAULT_CRL_VALIDITY_DURATION_DAYS=5475 # 15 years
|
||||
readonly EASYRSA_VERSION="3.2.4"
|
||||
readonly EASYRSA_SHA256="ed65e88cea892268efa71eb1161ce13af3beded6754301e1e713e36ff3613cac"
|
||||
readonly EASYRSA_VERSION="3.2.5"
|
||||
readonly EASYRSA_SHA256="662ee3b453155aeb1dff7096ec052cd83176c460cfa82ac130ef8568ec4df490"
|
||||
|
||||
# =============================================================================
|
||||
# Logging Configuration
|
||||
@@ -671,7 +671,7 @@ function installQuestions() {
|
||||
log_menu " 12) NextDNS (Anycast: worldwide)"
|
||||
log_menu " 13) Custom"
|
||||
until [[ $DNS =~ ^[0-9]+$ ]] && [ "$DNS" -ge 1 ] && [ "$DNS" -le 13 ]; do
|
||||
read -rp "DNS [1-13]: " -e -i 11 DNS
|
||||
read -rp "DNS [1-13]: " -e -i 3 DNS
|
||||
if [[ $DNS == 2 ]] && [[ -e /etc/unbound/unbound.conf ]]; then
|
||||
log_menu ""
|
||||
log_prompt "Unbound is already installed."
|
||||
@@ -981,7 +981,7 @@ function installOpenVPN() {
|
||||
IPV6_SUPPORT=${IPV6_SUPPORT:-n}
|
||||
PORT_CHOICE=${PORT_CHOICE:-1}
|
||||
PROTOCOL_CHOICE=${PROTOCOL_CHOICE:-1}
|
||||
DNS=${DNS:-1}
|
||||
DNS=${DNS:-3}
|
||||
COMPRESSION_ENABLED=${COMPRESSION_ENABLED:-n}
|
||||
MULTI_CLIENT=${MULTI_CLIENT:-n}
|
||||
CUSTOMIZE_ENC=${CUSTOMIZE_ENC:-n}
|
||||
@@ -990,6 +990,7 @@ function installOpenVPN() {
|
||||
CLIENT_CERT_DURATION_DAYS=${CLIENT_CERT_DURATION_DAYS:-$DEFAULT_CERT_VALIDITY_DURATION_DAYS}
|
||||
SERVER_CERT_DURATION_DAYS=${SERVER_CERT_DURATION_DAYS:-$DEFAULT_CERT_VALIDITY_DURATION_DAYS}
|
||||
CONTINUE=${CONTINUE:-y}
|
||||
NEW_CLIENT=${NEW_CLIENT:-y}
|
||||
|
||||
if [[ -z $ENDPOINT ]]; then
|
||||
ENDPOINT=$(resolvePublicIP)
|
||||
@@ -1083,11 +1084,6 @@ function installOpenVPN() {
|
||||
|
||||
# Create the server directory (OpenVPN 2.4+ directory structure)
|
||||
run_cmd_fatal "Creating server directory" mkdir -p /etc/openvpn/server
|
||||
|
||||
# An old version of easy-rsa was available by default in some openvpn packages
|
||||
if [[ -d /etc/openvpn/server/easy-rsa/ ]]; then
|
||||
run_cmd "Removing old Easy-RSA" rm -rf /etc/openvpn/server/easy-rsa/
|
||||
fi
|
||||
fi
|
||||
|
||||
# Determine which user/group OpenVPN should run as
|
||||
@@ -1175,11 +1171,11 @@ function installOpenVPN() {
|
||||
;;
|
||||
2)
|
||||
# Generate tls-crypt key
|
||||
run_cmd_fatal "Generating tls-crypt key" openvpn --genkey --secret /etc/openvpn/server/tls-crypt.key
|
||||
run_cmd_fatal "Generating tls-crypt key" openvpn --genkey secret /etc/openvpn/server/tls-crypt.key
|
||||
;;
|
||||
3)
|
||||
# Generate tls-auth key
|
||||
run_cmd_fatal "Generating tls-auth key" openvpn --genkey --secret /etc/openvpn/server/tls-auth.key
|
||||
run_cmd_fatal "Generating tls-auth key" openvpn --genkey secret /etc/openvpn/server/tls-auth.key
|
||||
;;
|
||||
esac
|
||||
else
|
||||
@@ -1423,48 +1419,66 @@ verb 3" >>/etc/openvpn/server/server.conf
|
||||
installUnbound
|
||||
fi
|
||||
|
||||
# Add iptables rules in two scripts
|
||||
# Configure firewall rules
|
||||
log_info "Configuring firewall rules..."
|
||||
run_cmd_fatal "Creating iptables directory" mkdir -p /etc/iptables
|
||||
|
||||
# Script to add rules
|
||||
echo "#!/bin/sh
|
||||
if systemctl is-active --quiet firewalld; then
|
||||
# Use firewalld native commands for systems with firewalld active
|
||||
log_info "firewalld detected, using firewall-cmd..."
|
||||
run_cmd "Adding OpenVPN port to firewalld" firewall-cmd --permanent --add-port="$PORT/$PROTOCOL"
|
||||
run_cmd "Adding masquerade to firewalld" firewall-cmd --permanent --add-masquerade
|
||||
|
||||
# Add rich rules for VPN traffic (source-based rules work reliably with dynamic tun0 interface)
|
||||
run_cmd "Adding VPN subnet rule" firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.8.0.0/24" accept'
|
||||
|
||||
if [[ $IPV6_SUPPORT == 'y' ]]; then
|
||||
run_cmd "Adding IPv6 source rule" firewall-cmd --permanent --add-rich-rule='rule family="ipv6" source address="fd42:42:42:42::/112" accept'
|
||||
fi
|
||||
|
||||
run_cmd "Reloading firewalld" firewall-cmd --reload
|
||||
else
|
||||
# Use iptables for systems without firewalld
|
||||
run_cmd_fatal "Creating iptables directory" mkdir -p /etc/iptables
|
||||
|
||||
# Script to add rules
|
||||
echo "#!/bin/sh
|
||||
iptables -t nat -I POSTROUTING 1 -s 10.8.0.0/24 -o $NIC -j MASQUERADE
|
||||
iptables -I INPUT 1 -i tun0 -j ACCEPT
|
||||
iptables -I FORWARD 1 -i $NIC -o tun0 -j ACCEPT
|
||||
iptables -I FORWARD 1 -i tun0 -o $NIC -j ACCEPT
|
||||
iptables -I INPUT 1 -i $NIC -p $PROTOCOL --dport $PORT -j ACCEPT" >/etc/iptables/add-openvpn-rules.sh
|
||||
|
||||
if [[ $IPV6_SUPPORT == 'y' ]]; then
|
||||
echo "ip6tables -t nat -I POSTROUTING 1 -s fd42:42:42:42::/112 -o $NIC -j MASQUERADE
|
||||
if [[ $IPV6_SUPPORT == 'y' ]]; then
|
||||
echo "ip6tables -t nat -I POSTROUTING 1 -s fd42:42:42:42::/112 -o $NIC -j MASQUERADE
|
||||
ip6tables -I INPUT 1 -i tun0 -j ACCEPT
|
||||
ip6tables -I FORWARD 1 -i $NIC -o tun0 -j ACCEPT
|
||||
ip6tables -I FORWARD 1 -i tun0 -o $NIC -j ACCEPT
|
||||
ip6tables -I INPUT 1 -i $NIC -p $PROTOCOL --dport $PORT -j ACCEPT" >>/etc/iptables/add-openvpn-rules.sh
|
||||
fi
|
||||
fi
|
||||
|
||||
# Script to remove rules
|
||||
echo "#!/bin/sh
|
||||
# Script to remove rules
|
||||
echo "#!/bin/sh
|
||||
iptables -t nat -D POSTROUTING -s 10.8.0.0/24 -o $NIC -j MASQUERADE
|
||||
iptables -D INPUT -i tun0 -j ACCEPT
|
||||
iptables -D FORWARD -i $NIC -o tun0 -j ACCEPT
|
||||
iptables -D FORWARD -i tun0 -o $NIC -j ACCEPT
|
||||
iptables -D INPUT -i $NIC -p $PROTOCOL --dport $PORT -j ACCEPT" >/etc/iptables/rm-openvpn-rules.sh
|
||||
|
||||
if [[ $IPV6_SUPPORT == 'y' ]]; then
|
||||
echo "ip6tables -t nat -D POSTROUTING -s fd42:42:42:42::/112 -o $NIC -j MASQUERADE
|
||||
if [[ $IPV6_SUPPORT == 'y' ]]; then
|
||||
echo "ip6tables -t nat -D POSTROUTING -s fd42:42:42:42::/112 -o $NIC -j MASQUERADE
|
||||
ip6tables -D INPUT -i tun0 -j ACCEPT
|
||||
ip6tables -D FORWARD -i $NIC -o tun0 -j ACCEPT
|
||||
ip6tables -D FORWARD -i tun0 -o $NIC -j ACCEPT
|
||||
ip6tables -D INPUT -i $NIC -p $PROTOCOL --dport $PORT -j ACCEPT" >>/etc/iptables/rm-openvpn-rules.sh
|
||||
fi
|
||||
fi
|
||||
|
||||
run_cmd "Making add-openvpn-rules.sh executable" chmod +x /etc/iptables/add-openvpn-rules.sh
|
||||
run_cmd "Making rm-openvpn-rules.sh executable" chmod +x /etc/iptables/rm-openvpn-rules.sh
|
||||
run_cmd "Making add-openvpn-rules.sh executable" chmod +x /etc/iptables/add-openvpn-rules.sh
|
||||
run_cmd "Making rm-openvpn-rules.sh executable" chmod +x /etc/iptables/rm-openvpn-rules.sh
|
||||
|
||||
# Handle the rules via a systemd script
|
||||
echo "[Unit]
|
||||
# Handle the rules via a systemd script
|
||||
echo "[Unit]
|
||||
Description=iptables rules for OpenVPN
|
||||
After=firewalld.service
|
||||
Before=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
@@ -1477,10 +1491,11 @@ RemainAfterExit=yes
|
||||
[Install]
|
||||
WantedBy=multi-user.target" >/etc/systemd/system/iptables-openvpn.service
|
||||
|
||||
# Enable service and apply rules
|
||||
run_cmd "Reloading systemd" systemctl daemon-reload
|
||||
run_cmd "Enabling iptables service" systemctl enable iptables-openvpn
|
||||
run_cmd "Starting iptables service" systemctl start iptables-openvpn
|
||||
# Enable service and apply rules
|
||||
run_cmd "Reloading systemd" systemctl daemon-reload
|
||||
run_cmd "Enabling iptables service" systemctl enable iptables-openvpn
|
||||
run_cmd "Starting iptables service" systemctl start iptables-openvpn
|
||||
fi
|
||||
|
||||
# If the server is behind a NAT, use the correct IP address for the clients to connect to
|
||||
if [[ $ENDPOINT != "" ]]; then
|
||||
@@ -1522,9 +1537,13 @@ verb 3" >>/etc/openvpn/server/client-template.txt
|
||||
fi
|
||||
|
||||
# Generate the custom client.ovpn
|
||||
log_info "Generating first client certificate..."
|
||||
newClient
|
||||
log_success "If you want to add more clients, you simply need to run this script another time!"
|
||||
if [[ $NEW_CLIENT == "n" ]]; then
|
||||
log_info "No clients added. To add clients, simply run the script again."
|
||||
else
|
||||
log_info "Generating first client certificate..."
|
||||
newClient
|
||||
log_success "If you want to add more clients, you simply need to run this script another time!"
|
||||
fi
|
||||
}
|
||||
|
||||
# Helper function to get the home directory for storing client configs
|
||||
@@ -1651,6 +1670,15 @@ function selectClient() {
|
||||
log_fatal "You have no existing clients!"
|
||||
fi
|
||||
|
||||
# If CLIENT is set, validate it exists as a valid client
|
||||
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
|
||||
return
|
||||
else
|
||||
log_fatal "Client '$CLIENT' not found or not valid"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $show_expiry == "true" ]]; then
|
||||
local i=1
|
||||
while read -r client; do
|
||||
@@ -1677,6 +1705,88 @@ function selectClient() {
|
||||
CLIENT=$(tail -n +2 /etc/openvpn/server/easy-rsa/pki/index.txt | grep "^V" | cut -d '=' -f 2 | sed -n "$CLIENTNUMBER"p)
|
||||
}
|
||||
|
||||
function listClients() {
|
||||
log_header "Client Certificates"
|
||||
|
||||
local index_file="/etc/openvpn/server/easy-rsa/pki/index.txt"
|
||||
local number_of_clients
|
||||
# Exclude server certificates (CN starting with server_)
|
||||
number_of_clients=$(tail -n +2 "$index_file" | grep "^[VR]" | grep -cv "/CN=server_")
|
||||
|
||||
if [[ $number_of_clients == '0' ]]; then
|
||||
log_warn "You have no existing client certificates!"
|
||||
return
|
||||
fi
|
||||
|
||||
log_info "Found $number_of_clients client certificate(s)"
|
||||
log_menu ""
|
||||
printf " %-25s %-10s %-12s %s\n" "Name" "Status" "Expiry" "Remaining"
|
||||
printf " %-25s %-10s %-12s %s\n" "----" "------" "------" "---------"
|
||||
|
||||
local cert_dir="/etc/openvpn/server/easy-rsa/pki/issued"
|
||||
|
||||
# Parse index.txt and sort by expiry date (oldest first)
|
||||
# Exclude server certificates (CN starting with server_)
|
||||
{
|
||||
while read -r line; do
|
||||
local status="${line:0:1}"
|
||||
local client_name
|
||||
client_name=$(echo "$line" | sed 's/.*\/CN=//')
|
||||
|
||||
# Format status
|
||||
local status_text
|
||||
if [[ "$status" == "V" ]]; then
|
||||
status_text="Valid"
|
||||
elif [[ "$status" == "R" ]]; then
|
||||
status_text="Revoked"
|
||||
else
|
||||
status_text="Unknown"
|
||||
fi
|
||||
|
||||
# Get expiry date from certificate file
|
||||
local cert_file="$cert_dir/$client_name.crt"
|
||||
local expiry_date="unknown"
|
||||
local relative="unknown"
|
||||
|
||||
if [[ -f "$cert_file" ]]; then
|
||||
# Get expiry from certificate (format: notAfter=Mon DD HH:MM:SS YYYY GMT)
|
||||
local enddate
|
||||
enddate=$(openssl x509 -enddate -noout -in "$cert_file" 2>/dev/null | cut -d= -f2)
|
||||
|
||||
if [[ -n "$enddate" ]]; then
|
||||
# Parse date and convert to epoch
|
||||
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
|
||||
# Format as YYYY-MM-DD
|
||||
expiry_date=$(date -d "@$expiry_epoch" +%Y-%m-%d 2>/dev/null || date -r "$expiry_epoch" +%Y-%m-%d 2>/dev/null)
|
||||
|
||||
# Calculate days remaining
|
||||
local now_epoch days_remaining
|
||||
now_epoch=$(date +%s)
|
||||
days_remaining=$(((expiry_epoch - now_epoch) / 86400))
|
||||
|
||||
if [[ $days_remaining -lt 0 ]]; then
|
||||
relative="$((-days_remaining)) days ago"
|
||||
elif [[ $days_remaining -eq 0 ]]; then
|
||||
relative="today"
|
||||
elif [[ $days_remaining -eq 1 ]]; then
|
||||
relative="1 day"
|
||||
else
|
||||
relative="$days_remaining days"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
printf " %-25s %-10s %-12s %s\n" "$client_name" "$status_text" "$expiry_date" "$relative"
|
||||
done < <(tail -n +2 "$index_file" | grep "^[VR]" | grep -v "/CN=server_" | sort -t$'\t' -k2)
|
||||
}
|
||||
|
||||
log_menu ""
|
||||
}
|
||||
|
||||
function newClient() {
|
||||
log_header "New Client Setup"
|
||||
log_prompt "Tell me a name for the client."
|
||||
@@ -1717,10 +1827,18 @@ function newClient() {
|
||||
run_cmd_fatal "Building client certificate" ./easyrsa --batch build-client-full "$CLIENT" nopass
|
||||
;;
|
||||
2)
|
||||
log_warn "You will be asked for the client password below"
|
||||
# Run directly (not via run_cmd) so password prompt is visible to user
|
||||
if ! ./easyrsa --batch build-client-full "$CLIENT"; then
|
||||
log_fatal "Building client certificate failed"
|
||||
if [[ -z "$PASSPHRASE" ]]; then
|
||||
log_warn "You will be asked for the client password below"
|
||||
# Run directly (not via run_cmd) so password prompt is visible to user
|
||||
if ! ./easyrsa --batch build-client-full "$CLIENT"; then
|
||||
log_fatal "Building client certificate failed"
|
||||
fi
|
||||
else
|
||||
log_info "Using provided passphrase for client certificate"
|
||||
# Use env var to avoid exposing passphrase in install log
|
||||
export EASYRSA_PASSPHRASE="$PASSPHRASE"
|
||||
run_cmd_fatal "Building client certificate" ./easyrsa --batch --passin=env:EASYRSA_PASSPHRASE --passout=env:EASYRSA_PASSPHRASE build-client-full "$CLIENT"
|
||||
unset EASYRSA_PASSPHRASE
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
@@ -2010,15 +2128,24 @@ function removeOpenVPN() {
|
||||
# Remove customised service
|
||||
run_cmd "Removing service file" rm -f /etc/systemd/system/openvpn-server@.service
|
||||
|
||||
# Remove the iptables rules related to the script
|
||||
log_info "Removing iptables rules..."
|
||||
run_cmd "Stopping iptables service" systemctl stop iptables-openvpn
|
||||
# Cleanup
|
||||
run_cmd "Disabling iptables service" systemctl disable iptables-openvpn
|
||||
run_cmd "Removing iptables service file" rm /etc/systemd/system/iptables-openvpn.service
|
||||
run_cmd "Reloading systemd" systemctl daemon-reload
|
||||
run_cmd "Removing iptables add script" rm /etc/iptables/add-openvpn-rules.sh
|
||||
run_cmd "Removing iptables rm script" rm /etc/iptables/rm-openvpn-rules.sh
|
||||
# Remove firewall rules
|
||||
log_info "Removing firewall rules..."
|
||||
if systemctl is-active --quiet firewalld && firewall-cmd --list-ports | grep -q "$PORT/$PROTOCOL"; then
|
||||
# firewalld was used
|
||||
run_cmd "Removing OpenVPN port from firewalld" firewall-cmd --permanent --remove-port="$PORT/$PROTOCOL"
|
||||
run_cmd "Removing masquerade from firewalld" firewall-cmd --permanent --remove-masquerade
|
||||
run_cmd "Removing VPN subnet rule" firewall-cmd --permanent --remove-rich-rule='rule family="ipv4" source address="10.8.0.0/24" accept' 2>/dev/null || true
|
||||
run_cmd "Removing IPv6 source rule" firewall-cmd --permanent --remove-rich-rule='rule family="ipv6" source address="fd42:42:42:42::/112" accept' 2>/dev/null || true
|
||||
run_cmd "Reloading firewalld" firewall-cmd --reload
|
||||
elif [[ -f /etc/systemd/system/iptables-openvpn.service ]]; then
|
||||
# iptables was used
|
||||
run_cmd "Stopping iptables service" systemctl stop iptables-openvpn
|
||||
run_cmd "Disabling iptables service" systemctl disable iptables-openvpn
|
||||
run_cmd "Removing iptables service file" rm /etc/systemd/system/iptables-openvpn.service
|
||||
run_cmd "Reloading systemd" systemctl daemon-reload
|
||||
run_cmd "Removing iptables add script" rm -f /etc/iptables/add-openvpn-rules.sh
|
||||
run_cmd "Removing iptables rm script" rm -f /etc/iptables/rm-openvpn-rules.sh
|
||||
fi
|
||||
|
||||
# SELinux
|
||||
if hash sestatus 2>/dev/null; then
|
||||
@@ -2085,12 +2212,13 @@ function manageMenu() {
|
||||
log_menu ""
|
||||
log_prompt "What do you want to do?"
|
||||
log_menu " 1) Add a new user"
|
||||
log_menu " 2) Revoke existing user"
|
||||
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
|
||||
log_menu " 2) List client certificates"
|
||||
log_menu " 3) Revoke existing user"
|
||||
log_menu " 4) Renew certificate"
|
||||
log_menu " 5) Remove OpenVPN"
|
||||
log_menu " 6) Exit"
|
||||
until [[ ${MENU_OPTION:-$menu_option} =~ ^[1-6]$ ]]; do
|
||||
read -rp "Select an option [1-6]: " menu_option
|
||||
done
|
||||
menu_option="${MENU_OPTION:-$menu_option}"
|
||||
|
||||
@@ -2099,15 +2227,18 @@ function manageMenu() {
|
||||
newClient
|
||||
;;
|
||||
2)
|
||||
revokeClient
|
||||
listClients
|
||||
;;
|
||||
3)
|
||||
renewMenu
|
||||
revokeClient
|
||||
;;
|
||||
4)
|
||||
removeOpenVPN
|
||||
renewMenu
|
||||
;;
|
||||
5)
|
||||
removeOpenVPN
|
||||
;;
|
||||
6)
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -5,7 +5,10 @@ ARG BASE_IMAGE=ubuntu:24.04
|
||||
FROM ${BASE_IMAGE}
|
||||
|
||||
ARG BASE_IMAGE
|
||||
# Set to "y" to install and enable firewalld for testing
|
||||
ARG ENABLE_FIREWALLD=n
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV ENABLE_FIREWALLD=${ENABLE_FIREWALLD}
|
||||
|
||||
# Install basic dependencies based on the OS
|
||||
# dnsutils/bind-utils provides dig for DNS testing with Unbound
|
||||
@@ -16,10 +19,12 @@ RUN if command -v apt-get >/dev/null; then \
|
||||
elif command -v dnf >/dev/null; then \
|
||||
dnf install -y --allowerasing \
|
||||
iproute iptables curl procps-ng systemd tar gzip bind-utils \
|
||||
&& if [ "$ENABLE_FIREWALLD" = "y" ]; then dnf install -y firewalld; fi \
|
||||
&& dnf clean all; \
|
||||
elif command -v yum >/dev/null; then \
|
||||
yum install -y \
|
||||
iproute iptables curl procps-ng systemd tar gzip bind-utils \
|
||||
&& if [ "$ENABLE_FIREWALLD" = "y" ]; then yum install -y firewalld; fi \
|
||||
&& yum clean all; \
|
||||
elif command -v pacman >/dev/null; then \
|
||||
pacman -Syu --noconfirm \
|
||||
@@ -31,6 +36,11 @@ RUN if command -v apt-get >/dev/null; then \
|
||||
&& zypper clean -a; \
|
||||
fi
|
||||
|
||||
# Enable firewalld if requested (must be done after systemd is available)
|
||||
RUN if [ "$ENABLE_FIREWALLD" = "y" ] && command -v firewall-cmd >/dev/null; then \
|
||||
systemctl enable firewalld; \
|
||||
fi
|
||||
|
||||
# Create TUN device (will be mounted at runtime)
|
||||
RUN mkdir -p /dev/net
|
||||
|
||||
|
||||
@@ -359,6 +359,86 @@ touch /shared/new-client-connected
|
||||
echo ""
|
||||
echo "=== Certificate Revocation E2E Tests PASSED ==="
|
||||
|
||||
# =====================================================
|
||||
# Test PASSPHRASE-protected client connection
|
||||
# =====================================================
|
||||
echo ""
|
||||
echo "=== Testing PASSPHRASE-protected Client Connection ==="
|
||||
|
||||
PASSPHRASE_CLIENT="passphrasetest"
|
||||
|
||||
# Wait for passphrase test client config
|
||||
echo "Waiting for passphrase test client config..."
|
||||
MAX_WAIT=120
|
||||
WAITED=0
|
||||
while [ ! -f /shared/passphrase-client-config-ready ] && [ $WAITED -lt $MAX_WAIT ]; do
|
||||
sleep 2
|
||||
WAITED=$((WAITED + 2))
|
||||
echo "Waiting for passphrase test config... ($WAITED/$MAX_WAIT seconds)"
|
||||
done
|
||||
|
||||
if [ ! -f /shared/passphrase-client-config-ready ]; then
|
||||
echo "FAIL: Passphrase test client config not ready in time"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "/shared/$PASSPHRASE_CLIENT.ovpn" ]; then
|
||||
echo "FAIL: Passphrase test client config file not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "/shared/$PASSPHRASE_CLIENT.pass" ]; then
|
||||
echo "FAIL: Passphrase file not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Passphrase test client config found!"
|
||||
|
||||
# Disconnect current VPN before connecting with passphrase client
|
||||
echo "Disconnecting current VPN connection..."
|
||||
pkill openvpn || true
|
||||
sleep 2
|
||||
|
||||
# Connect with passphrase-protected client using --askpass
|
||||
echo "Connecting with '$PASSPHRASE_CLIENT' certificate (passphrase-protected)..."
|
||||
openvpn --config "/shared/$PASSPHRASE_CLIENT.ovpn" --askpass "/shared/$PASSPHRASE_CLIENT.pass" --daemon --log /var/log/openvpn-passphrase.log
|
||||
|
||||
# Wait for connection
|
||||
echo "Waiting for VPN connection with passphrase-protected client..."
|
||||
MAX_WAIT=60
|
||||
WAITED=0
|
||||
while ! ip addr show tun0 2>/dev/null | grep -q "inet " && [ $WAITED -lt $MAX_WAIT ]; do
|
||||
sleep 2
|
||||
WAITED=$((WAITED + 2))
|
||||
echo "Waiting for tun0... ($WAITED/$MAX_WAIT seconds)"
|
||||
if [ -f /var/log/openvpn-passphrase.log ]; then
|
||||
tail -3 /var/log/openvpn-passphrase.log
|
||||
fi
|
||||
done
|
||||
|
||||
if ! ip addr show tun0 2>/dev/null | grep -q "inet "; then
|
||||
echo "FAIL: VPN connection with passphrase-protected client failed"
|
||||
cat /var/log/openvpn-passphrase.log || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "PASS: Connected with passphrase-protected '$PASSPHRASE_CLIENT' certificate"
|
||||
ip addr show tun0
|
||||
|
||||
# Verify connectivity
|
||||
if ping -c 2 10.8.0.1 >/dev/null 2>&1; then
|
||||
echo "PASS: Can ping VPN gateway with passphrase-protected client"
|
||||
else
|
||||
echo "FAIL: Cannot ping VPN gateway with passphrase-protected client"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Signal server that we connected with passphrase client
|
||||
touch /shared/passphrase-client-connected
|
||||
|
||||
echo ""
|
||||
echo "=== PASSPHRASE-protected Client Tests PASSED ==="
|
||||
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo " ALL TESTS PASSED!"
|
||||
|
||||
@@ -77,15 +77,22 @@ fi
|
||||
# Verify all expected files were created
|
||||
echo "Verifying installation..."
|
||||
MISSING_FILES=0
|
||||
for f in \
|
||||
/etc/openvpn/server/server.conf \
|
||||
/etc/openvpn/server/ca.crt \
|
||||
/etc/openvpn/server/ca.key \
|
||||
"/etc/openvpn/server/$TLS_KEY_FILE" \
|
||||
/etc/openvpn/server/crl.pem \
|
||||
/etc/openvpn/server/easy-rsa/pki/ca.crt \
|
||||
/etc/iptables/add-openvpn-rules.sh \
|
||||
/root/testclient.ovpn; do
|
||||
# Build list of required files
|
||||
REQUIRED_FILES=(
|
||||
/etc/openvpn/server/server.conf
|
||||
/etc/openvpn/server/ca.crt
|
||||
/etc/openvpn/server/ca.key
|
||||
"/etc/openvpn/server/$TLS_KEY_FILE"
|
||||
/etc/openvpn/server/crl.pem
|
||||
/etc/openvpn/server/easy-rsa/pki/ca.crt
|
||||
/root/testclient.ovpn
|
||||
)
|
||||
# Only check for iptables script if firewalld is not active
|
||||
if ! systemctl is-active --quiet firewalld; then
|
||||
REQUIRED_FILES+=(/etc/iptables/add-openvpn-rules.sh)
|
||||
fi
|
||||
|
||||
for f in "${REQUIRED_FILES[@]}"; do
|
||||
if [ ! -f "$f" ]; then
|
||||
echo "ERROR: Missing file: $f"
|
||||
MISSING_FILES=$((MISSING_FILES + 1))
|
||||
@@ -177,7 +184,7 @@ 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 CLIENT_CERT_DURATION_DAYS=3650 bash /opt/openvpn-install.sh) 2>&1 | tee "$RENEW_OUTPUT" || true
|
||||
(MENU_OPTION=4 RENEW_OPTION=1 CLIENTNUMBER=1 CLIENT_CERT_DURATION_DAYS=3650 bash /opt/openvpn-install.sh) 2>&1 | tee "$RENEW_OUTPUT" || true
|
||||
|
||||
# Verify renewal succeeded
|
||||
if grep -q "Certificate for client testclient renewed" "$RENEW_OUTPUT"; then
|
||||
@@ -257,7 +264,7 @@ 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 SERVER_CERT_DURATION_DAYS=3650 bash /opt/openvpn-install.sh) 2>&1 | tee "$RENEW_SERVER_OUTPUT" || true
|
||||
(MENU_OPTION=4 RENEW_OPTION=2 CONTINUE=y SERVER_CERT_DURATION_DAYS=3650 bash /opt/openvpn-install.sh) 2>&1 | tee "$RENEW_SERVER_OUTPUT" || true
|
||||
|
||||
# Verify renewal succeeded
|
||||
if grep -q "Server certificate renewed successfully" "$RENEW_SERVER_OUTPUT"; then
|
||||
@@ -380,21 +387,58 @@ echo ""
|
||||
# Verify OpenVPN server (started by systemd via install script)
|
||||
echo "Verifying OpenVPN server..."
|
||||
|
||||
# Verify iptables NAT rules exist (applied by iptables-openvpn service)
|
||||
echo "Verifying iptables NAT rules..."
|
||||
for _ in $(seq 1 10); do
|
||||
if iptables -t nat -L POSTROUTING -n | grep -q "10.8.0.0"; then
|
||||
echo "PASS: NAT POSTROUTING rule for 10.8.0.0/24 exists"
|
||||
break
|
||||
# Verify firewall rules exist
|
||||
echo "Verifying firewall rules..."
|
||||
if systemctl is-active --quiet firewalld; then
|
||||
# firewalld is active - verify masquerade is enabled
|
||||
echo "firewalld detected, checking masquerade..."
|
||||
for _ in $(seq 1 10); do
|
||||
if firewall-cmd --query-masquerade 2>/dev/null; then
|
||||
echo "PASS: firewalld masquerade is enabled"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
if ! firewall-cmd --query-masquerade 2>/dev/null; then
|
||||
echo "FAIL: firewalld masquerade is not enabled"
|
||||
echo "Current firewalld config:"
|
||||
firewall-cmd --list-all 2>&1 || true
|
||||
exit 1
|
||||
fi
|
||||
# Verify port is open
|
||||
if firewall-cmd --list-ports | grep -q "1194/udp"; then
|
||||
echo "PASS: OpenVPN port is open in firewalld"
|
||||
else
|
||||
echo "FAIL: OpenVPN port not found in firewalld"
|
||||
firewall-cmd --list-ports
|
||||
exit 1
|
||||
fi
|
||||
# Verify VPN subnet rich rule exists
|
||||
if firewall-cmd --list-rich-rules | grep -q 'source address="10.8.0.0/24"'; then
|
||||
echo "PASS: VPN subnet rich rule is configured"
|
||||
else
|
||||
echo "FAIL: VPN subnet rich rule not found in firewalld"
|
||||
echo "Current rich rules:"
|
||||
firewall-cmd --list-rich-rules
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# iptables mode - verify NAT rules
|
||||
echo "iptables mode, checking NAT rules..."
|
||||
for _ in $(seq 1 10); do
|
||||
if iptables -t nat -L POSTROUTING -n | grep -q "10.8.0.0"; then
|
||||
echo "PASS: NAT POSTROUTING rule for 10.8.0.0/24 exists"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
if ! iptables -t nat -L POSTROUTING -n | grep -q "10.8.0.0"; then
|
||||
echo "FAIL: NAT POSTROUTING rule for 10.8.0.0/24 not found"
|
||||
echo "Current NAT rules:"
|
||||
iptables -t nat -L POSTROUTING -n -v
|
||||
systemctl status iptables-openvpn 2>&1 || true
|
||||
exit 1
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
if ! iptables -t nat -L POSTROUTING -n | grep -q "10.8.0.0"; then
|
||||
echo "FAIL: NAT POSTROUTING rule for 10.8.0.0/24 not found"
|
||||
echo "Current NAT rules:"
|
||||
iptables -t nat -L POSTROUTING -n -v
|
||||
systemctl status iptables-openvpn 2>&1 || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Verify IP forwarding is enabled
|
||||
@@ -501,19 +545,11 @@ if [ ! -f /shared/revoke-client-disconnected ]; then
|
||||
fi
|
||||
echo "Client disconnected"
|
||||
|
||||
# Now revoke the certificate
|
||||
# Now revoke the certificate using the new CLIENT name feature
|
||||
echo "Revoking certificate for '$REVOKE_CLIENT'..."
|
||||
REVOKE_OUTPUT="/tmp/revoke-output.log"
|
||||
# MENU_OPTION=2 is revoke, CLIENTNUMBER is dynamically determined from index.txt
|
||||
# We need to find the client number for revoketest
|
||||
REVOKE_CLIENT_NUM=$(tail -n +2 /etc/openvpn/server/easy-rsa/pki/index.txt | grep "^V" | grep -n "CN=$REVOKE_CLIENT\$" | cut -d: -f1)
|
||||
if [ -z "$REVOKE_CLIENT_NUM" ]; then
|
||||
echo "ERROR: Could not find client number for '$REVOKE_CLIENT'"
|
||||
cat /etc/openvpn/server/easy-rsa/pki/index.txt
|
||||
exit 1
|
||||
fi
|
||||
echo "Revoke client number: $REVOKE_CLIENT_NUM"
|
||||
(MENU_OPTION=2 CLIENTNUMBER=$REVOKE_CLIENT_NUM bash /opt/openvpn-install.sh) 2>&1 | tee "$REVOKE_OUTPUT" || true
|
||||
# MENU_OPTION=3 is revoke, CLIENT specifies the client name directly
|
||||
(MENU_OPTION=3 CLIENT=$REVOKE_CLIENT bash /opt/openvpn-install.sh) 2>&1 | tee "$REVOKE_OUTPUT" || true
|
||||
|
||||
if grep -q "Certificate for client $REVOKE_CLIENT revoked" "$REVOKE_OUTPUT"; then
|
||||
echo "PASS: Certificate for '$REVOKE_CLIENT' revoked successfully"
|
||||
@@ -553,6 +589,47 @@ echo "PASS: Connection with revoked certificate correctly rejected"
|
||||
|
||||
echo "=== Certificate Revocation Tests PASSED ==="
|
||||
|
||||
# =====================================================
|
||||
# Test listing client certificates
|
||||
# =====================================================
|
||||
echo ""
|
||||
echo "=== Testing List Client Certificates ==="
|
||||
|
||||
# At this point we have 3 client certificates:
|
||||
# - testclient (Valid) - the renewed certificate
|
||||
# - testclient (Revoked) - the old certificate revoked during renewal
|
||||
# - revoketest (Revoked) - the revoked certificate
|
||||
LIST_OUTPUT="/tmp/list-clients-output.log"
|
||||
(MENU_OPTION=2 bash /opt/openvpn-install.sh) 2>&1 | tee "$LIST_OUTPUT" || true
|
||||
|
||||
# Verify list output contains expected clients
|
||||
if grep -q "testclient" "$LIST_OUTPUT" && grep -q "Valid" "$LIST_OUTPUT"; then
|
||||
echo "PASS: List shows testclient as Valid"
|
||||
else
|
||||
echo "FAIL: List does not show testclient correctly"
|
||||
cat "$LIST_OUTPUT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if grep -q "$REVOKE_CLIENT" "$LIST_OUTPUT" && grep -q "Revoked" "$LIST_OUTPUT"; then
|
||||
echo "PASS: List shows $REVOKE_CLIENT as Revoked"
|
||||
else
|
||||
echo "FAIL: List does not show $REVOKE_CLIENT correctly"
|
||||
cat "$LIST_OUTPUT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Verify certificate count (3 certs: testclient valid, testclient revoked from renewal, revoketest revoked)
|
||||
if grep -q "Found 3 client certificate(s)" "$LIST_OUTPUT"; then
|
||||
echo "PASS: List shows correct certificate count"
|
||||
else
|
||||
echo "FAIL: List does not show correct certificate count"
|
||||
cat "$LIST_OUTPUT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "=== List Client Certificates Tests PASSED ==="
|
||||
|
||||
# =====================================================
|
||||
# Test reusing revoked client name
|
||||
# =====================================================
|
||||
@@ -618,6 +695,85 @@ fi
|
||||
echo "PASS: Client connected with new '$REVOKE_CLIENT' certificate"
|
||||
|
||||
echo "=== Reuse of Revoked Client Name Tests PASSED ==="
|
||||
|
||||
# =====================================================
|
||||
# Test PASSPHRASE support for headless client creation
|
||||
# =====================================================
|
||||
echo ""
|
||||
echo "=== Testing PASSPHRASE Support ==="
|
||||
|
||||
PASSPHRASE_CLIENT="passphrasetest"
|
||||
TEST_PASSPHRASE="TestP@ssw0rd#123"
|
||||
echo "Creating client '$PASSPHRASE_CLIENT' with passphrase in headless mode..."
|
||||
PASSPHRASE_OUTPUT="/tmp/passphrase-output.log"
|
||||
(MENU_OPTION=1 CLIENT=$PASSPHRASE_CLIENT PASS=2 PASSPHRASE="$TEST_PASSPHRASE" CLIENT_CERT_DURATION_DAYS=3650 bash /opt/openvpn-install.sh) 2>&1 | tee "$PASSPHRASE_OUTPUT" || true
|
||||
|
||||
# Verify client was created
|
||||
if [ -f "/root/$PASSPHRASE_CLIENT.ovpn" ]; then
|
||||
echo "PASS: Client '$PASSPHRASE_CLIENT' with passphrase created successfully"
|
||||
else
|
||||
echo "FAIL: Failed to create client '$PASSPHRASE_CLIENT' with passphrase"
|
||||
cat "$PASSPHRASE_OUTPUT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Verify the passphrase is NOT leaked in the output
|
||||
if grep -q "$TEST_PASSPHRASE" "$PASSPHRASE_OUTPUT"; then
|
||||
echo "FAIL: Passphrase was leaked in command output!"
|
||||
exit 1
|
||||
else
|
||||
echo "PASS: Passphrase not leaked in command output"
|
||||
fi
|
||||
|
||||
# Verify the log file doesn't contain the passphrase
|
||||
if [ -f /opt/openvpn-install.log ] && grep -q "$TEST_PASSPHRASE" /opt/openvpn-install.log; then
|
||||
echo "FAIL: Passphrase was leaked in log file!"
|
||||
exit 1
|
||||
else
|
||||
echo "PASS: Passphrase not leaked in log file"
|
||||
fi
|
||||
|
||||
# Verify certificate was created with encryption (key should be encrypted)
|
||||
CLIENT_KEY="/etc/openvpn/server/easy-rsa/pki/private/$PASSPHRASE_CLIENT.key"
|
||||
if [ -f "$CLIENT_KEY" ]; then
|
||||
if grep -q "ENCRYPTED" "$CLIENT_KEY"; then
|
||||
echo "PASS: Client key is encrypted"
|
||||
else
|
||||
echo "FAIL: Client key is not encrypted"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "FAIL: Client key not found at $CLIENT_KEY"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Copy config for passphrase client connectivity test
|
||||
cp "/root/$PASSPHRASE_CLIENT.ovpn" "/shared/$PASSPHRASE_CLIENT.ovpn"
|
||||
sed -i 's/^remote .*/remote openvpn-server 1194/' "/shared/$PASSPHRASE_CLIENT.ovpn"
|
||||
# Write passphrase to a file for client to use with --askpass
|
||||
echo "$TEST_PASSPHRASE" >"/shared/$PASSPHRASE_CLIENT.pass"
|
||||
echo "Copied $PASSPHRASE_CLIENT config and passphrase to /shared/"
|
||||
|
||||
# Signal client that passphrase test config is ready
|
||||
touch /shared/passphrase-client-config-ready
|
||||
|
||||
# Wait for client to confirm connection with passphrase client
|
||||
echo "Waiting for client to connect with '$PASSPHRASE_CLIENT' certificate..."
|
||||
MAX_WAIT=60
|
||||
WAITED=0
|
||||
while [ ! -f /shared/passphrase-client-connected ] && [ $WAITED -lt $MAX_WAIT ]; do
|
||||
sleep 2
|
||||
WAITED=$((WAITED + 2))
|
||||
echo "Waiting for passphrase client connection... ($WAITED/$MAX_WAIT seconds)"
|
||||
done
|
||||
|
||||
if [ ! -f /shared/passphrase-client-connected ]; then
|
||||
echo "FAIL: Client did not connect with passphrase-protected certificate"
|
||||
exit 1
|
||||
fi
|
||||
echo "PASS: Client connected with passphrase-protected certificate"
|
||||
|
||||
echo "=== PASSPHRASE Support Tests PASSED ==="
|
||||
echo ""
|
||||
echo "=== All Revocation Tests PASSED ==="
|
||||
|
||||
|
||||
Reference in New Issue
Block a user