From 5153b88d0152570ee71e927a0dccdd4e9d11e06f Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Thu, 3 Feb 2022 14:15:33 +0100 Subject: [PATCH 01/23] evolinux-base: option to bypass raid-related tasks --- CHANGELOG.md | 2 ++ evolinux-base/defaults/main.yml | 1 + evolinux-base/tasks/hardware.yml | 11 ++++++++--- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dacd8ef3..e03b8306 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ The **patch** part changes is incremented if multiple releases happen the same m ### Added +* evolinux-base: option to bypass raid-related tasks + ### Changed ### Fixed diff --git a/evolinux-base/defaults/main.yml b/evolinux-base/defaults/main.yml index 591bc62b..9debc8ab 100644 --- a/evolinux-base/defaults/main.yml +++ b/evolinux-base/defaults/main.yml @@ -78,6 +78,7 @@ evolinux_packages_include: True evolinux_packages_system: True evolinux_packages_diagnostic: True evolinux_packages_hardware: True +evolinux_packages_hardware_raid: True evolinux_packages_common: True evolinux_packages_stretch: True evolinux_packages_buster: True diff --git a/evolinux-base/tasks/hardware.yml b/evolinux-base/tasks/hardware.yml index e072f95c..ab838284 100644 --- a/evolinux-base/tasks/hardware.yml +++ b/evolinux-base/tasks/hardware.yml @@ -101,6 +101,7 @@ when: - "'Hewlett-Packard Company Smart Array' in raidmodel.stdout" - "'Adaptec Smart Storage PQI' in raidmodel.stdout" + - evolinux_packages_hardware_raid | bool # NOTE: check_hpraid cron use check_hpraid from nagios-nrpe role # So, if nagios-nrpe role is not installed it will not work @@ -149,9 +150,11 @@ tags: - packages - config - when: "'Hewlett-Packard Company Smart Array' in raidmodel.stdout" + when: + - "'Hewlett-Packard Company Smart Array' in raidmodel.stdout" + - evolinux_packages_hardware_raid | bool -- name: MegaRAID SAS package is present +- name: MegaCLI SAS package is present block: - name: HWRaid embedded GPG key is absent apt_key: @@ -206,6 +209,8 @@ tags: - packages - config - when: "'MegaRAID' in raidmodel.stdout" + when: + - "'MegaRAID' in raidmodel.stdout" + - evolinux_packages_hardware_raid | bool - meta: flush_handlers From 9e27d9707bd896321f1b6850bed052e2a7c409a8 Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Thu, 3 Feb 2022 14:16:09 +0100 Subject: [PATCH 02/23] kvm-host: add missing default value --- CHANGELOG.md | 1 + kvm-host/defaults/main.yml | 4 +++- kvm-host/tasks/ssh.yml | 12 ++++++++++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e03b8306..a28e9801 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ The **patch** part changes is incremented if multiple releases happen the same m ### Added * evolinux-base: option to bypass raid-related tasks +* kvm-host: add missing default value ### Changed diff --git a/kvm-host/defaults/main.yml b/kvm-host/defaults/main.yml index bec20a12..574c249f 100644 --- a/kvm-host/defaults/main.yml +++ b/kvm-host/defaults/main.yml @@ -1,4 +1,6 @@ --- kvm_custom_libvirt_images_path: '' kvm_install_drbd: True -kvm_scripts_dir: /usr/local/sbin \ No newline at end of file +kvm_scripts_dir: /usr/local/sbin + +kvm_pair: null \ No newline at end of file diff --git a/kvm-host/tasks/ssh.yml b/kvm-host/tasks/ssh.yml index a36f7549..54f69652 100644 --- a/kvm-host/tasks/ssh.yml +++ b/kvm-host/tasks/ssh.yml @@ -34,7 +34,11 @@ special_time: "hourly" user: root job: "rsync -a --delete /etc/libvirt/qemu/*xml {{ hostvars[kvm_pair]['lan.ip'] }}:/root/libvirt-{{ inventory_hostname }}/" - when: kvm_pair != inventory_hostname + when: + - kvm_pair is defined + - kvm_pair is not none + - kvm_pair | length > 0 + - kvm_pair != inventory_hostname tags: crontab - name: Crontab for sync list of running vm @@ -44,5 +48,9 @@ special_time: "daily" user: root job: "virsh list --all | tee /root/virsh-list.txt | ssh {{ hostvars[kvm_pair]['lan.ip'] }} 'cat >/root/libvirt-{{ inventory_hostname }}/virsh-list.txt'" - when: kvm_pair != inventory_hostname + when: + - kvm_pair is defined + - kvm_pair is not none + - kvm_pair | length > 0 + - kvm_pair != inventory_hostname tags: crontab From 0cbdda840d2135af47a903a501b5f00cc61d29b6 Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Thu, 3 Feb 2022 14:18:20 +0100 Subject: [PATCH 03/23] Explicit permissions for systemd overrides --- CHANGELOG.md | 1 + munin/tasks/main.yml | 2 ++ postgresql/tasks/config.yml | 1 + squid/tasks/systemd.yml | 1 + 4 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a28e9801..1b88fd45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ The **patch** part changes is incremented if multiple releases happen the same m ### Added +* Explicit permissions for systemd overrides * evolinux-base: option to bypass raid-related tasks * kvm-host: add missing default value diff --git a/munin/tasks/main.yml b/munin/tasks/main.yml index 81769488..d7cf8e2a 100644 --- a/munin/tasks/main.yml +++ b/munin/tasks/main.yml @@ -102,6 +102,8 @@ option: "ProtectHome" value: "false" state: present + create: yes + mode: "0644" notify: - systemd daemon-reload - restart munin-node diff --git a/postgresql/tasks/config.yml b/postgresql/tasks/config.yml index 83b10e25..f29026df 100644 --- a/postgresql/tasks/config.yml +++ b/postgresql/tasks/config.yml @@ -10,6 +10,7 @@ src: postgresql.service.override.conf dest: /etc/systemd/system/postgresql@.service.d/override.conf force: yes + mode: "0644" notify: - reload systemd - restart postgresql diff --git a/squid/tasks/systemd.yml b/squid/tasks/systemd.yml index ac9eb7e9..c84e52d6 100644 --- a/squid/tasks/systemd.yml +++ b/squid/tasks/systemd.yml @@ -19,6 +19,7 @@ template: src: systemd-override.conf.j2 dest: /etc/systemd/system/squid.service.d/override.conf + mode: "0644" force: yes register: _squid_systemd_override From 981128dc176d1f11a65c8dc7e1a3cda460fc76a4 Mon Sep 17 00:00:00 2001 From: Jeremy Dubois Date: Thu, 3 Feb 2022 18:35:16 +0100 Subject: [PATCH 04/23] 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 From a2f73bb7dfa17f9b57d5e84d8f4f6dfa8e3595f4 Mon Sep 17 00:00:00 2001 From: Ludovic Poujol Date: Mon, 7 Feb 2022 15:17:23 +0100 Subject: [PATCH 05/23] elasticsearch: Use `/etc/elasticsearch/jvm.options.d/evolinux` instead of default `/etc/elasticsearch/jvm.options` --- CHANGELOG.md | 1 + elasticsearch/tasks/configuration.yml | 12 ++++++++++-- elasticsearch/tasks/tmpdir.yml | 8 ++++++-- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de064a55..62590672 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ The **patch** part changes is incremented if multiple releases happen the same m ### Changed +* elasticsearch: Use `/etc/elasticsearch/jvm.options.d/evolinux` instead of default `/etc/elasticsearch/jvm.options` * openvpn: make it compatible with OpenBSD and add some improvements ### Fixed diff --git a/elasticsearch/tasks/configuration.yml b/elasticsearch/tasks/configuration.yml index 5afa94b0..6d9b9542 100644 --- a/elasticsearch/tasks/configuration.yml +++ b/elasticsearch/tasks/configuration.yml @@ -96,17 +96,25 @@ - name: JVM Heap size (min) is set lineinfile: - dest: /etc/elasticsearch/jvm.options + dest: /etc/elasticsearch/jvm.options.d/evolinux regexp: "^-Xms" line: "-Xms{{ elasticsearch_jvm_xms }}" + create: yes + owner: root + group: elasticsearch + mode: 0640 tags: - config - name: JVM Heap size (max) is set lineinfile: - dest: /etc/elasticsearch/jvm.options + dest: /etc/elasticsearch/jvm.options.d/evolinux regexp: "^-Xmx" line: "-Xmx{{ elasticsearch_jvm_xmx }}" + create: yes + owner: root + group: elasticsearch + mode: 0640 tags: - config diff --git a/elasticsearch/tasks/tmpdir.yml b/elasticsearch/tasks/tmpdir.yml index 920300d7..6164731f 100644 --- a/elasticsearch/tasks/tmpdir.yml +++ b/elasticsearch/tasks/tmpdir.yml @@ -26,10 +26,13 @@ - name: change JVM tmpdir (< 6.x) lineinfile: - dest: /etc/elasticsearch/jvm.options + dest: /etc/elasticsearch/jvm.options.d/evolinux line: "-Djava.io.tmpdir={{ _elasticsearch_custom_tmpdir }}" regexp: "^-Djava.io.tmpdir=" - insertafter: "## JVM configuration" + create: yes + owner: root + group: elasticsearch + mode: 0640 notify: - restart elasticsearch tags: @@ -48,6 +51,7 @@ - elasticsearch when: elastic_stack_version is version('6', '>=') + # Note : Should not do any changes as -Djava.io.tmpdir=${ES_TMPDIR} is already here in the default config. - name: change JVM tmpdir (>= 6.x) lineinfile: dest: /etc/elasticsearch/jvm.options From e080b37be2a313a88b799602b7894b0eeeb01cf2 Mon Sep 17 00:00:00 2001 From: "William Hirigoyen (Evolix)" Date: Tue, 8 Feb 2022 11:11:07 +0100 Subject: [PATCH 06/23] Add Includes in PHPVersion search. --- packweb-apache/files/phpContainer | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packweb-apache/files/phpContainer b/packweb-apache/files/phpContainer index 0f634d6a..a3e2855f 100644 --- a/packweb-apache/files/phpContainer +++ b/packweb-apache/files/phpContainer @@ -8,6 +8,23 @@ fi; PHPVersion=$(grep SetHandler /etc/apache2/sites-enabled/$LOGNAME.conf 2>/dev/null | grep -m 1 -o 'fpm[0-9][0-9]' | head -n 1 | sed 's/php//g' | sed 's/fpm//g') +# If $PHPVersion is empty, look for "SetHandler" in the includes. +if [ "$PHPVersion" == "" ]; then + includes=$(grep -w "Include" /etc/apache2/sites-enabled/$LOGNAME.conf | uniq | awk '{print $2}') + for f in "$includes"; do + # Relative path -> absolute + if [ ${f:0:1} != "/" ]; then + f="/etc/apache2/${f}" + fi + + # Grep again + PHPVersion=$(grep SetHandler "${f}" 2>/dev/null | grep -m 1 -o 'fpm[0-9][0-9]' | head -n 1 | sed 's/php//g' | sed 's/fpm//g') + if [ "$PHPVersion" != "" ]; then + break + fi + done +fi + if [ "$PHPVersion" != "" ]; then lxc-attach -n php$PHPVersion -- su - $LOGNAME -c "cd \"${PWD@E}\" && php ${*@Q}" else From 9995fca35d68b6a63a120e3cabb60c9292bc29d3 Mon Sep 17 00:00:00 2001 From: Ludovic Poujol Date: Tue, 8 Feb 2022 16:16:24 +0100 Subject: [PATCH 07/23] varnish: update munin plugin to work with recent varnish versions --- CHANGELOG.md | 3 +- varnish/files/munin/varnish4_ | 1165 --------------------------- varnish/files/munin/varnish5.conf | 2 + varnish/files/munin/varnish5_ | 1221 +++++++++++++++++++++++++++++ varnish/tasks/munin.yml | 29 +- 5 files changed, 1244 insertions(+), 1176 deletions(-) delete mode 100644 varnish/files/munin/varnish4_ create mode 100644 varnish/files/munin/varnish5.conf create mode 100644 varnish/files/munin/varnish5_ diff --git a/CHANGELOG.md b/CHANGELOG.md index 62590672..3f413ee4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,10 +33,11 @@ The **patch** part changes is incremented if multiple releases happen the same m * rbenv: install Ruby 3.1.0 by default * evolinux-base: backup-server-state: add "force" mode + ### Fixed * evolinux-base: backup-server-state: fix systemctl invocation - +* varnish: update munin plugin to work with recent varnish versions ## [22.01.2] 2022-01-27 diff --git a/varnish/files/munin/varnish4_ b/varnish/files/munin/varnish4_ deleted file mode 100644 index 60dc8212..00000000 --- a/varnish/files/munin/varnish4_ +++ /dev/null @@ -1,1165 +0,0 @@ -#!/usr/bin/perl -# -*- perl -*- -# -# varnish4_ - Munin plugin to for Varnish 4.x -# Copyright (C) 2009 Redpill Linpro AS -# -# Author: Kristian Lyngstol -# -# 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 2 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, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -=head1 NAME - -varnish4_ - Munin plugin to monitor various aspects of varnish - -=head1 APPLICABLE SYSTEMS - -Varnish 4.x with varnishstat - -=head1 CONFIGURATION - -The plugin needs to be able to execute varnishstat. - -The configuration section shows the defaults - [varnish4_*] - env.varnishstat varnishstat - env.name - -env.varnishstat can be a full path to varnishstat if it's -not in the path already. - -env.name is blank (undefined) by default and can be used to specify a -n -name argument to varnish if multiple instances are running on the same -server. - -A few aspects are not linked by default. They are marked as -'DEBUG' => 'yes' (or any other value). They are: - -vcl, bans, bans_lurker, lru, objects_per_objhead, -losthdr, esi, hcb, shm, shm_writes, overflow, -session, session_herd, gzip - -You can link them yourself with something like this: - - ln -s @@LIBDIR@@/plugins/varnish4_ \ - @@CONFDIR@@/plugins/varnish4_data_structures - -=head1 INTERPRETATION - -Each graph uses data from varnishstat. - -=head1 MAGIC MARKERS - - #%# family=auto - #%# capabilities=autoconf suggest - -=head1 VERSION - - $Id$ - -=head1 BUGS - -The hit_rate graph requires munin r2040 or newer to display -correctly. - -=head1 PATCHES-TO - -Please send patches to Kristian Lyngstol -and/or varnish-misc@varnish-cache.org for significant changes. Munin SVN -is the authoritative repository for this plugin. - -=head1 AUTHOR - -Kristian Lyngstol - -=head1 MODIFICATIONS - -Ingo Oppermann - -=head1 LICENSE - -GPLv2 - -=cut - - -use XML::Parser; -use strict; - -# Set to 1 to enable output when a variable is defined in a graph but -# omitted because it doesn't exist in varnishstat. -my $DEBUG = 0; - -# Set to 1 to ignore 'DEBUG' and suggest all available aspects. -my $FULL_SUGGEST = 0; - -# Varnishstat executable. Include full path if it's not in your path. -my $varnishstatexec = exists $ENV{'varnishstat'} ? $ENV{'varnishstat'} : "varnishstat"; - -# For multiple instances -my $varnishname = exists $ENV{'name'} ? $ENV{'name'} : undef; - -my $self; # Haha, myself, what a clever pun. - -# Parameters that can be defined on top level of a graph. Config will print -# them as "graph_$foo $value\n" -my @graph_parameters = ('title','total','order','scale','vlabel','args'); - -# Parameters that can be defined on a value-to-value basis and will be -# blindly passed to config. Printed as "$fieldname.$param $value\n". -# -# 'label' is hardcoded as it defaults to a varnishstat-description if not -# set. -my @field_parameters = ('graph', 'min', 'max', 'draw', 'cdef', 'warning', - 'colour', 'info', 'type'); - -# Varnishstat data is stored here. Example -# ('n_vbe' => { 'value' => '124', 'description'=>...,'flag'=>... }, SMA => -# { s0 => { 'value' => '...', 'flag'=> '...' },'Transient' => ...}) -# Both dynamic and static counters are kept here. -# -# Notes: -# - The 'flag' field for a counter is in RRD-dialect, not varnishstat -my %data; - -# Data structure that defines all possible graphs (aspects) and how they -# are to be plotted. Every top-level entry is a graph/aspect. Each -# top-level graph MUST have title set and 'values'. -# -# The 'values' hash must have at least one value definition. The actual -# value used is either fetched from varnishstat based on the value-name, or -# if 'rpn' is defined: calculated. 'type' SHOULD be set. -# -# Graphs with 'DEBUG' set to anything is omitted from 'suggest'. -# -# 'rpn' on values allows easy access to graphs consisting of multiple -# values from varnishstat. (Reverse polish notation). The RPN -# implementation only accepts +-*/ and varnishstat-values. -# -# With the exception of 'label', which is filled with the -# varnishstat-description if left undefined, any value left undefined will -# be left up to Munin to define/ignore/yell about. -# -# For dynamic counters, the values listed need to specify a counter and -# family. This will plot the specified counter for each identity within -# that family. Example: family of SMA, counter c_fail. This will create a -# c_fail-counter for each of the SMA-identities (e.g: Transient, s0, etc). -# For dynamic graphs, the value-name is only used to identify the data -# point, and does not relate to any varnishstat data as that is set by -# family/counter. -# -# Note that dynamic counters fetch the type from the XML and things like -# min/max are currently not supported (and silently ignored). -# -# See munin documentation or rrdgraph/rrdtool for more information. -my %ASPECTS = ( - 'request_rate' => { - 'title' => 'Request rates', - 'order' => 'cache_hit cache_hitpass cache_miss ' - . 'backend_conn backend_unhealthy ' - . 'client_req client_conn' , - 'values' => { - 'sess_conn' => { - 'type' => 'DERIVE', - 'min' => '0', - 'colour' => '444444', - 'graph' => 'ON' - }, - 'client_req' => { - 'type' => 'DERIVE', - 'colour' => '111111', - 'min' => '0' - }, - 'cache_hit' => { - 'type' => 'DERIVE', - 'draw' => 'AREA', - 'colour' => '00FF00', - 'min' => '0' - }, - 'cache_hitpass' => { - 'info' => 'Hitpass are cached passes: An ' - . 'entry in the cache instructing ' - . 'Varnish to pass. Typically ' - . 'achieved after a pass in ' - . 'vcl_fetch.', - 'type' => 'DERIVE', - 'draw' => 'STACK', - 'colour' => 'FFFF00', - 'min' => '0' - }, - 'cache_miss' => { - 'type' => 'DERIVE', - 'colour' => 'FF0000', - 'draw' => 'STACK', - 'min' => '0' - }, - 'backend_conn' => { - 'type' => 'DERIVE', - 'colour' => '995599', - 'min' => '0' - }, - 'backend_unhealthy' => { - 'type' => 'DERIVE', - 'min' => '0', - 'colour' => 'FF55FF' - }, - 's_pipe' => { - 'type' => 'DERIVE', - 'min' => '0', - 'colour' => '1d2bdf' - }, - 's_pass' => { - 'type' => 'DERIVE', - 'min' => '0', - 'colour' => '785d0d' - } - } - }, - 'hit_rate' => { - 'title' => 'Hit rates', - 'order' => 'client_req cache_hit cache_miss ' - . 'cache_hitpass' , - 'vlabel' => '%', - 'args' => '-u 100 --rigid', - 'scale' => 'no', - 'values' => { - 'client_req' => { - 'type' => 'DERIVE', - 'min' => '0', - 'graph' => 'off', - 'rpn' => [ 'cache_hit' , 'cache_miss' , 'cache_hitpass' , '+' , '+' ] - }, - 'cache_hit' => { - 'type' => 'DERIVE', - 'min' => '0', - 'draw' => 'AREA', - 'cdef' => 'cache_hit,client_req,/,100,*' - }, - 'cache_miss' => { - 'type' => 'DERIVE', - 'draw' => 'STACK', - 'min' => '0', - 'cdef' => 'cache_miss,client_req,/,100,*' - }, - 'cache_hitpass' => { - 'type' => 'DERIVE', - 'draw' => 'STACK', - 'min' => '0', - 'cdef' => 'cache_hitpass,client_req,/,100,*' - }, - } - }, - 'backend_traffic' => { - 'title' => 'Backend traffic', - 'values' => { - 'backend_conn' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'backend_unhealthy' => { - 'type' => 'DERIVE', - 'min' => '0', - 'warning' => ':1' - }, - 'backend_busy' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'backend_fail' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'backend_reuse' => { - 'type' => 'DERIVE', - 'min' => 0 - }, - 'backend_recycle' => { - 'type' => 'DERIVE', - 'min' => 0 - }, - 'backend_toolate' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'backend_retry' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'backend_req' => { - 'type' => 'DERIVE', - 'min' => '0' - } - } - }, - 'objects' => { - 'title' => 'Number of objects', - 'order' => 'n_object n_objectcore n_vampireobject n_objecthead', - 'values' => { - 'n_object' => { - 'type' => 'GAUGE', - 'label' => 'Number of objects' - }, - 'n_objectcore' => { - 'type' => 'GAUGE', - 'label' => 'Number of object cores' - }, - 'n_vampireobject' => { - 'type' => 'GAUGE', - 'label' => 'Number of unresurrected objects' - }, - 'n_objecthead' => { - 'type' => 'GAUGE', - 'label' => 'Number of object heads', - 'info' => 'Each object head can have one ' - . 'or more object attached, ' - . 'typically based on the Vary: header' - } - } - }, - 'transfer_rates' => { - 'title' => 'Transfer rates', - 'order' => 's_resp_bodybytes s_resp_hdrbytes', - 'args' => '-l 0', - 'vlabel' => 'bit/s', - 'values' => { - 's_resp_hdrbytes' => { - 'type' => 'DERIVE', - 'label' => 'Header traffic', - 'draw' => 'STACK', - 'min' => '0', - 'info' => 'HTTP Header traffic. TCP/IP ' - . 'overhead is not included.', - 'cdef' => 's_resp_hdrbytes,8,*' - }, - 's_resp_bodybytes' => { - 'type' => 'DERIVE', - 'draw' => 'AREA', - 'label' => 'Body traffic', - 'min' => '0', - 'cdef' => 's_resp_bodybytes,8,*' - } - } - }, - 'threads' => { - 'title' => 'Thread status', - 'values' => { - 'threads' => { - 'type' => 'GAUGE', - 'min' => '0', - 'warning' => '1:' - }, - 'threads_created' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'threads_failed' => { - 'type' => 'DERIVE', - 'min' => '0', - 'warning' => ':1' - }, - 'threads_limited' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'threads_destroyed' => { - 'type' => 'DERIVE', - 'min' => '0', - 'warning' => ':1' - } - } - }, - 'memory_usage' => { - 'title' => 'Memory usage', - 'args' => '--base 1024', - 'vlabel' => 'bytes', - 'values' => { - 'sms_balloc' => { - 'type' => 'GAUGE', - }, - 'sms_nbytes' => { - 'type' => 'GAUGE', - }, - 'SMA_1' => { - 'counter' => 'g_bytes', - 'family' => 'SMA', - }, - 'SMA_2' => { - 'counter' => 'g_space', - 'family' => 'SMA', - }, - 'SMA_3' => { - 'counter' => 'c_bytes', - 'family' => 'SMA' - }, - 'SMF_1' => { - 'counter' => 'g_bytes', - 'family' => 'SMF', - }, - 'SMF_2' => { - 'counter' => 'g_space', - 'family' => 'SMF', - } - } - }, - 'uptime' => { - 'title' => 'Varnish uptime', - 'vlabel' => 'days', - 'scale' => 'no', - 'values' => { - 'uptime' => { - 'type' => 'GAUGE', - 'cdef' => 'uptime,86400,/' - } - } - }, - 'objects_per_objhead' => { - 'title' => 'Objects per objecthead', - 'DEBUG' => 'yes', - 'values' => { - 'obj_per_objhead' => { - 'type' => 'GAUGE', - 'label' => 'Objects per object heads', - 'rpn' => [ 'n_object','n_objecthead','/' ] - } - } - }, - 'losthdr' => { - 'title' => 'HTTP Header overflows', - 'DEBUG' => 'yes', - 'values' => { - 'losthdr' => { - 'type' => 'DERIVE', - 'min' => '0' - } - } - }, - 'hcb' => { - 'title' => 'Critbit data', - 'DEBUG' => 'yes', - 'values' => { - 'hcb_nolock' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'hcb_lock' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'hcb_insert' => { - 'type' => 'DERIVE', - 'min' => '0' - } - } - }, - 'esi' => { - 'title' => 'ESI', - 'DEBUG' => 'yes', - 'values' => { - 'esi_parse' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'esi_errors' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'esi_warnings' => { - 'type' => 'DERIVE', - 'min' => '0' - } - } - }, - 'session' => { - 'title' => 'Sessions', - 'DEBUG' => 'yes', - 'values' => { - 'sess_conn' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'sess_drop' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'sess_fail' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'sess_pipe_overflow' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'sess_queued' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'sess_dropped' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'sess_closed' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'sess_pipeline' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'sess_readahead' => { - 'type' => 'DERIVE', - 'min' => '0' - } - } - }, - 'session_herd' => { - 'title' => 'Session herd', - 'DEBUG' => 'yes', - 'values' => { - 'sess_herd' => { - 'type' => 'DERIVE', - 'min' => '0' - } - } - }, - 'shm_writes' => { - 'title' => 'SHM writes and records', - 'DEBUG' => 'yes', - 'values' => { - 'shm_records' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'shm_writes' => { - 'type' => 'DERIVE', - 'min' => '0' - } - } - }, - 'shm' => { - 'title' => 'Shared memory activity', - 'DEBUG' => 'yes', - 'values' => { - 'shm_flushes' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'shm_cont' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'shm_cycles' => { - 'type' => 'DERIVE', - 'min' => '0' - } - } - }, - 'allocations' => { - 'title' => 'Memory allocation requests', - 'DEBUG' => 'yes', - 'values' => { - 'sm_nreq' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'sma_nreq' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'sms_nreq' => { - 'type' => 'DERIVE', - 'min' => '0' - } - } - }, - 'vcl' => { - 'title' => 'VCL', - 'DEBUG' => 'yes', - 'values' => { - 'n_backend' => { - 'type' => 'GAUGE' - }, - 'n_vcl' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'n_vcl_avail' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'n_vcl_discard' => { - 'type' => 'DERIVE', - 'min' => '0' - } - } - }, - 'bans' => { - 'title' => 'Bans', - 'DEBUG' => 'yes', - 'values' => { - 'bans' => { - 'type' => 'GAUGE' - }, - 'bans_added' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'bans_deleted' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'bans_completed' => { - 'type' => 'GAUGE' - }, - 'bans_obj' => { - 'type' => 'GAUGE' - }, - 'bans_req' => { - 'type' => 'GAUGE' - }, - 'bans_tested' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'bans_obj_killed' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'bans_tests_tested' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'bans_dups' => { - 'type' => 'GAUGE' - }, - 'bans_persisted_bytes' => { - 'type' => 'GAUGE' - }, - 'bans_persisted_fragmentation' => { - 'type' => 'GAUGE' - } - } - }, - 'bans_lurker' => { - 'title' => 'Ban Lurker', - 'DEBUG' => 'yes', - 'values' => { - 'bans_lurker_tested' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'bans_lurker_tests_tested' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'bans_lurker_obj_killed' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'bans_lurker_contention' => { - 'type' => 'DERIVE', - 'min' => '0' - } - } - }, - 'expunge' => { - 'title' => 'Object expunging', - 'order' => 'n_expired n_lru_nuked', - 'values' => { - 'n_expired' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'n_lru_nuked' => { - 'type' => 'DERIVE', - 'min' => '0' - } - } - }, - 'lru' => { - 'title' => 'LRU activity', - 'DEBUG' => 'yes', - 'values' => { - 'n_lru_nuked' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'n_lru_moved' => { - 'type' => 'DERIVE', - 'min' => '0' - } - } - }, - 'bad' => { - 'title' => 'Misbehavior', - 'values' => { - 'SMA_1' => { - 'counter' => 'c_fail', - 'family' => 'SMA', - }, - 'SMF_1' => { - 'counter' => 'c_fail', - 'family' => 'SMF', - }, - 'sess_drop' => { - 'type' => 'DERIVE' - }, - 'backend_unhealthy' => { - 'type' => 'DERIVE' - }, - 'fetch_failed' => { - 'type' => 'DERIVE' - }, - 'backend_busy' => { - 'type' => 'DERIVE' - }, - 'threads_failed' => { - 'type' => 'DERIVE' - }, - 'threads_limited' => { - 'type' => 'DERIVE' - }, - 'threads_destroyed' => { - 'type' => 'DERIVE' - }, - 'thread_queue_len' => { - 'type' => 'GAUGE' - }, - 'losthdr' => { - 'type' => 'DERIVE' - }, - 'esi_errors' => { - 'type' => 'DERIVE' - }, - 'esi_warnings' => { - 'type' => 'DERIVE' - }, - 'sess_fail' => { - 'type' => 'DERIVE' - }, - 'sess_pipe_overflow' => { - 'type' => 'DERIVE' - } - } - }, - 'gzip' => { - 'title' => 'GZIP activity', - 'DEBUG' => 'yes', - 'values' => { - 'n_gzip' => { - 'type' => 'DERIVE', - 'min' => '0' - }, - 'n_gunzip' => { - 'type' => 'DERIVE', - 'min' => '0' - } - } - } -); - -################################ -# Various helper functions # -################################ - -# Translate $_[0] from varnish' internal types (flags) to munin/rrd -# variants (e.g: from 'i' to GAUGE). Returns the result. -sub translate_type -{ - my $d = $_[0]; - if ($d eq "i") { - $d = "GAUGE"; - } elsif ($d eq "a") { - $d = "DERIVE"; - } - return $d; -} - -# Print the value of a two-dimensional hash if it exist. -# Returns false if non-existent. -# -# Output is formatted for plugins if arg4 is blank, otherwise arg4 is used -# as the title/name of the field (ie: arg4=graph_title). -sub print_if_exist -{ - my %values = %{$_[0]}; - my $value = $_[1]; - my $field = $_[2]; - my $title = "$value.$field"; - if (defined($_[3])) { - $title = $_[3]; - } - if (defined($values{$value}{$field})) { - print "$title $values{$value}{$field}\n"; - } else { - return 0; - } -} - -# Create a output-friendly name -sub normalize_name -{ - my $name = $_[0]; - $name =~ s/[^a-zA-Z0-9]/_/g; - return $name; -} - -# Braindead RPN: +,-,/,* will pop two items from @stack, and perform -# the relevant operation on the items. If the item in the array isn't one -# of the 4 basic math operations, a value from varnishstat is pushed on to -# the stack. IE: 'client_req','client_conn','/' will leave the value of -# "client_req/client_conn" on the stack. -# -# If only one item is left on the stack, it is printed. Otherwise, an error -# message is printed. -sub rpn -{ - my @stack; - my $left; - my $right; - foreach my $item (@{$_[0]}) { - if ($item eq "+") { - $right = pop(@stack); - $left = pop(@stack); - push(@stack,$left+$right); - } elsif ($item eq "-") { - $right = pop(@stack); - $left = pop(@stack); - push(@stack,$left-$right); - } elsif ($item eq "/") { - $right = pop(@stack); - $left = pop(@stack); - push(@stack,$left/$right); - } elsif ($item eq "*") { - $right = pop(@stack); - $left = pop(@stack); - push(@stack,$left*$right); - } else { - push(@stack,int($data{$item}{'value'})); - } - } - if (@stack > 1) - { - print STDERR "RPN error: Stack has more than one item left.\n"; - print STDERR "@stack\n"; - exit 255; - } - print "@stack"; - print "\n"; -} - -# Bail-function. -sub usage -{ - if (@_) { - print STDERR "@_" . "\n\n"; - } - print STDERR "Known arguments: suggest, config, autoconf.\n"; - print STDERR "Run with suggest to get a list of known aspects.\n"; - exit 1; -} - -################################ -# XML Parsing # -################################ -# The following code is for parsing varnishstat -x. While %data should be -# stable, the following bits can easily be replaced with anything (json, an -# other xml-parser, magic, etc) -# -# The basic concept is simple enough. Only worry about stuff inside -# . Updating %state on each new data field, and commit it to %data -# when is seen. -# -# We do use translate_type() on the 'flag' field. - - -# Internal state for the XML parsing -my %state = ( - 'stat' => 0, # inside or not - 'field' => 'none', # , , , etc. -); - -# Reset the state of XML, mainly used for end-elements. -sub xml_reset_state() { - $state{'stat'} = '0'; - $state{'field'} = 'none'; - $state{'values'} = (); -} - -# Callback for data entry. Cleans leading whitespace and updates state. -sub xml_characters { - my $d = $_[1]; - if ($state{'stat'} == 0) { - return; - } - if ($state{'field'} eq "type" && $d eq "MAIN") { - return; - } - $d =~ s/^\s*$//g; - if ($d eq "") { - return; - } - $state{'values'}{$state{'field'}} = $d; -} - -# Store the current state in %data. Issued at -# Note that 'flag' is translated to RRD-equivalents here. -sub xml_commit_state -{ - my $name = $state{'values'}{'name'}; - my $type = $state{'values'}{'type'}; - my $ident = $state{'values'}{'ident'}; - - foreach my $key (keys %{$state{'values'}}) { - my $data = $state{'values'}{$key}; - if ($key eq 'flag') { - $data = translate_type($data); - } - if (defined($type) and $type ne '' and defined($ident) and $ident ne '') { - $data{$type}{$ident}{$name}{$key} = $data; - } else { - $data{$name}{$key} = $data - } - } -} - -# Callback for end tag. E.g: -sub xml_end_elem { - my $element = $_[1]; - if ($element ne "stat") { - return; - } - - xml_commit_state(); - xml_reset_state(); -} - -# Callback for opening tag. E.g: -sub xml_start_elem { - $state{'field'} = $_[1]; - if ($state{'field'} eq "stat") { - $state{'stat'} = 1; - } -} - -################################ -# Internal API # -################################ - - -# Populate %data, includes both values and descriptions and more. -# Currently driven by XML, but that could change. -sub populate_stats -{ - my $arg = "-x"; - my $parser = new XML::Parser(Handlers => {Start => \&xml_start_elem, - End => \&xml_end_elem, - Char => \&xml_characters} ); - - if ($varnishname) { - $arg .= " -n $varnishname"; - } - - open (XMLDATA, "$varnishstatexec $arg|") or die "meh"; - $parser->parse(*XMLDATA, ProtocolEncoding => 'ISO-8859-1'); - close(XMLDATA); -} - -# Prints the fields in the list in $_[2] (e.g: 'value'/'description') for -# each identity of the varnish counter/family combination as defined by -# the $_[0]-counter on the aspect definition. Err, that's jibberish, so -# an example: -# -# e.g: dynamic_print('SMA_1','',('value')) -# e.g: dynamic_print('SMA_2','.label',('ident','description')) -# SMA_1 is the counter-value. If it is a dynamic counter, it has a counter -# and family-member (e.g: counter: c_req, family: SMA) and print_dynamic -# will print c_req for each SMA-identity. -# -# Note that the variables to print is a list. This is to allow printing a -# single item with multiple fields. Typically for identity+description so -# you can distinguish between different data points. -# -# Returns true if it was a dynamic counter. -sub print_dynamic -{ - my $name = $_[0]; - shift; - my $suffix = $_[0]; - shift; - my @field = @_; - if (!defined($ASPECTS{$self}{'values'}{$name}{'counter'})) { - return 0; - } - if (!defined($ASPECTS{$self}{'values'}{$name}{'family'})) { - return 0; - } - my $counter = $ASPECTS{$self}{'values'}{$name}{'counter'}; - my $type = $ASPECTS{$self}{'values'}{$name}{'family'}; - - foreach my $key (keys %{$data{$type}}) { - my $pname = normalize_name($type . "_" . $key . "_" . $counter); - print $pname . $suffix . " "; - my $i = 0; - foreach my $f (@field) { - if ($i != 0) { - print " "; - } - $i += 1; - print $data{$type}{$key}{$counter}{$f}; - } - print "\n"; - } - return 1; -} - -# Read and verify the aspect ($self). -sub set_aspect -{ - $self = $0; - $self =~ s/^.*\/varnish[0-9]?_//; - if (!defined($ASPECTS{$self}) && @ARGV == 0) { - usage "No such aspect"; - } -} - -# Print 'yes' if it's reasonable to use this plugin, or 'no' with a -# human-readable error message. Always exit true, even if the response -# is 'no'. -sub autoconf -{ - # XXX: Solaris outputs errors to stderr and always returns true. - # XXX: See #873 - if (`which $varnishstatexec 2>/dev/null` =~ m{^/}) { - print "yes\n"; - } else { - print "no ($varnishstatexec could not be found)\n"; - } - exit 0; -} - -# Suggest relevant aspects/values of $self. -# 'DEBUG'-graphs are excluded. -sub suggest -{ - foreach my $key (keys %ASPECTS) { - if (defined($ASPECTS{$key}{'DEBUG'}) && $FULL_SUGGEST != 1) { - next; - } - print "$key\n"; - } -} - -# Walk through the relevant aspect and print all top-level configuration -# values and value-definitions. -sub get_config -{ - my $graph = $_[0]; - - # Need to double-check since set_aspect only checks this if there - # is no argument (suggest/autoconf doesn't require a valid aspect) - if (!defined($ASPECTS{$graph})) { - usage "No such aspect"; - } - my %values = %{$ASPECTS{$graph}{'values'}}; - - print "graph_category Varnish\n"; - foreach my $field (@graph_parameters) { - print_if_exist(\%ASPECTS,$graph,$field,"graph_$field"); - } - - foreach my $value (sort keys %values) { - # Just print the description/type if it's a dynamic - # counter. It'll be silent if it isn't. - if(print_dynamic($value,'.label',('description','type','ident'))) { - print_dynamic($value,'.type',('flag')); - next; - } - - # Need either RPN definition or a varnishstat value. - if (!defined($data{$value}{'value'}) && - !defined($values{$value}{'rpn'})) { - if ($DEBUG) { - print "ERROR: $value not part of varnishstat.\n" - } - next; - } - - if (!print_if_exist(\%values,$value,'label')) { - print "$value.label $data{$value}{'description'}\n"; - } - foreach my $field (@field_parameters) { - print_if_exist(\%values,$value,$field); - } - } -} - -# Handle arguments (config, autoconf, suggest) -# Populate stats for config is necessary, but we want to avoid it for -# autoconf as it would generate a nasty error. -sub check_args -{ - if (@ARGV && $ARGV[0] eq '') { - shift @ARGV; - } - if (@ARGV == 1) { - if ($ARGV[0] eq "config") { - populate_stats; - get_config($self); - exit 0; - } elsif ($ARGV[0] eq "autoconf") { - autoconf($self); - exit 0; - } elsif ($ARGV[0] eq "suggest") { - suggest; - exit 0; - } - usage "Unknown argument"; - } -} - -################################ -# Execution starts here # -################################ - -set_aspect; -check_args; -populate_stats; - -# We only get here if we're supposed to. -# Walks through the relevant values and either prints the varnishstat, or -# if the 'rpn' variable is set, calls rpn() to execute ... the rpn. -# -# NOTE: Due to differences in varnish-versions, this checks if the value -# actually exist before using it. -foreach my $value (sort keys %{$ASPECTS{$self}{'values'}}) { - if (defined($ASPECTS{$self}{'values'}{$value}{'rpn'})) { - print "$value.value "; - rpn($ASPECTS{$self}{'values'}{$value}{'rpn'}); - } else { - if (print_dynamic($value,'.value',('value'))) { - next; - } - - if (!defined($data{$value}{'value'})) { - if ($DEBUG) { - print STDERR "Error: $value not part of " - . "varnishstat.\n"; - } - next; - } - print "$value.value "; - print "$data{$value}{'value'}\n"; - } -} diff --git a/varnish/files/munin/varnish5.conf b/varnish/files/munin/varnish5.conf new file mode 100644 index 00000000..bb367caf --- /dev/null +++ b/varnish/files/munin/varnish5.conf @@ -0,0 +1,2 @@ +[varnish5_*] +user vcache diff --git a/varnish/files/munin/varnish5_ b/varnish/files/munin/varnish5_ new file mode 100644 index 00000000..279805eb --- /dev/null +++ b/varnish/files/munin/varnish5_ @@ -0,0 +1,1221 @@ +#!/usr/bin/perl +# -*- perl -*- +# +# varnish5_ - Munin plugin to for Varnish 5.x and 6.x +# Copyright (C) 2009,2018 Redpill Linpro AS +# +# Author: Kristian Lyngstøl +# Pål-Eivind Johnsen +# +# 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 2 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +=head1 NAME + +varnish5_ - Munin plugin to monitor various aspects of varnish + +=head1 APPLICABLE SYSTEMS + +Varnish 5.x with varnishstat + +=head1 CONFIGURATION + +The plugin needs to be able to execute varnishstat. + +The configuration section shows the defaults + [varnish5_*] + group varnish + env.varnishstat varnishstat + env.name + +env.varnishstat can be a full path to varnishstat if it's +not in the path already. + +env.name is blank (undefined) by default and can be used to specify a -n +name argument to varnish if multiple instances are running on the same +server. + +A few aspects are not linked by default. They are marked as +'DEBUG' => 'yes' (or any other value). They are: + +vcl, bans, bans_lurker, lru, objects_per_objhead, +losthdr, esi, hcb, shm, shm_writes, overflow, +session, session_herd, gzip + +You can link them yourself with something like this: + + ln -s @@LIBDIR@@/plugins/varnish5_ \ + @@CONFDIR@@/plugins/varnish5_data_structures + +=head1 INTERPRETATION + +Each graph uses data from varnishstat. + +=head1 MAGIC MARKERS + + #%# family=auto + #%# capabilities=autoconf suggest + +=head1 VERSION + + $Id$ + +=head1 BUGS + +The hit_rate graph requires munin r2040 or newer to display +correctly. + +=head1 PATCHES-TO + +Please send patches to Kristian Lyngstøl +and/or varnish-misc@varnish-cache.org for significant changes. The +munin-contrib Git repo is the authoritative repository for this plugin. + +=head1 AUTHOR + +Kristian Lyngstøl + +=head1 MODIFICATIONS + +Ingo Oppermann +Pål-Eivind Johnsen + +=head1 LICENSE + +GPLv2 + +=cut + + +use XML::Parser; +use strict; + +# Set to 1 to enable output when a variable is defined in a graph but +# omitted because it doesn't exist in varnishstat. +my $DEBUG = 0; + +# Set to 1 to ignore 'DEBUG' and suggest all available aspects. +my $FULL_SUGGEST = 0; + +# Varnishstat executable. Include full path if it's not in your path. +my $varnishstatexec = exists $ENV{'varnishstat'} ? $ENV{'varnishstat'} : "varnishstat"; + +# For multiple instances +my $varnishname = exists $ENV{'name'} ? $ENV{'name'} : undef; + +my $self; # Haha, myself, what a clever pun. + +# Parameters that can be defined on top level of a graph. Config will print +# them as "graph_$foo $value\n" +my @graph_parameters = ('title','total','order','scale','vlabel','args'); + +# Parameters that can be defined on a value-to-value basis and will be +# blindly passed to config. Printed as "$fieldname.$param $value\n". +# +# 'label' is hardcoded as it defaults to a varnishstat-description if not +# set. +my @field_parameters = ('graph', 'min', 'max', 'draw', 'cdef', 'warning', + 'colour', 'info', 'type'); + +# Varnishstat data is stored here. Example +# ('n_vbe' => { 'value' => '124', 'description'=>...,'flag'=>... }, SMA => +# { s0 => { 'value' => '...', 'flag'=> '...' },'Transient' => ...}) +# Both dynamic and static counters are kept here. +# +# Notes: +# - The 'flag' field for a counter is in RRD-dialect, not varnishstat +my %data; + +# Data structure that defines all possible graphs (aspects) and how they +# are to be plotted. Every top-level entry is a graph/aspect. Each +# top-level graph MUST have title set and 'values'. +# +# The 'values' hash must have at least one value definition. The actual +# value used is either fetched from varnishstat based on the value-name, or +# if 'rpn' is defined: calculated. 'type' SHOULD be set. +# +# Graphs with 'DEBUG' set to anything is omitted from 'suggest'. +# +# 'rpn' on values allows easy access to graphs consisting of multiple +# values from varnishstat. (Reverse polish notation). The RPN +# implementation only accepts +-*/ and varnishstat-values. +# +# With the exception of 'label', which is filled with the +# varnishstat-description if left undefined, any value left undefined will +# be left up to Munin to define/ignore/yell about. +# +# For dynamic counters, the values listed need to specify a counter and +# family. This will plot the specified counter for each identity within +# that family. Example: family of SMA, counter c_fail. This will create a +# c_fail-counter for each of the SMA-identities (e.g: Transient, s0, etc). +# For dynamic graphs, the value-name is only used to identify the data +# point, and does not relate to any varnishstat data as that is set by +# family/counter. +# +# Note that dynamic counters fetch the type from the XML and things like +# min/max are currently not supported (and silently ignored). +# +# See munin documentation or rrdgraph/rrdtool for more information. +my %ASPECTS = ( + 'request_rate' => { + 'title' => 'Request rates', + 'order' => 'cache_hit cache_hitpass cache_miss cache_hitmiss' + . 'backend_conn backend_unhealthy ' + . 'client_req client_conn' , + 'values' => { + 'sess_conn' => { + 'type' => 'DERIVE', + 'min' => '0', + 'colour' => '444444', + 'graph' => 'ON' + }, + 'client_req' => { + 'type' => 'DERIVE', + 'colour' => '111111', + 'min' => '0' + }, + 'cache_hit' => { + 'type' => 'DERIVE', + 'draw' => 'AREA', + 'colour' => '00FF00', + 'min' => '0' + }, + 'cache_hitpass' => { + 'info' => 'Hitpass are cached passes: An ' + . 'entry in the cache instructing ' + . 'Varnish to pass. Typically ' + . 'achieved after a pass in ' + . 'vcl_fetch.', + 'type' => 'DERIVE', + 'draw' => 'STACK', + 'colour' => 'FFFF00', + 'min' => '0' + }, + 'cache_miss' => { + 'type' => 'DERIVE', + 'colour' => 'FF0000', + 'draw' => 'STACK', + 'min' => '0' + }, + 'cache_hitmiss' => { + 'info' => 'Hitmiss are cached missing: An ' + . 'entry in the cache instructing ' + . 'Varnish to pass. Typically ' + . 'achieved after a pass in ' + . 'vcl_fetch.', + 'type' => 'DERIVE', + 'draw' => 'STACK', + 'colour' => 'FFFF00', + 'min' => '0' + }, + 'backend_conn' => { + 'type' => 'DERIVE', + 'colour' => '995599', + 'min' => '0' + }, + 'backend_unhealthy' => { + 'type' => 'DERIVE', + 'min' => '0', + 'colour' => 'FF55FF' + }, + 's_pipe' => { + 'type' => 'DERIVE', + 'min' => '0', + 'colour' => '1d2bdf' + }, + 's_pass' => { + 'type' => 'DERIVE', + 'min' => '0', + 'colour' => '785d0d' + } + } + }, + 'hit_rate' => { + 'title' => 'Hit rates', + 'order' => 'client_req cache_hit cache_miss ' + . 'cache_hitpass cache_hitmiss' , + 'vlabel' => '%', + 'args' => '-l 0 -u 100 --rigid', + 'scale' => 'no', + 'values' => { + 'client_req' => { + 'type' => 'DERIVE', + 'min' => '0', + 'graph' => 'off', + 'rpn' => [ 'cache_hit' , 'cache_miss' , 'cache_hitpass' ,'cache_hitmiss', '+' , '+' ,'+' ] + }, + 'cache_hit' => { + 'type' => 'DERIVE', + 'min' => '0', + 'draw' => 'AREA', + 'cdef' => 'cache_hit,client_req,/,100,*' + }, + 'cache_miss' => { + 'type' => 'DERIVE', + 'draw' => 'STACK', + 'min' => '0', + 'cdef' => 'cache_miss,client_req,/,100,*' + }, + 'cache_hitpass' => { + 'type' => 'DERIVE', + 'draw' => 'STACK', + 'min' => '0', + 'cdef' => 'cache_hitpass,client_req,/,100,*' + }, + 'cache_hitmiss' => { + 'type' => 'DERIVE', + 'draw' => 'STACK', + 'min' => '0', + 'cdef' => 'cache_hitmiss,client_req,/,100,*' + } + } + }, + 'backend_traffic' => { + 'title' => 'Backend traffic', + 'values' => { + 'backend_conn' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'backend_unhealthy' => { + 'type' => 'DERIVE', + 'min' => '0', + 'warning' => ':1' + }, + 'backend_busy' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'backend_fail' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'backend_reuse' => { + 'type' => 'DERIVE', + 'min' => 0 + }, + 'backend_recycle' => { + 'type' => 'DERIVE', + 'min' => 0 + }, + 'backend_retry' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'backend_req' => { + 'type' => 'DERIVE', + 'min' => '0' + } + } + }, + 'objects' => { + 'title' => 'Number of objects', + 'order' => 'n_object n_objectcore n_vampireobject n_objecthead', + 'values' => { + 'n_object' => { + 'type' => 'GAUGE', + 'label' => 'Number of objects' + }, + 'n_objectcore' => { + 'type' => 'GAUGE', + 'label' => 'Number of object cores' + }, + 'n_vampireobject' => { + 'type' => 'GAUGE', + 'label' => 'Number of unresurrected objects' + }, + 'n_objecthead' => { + 'type' => 'GAUGE', + 'label' => 'Number of object heads', + 'info' => 'Each object head can have one ' + . 'or more object attached, ' + . 'typically based on the Vary: header' + } + } + }, + 'transfer_rates' => { + 'title' => 'Transfer rates', + 'order' => 's_resp_bodybytes s_resp_hdrbytes', + 'args' => '-l 0', + 'vlabel' => 'bit/s', + 'values' => { + 's_resp_hdrbytes' => { + 'type' => 'DERIVE', + 'label' => 'Header traffic', + 'draw' => 'STACK', + 'min' => '0', + 'info' => 'HTTP Header traffic. TCP/IP ' + . 'overhead is not included.', + 'cdef' => 's_resp_hdrbytes,8,*' + }, + 's_resp_bodybytes' => { + 'type' => 'DERIVE', + 'draw' => 'AREA', + 'label' => 'Body traffic', + 'min' => '0', + 'cdef' => 's_resp_bodybytes,8,*' + } + } + }, + 'threads' => { + 'title' => 'Thread status', + 'values' => { + 'threads' => { + 'type' => 'GAUGE', + 'min' => '0', + 'warning' => '1:' + }, + 'threads_created' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'threads_failed' => { + 'type' => 'DERIVE', + 'min' => '0', + 'warning' => ':1' + }, + 'threads_limited' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'threads_destroyed' => { + 'type' => 'DERIVE', + 'min' => '0', + 'warning' => ':1' + } + } + }, + 'memory_usage' => { + 'title' => 'Memory usage', + 'args' => '--base 1024', + 'vlabel' => 'bytes', + 'values' => { + 'SMA_1' => { + 'counter' => 'g_bytes', + 'family' => 'SMA', + }, + 'SMA_2' => { + 'counter' => 'g_space', + 'family' => 'SMA', + }, + 'SMA_3' => { + 'counter' => 'c_bytes', + 'family' => 'SMA' + }, + 'SMF_1' => { + 'counter' => 'g_bytes', + 'family' => 'SMF', + }, + 'SMF_2' => { + 'counter' => 'g_space', + 'family' => 'SMF', + }, + 'SMF_3' => { + 'counter' => 'c_bytes', + 'family' => 'SMF', + } + } + }, + 'main_uptime' => { + 'type' => 'MAIN', + 'title' => 'Varnish Child uptime', + 'vlabel' => 'days', + 'scale' => 'no', + 'values' => { + 'uptime' => { + 'type' => 'GAUGE', + 'cdef' => 'uptime,86400,/' + }, + } + }, + 'mgt_uptime' => { + 'type' => 'MGT', + 'title' => 'Varnish Management uptime', + 'vlabel' => 'days', + 'scale' => 'no', + 'values' => { + 'uptime' => { + 'type' => 'GAUGE', + 'cdef' => 'uptime,86400,/' + }, + } + }, + 'objects_per_objhead' => { + 'title' => 'Objects per objecthead', + 'DEBUG' => 'yes', + 'values' => { + 'n_objecthead' => { + 'type' => 'GAUGE', + 'label' => 'Objects per object heads', + 'rpn' => [ 'n_object','n_objecthead','/' ] + } + } + }, + 'losthdr' => { + 'title' => 'HTTP Header overflows', + 'DEBUG' => 'yes', + 'values' => { + 'losthdr' => { + 'type' => 'DERIVE', + 'min' => '0' + } + } + }, + 'hcb' => { + 'title' => 'Critbit data', + 'DEBUG' => 'yes', + 'values' => { + 'hcb_nolock' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'hcb_lock' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'hcb_insert' => { + 'type' => 'DERIVE', + 'min' => '0' + } + } + }, + 'esi' => { + 'title' => 'ESI', + 'DEBUG' => 'yes', + 'values' => { + 'esi_errors' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'esi_warnings' => { + 'type' => 'DERIVE', + 'min' => '0' + } + } + }, + 'session' => { + 'title' => 'Sessions', + 'DEBUG' => 'yes', + 'values' => { + 'sess_conn' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'sess_drop' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'sess_fail' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'sess_pipe_overflow' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'sess_queued' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'sess_dropped' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'sess_closed' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'sess_pipeline' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'sess_readahead' => { + 'type' => 'DERIVE', + 'min' => '0' + } + } + }, + 'session_herd' => { + 'title' => 'Session herd', + 'DEBUG' => 'yes', + 'values' => { + 'sess_herd' => { + 'type' => 'DERIVE', + 'min' => '0' + } + } + }, + 'shm_writes' => { + 'title' => 'SHM writes and records', + 'DEBUG' => 'yes', + 'values' => { + 'shm_records' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'shm_writes' => { + 'type' => 'DERIVE', + 'min' => '0' + } + } + }, + 'shm' => { + 'title' => 'Shared memory activity', + 'DEBUG' => 'yes', + 'values' => { + 'shm_flushes' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'shm_cont' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'shm_cycles' => { + 'type' => 'DERIVE', + 'min' => '0' + } + } + }, + 'allocations' => { + 'title' => 'Memory allocation requests', + 'DEBUG' => 'yes', + 'values' => { + 'sm_nreq' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'sma_nreq' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'sms_nreq' => { + 'type' => 'DERIVE', + 'min' => '0' + } + } + }, + 'vcl' => { + 'title' => 'VCL', + 'DEBUG' => 'yes', + 'values' => { + 'n_backend' => { + 'type' => 'GAUGE' + }, + 'n_vcl' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'n_vcl_avail' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'n_vcl_discard' => { + 'type' => 'DERIVE', + 'min' => '0' + } + } + }, + 'bans' => { + 'title' => 'Bans', + 'DEBUG' => 'yes', + 'values' => { + 'bans' => { + 'type' => 'GAUGE' + }, + 'bans_added' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'bans_deleted' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'bans_completed' => { + 'type' => 'GAUGE' + }, + 'bans_obj' => { + 'type' => 'GAUGE' + }, + 'bans_req' => { + 'type' => 'GAUGE' + }, + 'bans_tested' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'bans_obj_killed' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'bans_tests_tested' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'bans_dups' => { + 'type' => 'GAUGE' + }, + 'bans_persisted_bytes' => { + 'type' => 'GAUGE' + }, + 'bans_persisted_fragmentation' => { + 'type' => 'GAUGE' + } + } + }, + 'bans_lurker' => { + 'title' => 'Ban Lurker', + 'DEBUG' => 'yes', + 'values' => { + 'bans_lurker_tested' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'bans_lurker_tests_tested' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'bans_lurker_obj_killed' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'bans_lurker_contention' => { + 'type' => 'DERIVE', + 'min' => '0' + } + } + }, + 'expunge' => { + 'title' => 'Object expunging', + 'order' => 'n_expired n_lru_nuked', + 'values' => { + 'n_expired' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'n_lru_nuked' => { + 'type' => 'DERIVE', + 'min' => '0' + } + } + }, + 'lru' => { + 'title' => 'LRU activity', + 'DEBUG' => 'yes', + 'values' => { + 'n_lru_nuked' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'n_lru_moved' => { + 'type' => 'DERIVE', + 'min' => '0' + } + } + }, + 'bad' => { + 'title' => 'Misbehavior', + 'values' => { + 'SMA_1' => { + 'counter' => 'c_fail', + 'family' => 'SMA', + }, + 'SMF_1' => { + 'counter' => 'c_fail', + 'family' => 'SMF', + }, + 'sess_drop' => { + 'type' => 'DERIVE' + }, + 'backend_unhealthy' => { + 'type' => 'DERIVE' + }, + 'fetch_failed' => { + 'type' => 'DERIVE' + }, + 'backend_busy' => { + 'type' => 'DERIVE' + }, + 'threads_failed' => { + 'type' => 'DERIVE' + }, + 'threads_limited' => { + 'type' => 'DERIVE' + }, + 'threads_destroyed' => { + 'type' => 'DERIVE' + }, + 'thread_queue_len' => { + 'type' => 'GAUGE' + }, + 'losthdr' => { + 'type' => 'DERIVE' + }, + 'esi_errors' => { + 'type' => 'DERIVE' + }, + 'esi_warnings' => { + 'type' => 'DERIVE' + }, + 'sess_fail' => { + 'type' => 'DERIVE' + }, + 'sess_pipe_overflow' => { + 'type' => 'DERIVE' + + } + } + }, + 'gzip' => { + 'title' => 'GZIP activity', + 'DEBUG' => 'yes', + 'values' => { + 'n_gzip' => { + 'type' => 'DERIVE', + 'min' => '0' + }, + 'n_gunzip' => { + 'type' => 'DERIVE', + 'min' => '0' + } + } + }, + 'backend' => { + 'title' => 'Backend Status', + 'DEBUG' => 'yes', + 'values' => { + 'VBE.boot_1' => { + 'counter' => 'happy', + 'family' => 'VBE', + }, + + } + } + +); + +################################ +# Various helper functions # +################################ + +# Translate $_[0] from varnish' internal types (flags) to munin/rrd +# variants (e.g: from 'i' to GAUGE). Returns the result. +sub translate_type +{ + my $d = $_[0]; + if ($d eq "i" or $d eq "g") { + $d = "GAUGE"; + } elsif ($d eq "a" or $d eq "c") { + $d = "DERIVE"; + } + return $d; +} + +# Print the value of a two-dimensional hash if it exist. +# Returns false if non-existent. +# +# Output is formatted for plugins if arg4 is blank, otherwise arg4 is used +# as the title/name of the field (ie: arg4=graph_title). +sub print_if_exist +{ + my %values = %{$_[0]}; + my $value = $_[1]; + my $field = $_[2]; + my $pvalue = normalize_name($value); + + my $title = "$pvalue.$field"; + if (defined($_[3])) { + $title = $_[3]; + } + if (defined($values{$value}{$field})) { + print "$title $values{$value}{$field}\n"; + } else { + return 0; + } +} + +# Create a output-friendly name +sub normalize_name +{ + my $name = $_[0]; + $name =~ s/[^a-zA-Z0-9]/_/g; + return $name; +} + +# Braindead RPN: +,-,/,* will pop two items from @stack, and perform +# the relevant operation on the items. If the item in the array isn't one +# of the 4 basic math operations, a value from varnishstat is pushed on to +# the stack. IE: 'client_req','client_conn','/' will leave the value of +# "client_req/client_conn" on the stack. +# +# If only one item is left on the stack, it is printed. Otherwise, an error +# message is printed. +sub rpn +{ + my @stack; + my $left; + my $right; + foreach my $item (@{$_[0]}) { + if ($item eq "+") { + $right = pop(@stack); + $left = pop(@stack); + push(@stack,$left+$right); + } elsif ($item eq "-") { + $right = pop(@stack); + $left = pop(@stack); + push(@stack,$left-$right); + } elsif ($item eq "/") { + $right = pop(@stack); + $left = pop(@stack); + push(@stack,$left/$right); + } elsif ($item eq "*") { + $right = pop(@stack); + $left = pop(@stack); + push(@stack,$left*$right); + } else { + push(@stack,int($data{$item}{'value'})); + } + } + if (@stack > 1) + { + print STDERR "RPN error: Stack has more than one item left.\n"; + print STDERR "@stack\n"; + exit 255; + } + print "@stack"; + print "\n"; +} + +# Bail-function. +sub usage +{ + if (@_) { + print STDERR "@_" . "\n\n"; + } + print STDERR "Known arguments: suggest, config, autoconf.\n"; + print STDERR "Run with suggest to get a list of known aspects.\n"; + exit 1; +} + +################################ +# XML Parsing # +################################ +# The following code is for parsing varnishstat -x. While %data should be +# stable, the following bits can easily be replaced with anything (json, an +# other xml-parser, magic, etc) +# +# The basic concept is simple enough. Only worry about stuff inside +# . Updating %state on each new data field, and commit it to %data +# when is seen. +# +# We do use translate_type() on the 'flag' field. + + +# Internal state for the XML parsing +my %state = ( + 'stat' => 0, # inside or not + 'field' => 'none', # , , , etc. +); + +# Reset the state of XML, mainly used for end-elements. +sub xml_reset_state() { + $state{'stat'} = '0'; + $state{'field'} = 'none'; + $state{'values'} = (); +} + +# Callback for data entry. Cleans leading whitespace and updates state. +sub xml_characters { + my $d = $_[1]; + if ($state{'stat'} == 0) { + return; + } + if ($state{'field'} eq "type" && $d eq "MAIN") { + return; + } + $d =~ s/^\s*$//g; + if ($d eq "") { + return; + } + $state{'values'}{$state{'field'}} = $d; +} + +# Store the current state in %data. Issued at +# Note that 'flag' is translated to RRD-equivalents here. +sub xml_commit_state +{ + my $configtype = $ASPECTS{$self}{'type'}; + my $name = $state{'values'}{'name'}; + my @namelist = split(/\./,$name); + my $type = shift @namelist; + if ($configtype eq '' || $configtype eq $type) { + my $name = ""; + my $ident = ""; + if (scalar(@namelist) == 1) { + $name = shift @namelist; + } elsif (scalar(@namelist) == 2) { + $ident = shift @namelist; + $name = shift @namelist; + } else { + $name = pop @namelist; + $ident = join('_', @namelist); + } + foreach my $key (keys %{$state{'values'}}) { + my $data = $state{'values'}{$key}; + if ($key eq 'flag') { + $data = translate_type($data); + } + if (defined($type) and $type ne '' and defined($ident) and $ident ne '') { + $data{$type}{$ident}{$name}{$key} = $data; + } else { + $data{$name}{$key} = $data; + } + } + } +} + +# Callback for end tag. E.g: +sub xml_end_elem { + my $element = $_[1]; + if ($element ne "stat") { + return; + } + + xml_commit_state(); + xml_reset_state(); +} + +# Callback for opening tag. E.g: +sub xml_start_elem { + $state{'field'} = $_[1]; + if ($state{'field'} eq "stat") { + $state{'stat'} = 1; + } +} + +################################ +# Internal API # +################################ + + +# Populate %data, includes both values and descriptions and more. +# Currently driven by XML, but that could change. +sub populate_stats +{ + my $arg = "-x"; + my $parser = new XML::Parser(Handlers => {Start => \&xml_start_elem, + End => \&xml_end_elem, + Char => \&xml_characters} ); + + if ($varnishname) { + $arg .= " -n $varnishname"; + } + + open (XMLDATA, "$varnishstatexec $arg|") or die "meh"; + $parser->parse(*XMLDATA, ProtocolEncoding => 'ISO-8859-1'); + close(XMLDATA); +} + +# Prints the fields in the list in $_[2] (e.g: 'value'/'description') for +# each identity of the varnish counter/family combination as defined by +# the $_[0]-counter on the aspect definition. Err, that's jibberish, so +# an example: +# +# e.g: dynamic_print('SMA_1','',('value')) +# e.g: dynamic_print('SMA_2','.label',('ident','description')) +# SMA_1 is the counter-value. If it is a dynamic counter, it has a counter +# and family-member (e.g: counter: c_req, family: SMA) and print_dynamic +# will print c_req for each SMA-identity. +# +# Note that the variables to print is a list. This is to allow printing a +# single item with multiple fields. Typically for identity+description so +# you can distinguish between different data points. +# +# Returns true if it was a dynamic counter. +sub print_dynamic +{ + my $name = $_[0]; + shift; + my $suffix = $_[0]; + shift; + my @field = @_; + if (!defined($ASPECTS{$self}{'values'}{$name}{'counter'})) { + return 0; + } + if (!defined($ASPECTS{$self}{'values'}{$name}{'family'})) { + return 0; + } + my $counter = $ASPECTS{$self}{'values'}{$name}{'counter'}; + my $type = $ASPECTS{$self}{'values'}{$name}{'family'}; + + foreach my $key (keys %{$data{$type}}) { + my $pname = normalize_name($type . "_" . $key . "_" . $counter); + print $pname . $suffix . " "; + my $i = 0; + foreach my $f (@field) { + if ($i != 0) { + print " "; + } + $i += 1; + print $data{$type}{$key}{$counter}{$f}; + } + print "\n"; + } + return 1; +} + +# Read and verify the aspect ($self). +sub set_aspect +{ + $self = $0; + $self =~ s/^.*\/varnish[0-9]?_//; + return if defined($ASPECTS{$self}); + # remove instance name and try again + $self =~ s/^.*?_//; + if (!defined($ASPECTS{$self}) && @ARGV == 0) { + usage "No such aspect"; + } +} + +# Print 'yes' if it's reasonable to use this plugin, or 'no' with a +# human-readable error message. Always exit true, even if the response +# is 'no'. +sub autoconf +{ + # XXX: Solaris outputs errors to stderr and always returns true. + # XXX: See #873 + if (`which $varnishstatexec 2>/dev/null` =~ m{^/}) { + print "yes\n"; + } else { + print "no ($varnishstatexec could not be found)\n"; + } + exit 0; +} + +# Suggest relevant aspects/values of $self. +# 'DEBUG'-graphs are excluded. +sub suggest +{ + foreach my $key (keys %ASPECTS) { + if (defined($ASPECTS{$key}{'DEBUG'}) && $FULL_SUGGEST != 1) { + next; + } + print "$key\n"; + } +} + +# Walk through the relevant aspect and print all top-level configuration +# values and value-definitions. +sub get_config +{ + my $graph = $_[0]; + + # Need to double-check since set_aspect only checks this if there + # is no argument (suggest/autoconf doesn't require a valid aspect) + if (!defined($ASPECTS{$graph})) { + usage "No such aspect"; + } + my %values = %{$ASPECTS{$graph}{'values'}}; + + print "graph_category varnish\n"; + foreach my $field (@graph_parameters) { + print_if_exist(\%ASPECTS,$graph,$field,"graph_$field"); + } + + foreach my $value (sort keys %values) { + # Just print the description/type if it's a dynamic + # counter. It'll be silent if it isn't. + if(print_dynamic($value,'.label',('description','type','ident'))) { + print_dynamic($value,'.type',('flag')); + next; + } + + # Need either RPN definition or a varnishstat value. + if (!defined($data{$value}{'value'}) && + !defined($values{$value}{'rpn'})) { + if ($DEBUG) { + print STDERR "ERROR: $value not part of varnishstat.\n" + } + next; + } + + if (!print_if_exist(\%values,$value,'label')) { + my $pvalue = normalize_name($value); + print "$pvalue.label $data{$value}{'description'}\n"; + } + foreach my $field (@field_parameters) { + print_if_exist(\%values,$value,$field); + } + } +} + +# Handle arguments (config, autoconf, suggest) +# Populate stats for config is necessary, but we want to avoid it for +# autoconf as it would generate a nasty error. +sub check_args +{ + if (@ARGV && $ARGV[0] eq '') { + shift @ARGV; + } + if (@ARGV == 1) { + if ($ARGV[0] eq "config") { + populate_stats; + get_config($self); + exit 0; + } elsif ($ARGV[0] eq "autoconf") { + autoconf($self); + exit 0; + } elsif ($ARGV[0] eq "suggest") { + suggest; + exit 0; + } + usage "Unknown argument"; + } +} + +################################ +# Execution starts here # +################################ + +set_aspect; +check_args; +populate_stats; + +# We only get here if we're supposed to. +# Walks through the relevant values and either prints the varnishstat, or +# if the 'rpn' variable is set, calls rpn() to execute ... the rpn. +# +# NOTE: Due to differences in varnish-versions, this checks if the value +# actually exist before using it. +foreach my $value (keys %{$ASPECTS{$self}{'values'}}) { + my $pvalue = normalize_name($value); + if (defined($ASPECTS{$self}{'values'}{$value}{'rpn'})) { + print "$pvalue.value "; + rpn($ASPECTS{$self}{'values'}{$value}{'rpn'}); + } else { + if (print_dynamic($value,'.value',('value'))) { + next; + } + + if (!defined($data{$value}{'value'})) { + if ($DEBUG) { + print STDERR "Error: $value not part of " + . "varnishstat.\n"; + } + next; + } + print "$pvalue.value "; + print "$data{$value}{'value'}\n"; + } +} diff --git a/varnish/tasks/munin.yml b/varnish/tasks/munin.yml index 1d58aee6..1ccf5f88 100644 --- a/varnish/tasks/munin.yml +++ b/varnish/tasks/munin.yml @@ -22,29 +22,38 @@ mode: "0755" tags: varnish -- name: Copy varnish4 munin plugin +- name: Copy varnish5 munin plugin copy: - src: munin/varnish4_ + src: munin/varnish5_ dest: /usr/local/share/munin/plugins/ mode: "0755" notify: restart munin-node tags: varnish -- name: Enable varnish4 munin plugin +- name: Enable varnish5 munin plugin file: - src: /usr/local/share/munin/plugins/varnish4_ - dest: "/etc/munin/plugins/varnish4_{{item}}" + src: /usr/local/share/munin/plugins/varnish5_ + dest: "/etc/munin/plugins/varnish5_{{item}}" state: link loop: - - backend_traffic - - bad - - expunge - - hit_rate - memory_usage + - expunge - objects - request_rate + - mgt_uptime - threads + - backend_traffic + - hit_rate + - main_uptime - transfer_rates - - uptime + - bad + notify: restart munin-node + tags: varnish + +- name: Copy varnish5 munin plugin config + copy: + src: munin/varnish5.conf + dest: /etc/munin/plugin-conf.d/varnish5 + mode: "0644" notify: restart munin-node tags: varnish From 68b4b0803eb73dea69e6cba23d7fe4f70f83ccdc Mon Sep 17 00:00:00 2001 From: "William Hirigoyen (Evolix)" Date: Thu, 10 Feb 2022 18:03:32 +0100 Subject: [PATCH 08/23] =?UTF-8?q?#60953=20D=C3=A9sactivation=20AppArmor=20?= =?UTF-8?q?par=20d=C3=A9faut=20dans=20LXC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lxc/templates/default.conf | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lxc/templates/default.conf b/lxc/templates/default.conf index a656fd3c..c4b38d42 100644 --- a/lxc/templates/default.conf +++ b/lxc/templates/default.conf @@ -32,3 +32,8 @@ lxc.arch = x86_64 # Start containers on boot by default lxc.start.auto = 1 + +{% if ansible_distribution_major_version is version('9', '>') %} +# Set LXC container unconfined in AppArmor +lxc.apparmor.profile = unconfined +{% endif %} From ebfa8df6bcf1f1b997db9f81992f371d52ebaaf2 Mon Sep 17 00:00:00 2001 From: Brice Waegeneire Date: Mon, 14 Feb 2022 12:00:09 +0100 Subject: [PATCH 09/23] nrpe: Add check_mount_rw --- nagios-nrpe/files/plugins/check_mount_rw | 30 ++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100755 nagios-nrpe/files/plugins/check_mount_rw diff --git a/nagios-nrpe/files/plugins/check_mount_rw b/nagios-nrpe/files/plugins/check_mount_rw new file mode 100755 index 00000000..06ffbd45 --- /dev/null +++ b/nagios-nrpe/files/plugins/check_mount_rw @@ -0,0 +1,30 @@ +#!/bin/sh + +output=$(mktemp --tmpdir $(basename $0).XXXXXXXXXX) +critical_count=0 +ok_count=0 + +trap "rm -f $output" EXIT + +for mountpoint in $@; do + if findmnt -O ro --noheadings "$mountpoint" 1>/dev/null 2>&1; then + echo "CRITICAL - $mountpoint" >> "$output" + critical_count=$(( critical_count + 1)) + else + echo "OK - $mountpoint" >> "$output" + ok_count=$(( ok_count + 1)) + fi +done + +total_count=$(( ok_count + critical_count )) + +if [ $ok_count -eq $total_count ]; then + printf "OK - %d/%d no read-only mountpoint\n\n" "$ok_count" "$total_count" + cat "$output" + exit 0 +else + printf "CRITICAL - %d/%d read-only mountpoint\n\n" "$critical_count" "$total_count" + cat "$output" + exit 2 +fi + From f3c443d07687fc5621528a76e473c26cb47a3943 Mon Sep 17 00:00:00 2001 From: Jeremy Dubois Date: Tue, 15 Feb 2022 15:50:04 +0100 Subject: [PATCH 10/23] openvpn: now check that openvpn has been restarted since last certificates renewal --- CHANGELOG.md | 1 + openvpn/files/check_openvpn_certificates.sh | 176 +++++++++++++------- 2 files changed, 121 insertions(+), 56 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f413ee4..59d04a55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ The **patch** part changes is incremented if multiple releases happen the same m * Explicit permissions for systemd overrides * evolinux-base: option to bypass raid-related tasks * kvm-host: add missing default value +* openvpn: now check that openvpn has been restarted since last certificates renewal ### Changed diff --git a/openvpn/files/check_openvpn_certificates.sh b/openvpn/files/check_openvpn_certificates.sh index 47dca4b6..e010ce07 100644 --- a/openvpn/files/check_openvpn_certificates.sh +++ b/openvpn/files/check_openvpn_certificates.sh @@ -16,13 +16,22 @@ CA_ECHO="" error() { if [ $? -eq 2 ] && [ "X$CERT_ECHO" = "X" ] && [ "X$CA_ECHO" = "X" ] ; then - echo "CRITICAL - The check exited with an error. Is the conf_file var containing the real conf file location ? On Debian, is the check executed with sudo ?" + echo "CRITICAL - The check exited with an error. Is the conf_file var containing the real conf file location ? On Debian, is the check executed with sudo ? On OpenBSD, is the check executed with doas ? Is OpenVPN running ?" fi } SYSTEM=$(uname | tr '[:upper:]' '[:lower:]') date_cmd=$(command -v date) +# Some backup servers don't have OpenVPN running while they are backup +is_backup_not_running_openvpn="1" +if [ "$SYSTEM" = "openbsd" ]; then + carp=$(/sbin/ifconfig carp0 2>/dev/null | grep 'status' | cut -d' ' -f2) + if [ "$carp" = "backup" ] && ! rcctl ls on | grep -q openvpn; then + is_backup_not_running_openvpn="0" + fi +fi + # Dates in seconds _15_days="1296000" _30_days="2592000" @@ -30,7 +39,7 @@ current_date=$($date_cmd +"%s") # Trying to define the OpenVPN conf file location - default to /etc/openvpn/server.conf conf_file=$(ps auwwwx | grep openvpn | grep -- --config | grep -v sed | sed -e "s/.*config \(\/etc\/openvpn.*.conf\).*/\1/" | head -1) -[ "$SYSTEM" = "openbsd" ] && conf_file=${conf_file:-$(grep openvpn_flags /etc/rc.conf.local | sed -e "s/.*config \(\/etc\/openvpn.*.conf\).*/\1/")} +if [ "$SYSTEM" = "openbsd" ]; then conf_file=${conf_file:-$(grep openvpn_flags /etc/rc.conf.local | sed -e "s/.*config \(\/etc\/openvpn.*.conf\).*/\1/")}; fi conf_file=${conf_file:-"/etc/openvpn/server.conf"} # Get the cert and ca file location, based on the OpenVPN conf file location @@ -44,22 +53,34 @@ ca_file=$(echo $ca_file | sed -e "s/^ca *\//\//") cert_expiration_date=$(grep "Not After" $cert_file | sed -e "s/.*Not After : //") ca_expiration_date=$(openssl x509 -enddate -noout -in $ca_file | cut -d '=' -f 2) +# Get the date of last modification of cert and ca certificates +if [ "$SYSTEM" = "openbsd" ]; then + seconds_last_cert_modification_date=$(stat -f %m "$cert_file") + seconds_last_ca_modification_date=$(stat -f %m "$ca_file") +else + seconds_last_cert_modification_date=$(stat -c %Y "$cert_file") + seconds_last_ca_modification_date=$(stat -c %Y "$ca_file") +fi + +# Get the date of last OpenVPN restart +last_openvpn_restart_date=$(ps awwwx -O lstart | grep openvpn | grep -vE "grep|check_openvpn_certificates.sh" | awk '{print $3,$4,$5,$6}') + test_cert_expiration() { # Already expired - Cert file if [ $current_date -ge $1 ]; then - CERT_ECHO="CRITICAL - The server certificate has expired on $formatted_cert_expiration_date" + CERT_ECHO="CRITICAL - The server certificate has expired on $formated_cert_expiration_date" CERT_STATE=$STATE_CRITICAL # Expiration in 15 days or less - Cert file elif [ $((current_date+_15_days)) -ge $1 ]; then - CERT_ECHO="CRITICAL - The server certificate expires in 15 days or less : $formatted_cert_expiration_date" + CERT_ECHO="CRITICAL - The server certificate expires in 15 days or less : $formated_cert_expiration_date" CERT_STATE=$STATE_CRITICAL # Expiration in 30 days or less - Cert file elif [ $((current_date+_30_days)) -ge $1 ]; then - CERT_ECHO="WARNING - The server certificate expires in 30 days or less : $formatted_cert_expiration_date" + CERT_ECHO="WARNING - The server certificate expires in 30 days or less : $formated_cert_expiration_date" CERT_STATE=$STATE_WARNING # Expiration in more than 30 days - Cert file else - CERT_ECHO="OK - The server certificate expires on $formatted_cert_expiration_date" + CERT_ECHO="OK - The server certificate expires on $formated_cert_expiration_date" CERT_STATE=$STATE_OK fi } @@ -67,74 +88,117 @@ test_cert_expiration() { test_ca_expiration() { # Already expired - CA file if [ $current_date -ge $1 ]; then - CA_ECHO="CRITICAL - The server CA has expired on $formatted_ca_expiration_date" + CA_ECHO="CRITICAL - The server CA has expired on $formated_ca_expiration_date" CA_STATE=$STATE_CRITICAL # Expiration in 15 days or less - CA file elif [ $((current_date+_15_days)) -ge $1 ]; then - CA_ECHO="CRITICAL - The server CA expires in 15 days or less : $formatted_ca_expiration_date" + CA_ECHO="CRITICAL - The server CA expires in 15 days or less : $formated_ca_expiration_date" CA_STATE=$STATE_CRITICAL # Expiration in 30 days or less - CA file elif [ $((current_date+_30_days)) -ge $1 ]; then - CA_ECHO="WARNING - The server CA expires in 30 days or less : $formatted_ca_expiration_date" + CA_ECHO="WARNING - The server CA expires in 30 days or less : $formated_ca_expiration_date" CA_STATE=$STATE_WARNING # Expiration in more than 30 days - CA file else - CA_ECHO="OK - The server CA expires on $formatted_ca_expiration_date" + CA_ECHO="OK - The server CA expires on $formated_ca_expiration_date" CA_STATE=$STATE_OK fi } -# Linux and BSD systems do not implement 'date' the same way -if [ "$SYSTEM" = "linux" ]; then +test_openvpn_restarted_since_last_ca_cert_modification() { + if [ $is_backup_not_running_openvpn -eq "0" ]; then + RESTART_ECHO="OK - OpenVPN is not running because server is backup" + RESTART_STATE=$STATE_OK + else + if [ $seconds_last_cert_modification_date -ge $1 ] || [ $seconds_last_ca_modification_date -ge $1 ]; then + RESTART_ECHO="CRITICAL - OpenVPN hasn't been restarted since the last renewal of CA or CERT certificate" + RESTART_STATE=$STATE_CRITICAL + else + RESTART_ECHO="OK - OpenVPN has been restarted since the last renewal of CA and CERT certificate" + RESTART_STATE=$STATE_OK + fi + fi +} - # Cert expiration date human formated then in seconds - formatted_cert_expiration_date=$(TZ="Europe/Paris" $date_cmd -d "$cert_expiration_date" +"%F %T %Z") - seconds_cert_expiration_date=$(TZ="Europe/Paris" $date_cmd -d "$cert_expiration_date" +"%s") +main() { + # Linux and BSD systems do not implement 'date' the same way + if [ "$SYSTEM" = "linux" ]; then + + # Cert expiration date human formated then in seconds + formated_cert_expiration_date=$(TZ="Europe/Paris" $date_cmd -d "$cert_expiration_date" +"%F %T %Z") + seconds_cert_expiration_date=$(TZ="Europe/Paris" $date_cmd -d "$cert_expiration_date" +"%s") + + # CA expiration date human formated then in seconds + formated_ca_expiration_date=$(TZ="Europe/Paris" $date_cmd -d "$ca_expiration_date" +"%F %T %Z") + seconds_ca_expiration_date=$(TZ="Europe/Paris" $date_cmd -d "$ca_expiration_date" +"%s") - # CA expiration date human formated then in seconds - formatted_ca_expiration_date=$(TZ="Europe/Paris" $date_cmd -d "$ca_expiration_date" +"%F %T %Z") - seconds_ca_expiration_date=$(TZ="Europe/Paris" $date_cmd -d "$ca_expiration_date" +"%s") + # Last OpenVPN restart in seconds + seconds_last_openvpn_restart_date=$(TZ="Europe/Paris" $date_cmd -d "$last_openvpn_restart_date" +%s) + + test_cert_expiration $seconds_cert_expiration_date + test_ca_expiration $seconds_ca_expiration_date + test_openvpn_restarted_since_last_ca_cert_modification $seconds_last_openvpn_restart_date + + elif [ "$SYSTEM" = "openbsd" ]; then - test_cert_expiration $seconds_cert_expiration_date - test_ca_expiration $seconds_ca_expiration_date + # Cert expiration date for POSIX date, human formated then in seconds + posix_cert_expiration_date=$(echo "$cert_expiration_date" | awk '{ printf $4" "(index("JanFebMarAprMayJunJulAugSepOctNovDec",$1)+2)/3" "$2" ",split($3,time,":"); print time[1],time[2],time[3]}' | awk '{printf "%04d%02d%02d%02d%02d.%02d\n", $1, $2, $3, $4, $5, $6}') + cert_zone=$(echo "$cert_expiration_date" | awk '{print $5}') + formated_cert_expiration_date=$(TZ=$cert_zone $date_cmd -j -z "Europe/Paris" "$posix_cert_expiration_date" +"%F %T %Z") + seconds_cert_expiration_date=$(TZ=$cert_zone $date_cmd -j -z "Europe/Paris" "$posix_cert_expiration_date" +"%s") + + # CA expiration date for POSIX date, human formated then in seconds + posix_ca_expiration_date=$(echo "$ca_expiration_date" | awk '{ printf $4" "(index("JanFebMarAprMayJunJulAugSepOctNovDec",$1)+2)/3" "$2" ",split($3,time,":"); print time[1],time[2],time[3]}' | awk '{printf "%04d%02d%02d%02d%02d.%02d\n", $1, $2, $3, $4, $5, $6}') + ca_zone=$(echo "$ca_expiration_date" | awk '{print $5}') + formated_ca_expiration_date=$(TZ=$ca_zone $date_cmd -j -z "Europe/Paris" "$posix_ca_expiration_date" +"%F %T %Z") + seconds_ca_expiration_date=$(TZ=$ca_zone $date_cmd -j -z "Europe/Paris" "$posix_ca_expiration_date" +"%s") -elif [ "$SYSTEM" = "openbsd" ]; then + test_cert_expiration $seconds_cert_expiration_date + test_ca_expiration $seconds_ca_expiration_date - # Cert expiration date for POSIX date, human formated then in seconds - posix_cert_expiration_date=$(echo "$cert_expiration_date" | awk '{ printf $4" "(index("JanFebMarAprMayJunJulAugSepOctNovDec",$1)+2)/3" "$2" ",split($3,time,":"); print time[1],time[2],time[3]}' | awk '{printf "%04d%02d%02d%02d%02d.%02d\n", $1, $2, $3, $4, $5, $6}') - cert_zone=$(echo "$cert_expiration_date" | awk '{print $5}') - formatted_cert_expiration_date=$(TZ=$cert_zone $date_cmd -j -z "Europe/Paris" "$posix_cert_expiration_date" +"%F %T %Z") - seconds_cert_expiration_date=$(TZ=$cert_zone $date_cmd -j -z "Europe/Paris" "$posix_cert_expiration_date" +"%s") + if [ $is_backup_not_running_openvpn -eq "0" ]; then + test_openvpn_restarted_since_last_ca_cert_modification 0 + else + # Last OpenVPN restart in POSIX format, then in seconds + posix_last_openvpn_restart_date=$(echo "$last_openvpn_restart_date" | awk '{ printf $4" "(index("JanFebMarAprMayJunJulAugSepOctNovDec",$1)+2)/3" "$2" ",split($3,time,":"); print time[1],time[2],time[3]}' | awk '{printf "%04d%02d%02d%02d%02d.%02d\n", $1, $2, $3, $4, $5, $6}') + seconds_last_openvpn_restart_date=$($date_cmd -j "$posix_last_openvpn_restart_date" +%s) - # CA expiration date for POSIX date, human formated then in seconds - posix_ca_expiration_date=$(echo "$ca_expiration_date" | awk '{ printf $4" "(index("JanFebMarAprMayJunJulAugSepOctNovDec",$1)+2)/3" "$2" ",split($3,time,":"); print time[1],time[2],time[3]}' | awk '{printf "%04d%02d%02d%02d%02d.%02d\n", $1, $2, $3, $4, $5, $6}') - ca_zone=$(echo "$ca_expiration_date" | awk '{print $5}') - formatted_ca_expiration_date=$(TZ=$ca_zone $date_cmd -j -z "Europe/Paris" "$posix_ca_expiration_date" +"%F %T %Z") - seconds_ca_expiration_date=$(TZ=$ca_zone $date_cmd -j -z "Europe/Paris" "$posix_ca_expiration_date" +"%s") + test_openvpn_restarted_since_last_ca_cert_modification $seconds_last_openvpn_restart_date + fi - test_cert_expiration $seconds_cert_expiration_date - test_ca_expiration $seconds_ca_expiration_date + # If neither Linux nor BSD + else + + echo "CRITICAL - OS not supported" + STATE=$STATE_CRITICAL + exit $STATE + + fi + + if [ $RESTART_STATE -gt $STATE_OK ]; then + echo $RESTART_ECHO + echo $CERT_ECHO + echo $CA_ECHO + exit $RESTART_STATE + else + # Display the first one that expires first + if [ $CA_STATE -gt $CERT_STATE ]; then + echo $CA_ECHO + echo $CERT_ECHO + echo $RESTART_ECHO + exit $CA_STATE + elif [ $CERT_STATE -gt $CA_STATE ]; then + echo $CERT_ECHO + echo $CA_ECHO + echo $RESTART_ECHO + exit $CERT_STATE + else + echo $CERT_ECHO + echo $CA_ECHO + echo $RESTART_ECHO + exit $CERT_STATE + fi + fi +} -# If neither Linux nor BSD -else - - echo "CRITICAL - OS not supported" - STATE=$STATE_CRITICAL - exit $STATE - -fi - -# Display the first one that expires first -if [ $CA_STATE -gt $CERT_STATE ]; then - echo $CA_ECHO - echo $CERT_ECHO - exit $CA_STATE -elif [ $CERT_STATE -gt $CA_STATE ]; then - echo $CERT_ECHO - echo $CA_ECHO - exit $CERT_STATE -else - echo $CERT_ECHO - echo $CA_ECHO - exit $CERT_STATE -fi +main From 1fdc0f2566fd9b4b7e315e31e4f16fa224c1ae97 Mon Sep 17 00:00:00 2001 From: "William Hirigoyen (Evolix)" Date: Tue, 15 Feb 2022 17:46:14 +0100 Subject: [PATCH 11/23] Fix missing evolinux_server_custom file copy in Nginx role. --- nginx/tasks/main.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/nginx/tasks/main.yml b/nginx/tasks/main.yml index 6bb09f03..b3f1c313 100644 --- a/nginx/tasks/main.yml +++ b/nginx/tasks/main.yml @@ -66,6 +66,20 @@ - name: Include IP address whitelist task include: ip_whitelist.yml +- name: Copy evolinux_server_custom + copy: + src: nginx/snippets/evolinux_server_custom + dest: /etc/nginx/snippets/evolinux_server_custom + owner: www-data + group: www-data + directory_mode: "0640" + mode: "0640" + force: no + notify: reload nginx + tags: + - nginx + - ips + - name: Copy private_htpasswd copy: src: nginx/snippets/private_htpasswd From 03c97f2d0faea667797b18a350914e9e5fb3da66 Mon Sep 17 00:00:00 2001 From: Jeremy Dubois Date: Tue, 15 Feb 2022 18:06:13 +0100 Subject: [PATCH 12/23] openvpn: fix last_openvpn_restart_date variable --- openvpn/files/check_openvpn_certificates.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openvpn/files/check_openvpn_certificates.sh b/openvpn/files/check_openvpn_certificates.sh index e010ce07..26808868 100644 --- a/openvpn/files/check_openvpn_certificates.sh +++ b/openvpn/files/check_openvpn_certificates.sh @@ -63,7 +63,7 @@ else fi # Get the date of last OpenVPN restart -last_openvpn_restart_date=$(ps awwwx -O lstart | grep openvpn | grep -vE "grep|check_openvpn_certificates.sh" | awk '{print $3,$4,$5,$6}') +last_openvpn_restart_date=$(ps awwwx -O lstart | grep openvpn | grep -- --daemon | grep -- --config | head -1 | awk '{print $3,$4,$5,$6}') test_cert_expiration() { # Already expired - Cert file From 799466788fcc57346d94afe40b38b08b63b596ae Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Thu, 17 Feb 2022 14:50:21 +0100 Subject: [PATCH 13/23] lxc-php: preliminary support for PHP 8.1 container --- CHANGELOG.md | 1 + lxc-php/defaults/main.yml | 1 + lxc-php/handlers/main.yml | 5 +++ lxc-php/tasks/main.yml | 3 ++ lxc-php/tasks/php81.yml | 63 +++++++++++++++++++++++++++++ nagios-nrpe/templates/evolix.cfg.j2 | 1 + packweb-apache/meta/main.yml | 1 + 7 files changed, 75 insertions(+) create mode 100644 lxc-php/tasks/php81.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 59d04a55..afaccbbc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ The **patch** part changes is incremented if multiple releases happen the same m * evolinux-base: option to bypass raid-related tasks * kvm-host: add missing default value * openvpn: now check that openvpn has been restarted since last certificates renewal +* lxc-php: preliminary support for PHP 8.1 container ### Changed diff --git a/lxc-php/defaults/main.yml b/lxc-php/defaults/main.yml index 9eb226f1..415d1c9e 100644 --- a/lxc-php/defaults/main.yml +++ b/lxc-php/defaults/main.yml @@ -20,3 +20,4 @@ lxc_php_container_releases: php73: "buster" php74: "bullseye" php80: "bullseye" + php81: "bullseye" diff --git a/lxc-php/handlers/main.yml b/lxc-php/handlers/main.yml index 27ba8157..a757a2d0 100644 --- a/lxc-php/handlers/main.yml +++ b/lxc-php/handlers/main.yml @@ -1,4 +1,9 @@ --- +- name: Reload php81-fpm + lxc_container: + name: "{{ lxc_php_version }}" + container_command: "systemctl reload php8.1-fpm" + - name: Reload php80-fpm lxc_container: name: "{{ lxc_php_version }}" diff --git a/lxc-php/tasks/main.yml b/lxc-php/tasks/main.yml index 0de38336..c6d85fbe 100644 --- a/lxc-php/tasks/main.yml +++ b/lxc-php/tasks/main.yml @@ -24,4 +24,7 @@ - include: "php80.yml" when: lxc_php_version == "php80" +- include: "php81.yml" + when: lxc_php_version == "php81" + - include: "misc.yml" diff --git a/lxc-php/tasks/php81.yml b/lxc-php/tasks/php81.yml new file mode 100644 index 00000000..f4498dd2 --- /dev/null +++ b/lxc-php/tasks/php81.yml @@ -0,0 +1,63 @@ +--- + +- name: "{{ lxc_php_version }} - Install dependency packages" + lxc_container: + name: "{{ lxc_php_version }}" + container_command: "DEBIAN_FRONTEND=noninteractive apt install -y wget apt-transport-https gnupg" + +- name: "{{ lxc_php_version }} - fix bullseye repository" + replace: + dest: "/var/lib/lxc/{{ lxc_php_version }}/rootfs/etc/apt/sources.list" + regexp: 'bullseye/updates' + replace: 'bullseye-security' + +- name: "{{ lxc_php_version }} - Add sury repo" + lineinfile: + dest: "/var/lib/lxc/{{ lxc_php_version }}/rootfs/etc/apt/sources.list.d/sury.list" + line: "{{ item }}" + state: present + create: yes + mode: "0644" + loop: + - "deb https://packages.sury.org/php/ bullseye main" + - "deb http://pub.evolix.net/ bullseye-php81/" + +- name: copy pub.evolix.net GPG key + copy: + src: reg.asc + dest: /var/lib/lxc/{{ lxc_php_version }}/rootfs/etc/apt/trusted.gpg.d/reg.asc + mode: "0644" + owner: root + group: root + +- name: copy packages.sury.org GPG Key + copy: + src: sury.gpg + dest: /var/lib/lxc/{{ lxc_php_version }}/rootfs/etc/apt/trusted.gpg.d/sury.gpg + mode: "0644" + owner: root + group: root + +- name: "{{ lxc_php_version }} - Update APT cache" + lxc_container: + name: "{{ lxc_php_version }}" + container_command: "DEBIAN_FRONTEND=noninteractive apt update" + +- name: "{{ lxc_php_version }} - Install PHP packages" + lxc_container: + name: "{{ lxc_php_version }}" + container_command: "DEBIAN_FRONTEND=noninteractive apt install -y php-fpm php-cli php-gd php-intl php-imap php-ldap php-mysql php-pgsql php-sqlite3 php-curl php-zip php-mbstring php-zip composer libphp-phpmailer" + +- name: "{{ lxc_php_version }} - Copy evolinux PHP configuration" + template: + src: z-evolinux-defaults.ini.j2 + dest: "{{ line_item }}" + mode: "0644" + notify: "Reload {{ lxc_php_version }}-fpm" + loop: + - "/var/lib/lxc/{{ lxc_php_version }}/rootfs/etc/php/8.1/fpm/conf.d/z-evolinux-defaults.ini" + - "/var/lib/lxc/{{ lxc_php_version }}/rootfs/etc/php/8.1/cli/conf.d/z-evolinux-defaults.ini" + loop_control: + loop_var: line_item + +- include: "mail_opensmtpd.yml" diff --git a/nagios-nrpe/templates/evolix.cfg.j2 b/nagios-nrpe/templates/evolix.cfg.j2 index 7b63b017..80eaaaf2 100644 --- a/nagios-nrpe/templates/evolix.cfg.j2 +++ b/nagios-nrpe/templates/evolix.cfg.j2 @@ -80,6 +80,7 @@ command[check_php-fpm70]=sudo {{ nagios_plugins_directory }}/check_phpfpm_multi command[check_php-fpm73]=sudo {{ nagios_plugins_directory }}/check_phpfpm_multi /var/lib/lxc/php73/rootfs/etc/php/7.3/fpm/pool.d/ command[check_php-fpm74]=sudo {{ nagios_plugins_directory }}/check_phpfpm_multi /var/lib/lxc/php74/rootfs/etc/php/7.4/fpm/pool.d/ command[check_php-fpm80]=sudo {{ nagios_plugins_directory }}/check_phpfpm_multi /var/lib/lxc/php80/rootfs/etc/php/8.0/fpm/pool.d/ +command[check_php-fpm81]=sudo {{ nagios_plugins_directory }}/check_phpfpm_multi /var/lib/lxc/php81/rootfs/etc/php/8.1/fpm/pool.d/ command[check_ipmi_sensors]=sudo /usr/lib/nagios/plugins/check_ipmi_sensor command[check_raid_status]=/usr/lib/nagios/plugins/check_raid diff --git a/packweb-apache/meta/main.yml b/packweb-apache/meta/main.yml index ad211bbb..bbf086ce 100644 --- a/packweb-apache/meta/main.yml +++ b/packweb-apache/meta/main.yml @@ -38,5 +38,6 @@ dependencies: - { role: evolix/lxc-php, lxc_php_version: php73, lxc_php_create_mysql_link: True, when: "'php73' in packweb_multiphp_versions" } - { role: evolix/lxc-php, lxc_php_version: php74, lxc_php_create_mysql_link: True, when: "'php74' in packweb_multiphp_versions" } - { role: evolix/lxc-php, lxc_php_version: php80, lxc_php_create_mysql_link: True, when: "'php80' in packweb_multiphp_versions" } + - { role: evolix/lxc-php, lxc_php_version: php81, lxc_php_create_mysql_link: True, when: "'php81' in packweb_multiphp_versions" } - { role: evolix/webapps/evoadmin-web, evoadmin_enable_vhost: "{{ packweb_enable_evoadmin_vhost }}", evoadmin_multiphp_versions: "{{ packweb_multiphp_versions }}" } - { role: evolix/evoacme } From e79141d2d21c3fe5a9296886cec973fcb2897de5 Mon Sep 17 00:00:00 2001 From: Ludovic Poujol Date: Thu, 17 Feb 2022 16:25:20 +0100 Subject: [PATCH 14/23] lxc: Fail if /var is nosuid --- CHANGELOG.md | 1 + lxc/tasks/main.yml | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index afaccbbc..f55cf0cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ The **patch** part changes is incremented if multiple releases happen the same m ### Changed * elasticsearch: Use `/etc/elasticsearch/jvm.options.d/evolinux` instead of default `/etc/elasticsearch/jvm.options` +* lxc: Fail if /var is nosuid * openvpn: make it compatible with OpenBSD and add some improvements ### Fixed diff --git a/lxc/tasks/main.yml b/lxc/tasks/main.yml index daf2885a..70f5dc2b 100644 --- a/lxc/tasks/main.yml +++ b/lxc/tasks/main.yml @@ -43,8 +43,8 @@ - lxc_unprivilegied_containers | bool - root_subuids.rc != 0 -- name: Check if /var has not mount options nodev or noexec - shell: findmnt | grep -E "/var[^/]" | grep -e nodev -e noexec +- name: Check if /var has not mount options or nosuid or nodev or noexec + shell: findmnt | grep -E "/var[^/]" | grep -e nodev -e noexec -e nosuid register: check_var changed_when: false failed_when: "check_var.rc == 0" From 39949ea921bf3acc75bd009f37d2ba2ff31f4d46 Mon Sep 17 00:00:00 2001 From: Ludovic Poujol Date: Mon, 21 Feb 2022 11:31:00 +0100 Subject: [PATCH 15/23] generate-ldif: Add support for php-fpm in containers --- CHANGELOG.md | 1 + generate-ldif/templates/generateldif.sh.j2 | 90 ++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f55cf0cd..b84e4efe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ The **patch** part changes is incremented if multiple releases happen the same m * Explicit permissions for systemd overrides * evolinux-base: option to bypass raid-related tasks +* generate-ldif: Add support for php-fpm in containers * kvm-host: add missing default value * openvpn: now check that openvpn has been restarted since last certificates renewal * lxc-php: preliminary support for PHP 8.1 container diff --git a/generate-ldif/templates/generateldif.sh.j2 b/generate-ldif/templates/generateldif.sh.j2 index aa3ec7dd..3b2a6fd2 100755 --- a/generate-ldif/templates/generateldif.sh.j2 +++ b/generate-ldif/templates/generateldif.sh.j2 @@ -602,6 +602,96 @@ ServiceVersion: PostgreSQL ${postgresql_version} EOT fi +# LXC (multiphp) +if is_pkg_installed lxc; then + +if lxc-ls | grep -q php56 ; then + cat <> "${ldif_file}" + +dn: ServiceName=ServiceName=php-fpm56,${computer_dn} +NagiosEnabled: TRUE +ipServiceProtocol: tcp +objectClass: EvoService +ServiceName: PHP-FPM (multiphp) +ipServicePort: 443 +ServiceType: web +ServiceVersion: PHP-FPM 5.6 (multiphp) +EOT +fi + +if lxc-ls | grep -q php70 ; then + cat <> "${ldif_file}" + +dn: ServiceName=ServiceName=php-fpm70,${computer_dn} +NagiosEnabled: TRUE +ipServiceProtocol: tcp +objectClass: EvoService +ServiceName: PHP-FPM (multiphp) +ipServicePort: 443 +ServiceType: web +ServiceVersion: PHP-FPM 7.0 (multiphp) +EOT +fi + +if lxc-ls | grep -q php73 ; then + cat <> "${ldif_file}" + +dn: ServiceName=ServiceName=php-fpm73,${computer_dn} +NagiosEnabled: TRUE +ipServiceProtocol: tcp +objectClass: EvoService +ServiceName: PHP-FPM (multiphp) +ipServicePort: 443 +ServiceType: web +ServiceVersion: PHP-FPM 7.3 (multiphp) +EOT +fi + +if lxc-ls | grep -q php74 ; then + cat <> "${ldif_file}" + +dn: ServiceName=ServiceName=php-fpm74,${computer_dn} +NagiosEnabled: TRUE +ipServiceProtocol: tcp +objectClass: EvoService +ServiceName: PHP-FPM (multiphp) +ipServicePort: 443 +ServiceType: web +ServiceVersion: PHP-FPM 7.4 (multiphp) +EOT +fi + +if lxc-ls | grep -q php80 ; then + cat <> "${ldif_file}" + +dn: ServiceName=ServiceName=php-fpm80,${computer_dn} +NagiosEnabled: TRUE +ipServiceProtocol: tcp +objectClass: EvoService +ServiceName: PHP-FPM (multiphp) +ipServicePort: 443 +ServiceType: web +ServiceVersion: PHP-FPM 8.0 (multiphp) +EOT +fi + +if lxc-ls | grep -q php81 ; then + cat <> "${ldif_file}" + +dn: ServiceName=ServiceName=php-fpm81,${computer_dn} +NagiosEnabled: TRUE +ipServiceProtocol: tcp +objectClass: EvoService +ServiceName: PHP-FPM (multiphp) +ipServicePort: 443 +ServiceType: web +ServiceVersion: PHP-FPM 8.1 (multiphp) +EOT +fi + +fi +# END - LXC (multiphp) + # mdadm if is_pkg_installed mdadm; then mdadm_version=$(get_pkg_version mdadm) From 69a9cb9591563d6ab970f4644e4226abefb89562 Mon Sep 17 00:00:00 2001 From: Ludovic Poujol Date: Wed, 23 Feb 2022 10:14:43 +0100 Subject: [PATCH 16/23] elasticsearch: Use `/etc/elasticsearch/jvm.options.d/evolinux.options` instead of default `/etc/elasticsearch/jvm.options` Note : Files in that folder require the ".options" prefix Fixes a2f73bb7dfa17f9b57d5e84d8f4f6dfa8e3595f4 --- elasticsearch/tasks/configuration.yml | 4 ++-- elasticsearch/tasks/tmpdir.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/elasticsearch/tasks/configuration.yml b/elasticsearch/tasks/configuration.yml index 6d9b9542..83dd130a 100644 --- a/elasticsearch/tasks/configuration.yml +++ b/elasticsearch/tasks/configuration.yml @@ -96,7 +96,7 @@ - name: JVM Heap size (min) is set lineinfile: - dest: /etc/elasticsearch/jvm.options.d/evolinux + dest: /etc/elasticsearch/jvm.options.d/evolinux.options regexp: "^-Xms" line: "-Xms{{ elasticsearch_jvm_xms }}" create: yes @@ -108,7 +108,7 @@ - name: JVM Heap size (max) is set lineinfile: - dest: /etc/elasticsearch/jvm.options.d/evolinux + dest: /etc/elasticsearch/jvm.options.d/evolinux.options regexp: "^-Xmx" line: "-Xmx{{ elasticsearch_jvm_xmx }}" create: yes diff --git a/elasticsearch/tasks/tmpdir.yml b/elasticsearch/tasks/tmpdir.yml index 6164731f..c9ad3c19 100644 --- a/elasticsearch/tasks/tmpdir.yml +++ b/elasticsearch/tasks/tmpdir.yml @@ -26,7 +26,7 @@ - name: change JVM tmpdir (< 6.x) lineinfile: - dest: /etc/elasticsearch/jvm.options.d/evolinux + dest: /etc/elasticsearch/jvm.options.d/evolinux.options line: "-Djava.io.tmpdir={{ _elasticsearch_custom_tmpdir }}" regexp: "^-Djava.io.tmpdir=" create: yes From 6321f32e8108a8bba62a66f206565d4ece6028c5 Mon Sep 17 00:00:00 2001 From: Eric Morino Date: Thu, 24 Feb 2022 10:42:48 +0100 Subject: [PATCH 17/23] Add zzz-evolinux-custom.conf to dovecot role --- dovecot/tasks/main.yml | 9 +++++++++ dovecot/templates/zzz-evolinux-custom.conf.j2 | 1 + 2 files changed, 10 insertions(+) create mode 100644 dovecot/templates/zzz-evolinux-custom.conf.j2 diff --git a/dovecot/tasks/main.yml b/dovecot/tasks/main.yml index 1bebbafc..49afb681 100644 --- a/dovecot/tasks/main.yml +++ b/dovecot/tasks/main.yml @@ -69,6 +69,15 @@ tags: - dovecot +- name: deploy file for custom configuration + template: + src: zzz-evolinux-custom.conf.j2 + dest: /etc/dovecot/conf.d/zzz-evolinux-custom.conf + mode: "0644" + notify: reload dovecot + tags: + - dovecot + - include: munin.yml tags: - dovecot diff --git a/dovecot/templates/zzz-evolinux-custom.conf.j2 b/dovecot/templates/zzz-evolinux-custom.conf.j2 new file mode 100644 index 00000000..52a3a94d --- /dev/null +++ b/dovecot/templates/zzz-evolinux-custom.conf.j2 @@ -0,0 +1 @@ +## Put your customized configuration here, verify configuration with "doveconf -n" and /var/log/mail.log From d9e95218ce981686064d6f95268308cd4fdf7921 Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Thu, 24 Feb 2022 11:49:04 +0100 Subject: [PATCH 18/23] apt_hold_packages: broadcast message with wall, if present --- CHANGELOG.md | 1 + apt/files/check_held_packages.sh | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b84e4efe..8aa27616 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ The **patch** part changes is incremented if multiple releases happen the same m ### Added +* apt: apt_hold_packages: broadcast message with wall, if present * Explicit permissions for systemd overrides * evolinux-base: option to bypass raid-related tasks * generate-ldif: Add support for php-fpm in containers diff --git a/apt/files/check_held_packages.sh b/apt/files/check_held_packages.sh index 181b9679..0ee3f723 100644 --- a/apt/files/check_held_packages.sh +++ b/apt/files/check_held_packages.sh @@ -21,7 +21,12 @@ if [ -f ${config_file} ]; then if [ -n "${package}" ]; then if is_installed ${package} && ! is_held ${package}; then apt-mark hold ${package} - >&2 echo "Package \`${package}' has been marked \`hold'." + msg="Package \`${package}' has been marked \`hold'." + >&2 echo "${msg}" + wall_bin=$(command -v wall) + if [ -n "${wall_bin}" ]; then + "${wall_bin}" --timeout 5 "${msg}" + fi return_code=1 fi fi From 53af37e055004eb049214d808cf0f9b5ec365f64 Mon Sep 17 00:00:00 2001 From: Gregory Colpart Date: Thu, 24 Feb 2022 15:31:18 +0100 Subject: [PATCH 19/23] We use now TCP/8891, cf HowtoOpenDKIM --- opendkim/files/opendkim.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opendkim/files/opendkim.conf b/opendkim/files/opendkim.conf index 37536b93..ed80dc8b 100644 --- a/opendkim/files/opendkim.conf +++ b/opendkim/files/opendkim.conf @@ -1,5 +1,5 @@ UserID opendkim:opendkim -Socket inet:54321@127.0.0.1 +Socket inet:8891@127.0.0.1 PidFile /var/run/opendkim/opendkim.pid OversignHeaders From TrustAnchorFile /usr/share/dns/root.key From c8ef7e9b75734c24c4ef9b9cabe4739ff9c74f18 Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Tue, 1 Mar 2022 14:02:22 +0100 Subject: [PATCH 20/23] redis: check_redis_instances tolerates absence of instances --- CHANGELOG.md | 5 +++-- redis/files/check_redis_instances.sh | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8aa27616..f9323117 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,12 +13,13 @@ The **patch** part changes is incremented if multiple releases happen the same m ### Added * apt: apt_hold_packages: broadcast message with wall, if present -* Explicit permissions for systemd overrides * evolinux-base: option to bypass raid-related tasks +* Explicit permissions for systemd overrides * generate-ldif: Add support for php-fpm in containers * kvm-host: add missing default value -* openvpn: now check that openvpn has been restarted since last certificates renewal * lxc-php: preliminary support for PHP 8.1 container +* openvpn: now check that openvpn has been restarted since last certificates renewal +* redis: check_redis_instances tolerates absence of instances ### Changed diff --git a/redis/files/check_redis_instances.sh b/redis/files/check_redis_instances.sh index a7dead82..32580486 100644 --- a/redis/files/check_redis_instances.sh +++ b/redis/files/check_redis_instances.sh @@ -73,7 +73,7 @@ if systemctl is-enabled -q redis-server; then fi # additional instances -conf_files=$(ls -1 /etc/redis-*/redis.conf) +conf_files=$(ls -1 /etc/redis-*/redis.conf 2> /dev/null) for conf_file in ${conf_files}; do name=$(dirname "${conf_file}" | sed '{s|/etc/redis-||}') if systemctl is-enabled -q "redis-server@${name}.service"; then From 1dc4d0e133b5976323b8d8b1c7e031e78986ab0e Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Tue, 1 Mar 2022 14:04:05 +0100 Subject: [PATCH 21/23] redis: always install check_redis_instances --- CHANGELOG.md | 1 + redis/tasks/nrpe.yml | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9323117..65156dca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ The **patch** part changes is incremented if multiple releases happen the same m * kvm-host: add missing default value * lxc-php: preliminary support for PHP 8.1 container * openvpn: now check that openvpn has been restarted since last certificates renewal +* redis: always install check_redis_instances * redis: check_redis_instances tolerates absence of instances ### Changed diff --git a/redis/tasks/nrpe.yml b/redis/tasks/nrpe.yml index a93c21af..b317c4e6 100644 --- a/redis/tasks/nrpe.yml +++ b/redis/tasks/nrpe.yml @@ -87,7 +87,6 @@ mode: "0755" owner: root group: root - when: redis_instance_name is defined tags: - redis - nrpe From 270d03b6a6256a26f2298da1d9b7a3e0eced4507 Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Wed, 2 Mar 2022 09:40:52 +0100 Subject: [PATCH 22/23] evolinx-users: optimize sudo configuration --- CHANGELOG.md | 2 ++ evolinux-users/tasks/main.yml | 4 ---- evolinux-users/tasks/sudo.yml | 16 +++++++++++++-- ...do_stretch.yml => sudo_stretch_common.yml} | 20 ++++++++----------- evolinux-users/tasks/sudo_stretch_user.yml | 13 ++++++++++++ 5 files changed, 37 insertions(+), 18 deletions(-) rename evolinux-users/tasks/{sudo_stretch.yml => sudo_stretch_common.yml} (57%) create mode 100644 evolinux-users/tasks/sudo_stretch_user.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 65156dca..ee010c11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,8 @@ The **patch** part changes is incremented if multiple releases happen the same m ### Changed * elasticsearch: Use `/etc/elasticsearch/jvm.options.d/evolinux` instead of default `/etc/elasticsearch/jvm.options` +* evolinux-users: check permissions for /etc/sudoers.d +* evolinux-users: optimize sudo configuration * lxc: Fail if /var is nosuid * openvpn: make it compatible with OpenBSD and add some improvements diff --git a/evolinux-users/tasks/main.yml b/evolinux-users/tasks/main.yml index 8f12ba1b..1b838e01 100644 --- a/evolinux-users/tasks/main.yml +++ b/evolinux-users/tasks/main.yml @@ -20,10 +20,6 @@ - name: Configure sudo include: sudo.yml - vars: - user: "{{ item.value }}" - loop: "{{ evolinux_users | dict2items }}" - when: evolinux_users | length > 0 - name: Configure SSH include: ssh.yml diff --git a/evolinux-users/tasks/sudo.yml b/evolinux-users/tasks/sudo.yml index c27f5a29..4056e7ad 100644 --- a/evolinux-users/tasks/sudo.yml +++ b/evolinux-users/tasks/sudo.yml @@ -1,9 +1,21 @@ --- - include: sudo_jessie.yml - when: ansible_distribution_release == "jessie" + vars: + user: "{{ item.value }}" + loop: "{{ evolinux_users | dict2items }}" + when: + - evolinux_users | length > 0 + - ansible_distribution_release == "jessie" -- include: sudo_stretch.yml + +- block: + - include: sudo_stretch_common.yml + + - include: sudo_stretch_user.yml + vars: + user: "{{ item.value }}" + loop: "{{ evolinux_users | dict2items }}" when: - ansible_distribution_major_version is defined - ansible_distribution_major_version is version('9', '>=') diff --git a/evolinux-users/tasks/sudo_stretch.yml b/evolinux-users/tasks/sudo_stretch_common.yml similarity index 57% rename from evolinux-users/tasks/sudo_stretch.yml rename to evolinux-users/tasks/sudo_stretch_common.yml index dc744c56..fb8f9ac7 100644 --- a/evolinux-users/tasks/sudo_stretch.yml +++ b/evolinux-users/tasks/sudo_stretch_common.yml @@ -1,5 +1,13 @@ --- +- name: "/etc/sudoers.d presence and permissions" + file: + path: /etc/sudoers.d + owner: root + group: root + mode: "0750" + state: directory + - name: "Verify 'evolinux' sudoers file presence (Debian 9 or later)" template: src: sudoers_stretch.j2 @@ -13,15 +21,3 @@ group: name: "{{ evolinux_sudo_group }}" system: yes - -- name: "Add user to '{{ evolinux_sudo_group }}' group (Debian 9 or later)" - user: - name: '{{ user.name }}' - groups: "{{ evolinux_sudo_group }}" - append: yes - -- name: "Add user to 'adm' group (Debian 9 or later)" - user: - name: '{{ user.name }}' - groups: "adm" - append: yes diff --git a/evolinux-users/tasks/sudo_stretch_user.yml b/evolinux-users/tasks/sudo_stretch_user.yml new file mode 100644 index 00000000..97f1f77d --- /dev/null +++ b/evolinux-users/tasks/sudo_stretch_user.yml @@ -0,0 +1,13 @@ +--- + +- name: "Add user to '{{ evolinux_sudo_group }}' group (Debian 9 or later)" + user: + name: '{{ user.name }}' + groups: "{{ evolinux_sudo_group }}" + append: yes + +- name: "Add user to 'adm' group (Debian 9 or later)" + user: + name: '{{ user.name }}' + groups: "adm" + append: yes From e5dc503cfd254fca154c0068ca8e171422de7f77 Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Wed, 2 Mar 2022 09:42:12 +0100 Subject: [PATCH 23/23] Release 22.03 --- CHANGELOG.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee010c11..216de3dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,18 @@ The **patch** part changes is incremented if multiple releases happen the same m ### Added +### Changed + +### Fixed + +### Removed + +### Security + +## [22.03] 2022-03-02 + +### Added + * apt: apt_hold_packages: broadcast message with wall, if present * evolinux-base: option to bypass raid-related tasks * Explicit permissions for systemd overrides @@ -30,11 +42,7 @@ The **patch** part changes is incremented if multiple releases happen the same m * lxc: Fail if /var is nosuid * openvpn: make it compatible with OpenBSD and add some improvements -### Fixed -### Removed - -### Security ## [22.01.3] 2022-01-31