Merge pull request #251 from buchdag/buchdag-revoke1
Fix certificate revocation
This commit is contained in:
		@@ -38,3 +38,6 @@ openvpn --genkey --secret $EASYRSA_PKI/ta.key
 | 
			
		||||
 | 
			
		||||
# For a server key with a password, manually init; this is autopilot
 | 
			
		||||
easyrsa build-server-full "$OVPN_CN" nopass
 | 
			
		||||
 | 
			
		||||
# Generate the CRL for client/server certificates revocation.
 | 
			
		||||
easyrsa gen-crl
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										61
									
								
								bin/ovpn_revokeclient
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										61
									
								
								bin/ovpn_revokeclient
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,61 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Revoke a client certificate
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
if [ "$DEBUG" == "1" ]; then
 | 
			
		||||
    set -x
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
set -e
 | 
			
		||||
 | 
			
		||||
if [ -z "$OPENVPN" ]; then
 | 
			
		||||
    export OPENVPN="$PWD"
 | 
			
		||||
fi
 | 
			
		||||
if ! source "$OPENVPN/ovpn_env.sh"; then
 | 
			
		||||
    echo "Could not source $OPENVPN/ovpn_env.sh."
 | 
			
		||||
    exit 1
 | 
			
		||||
fi
 | 
			
		||||
if [ -z "$EASYRSA_PKI" ]; then
 | 
			
		||||
    export EASYRSA_PKI="$OPENVPN/pki"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
cn="$1"
 | 
			
		||||
parm="$2"
 | 
			
		||||
 | 
			
		||||
if [ ! -f "$EASYRSA_PKI/private/${cn}.key" ]; then
 | 
			
		||||
    echo "Unable to find \"${cn}\", please try again or generate the key first" >&2
 | 
			
		||||
    exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
revoke_client_certificate(){
 | 
			
		||||
    easyrsa revoke "$1"
 | 
			
		||||
    echo "Generating the Certificate Revocation List :"
 | 
			
		||||
    easyrsa gen-crl
 | 
			
		||||
    cp -f "$EASYRSA_PKI/crl.pem" "$OPENVPN/crl.pem"
 | 
			
		||||
    chmod 644 "$OPENVPN/crl.pem"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
remove_files(){
 | 
			
		||||
    rm -v "$EASYRSA_PKI/issued/${1}.crt"
 | 
			
		||||
    rm -v "$EASYRSA_PKI/private/${1}.key"
 | 
			
		||||
    rm -v "$EASYRSA_PKI/reqs/${1}.req"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
case "$parm" in
 | 
			
		||||
    "remove")
 | 
			
		||||
        revoke_client_certificate "$cn"
 | 
			
		||||
        remove_files "$cn"
 | 
			
		||||
        ;;
 | 
			
		||||
    "" | "keep")
 | 
			
		||||
        revoke_client_certificate "$cn"
 | 
			
		||||
        ;;
 | 
			
		||||
    *)
 | 
			
		||||
        echo "When revoking a client certificate, this script let you choose if you want to remove the corresponding crt, key and req files." >&2
 | 
			
		||||
        echo "Pease note that the removal of those files is required if you want to generate a new client certificate using the revoked certificate's CN." >&2
 | 
			
		||||
        echo "    1. keep (default): Keep the files." >&2
 | 
			
		||||
        echo "    2. remove: Remove the files." >&2
 | 
			
		||||
        echo "Please specify one of those options as second parameter." >&2
 | 
			
		||||
        ;;
 | 
			
		||||
esac
 | 
			
		||||
							
								
								
									
										13
									
								
								bin/ovpn_run
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								bin/ovpn_run
									
									
									
									
									
								
							@@ -74,13 +74,14 @@ if [ "$OVPN_DEFROUTE" != "0" ] || [ "$OVPN_NAT" == "1" ] ; then
 | 
			
		||||
	setupIptablesAndRouting
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Use a hacky hardlink as the CRL Needs to be readable by the user/group
 | 
			
		||||
# Use a copy of crl.pem as the CRL Needs to be readable by the user/group
 | 
			
		||||
# OpenVPN is running as.  Only pass arguments to OpenVPN if it's found.
 | 
			
		||||
