Linux Security Teil 3: Code-Details
Code-Detail 1
Eine PKI erstellen
$ wget -P ~/ https://github.com/OpenVPN/easy-rsa/releases/download/v3.0.6/EasyRSA-unix-v3.0.6.tgz
und installieren das tar-Archiv:
$ cd ~
$ tar zxvf EasyRSA-3.0.6.tgz
Beachte, dass wir im folgenden immer zwischen dem CA-System und dem VPN-Server hin und her springen müssen!
Genau das Gleiche machst du auf deinem openVPN-Server!
Wieder auf deinem CA-System, wechseln wir in das Verzeichnis «EasyRSA-3.0.6», welches beim entpacken der Tar-Archives erstellt wurde:
$ cd EasyRSA-3.0.6
Wir müssen nun die Daten zu deiner CA erfassen. Dafür kopieren wir “vars.example” und ändern diese Kopie:
$ cp vars.example vars
$ vi vars
Setze folgende Variablen nach deinen Anforderungen:
set_var EASYRSA_REQ_COUNTRY "CH"
set_var EASYRSA_REQ_PROVINCE "Wallis"
set_var EASYRSA_REQ_CITY "Betten"
set_var EASYRSA_REQ_ORG "Goatkeeper"
set_var EASYRSA_REQ_EMAIL "admin@goatkeeper.ch"
set_var EASYRSA_REQ_OU "Security Dpt."
Da EasyRSA SSL/TLS benutzt, vergewissere dich, dass “openssl” installiert ist:
$ openssl version
OpenSSL 1.1.1c 28 May 2019
Nun initialisieren wir die PKI:
$ ./easyrsa init-pki
...
init-pki complete; you may now create a CA or requests.
Your newly created PKI dir is: /home/user/EasyRSA-3.0.6/pki
Im nächsten Schritt werden zwei, für die CA sehr wichtige Dateien kreiert
ca.crt – das öffentliche Zertifikat der CA. Mit diesem werden wir später unserem openVPN-Server mitteilen, dass er Teil dieses Web-of-trust ist.
ca.key – der private Schlüssel der CA welcher zum signieren von Zertifikaten und Schlüsseln dieser CA benutzt wird:
Achtung: Dieser Schlüssel sollte nicht auf einem System liegen, welches online ist. Bewahre diese Datei auf einem ext. Datenträger auf und verwende sie nur bei Bedarf!!!
$ ./easyrsa build-ca nopass
. . .
Common Name (eg: your user, host, or server name) Easy-RSA CA:GoatHaven CA
Soweit so gut. Wir haben nun eine PKI erstellt. Bitte erinnere dich daran, dass wenn der “ca.key” in falsche Hände kommt, jeder Zertifikate für deine CA generieren und signieren kann.
Wechsle nun wieder zu deinem VPN-Server! Wir generieren nun den Schlüssel und Zertifikats-Request für deinen Server. Wechsle in das EasyRSA-Verzeichnis und initialisiere die PKI:
$ cd EasyRSA-3.0.6
$ ./easyrsa init-pki
Anschliessend generieren wir den Request:
$ ./easyrsa gen-req server nopass
mittels “nopass” verhindern wir, dass bei Verwendung des Requests jedesmal ein Passort abgefragt wird. Denn Server-Key kopieren wir nun nach “/etc/openvpn”:
$ sudo cp ~/EasyRSA-3.0.6/pki/private/server.key /etc/openvpn/
Den Request kopieren wir auf unser CA-System (PKI):
$ scp ~/EasyRSA-3.0.6/pki/reqs/server.req user@ip-deiner-CA:/tmp
Nun, wieder auf deinem CA-System (PKI) gehen wir wieder in das EasyRSA-Verzeichnis und importieren den Request:
$ cd ~/EasyRSA-3.0.6
$ ./easyrsa import-req /tmp/server.req server
und signieren anschliessend den Request:
$ ./easyrsa sign-req server server
Ob wir dieser Sache vertrauen wolle,n müssen wir noch bestätigen:
You are about to sign the following certificate.
Please check over the details shown below for accuracy. Note that this request
has not been cryptographically verified. Please be sure it came from a trusted
source or that you have verified the request checksum with the sender.
Request subject, to be signed as a server certificate for 3650 days:
subject=
commonName = server
Type the word 'yes' to continue, or any other input to abort.
Confirm request details: yes
Nun transferieren wir das signierte Zertifikat zu unseren VPN-Server:
$ scp pki/issued/server.crt user@your_vpn_server_ip:/tmp
und gleich noch das Zertifikat der CA:
$ scp pki/ca.crt user@your_vpn_server_ip:/tmp
Damit es nicht langweilig wird, loggen wir unser wieder auf dem VPN-Server ein und kopieren die Zertifikate:
$ sudo cp /tmp/{server.crt,ca.crt} /etc/openvpn/
Navigiere wieder zu deinem EasyRSA Directory:
$ cd EasyRSA-3.0.6/
Hier generierst du einen starken Diffie-Hellman-Schlüssel, welcher für den Austausch der Schlüssel gebraucht wird:
$ ./easyrsa gen-dh
Das dauert ein Momentchen. Ist das beendet, kreieren wir eine HMAC-Signature, um die Server-TLS-Integrität zu härten:
Nach Beendigung kopieren wir die Dateien in das “/etc/openvpn/” Verzeichnis:
$ sudo cp ~/EasyRSA-3.0.6/ta.key /etc/openvpn/
$ sudo cp ~/EasyRSA-3.0.4/pki/dh.pem /etc/openvpn/
Code-Detail 2
Generieren der Client Zertifikate/Schlüssel
#!/bin/bash
set -o errexit # be strong with errors
set -o nounset # be strong with unset vars
PROG="${0##/}" # Scriptname
USAGE="usage: $PROG clientname"
EASYRSA="EasyRSA-<VERSION>"
CA_SERVER="user@my-CA-server"
VPN_SERVER="<IP-Address of the openvpn server>"
VPN_SERVER_PORT="1194"
ZIP=/usr/bin/zip
if ! -x $ZIP ; then
echo "${PROG}: $ZIP not found, install it first" >&2
exit 1
fi
if (( $# != 1 )) ; then
echo $USAGE
exit 1
fi
if ! -d $EASYRSA ; then
echo "$EASYRSA missing or wrong version" >&2
exit 1
fi
CLIENT=$1
CLIENTCONFIG=$HOME/${CLIENT}-vpnconfig # define directory for config
echo "-----------------------------------------------------------------------------------------"
echo "
This script generates the keys/certs and a config file for your connetion to the openVPN
server.
EasyRSA is: $EASYRSA
CA-Server (PKI) is: $CA_SERVER
openVPN server is: $VPN_SERVER
Build a config for: $CLIENT
Config built in: $CLIENTCONFIG
NOTE: you need a working ssh-connection between your $VPN_SERVER and the $CA_SERVER!
If that's not what you want, hit ^C. Hit <ENTER> if that's OK
"
read OK
-d ${CLIENTCONFIG} || mkdir -pm 700 ${CLIENTCONFIG}
echo "generate the request"
cd ~/$EASYRSA
./easyrsa gen-req $CLIENT nopass
cp pki/private/${CLIENT}.key ${CLIENTCONFIG}
echo "secure copy the req to the CA-server"
scp pki/reqs/${CLIENT}.req $CA_SERVER:/tmp && stat=$? || stat=$?
case $stat in
0) ;; # all fine
*) echo "$PROG: scp to $CA_SERVER failed" >&2
exit 1
;;
esac
echo "Login to your CA-server and import/sign the request"
ssh -T $CA_SERVER "cd $EASYRSA;./easyrsa import-req /tmp/${CLIENT}.req $CLIENT;./easyrsa sign-req client $CLIENT" && stat=$? || stat=$?
case $stat in
0) ;; # all fine
*) echo "$PROG: scp to $CA_SERVER failed" >&2
exit 1
;;
esac
echo "Copy the ${CLIENT}.crt from your CA-Server to your local ${CLIENTCONFIG} directory."
scp ${CA_SERVER}:${EASYRSA}/pki/issued/${CLIENT}.crt ${CLIENTCONFIG}
cp ta.key ${CLIENTCONFIG}
echo "Copy the ca.crt (CA certificate) into your ${CLIENTCONFIG} directory"
scp root@${CA_SERVER}:/etc/openvpn/ca.crt ${CLIENTCONFIG}
cd $CLIENTCONFIG
echo -n "Create the ${CLIENT}.ovpn file now"
cat > ${CLIENTCONFIG}/${CLIENT}.ovpn << EdF
client
dev tun
persist-key
persist-tun
proto udp
nobind
remote-cert-tls server
auth SHA512
verb 3
remote ${VPN_SERVER} ${VPN_SERVER_PORT}
# To successfully import this profile, you
# want the client device's CA certificate copy,
# client certificate and key, and HMAC signature
# all in the same location as this .ovpn file.
ca ca.crt
cert ${CLIENT}.crt
key ${CLIENT}.key
tls-crypt ta.key
EdF
echo " done"
if -f ca.crt && -f ${CLIENT}.crt &&
-f ${CLIENT}.key && -f ta.key && -f ${CLIENT}.ovpn ; then
echo -n "Your kit seems complete. Will create ${CLIENT}.zip"
zip -r ${CLIENT}-openvpn.zip ${CLIENT}.ovpn ${CLIENT}.crt ${CLIENT}.key ca.crt ta.key
echo " done"
else
echo "you miss some files" >&2
exit 1
fi
exit 0
Code-Detail 3
Aufsetzen des openVPN-Servers
dev tun
persist-key
persist-tun
topology subnet
port 1194
proto udp
keepalive 10 120
# Location of certificate authority's cert.
ca /etc/openvpn/server/ca.crt
# Location of VPN server's TLS cert.
cert /etc/openvpn/server/server.crt
# Location of server's TLS key
key /etc/openvpn/server/server.key
# Location of DH parameter file.
dh /etc/openvpn/server/dh.pem
# The VPN's address block starts here.
server 10.89.0.0 255.255.255.0
explicit-exit-notify 1
# Drop root privileges and switch to the `ovpn` user after startup.
user ovpn
# OpenVPN process is exclusive member of ovpn group.
group ovpn
# Cryptography options. We force these onto clients by
# setting them here and not in client.ovpn. See
# `openvpn --show-tls`, `openvpn --show-ciphers` and
#`openvpn --show-digests` for all supported options.
tls-crypt /etc/openvpn/server/ta.key
auth SHA512 # This needs to be in client.ovpn too though.
tls-version-min 1.2
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256
ncp-ciphers AES-256-GCM:AES-256-CBC
# Logging options.
ifconfig-pool-persist ipp.txt
status openvpn-status.log
log /var/log/openvpn.log
verb 3
# Clients are to use this server as a network gateway.
push "redirect-gateway def1 bypass-dhcp"
# Push these DNS addresses to clients.
push "dhcp-option DNS 208.67.222.222"
push "dhcp-option DNS 208.67.220.220"
Code-Details 4
rules.v6
*filter
:INPUT ACCEPT 0:0
:FORWARD ACCEPT 0:0
:OUTPUT ACCEPT 0:0
-A INPUT -j REJECT --reject-with icmp6-port-unreachable
-A FORWARD -j REJECT --reject-with icmp6-port-unreachable
-A OUTPUT -j REJECT --reject-with icmp6-port-unreachable
COMMIT
Code-Details 5
rules.v4
#
# NAT wird erlaubt aus dem openvpn Subnetz
#
*nat
:PREROUTING ACCEPT 2:92
:INPUT ACCEPT 0:0
:POSTROUTING ACCEPT 0:0
:OUTPUT ACCEPT 0:0
-A POSTROUTING -s 10.89.0.0/24 -o ens18 -j MASQUERADE
COMMIT
#
# INPUT/FORWARD/OUTPUT Definition
#
*filter
:INPUT ACCEPT 0:0
:FORWARD ACCEPT 0:0
:OUTPUT ACCEPT 0:0
#
# Loopback darf alles
#
-A INPUT -i lo -j ACCEPT
-A INPUT -s 127.0.0.0/8 ! -i lo -j REJECT --reject-with icmp-port-unreachable
#
# ping erlaubt
#
-A INPUT -p icmp -m state --state NEW -m icmp --icmp-type 8 -j ACCEPT
-A INPUT -p icmp -m state --state RELATED,ESTABLISHED -j ACCEPT
#
# Ports 22222 (SSH), 1194 (openvpn), 53 (DNS) eingehend erlauben
#
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i ens18 -p tcp -m state --state NEW,ESTABLISHED -m tcp --dport 22222 -j ACCEPT
-A INPUT -i ens18 -p udp -m state --state NEW,ESTABLISHED -m udp --dport 1194 -j ACCEPT
-A INPUT -i ens18 -p udp -m state --state ESTABLISHED -m udp --sport 53 -j ACCEPT
-A INPUT -i ens18 -p tcp -m state --state ESTABLISHED -m tcp --sport 53 -j ACCEPT
#
Aus tun* Interface akzeptieren
#
-A INPUT -i tun0 -j ACCEPT
#
# Brute force Attacken blockieren
#
-A INPUT -m limit --limit 3/min -j LOG --log-prefix "iptables_INPUT_denied: "
-A INPUT -j REJECT --reject-with icmp-port-unreachable
#
# tun* Interface akzeptieren in der Chain (FORWARD)
#
-A FORWARD -i tun0 -j ACCEPT
#
# tunnel Netzwerk von tun* zu äusserem Interface (ens18)
#
-A FORWARD -s 10.89.0.0/24 -i tun0 -o ens18 -j ACCEPT
#
# Erlaube zugehoerige und bestehende Verbindungen
#
-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
#
# Brute force Attacken blockieren
#
-A FORWARD -m limit --limit 3/min -j LOG --log-prefix "iptables_FORWARD_denied: "
-A FORWARD -j REJECT --reject-with icmp-port-unreachable
#
# Loopback darf alles und icmp (ping & Co) geht durch
#
-A OUTPUT -o lo -j ACCEPT
-A OUTPUT -p icmp -j ACCEPT
#
# Erlaube zugehoerige und bestehende Verbindungen
#
-A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
#
# Erlaubte Ports nach aussen
-A OUTPUT -o ens18 -p tcp -m tcp --sport 22 -j ACCEPT
-A OUTPUT -o ens18 -p tcp -m tcp --dport 22 -j ACCEPT
-A OUTPUT -o ens18 -p tcp -m tcp --sport 22222 -j ACCEPT
-A OUTPUT -o ens18 -p tcp -m tcp --dport 22222 -j ACCEPT
-A OUTPUT -o ens18 -p udp -m state --state ESTABLISHED -m udp --sport 1194 -j ACCEPT
-A OUTPUT -o ens18 -p udp -m state --state NEW,ESTABLISHED -m udp --dport 53 -j ACCEPT
-A OUTPUT -o ens18 -p tcp -m state --state NEW,ESTABLISHED -m tcp --dport 53 -j ACCEPT
-A OUTPUT -o ens18 -p tcp -m state --state NEW,ESTABLISHED -m tcp --dport 80 -j ACCEPT
-A OUTPUT -o ens18 -p tcp -m state --state NEW,ESTABLISHED -m tcp --dport 443 -j ACCEPT
#
# tun* Interface akzeptieren in der Chain (OUTPUT)
#
-A OUTPUT -o tun0 -j ACCEPT
#
# Brute force Attacken blockieren
#
-A OUTPUT -m limit --limit 3/min -j LOG --log-prefix "iptables_OUTPUT_denied: "
-A OUTPUT -j REJECT --reject-with icmp-port-unreachable
COMMIT