Browse Source

openvpn: create master / client playbook

Fixes: main/infrastructure#157
keep-around/05c2d674f4da81fdd34021657358cfcdabed7eab
Loïc Dachary 1 year ago
committed by Loic Dachary
parent
commit
05c2d674f4
Signed by: dachary GPG Key ID: 992D23B392F9E4F2
  1. 4
      inventory/02-all.yml
  2. 2
      molecule/icinga/roles/icinga2_client/templates/host.conf
  3. 1
      molecule/openvpn/create.yml
  4. 1
      molecule/openvpn/destroy.yml
  5. 1
      molecule/openvpn/inventory/02-all.yml
  6. 1
      molecule/openvpn/inventory/all.yml
  7. 1
      molecule/openvpn/inventory/firewall.yml
  8. 5
      molecule/openvpn/inventory/group_vars/all/openvpn.yml
  9. 1
      molecule/openvpn/inventory/hosts.yml
  10. 4
      molecule/openvpn/inventory/test-hosts.yml
  11. 39
      molecule/openvpn/molecule.yml
  12. 30
      molecule/openvpn/openvpn-client-playbook.yml
  13. 22
      molecule/openvpn/openvpn-server-playbook.yml
  14. 10
      molecule/openvpn/playbook.yml
  15. 11
      molecule/openvpn/roles/openvpn/defaults/main.yml
  16. 69
      molecule/openvpn/roles/openvpn/files/check_udp_port
  17. 20
      molecule/openvpn/roles/openvpn/files/command-check_udp_port.conf
  18. 2
      molecule/openvpn/roles/openvpn/tasks/main.yml
  19. 125
      molecule/openvpn/roles/openvpn/tasks/openvpn.yml
  20. 31
      molecule/openvpn/roles/openvpn/templates/create-client.sh.j2
  21. 11
      molecule/openvpn/roles/openvpn/templates/nftables.conf.j2
  22. 18
      molecule/openvpn/roles/openvpn/templates/server.conf.j2
  23. 6
      molecule/openvpn/roles/openvpn/templates/vars.j2
  24. 28
      molecule/openvpn/test-openvpn-playbook.yml
  25. 16
      molecule/openvpn/tests/test_icinga.py
  26. 10
      molecule/openvpn/tests/test_openvpn.py
  27. 3
      tests/icinga_helper.py

4
inventory/02-all.yml

@ -37,3 +37,7 @@ gitlab:
pad-group:
hosts:
website-host:
openvpn-group:
hosts:
website-host:

2
molecule/icinga/roles/icinga2_client/templates/host.conf

@ -37,4 +37,6 @@ object Host "{{ inventory_hostname }}" {
/* Define git repos and attributes */
/* Define DNS zones and attributes */
/* END OF FILE */
}

1
molecule/openvpn/create.yml

@ -0,0 +1 @@
../infrastructure/create.yml

1
molecule/openvpn/destroy.yml

@ -0,0 +1 @@
../infrastructure/destroy.yml

1
molecule/openvpn/inventory/02-all.yml

@ -0,0 +1 @@
../../../inventory/02-all.yml

1
molecule/openvpn/inventory/all.yml

@ -0,0 +1 @@
../../../inventory/all.yml

1
molecule/openvpn/inventory/firewall.yml

@ -0,0 +1 @@
../../../inventory/firewall.yml

5
molecule/openvpn/inventory/group_vars/all/openvpn.yml

@ -0,0 +1,5 @@
---
openvpn_active_clients:
- openvpnclientname
openvpn_server_conf: |
push "route 10.11.12.0 255.255.255.0"

1
molecule/openvpn/inventory/hosts.yml

@ -0,0 +1 @@
../../../inventory/hosts.yml

4
molecule/openvpn/inventory/test-hosts.yml

@ -0,0 +1,4 @@
---
all:
hosts:
openvpnclient-host:

39
molecule/openvpn/molecule.yml

@ -0,0 +1,39 @@
---
driver:
name: delegated
lint:
name: yamllint
platforms:
- name: bind-host
- name: icinga-host
- name: website-host
- name: openvpnclient-host
provisioner:
name: ansible
options:
i: inventory
limit: bind-host,icinga-host,website-host,openvpnclient-host,localhost
lint:
name: ansible-lint
env:
ANSIBLE_ROLES_PATH: roles:../infrastructure/roles:../firewall/roles:../bind/roles:../icinga/roles:../jdauphant.nginx/roles:../enough-nginx/roles:../certificate/roles
inventory:
links:
group_vars: ../../inventory/group_vars
host_vars: ../../inventory/host_vars
scenario:
name: openvpn
test_sequence:
- destroy
- create
- converge
- verify
- destroy
verifier:
name: testinfra
options:
v: True
s: True
# k: test_service_openvpn
lint:
name: flake8