if [ -r "$EASYRSA_PKI/crl.pem" ]; then
 | 
			
		||||
    if [ ! -r "$OPENVPN/crl.pem" ]; then
 | 
			
		||||
        ln "$EASYRSA_PKI/crl.pem" "$OPENVPN/crl.pem"
 | 
			
		||||
        chmod 644 "$OPENVPN/crl.pem"
 | 
			
		||||
    fi
 | 
			
		||||
if [ "$EASYRSA_PKI/crl.pem" -nt "$OPENVPN/crl.pem" ]; then
 | 
			
		||||
    cp -f "$EASYRSA_PKI/crl.pem" "$OPENVPN/crl.pem"
 | 
			
		||||
    chmod 644 "$OPENVPN/crl.pem"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [ -r "$OPENVPN/crl.pem" ]; then
 | 
			
		||||
    addArg "--crl-verify" "$OPENVPN/crl.pem"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -34,9 +34,12 @@ After doing so, you will find the following files in each of the `$cn` directori
 | 
			
		||||
 | 
			
		||||
## Revoking Client Certificates
 | 
			
		||||
 | 
			
		||||
Revoke `client1`'s certificate and generate the certificate revocation list (CRL):
 | 
			
		||||
Revoke `client1`'s certificate and generate the certificate revocation list (CRL) using [`ovpn_revokeclient`](/bin/ovpn_revokeclient) script :
 | 
			
		||||
 | 
			
		||||
    docker run --rm -it -v $OVPN_DATA:/etc/openvpn kylemanna/openvpn easyrsa revoke client1
 | 
			
		||||
    docker run --rm -it -v $OVPN_DATA:/etc/openvpn kylemanna/openvpn easyrsa gen-crl
 | 
			
		||||
    docker run --rm -it -v $OVPN_DATA:/etc/openvpn kylemanna/openvpn ovpn_revokeclient client1
 | 
			
		||||
 | 
			
		||||
The OpenVPN server will read this change every time a client connects (no need to restart server) and deny clients access using revoked certificates.
 | 
			
		||||
 | 
			
		||||
You can optionally pass `remove` as second parameter to ovpn_revokeclient to remove the corresponding crt, key and req files :
 | 
			
		||||
 | 
			
		||||
    docker run --rm -it -v $OVPN_DATA:/etc/openvpn kylemanna/openvpn ovpn_revokeclient client1 remove
 | 
			
		||||
 
 | 
			
		||||
@@ -59,6 +59,15 @@ docker-compose run --rm openvpn easyrsa build-client-full $CLIENTNAME nopass
 | 
			
		||||
docker-compose run --rm openvpn ovpn_getclient $CLIENTNAME > $CLIENTNAME.ovpn
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* Revoke a client certificate
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
# Keep the corresponding crt, key and req files.
 | 
			
		||||
docker-compose run --rm openvpn ovpn_revokeclient $CLIENTNAME
 | 
			
		||||
# Remove the corresponding crt, key and req files.
 | 
			
		||||
docker-compose run --rm openvpn ovpn_revokeclient $CLIENTNAME remove
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Debugging Tips
 | 
			
		||||
 | 
			
		||||
* Create an environment variable with the name DEBUG and value of 1 to enable debug output (using "docker -e").
 | 
			
		||||
 
 | 
			
		||||
