From 981128dc176d1f11a65c8dc7e1a3cda460fc76a4 Mon Sep 17 00:00:00 2001 From: Jeremy Dubois Date: Thu, 3 Feb 2022 18:35:16 +0100 Subject: [PATCH] openvpn: make it compatible with OpenBSD and add some improvements --- CHANGELOG.md | 2 + openvpn/README.md | 13 +- ...eck_openvpn.pl => check_openvpn_debian.pl} | 0 openvpn/files/check_openvpn_openbsd.pl | 215 +++++++++++++ openvpn/handlers/main.yml | 8 + openvpn/tasks/debian.yml | 296 ++++++++++++++++++ openvpn/tasks/main.yml | 288 +---------------- openvpn/tasks/openbsd.yml | 235 ++++++++++++++ openvpn/templates/ovpn.conf.j2 | 1 + openvpn/templates/server.conf.j2 | 3 + 10 files changed, 780 insertions(+), 281 deletions(-) rename openvpn/files/{check_openvpn.pl => check_openvpn_debian.pl} (100%) create mode 100644 openvpn/files/check_openvpn_openbsd.pl create mode 100644 openvpn/tasks/debian.yml create mode 100644 openvpn/tasks/openbsd.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b88fd45..de064a55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ The **patch** part changes is incremented if multiple releases happen the same m ### Changed +* openvpn: make it compatible with OpenBSD and add some improvements + ### Fixed ### Removed diff --git a/openvpn/README.md b/openvpn/README.md index f68b9d66..27b507d4 100644 --- a/openvpn/README.md +++ b/openvpn/README.md @@ -7,6 +7,16 @@ Install and configure OpenVPN, based on [our HowtoOpenVPN wiki](https://wiki.evo Everything is in the `tasks/main.yml` file. Some manual actions are requested at the end of the playbook, to do before finishing the playbook. +Here is a copy of what is requested : + +* You have to manually create the CA on the server with `shellpki init server.example.com`. The command will ask you to create a password, and will ask you again to give the same one several times. +* You have to manually generate the CRL on the server with `openssl ca -gencrl -keyfile /etc/shellpki/cakey.key -cert /etc/shellpki/cacert.pem -out /etc/shellpki/crl.pem -config /etc/shellpki/openssl.cnf`. The previously created password will be asked. +* You have to manually create the server's certificate with `shellpki create server.example.com`. +* You have to adjust the config file `/etc/openvpn/server.conf` for the following parameters : `local` (to check), `cert` (to check), `key` (to add), `server` (to check), `push` (to complete if needed). +* Finally, you can (re)start the OpenVPN service with `systemctl restart openvpn@server.service` on Debian, or `rcctl restart openvpn` on OpenBSD. + +Then, you can use `shellpki` to generate client certificates. + ## Variables * `openvpn_lan`: network to use for OpenVPN @@ -15,5 +25,4 @@ Some manual actions are requested at the end of the playbook, to do before finis ## TODO -* Make it compatible with OpenBSD -* See TODO tasks in tasks/main.yml +* See TODO tasks in tasks/*.yml diff --git a/openvpn/files/check_openvpn.pl b/openvpn/files/check_openvpn_debian.pl similarity index 100% rename from openvpn/files/check_openvpn.pl rename to openvpn/files/check_openvpn_debian.pl diff --git a/openvpn/files/check_openvpn_openbsd.pl b/openvpn/files/check_openvpn_openbsd.pl new file mode 100644 index 00000000..78e0cdb7 --- /dev/null +++ b/openvpn/files/check_openvpn_openbsd.pl @@ -0,0 +1,215 @@ +#!/usr/bin/perl -w + +####################################################################### +# +# Copyright (c) 2007 Jaime Gascon Romero +# +# License Information: +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# $Id: check_openvpn.pl,v 1.1 2014/09/29 08:39:24 rdessort Exp $ +# $Revision: 1.1 $ +# Home Site: http://emergeworld.blogspot.com/ +# ##################################################################### + +use diagnostics; +use strict; +use Net::Telnet (); +use Getopt::Long qw(:config no_ignore_case); +use vars qw($PROGNAME $VERSION); +use lib "/usr/local/libexec/nagios/"; +use utils qw(%ERRORS); + +$PROGNAME = "check_openvpn"; +$VERSION = '$Revision: 1.1 $'; + +$ENV{'PATH'}=''; +$ENV{'BASH_ENV'}=''; +$ENV{'ENV'}=''; + +my ($opt_h, $opt_H, $opt_p, $opt_P, $opt_t, $opt_i, $opt_n, $opt_c, $opt_w, $opt_C, $opt_r); + +sub print_help (); +sub print_usage (); + +GetOptions + ("h" => \$opt_h, "help" => \$opt_h, + "H=s" => \$opt_H, "host=s" => \$opt_H, + "p=i" => \$opt_p, "port=i" => \$opt_p, + "P=s" => \$opt_P, "password=s" => \$opt_P, + "t=i" => \$opt_t, "timeout=i" => \$opt_t, + "i" => \$opt_i, "ip" => \$opt_i, + "n" => \$opt_n, "numeric" => \$opt_n, + "c" => \$opt_c, "critical" => \$opt_c, + "w" => \$opt_w, "warning" => \$opt_w, + "C=s" => \$opt_C, "common_name=s" => \$opt_C, + "r=s" => \$opt_r, "remote_ip=s" => \$opt_r, + ) or exit $ERRORS{'UNKNOWN'}; + +# default values +unless ( defined $opt_t ) { + $opt_t = 10; +} + +if ($opt_h) {print_help(); exit $ERRORS{'OK'};} + +if ( ! defined($opt_H) || ! defined($opt_p) ) { + print_usage(); + exit $ERRORS{'UNKNOWN'} +} + +my @lines; +my @clients; +my @clients_ip; +my $t; + +eval { +$t = new Net::Telnet (Timeout => $opt_t, + Port => $opt_p, + Prompt => '/END$/' + ); +$t->open($opt_H); +if ( defined $opt_P ) { + $t->waitfor('/ENTER PASSWORD:$/'); + $t->print($opt_P); +} +$t->waitfor('/^$/'); +@lines = $t->cmd("status 2"); +$t->close; +}; + +if ($@) { + print "OpenVPN Critical: Can't connect to server\n"; + exit $ERRORS{'CRITICAL'}; +} + + +if (defined $opt_i || defined $opt_r) { + foreach (@lines) { + if ($_ =~ /CLIENT_LIST,.*,(\d+\.\d+\.\d+\.\d+):\d+,/) { + push @clients_ip, $1; + } +} + if (defined $opt_i) { + print "OpenVPN OK: "."@clients_ip "; + exit $ERRORS{'OK'}; + } elsif (defined $opt_r) { + if ( ! grep /\b$opt_r\b/, @clients_ip) { + if (defined $opt_c) { + print "OpenVPN CRITICAL: $opt_r don't found"; + exit $ERRORS{'CRITICAL'}; + } else { + print "OpenVPN WARNING: $opt_r don't found"; + exit $ERRORS{'WARNING'}; + } + } + print "OpenVPN OK: "."@clients_ip "; + exit $ERRORS{'OK'}; + } +} + +foreach (@lines) { + if ($_ =~ /CLIENT_LIST,(.*),\d+\.\d+\.\d+\.\d+:\d+,/) { + push @clients, $1; + } +} + +if (defined $opt_C) { + if ( ! grep /\b$opt_C\b/, @clients) { + if (defined $opt_c) { + print "OpenVPN CRITICAL: $opt_C don't found"; + exit $ERRORS{'CRITICAL'}; + } else { + print "OpenVPN WARNING: $opt_C don't found"; + exit $ERRORS{'WARNING'}; + } + } +} + + +if (defined $opt_n) { +print "OpenVPN OK: ".@clients." connected clients."; +exit $ERRORS{'OK'}; +} + +print "OpenVPN OK: "."@clients "; +exit $ERRORS{'OK'}; + +####################################################################### +###### Subroutines #################################################### + +sub print_usage() { + print "Usage: $PROGNAME -H | --host -p | --port [-P | --password] [-t | --timeout] + [-i | --ip] [-n | --numeric] [-C | --common_name] [-r | --remote_ip] [-c | --critical] [-w | --warning]\n\n"; + print " $PROGNAME [-h | --help]\n"; +} + +sub print_help() { + print "$PROGNAME $VERSION\n\n"; + print "Copyright (c) 2007 Jaime Gascon Romero + +Nagios plugin to check the clients connected to a openvpn server. + +"; + print_usage(); + print " +-H | --host + IP address or hostname of the openvpn server. + +-p | --port + Management port interface of the openvpn server. + +-P | --password + Password for the management interface of the openvpn server. + +-t | --timeout + Timeout for the connection attempt. Optional, default 10 seconds. + + + Optional parameters + =================== + +-i | --ip + Prints the IP address of the remote client instead of the common name. + +-n | --numeric + Prints the number of clients connected to the openvpn server. + + + Matching Parameters + =================== + +-C | --common_name + The common name, as it is specified in the client certificate, who is wanted to check. + +-r | --remote_ip + The client remote ip address who is wanted to check. + +-c | --critical + Exits with CRITICAL status if the client specified by the common name or the remote ip address is not connected. + +-w | --warning + Exits with WARNING status if the client specified by the common name or the remote ip address is not connected. + + + Other Parameters + ================ + +-h | --help + Show this help. +"; + +} + +# vim:sts=2:sw=2:ts=2:et diff --git a/openvpn/handlers/main.yml b/openvpn/handlers/main.yml index 5ba1926c..44b0de93 100644 --- a/openvpn/handlers/main.yml +++ b/openvpn/handlers/main.yml @@ -4,3 +4,11 @@ service: name: nagios-nrpe-server state: restarted + +- name: restart nrpe + service: + name: nrpe + state: restarted + +- name: reload packetfilter + command: pfctl -f /etc/pf.conf diff --git a/openvpn/tasks/debian.yml b/openvpn/tasks/debian.yml new file mode 100644 index 00000000..f94e19b6 --- /dev/null +++ b/openvpn/tasks/debian.yml @@ -0,0 +1,296 @@ +--- + +- name: Install OpenVPN + apt: + name: openvpn + +- name: Delete unwanted OpenVPN folders + file: + state: absent + dest: "/etc/openvpn/{{ item }}" + with_items: + - client + - server + +- name: Clone shellpki repo + git: + repo: "https://gitea.evolix.org/evolix/shellpki.git" + dest: /root/shellpki + +- name: Create the shellpki user + user: + name: shellpki + system: yes + create_home: no + home: "/etc/shellpki" + shell: "/usr/sbin/nologin" + +- name: Create /etc/shellpki + file: + dest: "/etc/shellpki" + mode: "0755" + owner: shellpki + group: shellpki + state: directory + +- include_role: + name: evolix/remount-usr + +- name: Copy shellpki files + copy: + src: "{{ item.source }}" + dest: "{{ item.destination }}" + remote_src: yes + with_items: + - { source: "/root/shellpki/openssl.cnf", destination: "/etc/shellpki/openssl.cnf" } + - { source: "/root/shellpki/shellpki", destination: "/usr/local/sbin/shellpki" } + +- include_role: + name: evolix/remount-usr + +- name: Change files permissions + file: + dest: "{{ item.dest }}" + mode: "{{ item.mode }}" + owner: "{{ item.owner }}" + group: "{{ item.group }}" + with_items: + - { dest: "/etc/shellpki/openssl.cnf", mode: "0640", owner: "shellpki", group: "shellpki" } + - { dest: "/usr/local/sbin/shellpki", mode: "0755", owner: "root", group: "root" } + +- name: Delete local shellpki repo + file: + state: absent + dest: "/root/shellpki" + +- name: Add sudo rights + lineinfile: + dest: "/etc/sudoers.d/shellpki" + regexp: '/usr/local/sbin/shellpki' + line: "%shellpki ALL = (root) /usr/local/sbin/shellpki" + create: yes + mode: "0400" + owner: root + group: root + validate: 'visudo -cf %s' + +- name: Deploy OpenVPN client config template + template: + src: "ovpn.conf.j2" + dest: "/etc/shellpki/ovpn.conf" + mode: "0600" + owner: shellpki + group: shellpki + +- name: Generate dhparam + command: "openssl dhparam -out /etc/shellpki/dh2048.pem 2048" + +- include_role: + name: evolix/remount-usr + +- name: Fix CRL rights in shellpki command + lineinfile: + dest: "/usr/local/sbin/shellpki" + regexp: '{{ item.regexp }}' + insertafter: "{{ item.insertafter }}" + line: "{{ item.line }}" + with_items: + - { regexp: '^ chmod 644 /etc/shellpki/crl.pem$', line: " chmod 644 /etc/shellpki/crl.pem", insertafter: '^ chmod 640 "\${CACERT}"$' } + - { regexp: '^ chmod 755 /etc/shellpki/$', line: " chmod 755 /etc/shellpki/", insertafter: '^ chmod 644 /etc/shellpki/crl.pem$' } + +- name: Deploy OpenVPN server config + template: + src: "server.conf.j2" + dest: "/etc/openvpn/server.conf" + mode: "0600" + owner: root + group: root + +- name: Is minifirewall installed ? + stat: + path: "/etc/default/minifirewall" + check_mode: no + changed_when: false + register: minifirewall_config + +- name: Retrieve the default interface + shell: "grep '^INT=' /etc/default/minifirewall | cut -d\\' -f 2" + check_mode: no + changed_when: false + register: minifirewall_int + when: minifirewall_config.stat.exists + +- name: Add minifirewall rule in config file + lineinfile: + dest: "/etc/default/minifirewall" + line: "{{ item }}" + with_items: + - "# OpenVPN" + - "/sbin/iptables -t nat -A POSTROUTING -s {{ openvpn_lan }}/{{ openvpn_netmask_cidr }} -o $INT -j MASQUERADE" + when: minifirewall_config.stat.exists + +- name: Activate minifirewall rule + iptables: + table: nat + chain: POSTROUTING + source: "{{ openvpn_lan }}/{{ openvpn_netmask_cidr }}" + out_interface: "{{ minifirewall_int.stdout }}" + jump: MASQUERADE + when: minifirewall_config.stat.exists + +- name: Add 1194/udp OpenVPN port to public services in minifirewall + replace: + dest: "/etc/default/minifirewall" + regexp: "^SERVICESUDP1='(.*)?'$" + replace: "SERVICESUDP1='\\1 1194'" + backup: yes + when: minifirewall_config.stat.exists + +- name: Activate minifirewall rule for IPv4 + iptables: + chain: INPUT + protocol: udp + destination_port: "1194" + jump: ACCEPT + ip_version: ipv4 + when: minifirewall_config.stat.exists + +- name: Activate minifirewall rule for IPv6 + iptables: + chain: INPUT + protocol: udp + destination_port: "1194" + jump: ACCEPT + ip_version: ipv6 + when: minifirewall_config.stat.exists + +- name: Enable forwarding + sysctl: + name: net.ipv4.ip_forward + value: "1" + sysctl_file: "/etc/sysctl.d/openvpn.conf" + +- name: Generate a password for the management interface + set_fact: + management_pwd: "{{ lookup('password', '/dev/null length=15 chars=ascii_letters,digits') }}" + +- name: Set the management password + copy: + dest: "/etc/openvpn/management-pwd" + content: "{{ management_pwd }}" + mode: "0600" + owner: root + group: root + +- name: Enable openvpn service + systemd: + name: "openvpn@server.service" + enabled: yes + +- name: Is NRPE installed ? + stat: + path: "/etc/nagios/nrpe.d/evolix.cfg" + check_mode: no + changed_when: false + register: nrpe_evolix_config + +- name: Install NRPE check dependencies + apt: + name: libnet-telnet-perl + when: nrpe_evolix_config.stat.exists + +- include_role: + name: evolix/remount-usr + +- name: Install OpenVPN NRPE check + copy: + src: "files/check_openvpn_debian.pl" + dest: "/usr/local/lib/nagios/plugins/check_openvpn" + mode: "0755" + owner: root + group: nagios + when: nrpe_evolix_config.stat.exists + +- name: Configure NRPE OpenVPN check + lineinfile: + dest: "/etc/nagios/nrpe.d/evolix.cfg" + regexp: '^command\[check_openvpn\]=' + line: "command[check_openvpn]=/usr/local/lib/nagios/plugins/check_openvpn -H 127.0.0.1 -p 1195 -P {{ management_pwd }}" + notify: restart nagios-nrpe-server + when: nrpe_evolix_config.stat.exists + +- include_role: + name: evolix/remount-usr + +- name: Install OpenVPN certificates NRPE check + copy: + src: "files/check_openvpn_certificates.sh" + dest: "/usr/local/lib/nagios/plugins/check_openvpn_certificates.sh" + mode: "0755" + owner: root + group: nagios + when: nrpe_evolix_config.stat.exists + +- name: Add sudo rights for NRPE check + lineinfile: + dest: "/etc/sudoers.d/openvpn" + regexp: 'check_openvpn_certificates.sh' + line: "nagios ALL=NOPASSWD: /usr/local/lib/nagios/plugins/check_openvpn_certificates.sh" + create: yes + mode: "0400" + owner: root + group: root + validate: 'visudo -cf %s' + when: nrpe_evolix_config.stat.exists + +- name: Configure NRPE certificates check + lineinfile: + dest: "/etc/nagios/nrpe.d/evolix.cfg" + regexp: '^command\[check_openvpn_certificates\]=' + line: "command[check_openvpn_certificates]=sudo /usr/local/lib/nagios/plugins/check_openvpn_certificates.sh" + notify: restart nagios-nrpe-server + when: nrpe_evolix_config.stat.exists + +# BEGIN TODO : Get this script from master branch when cloning it at the beginning when dev branch is merged with master (this script is currently not available on master branch) +- name: Clone dev branch of shellpki repo + git: + repo: "https://gitea.evolix.org/evolix/shellpki.git" + dest: /root/shellpki-dev + version: dev + +- include_role: + name: evolix/remount-usr + +- name: Copy shellpki script + copy: + src: "/root/shellpki-dev/cert-expirations.sh" + dest: "/usr/share/scripts/cert-expirations.sh" + mode: "0700" + owner: root + group: root + remote_src: yes + +- name: Delete local shellpki-dev repo + file: + state: absent + dest: "/root/shellpki-dev" +# END TODO + +- name: Install cron to warn about certificates expiration + cron: + name: "OpenVPN certificates expiration" + special_time: monthly + job: '/usr/share/scripts/cert-expirations.sh | mail -E -s "PKI VPN {{ ansible_hostname }} : recapitulatif expirations" {{ client_email }}' + +- name: Warn the user about command to execute manually + pause: + prompt: | + /!\ WARNING /!\ + You have to manually create the CA on the server with "shellpki init {{ ansible_fqdn }}". The command will ask you to create a password, and will ask you again to give the same one several times. + You have to manually generate the CRL on the server with "openssl ca -gencrl -keyfile /etc/shellpki/cakey.key -cert /etc/shellpki/cacert.pem -out /etc/shellpki/crl.pem -config /etc/shellpki/openssl.cnf". The previously created password will be asked. + You have to manually create the server's certificate with "shellpki create {{ ansible_fqdn }}". + You have to adjust the config file "/etc/openvpn/server.conf" for the following parameters : local (to check), cert (to check), key (to add), server (to check), push (to complete if needed). + Finally, you can (re)start the OpenVPN service with "systemctl restart openvpn@server.service". + + Press enter to exit when it's done. + diff --git a/openvpn/tasks/main.yml b/openvpn/tasks/main.yml index 105b3c0b..1e20772a 100644 --- a/openvpn/tasks/main.yml +++ b/openvpn/tasks/main.yml @@ -1,285 +1,15 @@ --- -- name: This role is only compatible with Debian +- name: System compatibility checks assert: - that: "ansible_distribution == 'Debian'" - msg: "Only compatible with Debian" + that: "ansible_distribution == 'Debian' or ansible_distribution == 'OpenBSD'" + msg: "Only compatible with Debian and OpenBSD" -- name: Install OpenVPN - apt: - name: openvpn +- name: Include Debian version + include: debian.yml + when: ansible_distribution == "Debian" -- name: Delete unwanted OpenVPN folders - file: - state: absent - path: "/etc/openvpn/{{ item }}" - with_items: - - client - - server - -- name: Clone shellpki repo - git: - repo: "https://gitea.evolix.org/evolix/shellpki.git" - dest: /root/shellpki - -- name: Create the shellpki user - user: - name: shellpki - system: yes - create_home: no - home: "/etc/shellpki" - shell: "/usr/sbin/nologin" - -- name: Create /etc/shellpki - file: - path: "/etc/shellpki" - state: directory - -- include_role: - name: evolix/remount-usr - -- name: Copy shellpki files - copy: - src: "{{ item.source }}" - dest: "{{ item.destination }}" - remote_src: yes - with_items: - - { source: "/root/shellpki/openssl.cnf", destination: "/etc/shellpki/openssl.cnf" } - - { source: "/root/shellpki/shellpki", destination: "/usr/local/sbin/shellpki" } - -- include_role: - name: evolix/remount-usr - -- name: Change files permissions - file: - path: "{{ item.path }}" - mode: "{{ item.mode }}" - with_items: - - { path: "/etc/shellpki/openssl.cnf", mode: "0640" } - - { path: "/usr/local/sbin/shellpki", mode: "0755" } - -- name: Delete local shellpki repo - file: - state: absent - path: "/root/shellpki" - -- name: Change directory owner - file: - path: "/etc/shellpki" - owner: shellpki - recurse: yes - state: directory - -- name: Add sudo rights - lineinfile: - dest: "/etc/sudoers.d/shellpki" - regexp: '/usr/local/sbin/shellpki' - line: "%shellpki ALL = (root) /usr/local/sbin/shellpki" - create: yes - validate: 'visudo -cf %s' - -- name: Deploy OpenVPN client config template - template: - src: "ovpn.conf.j2" - dest: "/etc/shellpki/ovpn.conf" - -- name: Generate dhparam - command: "openssl dhparam -out /etc/shellpki/dh2048.pem 2048" - -- include_role: - name: evolix/remount-usr - -- name: Fix CRL rights in shellpki command - lineinfile: - path: "/usr/local/sbin/shellpki" - regexp: '{{ item.regexp }}' - insertafter: "{{ item.insertafter }}" - line: "{{ item.line }}" - with_items: - - { regexp: '^ chmod 644 /etc/shellpki/crl.pem$', line: " chmod 644 /etc/shellpki/crl.pem", insertafter: '^ chmod 640 "\${CACERT}"$' } - - { regexp: '^ chmod 755 /etc/shellpki/$', line: " chmod 755 /etc/shellpki/", insertafter: '^ chmod 644 /etc/shellpki/crl.pem$' } - -- name: Deploy OpenVPN server config - template: - src: "server.conf.j2" - dest: "/etc/openvpn/server.conf" - -- name: Is minifirewall installed ? - stat: - path: "/etc/default/minifirewall" - check_mode: no - register: minifirewall_config - -- name: Retrieve the default interface - shell: "grep '^INT=' /etc/default/minifirewall | cut -d\\' -f 2" - check_mode: no - changed_when: false - register: minifirewall_int - -- name: Add minifirewall rule in config file - lineinfile: - path: "/etc/default/minifirewall" - line: "{{ item }}" - with_items: - - "# OpenVPN" - - "/sbin/iptables -t nat -A POSTROUTING -s {{ openvpn_lan }}/{{ openvpn_netmask_cidr }} -o $INT -j MASQUERADE" - when: minifirewall_config.stat.exists - -- name: Activate minifirewall rule - iptables: - table: nat - chain: POSTROUTING - source: "{{ openvpn_lan }}/{{ openvpn_netmask_cidr }}" - out_interface: "{{ minifirewall_int.stdout }}" - jump: MASQUERADE - when: minifirewall_config.stat.exists - -- name: Add 1194/udp OpenVPN port to public services in minifirewall - replace: - path: "/etc/default/minifirewall" - regexp: "^SERVICESUDP1='(.*)?'$" - replace: "SERVICESUDP1='\\1 1194'" - backup: yes - when: minifirewall_config.stat.exists - -- name: Activate minifirewall rule for IPv4 - iptables: - chain: INPUT - protocol: udp - destination_port: "1194" - jump: ACCEPT - ip_version: ipv4 - when: minifirewall_config.stat.exists - -- name: Activate minifirewall rule for IPv6 - iptables: - chain: INPUT - protocol: udp - destination_port: "1194" - jump: ACCEPT - ip_version: ipv6 - when: minifirewall_config.stat.exists - -- name: Enable forwarding - sysctl: - name: net.ipv4.ip_forward - value: "1" - sysctl_file: "/etc/sysctl.d/openvpn.conf" - -- name: Generate a password for the management interface - set_fact: - management_pwd: "{{ lookup('password', '/dev/null length=15 chars=ascii_letters,digits') }}" - -- name: Set the management password - copy: - dest: "/etc/openvpn/management-pwd" - content: "{{ management_pwd }}" - -- name: Enable openvpn service - systemd: - name: "openvpn@server.service" - enabled: yes - -- name: Is NRPE installed ? - stat: - path: "/etc/nagios/nrpe.d/evolix.cfg" - check_mode: no - register: nrpe_evolix_config - -- name: Install NRPE check dependencies - apt: - name: libnet-telnet-perl - when: nrpe_evolix_config.stat.exists - -- include_role: - name: evolix/remount-usr - -- name: Install OpenVPN NRPE check - copy: - src: "files/check_openvpn.pl" - dest: "/usr/local/lib/nagios/plugins/check_openvpn" - mode: "0755" - owner: root - group: nagios - when: nrpe_evolix_config.stat.exists - -- name: Add NRPE check - lineinfile: - dest: "/etc/nagios/nrpe.d/evolix.cfg" - regexp: '^command\[check_openvpn\]=' - line: "command[check_openvpn]=/usr/local/lib/nagios/plugins/check_openvpn -H 127.0.0.1 -p 1195 -P {{ management_pwd }}" - notify: restart nagios-nrpe-server - when: nrpe_evolix_config.stat.exists - -- include_role: - name: evolix/remount-usr - -- name: Install OpenVPN certificates NRPE check - copy: - src: "files/check_openvpn_certificates.sh" - dest: "/usr/local/lib/nagios/plugins/check_openvpn_certificates.sh" - mode: "0755" - owner: root - group: nagios - when: nrpe_evolix_config.stat.exists - -- name: Add sudo rights for NRPE check - lineinfile: - dest: "/etc/sudoers.d/openvpn" - regexp: 'check_openvpn_certificates.sh' - line: "nagios ALL=NOPASSWD: /usr/local/lib/nagios/plugins/check_openvpn_certificates.sh" - create: yes - validate: 'visudo -cf %s' - when: nrpe_evolix_config.stat.exists - -- name: Add NRPE check - lineinfile: - dest: "/etc/nagios/nrpe.d/evolix.cfg" - regexp: '^command\[check_openvpn_certificates\]=' - line: "command[check_openvpn_certificates]=sudo /usr/local/lib/nagios/plugins/check_openvpn_certificates.sh" - notify: restart nagios-nrpe-server - when: nrpe_evolix_config.stat.exists - -# BEGIN TODO : Get this script from master branch when cloning it at the beginning when dev branch is merged with master (this script is currently not available on master branch) -- name: Clone dev branch of shellpki repo - git: - repo: "https://gitea.evolix.org/evolix/shellpki.git" - dest: /root/shellpki-dev - version: dev - -- include_role: - name: evolix/remount-usr - -- name: Copy shellpki script - copy: - src: "/root/shellpki-dev/cert-expirations.sh" - dest: "/usr/share/scripts/cert-expirations.sh" - mode: "0700" -# owner: root -# group: root - remote_src: yes - -- name: Delete local shellpki-dev repo - file: - state: absent - path: "/root/shellpki-dev" -# END TODO - -- name: Install cron to warn about certificates expiration - cron: - name: "OpenVPN certificates expiration" - special_time: monthly - job: '/usr/share/scripts/cert-expirations.sh | mail -E -s "PKI VPN {{ ansible_hostname }} : recapitulatif expirations" {{ client_email }}' - -- name: Warn the user about command to execute manually - pause: - prompt: | - /!\ WARNING /!\ - You have to manually create the CA on the server with "shellpki init {{ ansible_fqdn }}". The command will ask you to create a password, and will ask you again to give the same one several times. - You have to manually generate the CRL on the server with "openssl ca -gencrl -keyfile /etc/shellpki/cakey.key -cert /etc/shellpki/cacert.pem -out /etc/shellpki/crl.pem -config /etc/shellpki/openssl.cnf". The previously created password will be asked - You have to manually create the server's certificate with "shellpki create {{ ansible_fqdn }}" - You have to adjuste the config file "/etc/openvpn/server.conf" for the following parameters : local (to check), cert (to check), key (to add), server (to check), push (to complete if needed). - Finally, you can (re)start the OpenVPN service with "systemctl restart openvpn@server.service" - - Press enter to exit when it's done. +- name: Include OpenBSD version + include: openbsd.yml + when: ansible_distribution == "OpenBSD" diff --git a/openvpn/tasks/openbsd.yml b/openvpn/tasks/openbsd.yml new file mode 100644 index 00000000..2edbec70 --- /dev/null +++ b/openvpn/tasks/openbsd.yml @@ -0,0 +1,235 @@ +--- + +- name: Install OpenVPN + openbsd_pkg: + name: openvpn-- + when: ansible_distribution == 'OpenBSD' + +- name: Create /etc/openvpn + file: + dest: "/etc/openvpn" + state: directory + owner: root + group: wheel + mode: "0755" + +- name: Clone shellpki repo + git: + repo: "https://gitea.evolix.org/evolix/shellpki.git" + dest: /root/shellpki + +- name: Create the shellpki user + user: + name: _shellpki + system: yes + create_home: no + home: "/etc/shellpki" + shell: "/sbin/nologin" + +- name: Create /etc/shellpki + file: + dest: "/etc/shellpki" + state: directory + owner: _shellpki + group: _shellpki + mode: "0755" + +- name: Copy shellpki files + copy: + src: "{{ item.source }}" + dest: "{{ item.destination }}" + remote_src: yes + with_items: + - { source: "/root/shellpki/openssl.cnf", destination: "/etc/shellpki/openssl.cnf" } + - { source: "/root/shellpki/shellpki", destination: "/usr/local/sbin/shellpki" } + +- name: Change files permissions + file: + dest: "{{ item.dest }}" + mode: "{{ item.mode }}" + owner: "{{ item.owner }}" + group: "{{ item.group }}" + with_items: + - { dest: "/etc/shellpki/openssl.cnf", mode: "0640", owner: "_shellpki", group: "_shellpki"} + - { dest: "/usr/local/sbin/shellpki", mode: "0755", owner: "root", group: "wheel" } + +- name: Delete local shellpki repo + file: + state: absent + dest: "/root/shellpki" + +- name: Add sudo rights + lineinfile: + dest: "/etc/sudoers" + regexp: '/usr/local/sbin/shellpki' + line: "%_shellpki ALL = (root) /usr/local/sbin/shellpki" + validate: 'visudo -cf %s' + +- name: Deploy OpenVPN client config template + template: + src: "ovpn.conf.j2" + dest: "/etc/shellpki/ovpn.conf" + mode: "0640" + owner: _shellpki + group: _shellpki + +- name: Generate dhparam + command: "openssl dhparam -out /etc/shellpki/dh2048.pem 2048" + +- name: Fix CRL rights in shellpki command + lineinfile: + dest: "/usr/local/sbin/shellpki" + regexp: '{{ item.regexp }}' + insertafter: "{{ item.insertafter }}" + line: "{{ item.line }}" + with_items: + - { regexp: '^ chmod 644 /etc/shellpki/crl.pem$', line: " chmod 644 /etc/shellpki/crl.pem", insertafter: '^ chmod 640 "\${CACERT}"$' } + - { regexp: '^ chmod 755 /etc/shellpki/$', line: " chmod 755 /etc/shellpki/", insertafter: '^ chmod 644 /etc/shellpki/crl.pem$' } + +- name: Deploy OpenVPN server config + template: + src: "server.conf.j2" + dest: "/etc/openvpn/server.conf" + mode: "0600" + owner: root + group: wheel + +- name: Configure PacketFilter + lineinfile: + dest: "/etc/pf.conf" + line: "{{ item }}" + validate: 'pfctl -nf %s' + notify: reload packetfilter + with_items: + - "# OpenVPN" + - "pass in quick on $ext_if proto udp from any to self port 1194" + +- name: Create a cron to rotate the logs + cron: + name: "OpenVPN logs rotation" + weekday: "6" + hour: "4" + minute: "0" + job: "cp /var/log/openvpn.log /var/log/openvpn.log.$(date +\\%F) && echo \"$(date +\\%F' '\\%R) - logfile turned over via cron\" > /var/log/openvpn.log && gzip /var/log/openvpn.log.$(date +\\%F) && find /var/log/ -type f -name \"openvpn.log.*\" -mtime +365 -exec rm {} \\+" + +- name: Generate a password for the management interface + set_fact: + management_pwd: "{{ lookup('password', '/dev/null length=15 chars=ascii_letters,digits') }}" + +- name: Set the management password + copy: + dest: "/etc/openvpn/management-pwd" + content: "{{ management_pwd }}" + mode: "0600" + owner: root + group: wheel + +- name: Enable openvpn service + service: + name: openvpn + enabled: yes + +- name: Set openvpn flags + lineinfile: + dest: /etc/rc.conf.local + regexp: "^openvpn_flags=" + line: "openvpn_flags=--daemon --config /etc/openvpn/server.conf" + create: yes + +- name: Is NRPE installed ? + stat: + path: "/etc/nrpe.d/evolix.cfg" + check_mode: no + register: nrpe_evolix_config + +- name: Install NRPE check dependencies + openbsd_pkg: + name: p5-Net-Telnet + when: nrpe_evolix_config.stat.exists + +- name: Install OpenVPN NRPE check + copy: + src: "files/check_openvpn_openbsd.pl" + dest: "/usr/local/libexec/nagios/plugins/check_openvpn.pl" + mode: "0755" + owner: root + group: wheel + when: nrpe_evolix_config.stat.exists + +- name: Configure NRPE OpenVPN check + lineinfile: + dest: "/etc/nrpe.d/zzz_evolix.cfg" + regexp: '^command\[check_openvpn\]=' + line: "command[check_openvpn]=/usr/local/libexec/nagios/plugins/check_openvpn.pl -H 127.0.0.1 -p 1195 -P {{ management_pwd }}" + create: yes + mode: "0644" + owner: root + group: wheel + notify: restart nrpe + when: nrpe_evolix_config.stat.exists + +- name: Install OpenVPN certificates NRPE check + copy: + src: "files/check_openvpn_certificates.sh" + dest: "/usr/local/libexec/nagios/plugins/check_openvpn_certificates.sh" + mode: "0755" + owner: root + group: wheel + when: nrpe_evolix_config.stat.exists + +- name: Add doas rights for NRPE check + lineinfile: + dest: "/etc/doas.conf" + regexp: 'check_openvpn_certificates.sh' + line: "permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_openvpn_certificates.sh" + validate: 'doas -C %s' + when: nrpe_evolix_config.stat.exists + +- name: Configure NRPE certificates check + lineinfile: + dest: "/etc/nrpe.d/evolix.cfg" + regexp: '^command\[check_openvpn_certificates\]=' + line: "command[check_openvpn_certificates]=doas /usr/local/libexec/nagios/plugins/check_openvpn_certificates.sh" + notify: restart nrpe + when: nrpe_evolix_config.stat.exists + +# BEGIN TODO : Get this script from master branch when cloning it at the beginning when dev branch is merged with master (this script is currently not available on master branch) +- name: Clone dev branch of shellpki repo + git: + repo: "https://gitea.evolix.org/evolix/shellpki.git" + dest: /root/shellpki-dev + version: dev + +- name: Copy shellpki script + copy: + src: "/root/shellpki-dev/cert-expirations.sh" + dest: "/usr/share/scripts/cert-expirations.sh" + mode: "0700" + owner: root + group: wheel + remote_src: yes + +- name: Delete local shellpki-dev repo + file: + state: absent + dest: "/root/shellpki-dev" +# END TODO + +- name: Install cron to warn about certificates expiration + cron: + name: "OpenVPN certificates expiration" + special_time: monthly + job: '/usr/share/scripts/cert-expirations.sh | mail -E -s "PKI VPN {{ ansible_hostname }} : recapitulatif expirations" {{ client_email }}' + +- name: Warn the user about command to execute manually + pause: + prompt: | + /!\ WARNING /!\ + You have to manually create the CA on the server with "shellpki init {{ ansible_fqdn }}". The command will ask you to create a password, and will ask you again to give the same one several times. + You have to manually generate the CRL on the server with "openssl ca -gencrl -keyfile /etc/shellpki/cakey.key -cert /etc/shellpki/cacert.pem -out /etc/shellpki/crl.pem -config /etc/shellpki/openssl.cnf". The previously created password will be asked. + You have to manually create the server's certificate with "shellpki create {{ ansible_fqdn }}". + You have to adjust the config file "/etc/openvpn/server.conf" for the following parameters : local (to check), cert (to check), key (to add), server (to check), push (to complete if needed). + Finally, you can (re)start the OpenVPN service with "rcctl restart openvpn". + + Press enter to exit when it's done. + diff --git a/openvpn/templates/ovpn.conf.j2 b/openvpn/templates/ovpn.conf.j2 index d82b0b42..d1b3c214 100644 --- a/openvpn/templates/ovpn.conf.j2 +++ b/openvpn/templates/ovpn.conf.j2 @@ -5,6 +5,7 @@ proto udp remote {{ ansible_fqdn }} 1194 +nobind persist-key persist-tun diff --git a/openvpn/templates/server.conf.j2 b/openvpn/templates/server.conf.j2 index 0508ff9d..a89701e8 100644 --- a/openvpn/templates/server.conf.j2 +++ b/openvpn/templates/server.conf.j2 @@ -7,12 +7,15 @@ proto udp dev tun mode server keepalive 10 120 +tls-exit cipher AES-256-GCM # AES persist-key persist-tun +ifconfig-pool-persist /etc/openvpn/ipp.txt + status /var/log/openvpn-status.log log-append /var/log/openvpn.log