30
molecule/openvpn/openvpn-client-playbook.yml

@ -0,0 +1,30 @@
---
- name: create openvpn client directory
hosts: localhost
become: false
tasks:
- name: mkdir -p {{ openvpn_local_directory }}
file:
state: directory
path: "{{ openvpn_local_directory }}"
- name: create openvpn clients
hosts: openvpn-group
become: true
tasks:
- name: /etc/openvpn/easy-rsa/create-client.sh
shell: |
set -ex
if ! test -d /etc/openvpn/keys/{{ item }} ; then
/etc/openvpn/easy-rsa/create-client.sh {{ item }}
fi
loop: "{{ openvpn_active_clients }}"
- name: copy client credentials locally
fetch:
src: "/etc/openvpn/keys/{{ item }}.tar.gz"
dest: "{{ openvpn_local_directory }}/{{ item }}.tar.gz"
flat: yes
loop: "{{ openvpn_active_clients }}"

22
molecule/openvpn/openvpn-server-playbook.yml

@ -0,0 +1,22 @@
---
- name: firewall for openvpn
hosts: localhost
gather_facts: false
tasks:
- include_role:
name: firewall
vars:
firewall_server: "{{ item }}"
firewall_clients: [ 0.0.0.0/0 ]
firewall_protocols: [ udp ]
firewall_ports: [ 1194 ]
when: hostvars[item].ansible_host is defined
with_items: "{{ groups['openvpn-group'] | default([]) }}"
- name: install openvpn
hosts: openvpn-group
become: true
roles:
- role: openvpn

10
molecule/openvpn/playbook.yml

@ -0,0 +1,10 @@
---
- import_playbook: ../infrastructure/buster-playbook.yml
- import_playbook: ../firewall/firewall-playbook.yml
- import_playbook: ../icinga/test-icinga-playbook.yml
- import_playbook: ../bind/bind-playbook.yml
- import_playbook: ../bind/bind-client-playbook.yml
- import_playbook: ../icinga/icinga-playbook.yml
- import_playbook: openvpn-server-playbook.yml
- import_playbook: openvpn-client-playbook.yml
- import_playbook: test-openvpn-playbook.yml

11
molecule/openvpn/roles/openvpn/defaults/main.yml

@ -0,0 +1,11 @@
---
openvpn_country: FR
openvpn_province: Paris
openvpn_city: Paris
openvpn_org: Enough
openvpn_email: contact@enough.community
openvpn_ou: Enough Community
openvpn_server_conf: |
# same as openstack_internal_network_cidr by default
push "route 10.30.20.0 255.255.255.0"
openvpn_local_directory: /tmp/enough-openvpn

69
molecule/openvpn/roles/openvpn/files/check_udp_port

@ -0,0 +1,69 @@
#!/bin/sh
#
# check_udp_port - Checks if a UDP port is open using nmap utility
#
# Author: Aaron Eidt (aeidt4@uwo.ca)
#
STATE_OK=0
STATE_WARNING=1
STATE_CRITICAL=2
STATE_UNKNOWN=3
STATE_DEPENDENT=4
usage () {
printf "%s - Checks if a UDP port is open using nmap utility\n" $0
printf "check_udp_port 2014-06-09 Written by: Aaron Eidt (aeidt4@uwo.ca)\n\n"
printf "\nUsage: %s: -H remote_host -p port -s service_name\n\n -H Name or IP of remote host\n -p UDP port number to check\n -s Name of the service that should be listening on the port\n\n" $0
}
host=
port=
service=
while getopts H:p:s: o
do
case $o in
H)
host="$OPTARG"
;;
p)
port="$OPTARG"
;;
s)
service="$OPTARG"
;;
?)
usage
exit ${STATE_UNKNOWN}
;;
esac
done
if [ x$host = x -o x$port = x -o x$service = x ]; then
usage
exit ${STATE_UNKNOWN}
fi
result=`/usr/bin/nmap -sU -p $port -P0 $host`
f_result=`echo $result | egrep -o "${port}/udp [a-zA-Z0-9_-| ]+Nmap done"`
p_result=`echo $f_result | awk '{print $1" "$2" "$3}'`
if [ `echo $f_result | egrep -c 'open'` -gt 0 ]; then
nmap_service=`echo $f_result | awk '{print $3}'`
if [ $nmap_service = $service ]; then
echo "OK: $service listening on port $port: $p_result"
exit ${STATE_OK}
elif [ $nmap_service = "unknown" ]; then
echo "CRITICAL: Unknown service listening on port $port: $p_result"
exit ${STATE_CRITICAL}
else
echo "WARNING: Incorrect service $nmap_service listening on port $port: $p_result"
exit ${STATE_WARNING}
fi
fi
echo "CRITICAL: $p_result"
exit ${STATE_CRITICAL}