@@ -7,11 +7,12 @@ testAlias+=(
 | 
			
		||||
 | 
			
		||||
imageTests+=(
 | 
			
		||||
	[openvpn]='
 | 
			
		||||
		paranoid
 | 
			
		||||
	paranoid
 | 
			
		||||
        conf_options
 | 
			
		||||
        basic
 | 
			
		||||
        dual-proto
 | 
			
		||||
        otp
 | 
			
		||||
	iptables
 | 
			
		||||
	revocation
 | 
			
		||||
	'
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										87
									
								
								test/tests/revocation/run.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										87
									
								
								test/tests/revocation/run.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,87 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
set -e
 | 
			
		||||
 | 
			
		||||
[ -n "${DEBUG+x}" ] && set -x
 | 
			
		||||
 | 
			
		||||
OVPN_DATA="basic-data"
 | 
			
		||||
CLIENT1="travis-client1"
 | 
			
		||||
CLIENT2="travis-client2"
 | 
			
		||||
IMG="kylemanna/openvpn"
 | 
			
		||||
NAME="ovpn-test"
 | 
			
		||||
CLIENT_DIR="$(readlink -f "$(dirname "$BASH_SOURCE")/../../client")"
 | 
			
		||||
SERV_IP="$(ip -4 -o addr show scope global  | awk '{print $4}' | sed -e 's:/.*::' | head -n1)"
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Initialize openvpn configuration and pki.
 | 
			
		||||
#
 | 
			
		||||
docker volume create --name $OVPN_DATA
 | 
			
		||||
docker run --rm -v $OVPN_DATA:/etc/openvpn $IMG ovpn_genconfig -u udp://$SERV_IP
 | 
			
		||||
docker run --rm -v $OVPN_DATA:/etc/openvpn -it -e "EASYRSA_BATCH=1" -e "EASYRSA_REQ_CN=Travis-CI Test CA" $IMG ovpn_initpki nopass
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Fire up the server.
 | 
			
		||||
#
 | 
			
		||||
sudo iptables -N DOCKER || echo 'Firewall already configured'
 | 
			
		||||
sudo iptables -I FORWARD 1 -j DOCKER
 | 
			
		||||
docker run -d -v $OVPN_DATA:/etc/openvpn --cap-add=NET_ADMIN --privileged -p 1194:1194/udp --name $NAME $IMG
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Generate a first client certificate and configuration using $CLIENT1 as CN then revoke it.
 | 
			
		||||
#
 | 
			
		||||
docker exec -it $NAME easyrsa build-client-full $CLIENT1 nopass
 | 
			
		||||
docker exec -it $NAME ovpn_getclient $CLIENT1 > $CLIENT_DIR/config.ovpn
 | 
			
		||||
docker exec -it $NAME bash -c "echo 'yes' | ovpn_revokeclient $CLIENT1 remove"
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Test that openvpn client can't connect using $CLIENT1 config.
 | 
			
		||||
#
 | 
			
		||||
if docker run --rm -v $CLIENT_DIR:/client --cap-add=NET_ADMIN --privileged --net=host $IMG /client/wait-for-connect.sh; then
 | 
			
		||||
    echo "Client was able to connect after revocation test #1." >&2
 | 
			
		||||
    exit 2
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Generate and revoke a second client certificate using $CLIENT2 as CN, then test for failed client connection.
 | 
			
		||||
#
 | 
			
		||||
docker exec -it $NAME easyrsa build-client-full $CLIENT2 nopass
 | 
			
		||||
docker exec -it $NAME ovpn_getclient $CLIENT2 > $CLIENT_DIR/config.ovpn
 | 
			
		||||
docker exec -it $NAME bash -c "echo 'yes' | ovpn_revokeclient $CLIENT2 remove"
 | 
			
		||||
 | 
			
		||||
if docker run --rm -v $CLIENT_DIR:/client --cap-add=NET_ADMIN --privileged --net=host $IMG /client/wait-for-connect.sh; then
 | 
			
		||||
    echo "Client was able to connect after revocation test #2." >&2
 | 
			
		||||
    exit 2
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Restart the server
 | 
			
		||||
#
 | 
			
		||||
docker stop $NAME && docker start $NAME
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Test for failed connection using $CLIENT2 config again.
 | 
			
		||||
#
 | 
			
		||||
if docker run --rm -v $CLIENT_DIR:/client --cap-add=NET_ADMIN --privileged --net=host $IMG /client/wait-for-connect.sh; then
 | 
			
		||||
    echo "Client was able to connect after revocation test #3." >&2
 | 
			
		||||
    exit 2
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Stop the server and clean up
 | 
			
		||||
#
 | 
			
		||||
docker kill $NAME && docker rm $NAME
 | 
			
		||||
docker volume rm $OVPN_DATA
 | 
			
		||||
sudo iptables -D FORWARD 1
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Celebrate
 | 
			
		||||
#
 | 
			
		||||
cat <<EOF
 | 
			
		||||
 ___________
 | 
			
		||||
< it worked >
 | 
			
		||||
 -----------
 | 
			
		||||
        \   ^__^
 | 
			
		||||
         \  (oo)\_______
 | 
			
		||||
            (__)\       )\/\\
 | 
			
		||||
                ||----w |
 | 
			
		||||
                ||     ||
 | 
			
		||||
EOF
 | 
			
		||||
		Reference in New Issue
	
	Block a user