20
molecule/openvpn/roles/openvpn/files/command-check_udp_port.conf

@ -0,0 +1,20 @@
object CheckCommand "udp_port" {
import "ipv4-or-ipv6"
command = [
"/usr/bin/sudo",
PluginDir + "/check_udp_port",
"-H", "$udp_port_address$",
"-p", "$udp_port_port$"
]
arguments = {
"-s" = {
value = "$udp_port_service$"
required = true
description = "name of the service expected to listen"
}
}
vars.udp_port_address = "$check_address$"
}

2
molecule/openvpn/roles/openvpn/tasks/main.yml

@ -0,0 +1,2 @@
---
- import_tasks: openvpn.yml

125
molecule/openvpn/roles/openvpn/tasks/openvpn.yml

@ -0,0 +1,125 @@
---
- delegate_to: icinga-host
block:
- name: apt-get install nmap
apt:
name: nmap
state: present
- name: Icinga install command-check_udp_port.conf
copy:
src: command-check_udp_port.conf
dest: /etc/icinga2/conf.d/command-check_udp_port.conf
mode: 0444
- name: Icinga install check_udp_port
copy:
src: check_udp_port
dest: /usr/lib/nagios/plugins/check_udp_port
mode: 0555
- name: /etc/sudoers.d/icinga
copy:
content: |
nagios ALL=NOPASSWD: /usr/lib/nagios/plugins/check_udp_port
dest: /etc/sudoers.d/icinga2_check_udp_port
mode: 0440
owner: root
- name: Icinga for OpenVPN
copy:
content: |
apply Service "Check OpenVPN" {
import host.vars.service_template
check_command = "udp_port"
vars.udp_port_port = "1194"
vars.udp_port_service = "openvpn"
command_endpoint = NodeName
assign where host.vars.vpn == true
}
dest: /etc/icinga2/zones.d/global-templates/openvpn.conf
- name: Add OpenVPN check
blockinfile:
block: |
vars.vpn = true
path: /etc/icinga2/zones.d/master/{{ inventory_hostname }}/host.conf
insertbefore: "END OF FILE"
marker: "/* {mark} OpenVPN */"
- name: reload icinga2
systemd:
name: icinga2
state: reloaded
enabled: True
changed_when: False
- name: apt-get install openvpn nftables
apt:
name: [openvpn, nftables]
state: present
- name: net.ipv4.ip_forward=1
shell: |
set -ex
sed -i -e '/net.ipv4.ip_forward/s/.*/net.ipv4.ip_forward=1/' /etc/sysctl.conf
sysctl -p
- name: nftables
template:
src: nftables.conf.j2
dest: /etc/nftables.conf
- name: systemctl enable nftables
systemd:
name: nftables
enabled: yes
- name: nft -f /etc/nftables.conf
shell:
nft -f /etc/nftables.conf
changed_when: False
- name: cp -r /usr/share/easy-rsa /etc/openvpn/
shell:
cp -r /usr/share/easy-rsa /etc/openvpn
args:
creates: /etc/openvpn/easy-rsa
- name: /etc/openvpn/easy-rsa/vars
template:
src: vars.j2
dest: /etc/openvpn/easy-rsa/vars
- name: ./easyrsa init-pki
shell: |
set -ex
./easyrsa init-pki
yes | ./easyrsa build-ca nopass
echo server | ./easyrsa gen-req server nopass
echo yes | ./easyrsa sign-req server server
./easyrsa gen-dh
openvpn --genkey --secret ta.key
cp ta.key pki/ca.crt pki/private/server.key pki/issued/server.crt pki/dh.pem /etc/openvpn/
args:
creates: /etc/openvpn/server.key
chdir: /etc/openvpn/easy-rsa
- name: /etc/openvpn/server.conf
template:
src: server.conf.j2
dest: /etc/openvpn/server.conf
- name: systemctl enable openvpn@server ; systemctl start openvpn@server
systemd:
name: openvpn@server
state: restarted
enabled: yes
- name: /etc/openvpn/easy-rsa/create-client.sh
template:
src: create-client.sh.j2
dest: /etc/openvpn/easy-rsa/create-client.sh
mode: 0755

31
molecule/openvpn/roles/openvpn/templates/create-client.sh.j2

@ -0,0 +1,31 @@
#!/bin/bash
name=$1
cd /etc/openvpn/easy-rsa
echo $name | ./easyrsa gen-req $name nopass
echo yes | ./easyrsa sign-req client $name
mkdir -p /etc/openvpn/keys/$name
cp pki/issued/$name.crt pki/private/$name.key /etc/openvpn/keys/$name
cp ta.key /etc/openvpn/keys/$name/$name-server-ta.key
cp pki/ca.crt /etc/openvpn/keys/$name/$name-server-ca.crt
cat > /etc/openvpn/keys/$name/$name.conf <<EOF
client
dev tun
proto udp
remote {{ ansible_host }}
resolv-retry infinite
nobind
user nobody
group nogroup
persist-key
persist-tun
ca $name-server-ca.crt
cert $name.crt
key $name.key
remote-cert-tls server
tls-auth $name-server-ta.key 1
cipher AES-256-CBC
verb 3
EOF
cd /etc/openvpn/keys/$name
tar -zcvf ../$name.tar.gz .

11
molecule/openvpn/roles/openvpn/templates/nftables.conf.j2

@ -0,0 +1,11 @@
flush ruleset
table ip nat {
chain prerouting {
type nat hook prerouting priority 0; policy accept;
}
chain postrouting {
type nat hook postrouting priority 100; policy accept;
masquerade
}
}

18
molecule/openvpn/roles/openvpn/templates/server.conf.j2

@ -0,0 +1,18 @@
port 1194
proto udp
dev tun
ca ca.crt
cert server.crt
key server.key # This file should be kept secret
dh dh.pem
server 10.8.0.0 255.255.255.0
keepalive 10 120
tls-auth ta.key 0 # This file is secret
cipher AES-256-CBC
user nobody
group nogroup
persist-key
persist-tun
ifconfig-pool-persist ipp.txt
client-to-client
{{ openvpn_server_conf }}

6
molecule/openvpn/roles/openvpn/templates/vars.j2

@ -0,0 +1,6 @@
set_var EASYRSA_REQ_COUNTRY "{{ openvpn_country }}"
set_var EASYRSA_REQ_PROVINCE "{{ openvpn_province }}"
set_var EASYRSA_REQ_CITY "{{ openvpn_city }}"
set_var EASYRSA_REQ_ORG "{{ openvpn_org }}"
set_var EASYRSA_REQ_EMAIL "{{ openvpn_email }}"
set_var EASYRSA_REQ_OU "{{ openvpn_ou }}"

28
molecule/openvpn/test-openvpn-playbook.yml

@ -0,0 +1,28 @@
---
- name: create openvpnclientname
hosts: openvpnclient-host
become: true
tasks:
- name: apt-get install openvpn
apt:
name: [openvpn]
state: present
- name: copy client credentials
copy:
src: "{{ openvpn_local_directory }}/openvpnclientname.tar.gz"
dest: "/etc/openvpn/openvpnclientname.tar.gz"
- name: cd /etc/openvpn ; tar zxvf openvpnclientname.tar.gz
shell: |
set -ex
tar zxvf openvpnclientname.tar.gz
args:
chdir: /etc/openvpn
- name: systemctl enable openvpn@openvpnclientname ; systemctl start openvpn@openvpnclientname
systemd:
name: openvpn@openvpnclientname
state: restarted
enabled: yes

16
molecule/openvpn/tests/test_icinga.py

@ -0,0 +1,16 @@
from tests.icinga_helper import IcingaHelper
testinfra_hosts = ['icinga-host']
class TestChecks(IcingaHelper):
def test_host(self):
r = self.get_client().objects.get('Host', 'website-host')
assert r['attrs']['name'] == 'website-host'
def test_service_disk(self):
assert self.is_service_ok('website-host!disk')
def test_service_openvpn(self):
assert self.is_service_ok('website-host!Check OpenVPN ')

10
molecule/openvpn/tests/test_openvpn.py

@ -0,0 +1,10 @@
testinfra_hosts = ['openvpnclient-host']
# development-inventory/group_vars/all/openvpn.yml defines the route 10.11.12.0/24
def test_vpn_route(host):
cmd = host.run("ip route")
print(cmd.stdout)
print(cmd.stderr)
assert cmd.rc == 0
assert '10.11.12' in cmd.stdout

3
tests/icinga_helper.py

@ -55,6 +55,9 @@ class IcingaHelper(object):
# force the check to reduce the waiting time
#
client = self.get_client()
# For debug purposes
# answer = client.objects.list('Service')
# print(answer)
answer = client.actions.reschedule_check(
'Service',
'service.__name=="{}"'.format(name),

Loading…
Cancel
Save