Merge pull request 'Release 22.12' (#165) from unstable into stable
gitea/ansible-roles/pipeline/head This commit looks good Details
gitea/ansible-roles/pipeline/tag This commit looks good Details

Reviewed-on: #165
This commit is contained in:
Jérémy Lecour 2022-12-14 12:02:45 +01:00
commit e1e4f39778
121 changed files with 5581 additions and 696 deletions

View File

@ -20,6 +20,60 @@ The **patch** part changes is incremented if multiple releases happen the same m
### Security ### Security
## [22.12] 2022-12-14
### Added
* all: add signed-by option for additional APT sources
* all: preliminary work to support Debian 12
* all: use proper keyrings directory for APT version
* evolinux-base: replace regular kernel by cloud kernel on virtual servers
* lxc-php: set php-fpm umask to `007`
* nagios-nrpe: `check_ceph_*`
* nagios-nrpe: `check_haproxy_stats` supports DRAIN status
* packweb-apache: enable `log_forensic` module
* rabbitmq: add link in default page
* varnish: create special tmp directory for syntax validation
### Changed
* certbot: auto-detect HAPEE version in renewal hook
* evocheck: install script according to Debian version
* evolinux-base: `utils.yml` can be excluded
* evolinux-todo: execute tasks only for Debian distribution (because this task is a dependency for others roles used on different distributions)
* evolinux-user: add sudoers privilege for check `php_fpm81`
* evomaintenance: allow missing API endpoint if APi is disabled
* java: use default JRE package when version is not specified
* keepalived: change exit code (_warning_ if running but not on expected state ; _critical_ if not running)
* listupgrade: better detection for PostgreSQL
* listupgrade: sort/uniq of packages/services lists in email template
* lxc-solr: detect the real partition options
* lxc-solr: download URL according to Solr Version
* lxc-solr: set homedir and port at install
* minifirewall: whitelist deb.freexian.com
* openvpn: shellpki upstream release 22.12.2
* openvpn: specifies that the mail for expirations is for OpenVPN
* packweb-apache: manual dependencies resolution
* redis: some values should be quoted
* redis: variable to disable transparent hugepage (default: do nothing)
* squid: whitelist `deb.freexian.com`
* varnish: better package facts usage with check mode and tags
* varnish: systemd override depends on Varnish version instead of Debian version
### Fixed
* evolinux-user: Fix sudoers privilege for check `php_fpm80`
* nagios-nrpe: Fix check opendkim for recent change in listening port
* openvpn: Fix mode of shellpki script
* proftpd: Fix format of public key files controlled by Ansible
* proftpd: Fix mode of public key directory and files (they have to be accessible by `proftpd:nobody`)
* varnish: fix missing state, that blocked the task
### Removed
* openvpn: Deleted the task fixing the CRL rights since it has been fixed in upstream
## [22.09] 2022-09-19 ## [22.09] 2022-09-19
### Added ### Added
@ -151,7 +205,7 @@ The **patch** part changes is incremented if multiple releases happen the same m
* minifirewall: tail template follows symlinks * minifirewall: tail template follows symlinks
* mysql: add "set crypt_use_gpgme=no" Mutt option, for mysqltuner * mysql: add "set crypt_use_gpgme=no" Mutt option, for mysqltuner
### Fixed ### Fixed
* Role `postfix`: Add missing `localhost.localdomain localhost` to `mydestination` variable which caused undelivered of some local mails. * Role `postfix`: Add missing `localhost.localdomain localhost` to `mydestination` variable which caused undelivered of some local mails.
@ -443,6 +497,7 @@ The **patch** part changes is incremented if multiple releases happen the same m
### Added ### Added
* bookworm-detect: transitional role to help dealing with unreleased bookworm version
* dovecot: Update munin plugin & configure it * dovecot: Update munin plugin & configure it
* dovecot: vmail uid/gid are configurable * dovecot: vmail uid/gid are configurable
* evoacme: variable to disable Debian version check (default: False) * evoacme: variable to disable Debian version check (default: False)

View File

@ -25,3 +25,5 @@ apt_check_hold_cron_hour: "*/4"
apt_check_hold_cron_weekday: "*" apt_check_hold_cron_weekday: "*"
apt_check_hold_cron_day: "*" apt_check_hold_cron_day: "*"
apt_check_hold_cron_month: "*" apt_check_hold_cron_month: "*"
apt_keyring_dir: "{{ ansible_distribution_major_version is version('12', '<') | ternary('/etc/apt/trusted.gpg.d', '/etc/apt/keyrings') }}"

View File

@ -19,7 +19,7 @@
- name: Add Evolix GPG key - name: Add Evolix GPG key
copy: copy:
src: reg.asc src: reg.asc
dest: /etc/apt/trusted.gpg.d/reg.asc dest: "{{ apt_keyring_dir }}/reg.asc"
force: yes force: yes
mode: "0644" mode: "0644"
owner: root owner: root

View File

@ -0,0 +1,5 @@
# {{ ansible_managed }}
deb http://mirror.evolix.org/debian bookworm {{ apt_basics_components | mandatory }}
deb http://mirror.evolix.org/debian/ bookworm-updates {{ apt_basics_components | mandatory }}
deb http://security.debian.org/debian-security bookworm-security {{ apt_basics_components | mandatory }}

View File

@ -1,3 +1,7 @@
# {{ ansible_managed }} # {{ ansible_managed }}
deb http://pub.evolix.net/ {{ ansible_distribution_release }}/ {% if ansible_distribution_release == "bookworm" %}
deb [signed-by={{ apt_keyring_dir }}/reg.asc] http://pub.evolix.net/ bullseye/
{% else %}
deb [signed-by={{ apt_keyring_dir }}/reg.asc] http://pub.evolix.net/ {{ ansible_distribution_release }}/
{% endif %}

View File

@ -0,0 +1,11 @@
---
- debug:
var: ansible_lsb
# Force facts until Debian 12 is released because Ansible is dumb
- set_fact:
ansible_distribution_major_version: 12
ansible_distribution: "Debian"
ansible_distribution_release: "bookworm"
when: "ansible_lsb.codename == 'bookworm'"

View File

@ -10,7 +10,17 @@ debug() {
fi fi
} }
daemon_found_and_running() { daemon_found_and_running() {
test -n "$(pidof hapee-lb)" && test -n "${hapee_bin}" readonly hapee_main_pid=$(ps -u root u | grep hapee-lb | grep -v grep | awk '{print $2}')
if [ -n "${hapee_main_pid}" ] && [ -d "/proc/${hapee_main_pid}" ] ; then
readonly hapee_bin=$(readlink "/proc/${hapee_main_pid}/exe")
readonly hapee_config_file=$(cat "/proc/${hapee_main_pid}/cmdline" | tr "\0" " " | grep --only-matching --extended-regexp -- "-f \S+" | awk '{print $2}')
readonly hapee_pid_file=$(cat "/proc/${hapee_main_pid}/cmdline" | tr "\0" " " | grep --only-matching --extended-regexp -- "-p \S+" | awk '{print $2}')
readonly hapee_service_name="$(basename -s .pid "${hapee_pid_file}").service"
kill -0 "${hapee_main_pid}" && test -n "${hapee_bin}" && test -f "${hapee_config_file}" && systemctl -q is-active "${hapee_service_name}"
else
return 1
fi
} }
found_renewed_lineage() { found_renewed_lineage() {
test -f "${RENEWED_LINEAGE}/fullchain.pem" && test -f "${RENEWED_LINEAGE}/privkey.pem" test -f "${RENEWED_LINEAGE}/fullchain.pem" && test -f "${RENEWED_LINEAGE}/privkey.pem"
@ -40,12 +50,6 @@ detect_hapee_cert_dir() {
if [ -n "${config_cert_dir}" ]; then if [ -n "${config_cert_dir}" ]; then
debug "Cert directory is configured with ${config_cert_dir}" debug "Cert directory is configured with ${config_cert_dir}"
echo "${config_cert_dir}" echo "${config_cert_dir}"
elif [ -d "/etc/haproxy/ssl" ]; then
debug "No configured cert directory found, but /etc/haproxy/ssl exists"
echo "/etc/haproxy/ssl"
elif [ -d "/etc/ssl/haproxy" ]; then
debug "No configured cert directory found, but /etc/ssl/haproxy exists"
echo "/etc/ssl/haproxy"
else else
error "Cert directory not found." error "Cert directory not found."
fi fi
@ -56,7 +60,6 @@ main() {
fi fi
if daemon_found_and_running; then if daemon_found_and_running; then
readonly hapee_config_file="/etc/hapee-2.4/hapee-lb.cfg"
readonly hapee_cert_dir=$(detect_hapee_cert_dir) readonly hapee_cert_dir=$(detect_hapee_cert_dir)
if found_renewed_lineage; then if found_renewed_lineage; then
@ -72,7 +75,7 @@ main() {
if config_check; then if config_check; then
debug "HAPEE detected... reloading" debug "HAPEE detected... reloading"
systemctl reload hapee-2.4-lb.service systemctl reload "${hapee_service_name}"
else else
error "HAPEE config is broken, you must fix it !" error "HAPEE config is broken, you must fix it !"
fi fi
@ -88,6 +91,4 @@ readonly PROGNAME=$(basename "$0")
readonly VERBOSE=${VERBOSE:-"0"} readonly VERBOSE=${VERBOSE:-"0"}
readonly QUIET=${QUIET:-"0"} readonly QUIET=${QUIET:-"0"}
readonly hapee_bin="/opt/hapee-2.4/sbin/hapee-lb"
main main

View File

@ -28,10 +28,6 @@ main() {
if [ -z "${RENEWED_LINEAGE}" ]; then if [ -z "${RENEWED_LINEAGE}" ]; then
error "Missing RENEWED_LINEAGE environment variable (usually provided by certbot)." error "Missing RENEWED_LINEAGE environment variable (usually provided by certbot)."
fi fi
if [ -z "${servers}" ]; then
debug "Empty server list, skip."
exit 0
fi
if found_renewed_lineage; then if found_renewed_lineage; then
RENEWED_DOMAINS=${RENEWED_DOMAINS:-$(domain_from_cert)} RENEWED_DOMAINS=${RENEWED_DOMAINS:-$(domain_from_cert)}

View File

@ -28,3 +28,5 @@ docker_tls_ca_key: ca/ca-key.pem
docker_tls_cert: server/cert.pem docker_tls_cert: server/cert.pem
docker_tls_key: server/key.pem docker_tls_key: server/key.pem
docker_tls_csr: server/server.csr docker_tls_csr: server/server.csr
apt_keyring_dir: "{{ ansible_distribution_major_version is version('12', '<') | ternary('/etc/apt/trusted.gpg.d', '/etc/apt/keyrings') }}"

View File

@ -19,7 +19,7 @@
- name: Add Docker's official GPG key - name: Add Docker's official GPG key
copy: copy:
src: docker-debian.asc src: docker-debian.asc
dest: /etc/apt/trusted.gpg.d/docker-debian.asc dest: "{{ apt_keyring_dir }}/docker-debian.asc"
force: yes force: yes
mode: "0644" mode: "0644"
owner: root owner: root
@ -27,10 +27,16 @@
- name: Add Docker repository - name: Add Docker repository
apt_repository: apt_repository:
repo: 'deb [arch=amd64] https://download.docker.com/linux/debian {{ ansible_distribution_release }} stable' repo: 'deb [signed-by={{ apt_keyring_dir }}/docker-debian.asc] https://download.docker.com/linux/debian {{ ansible_distribution_release }} stable'
state: present state: present
filename: docker.list filename: docker.list
- name: Drop unsigned Docker repository
apt_repository:
repo: 'deb https://download.docker.com/linux/debian {{ ansible_distribution_release }} stable'
state: absent
filename: docker.list
- name: Install Docker - name: Install Docker
apt: apt:
name: name:

View File

@ -29,3 +29,5 @@ elasticsearch_plugin_head_clone_dir: "{{ elasticsearch_plugin_head_home }}/www"
elasticsearch_plugin_head_tmp_dir: "{{ elasticsearch_plugin_head_home }}/tmp" elasticsearch_plugin_head_tmp_dir: "{{ elasticsearch_plugin_head_home }}/tmp"
elasticsearch_additional_scripts_dir: /usr/share/scripts elasticsearch_additional_scripts_dir: /usr/share/scripts
apt_keyring_dir: "{{ ansible_distribution_major_version is version('12', '<') | ternary('/etc/apt/trusted.gpg.d', '/etc/apt/keyrings') }}"

View File

@ -29,7 +29,7 @@
- name: Elastic GPG key is installed - name: Elastic GPG key is installed
copy: copy:
src: elastic.asc src: elastic.asc
dest: /etc/apt/trusted.gpg.d/elastic.asc dest: "{{ apt_keyring_dir }}/elastic.asc"
force: yes force: yes
mode: "0644" mode: "0644"
owner: root owner: root
@ -40,7 +40,7 @@
- name: Elastic sources list is available - name: Elastic sources list is available
apt_repository: apt_repository:
repo: "deb https://artifacts.elastic.co/packages/{{ elastic_stack_version | mandatory }}/apt stable main" repo: "deb [signed-by={{ apt_keyring_dir }}/elastic.asc] https://artifacts.elastic.co/packages/{{ elastic_stack_version | mandatory }}/apt stable main"
filename: elastic filename: elastic
state: present state: present
update_cache: yes update_cache: yes
@ -48,6 +48,16 @@
- elasticsearch - elasticsearch
- packages - packages
- name: Unsigned Elastic sources list is not available
apt_repository:
repo: "deb https://artifacts.elastic.co/packages/{{ elastic_stack_version | mandatory }}/apt stable main"
filename: elastic
state: absent
update_cache: yes
tags:
- elasticsearch
- packages
- name: Elasticsearch is installed - name: Elasticsearch is installed
apt: apt:
name: elasticsearch name: elasticsearch

1307
evocheck/files/evocheck.jessie.sh Executable file
View File

@ -0,0 +1,1307 @@
#!/bin/bash
# EvoCheck
# Script to verify compliance of a Linux (Debian) server
# powered by Evolix
VERSION="22.11"
readonly VERSION
# base functions
show_version() {
cat <<END
evocheck version ${VERSION} (Jessie)
Copyright 2009-2022 Evolix <info@evolix.fr>,
Romain Dessort <rdessort@evolix.fr>,
Benoit Série <bserie@evolix.fr>,
Gregory Colpart <reg@evolix.fr>,
Jérémy Lecour <jlecour@evolix.fr>,
Tristan Pilat <tpilat@evolix.fr>,
Victor Laborie <vlaborie@evolix.fr>,
Alexis Ben Miloud--Josselin <abenmiloud@evolix.fr>,
and others.
evocheck comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
See the GNU General Public License v3.0 for details.
END
}
show_help() {
cat <<END
evocheck is a script that verifies Evolix conventions on Linux (Debian) servers.
Usage: evocheck
or evocheck --cron
or evocheck --quiet
or evocheck --verbose
Options
--cron disable a few checks
-v, --verbose increase verbosity of checks
-q, --quiet nothing is printed on stdout nor stderr
-h, --help print this message and exit
--version print version and exit
END
}
detect_os() {
# OS detection
DEBIAN_RELEASE=""
LSB_RELEASE_BIN=$(command -v lsb_release)
if [ -e /etc/debian_version ]; then
DEBIAN_MAIN_VERSION=$(cut -d "." -f 1 < /etc/debian_version)
if [ "${DEBIAN_MAIN_VERSION}" -ne "8" ]; then
echo "Debian ${DEBIAN_MAIN_VERSION} is incompatible with this version of evocheck." >&2
echo "This version is built for Debian 8 only." >&2
exit
fi
DEBIAN_RELEASE="jessie"
fi
}
is_pack_web(){
test -e /usr/share/scripts/web-add.sh || test -e /usr/share/scripts/evoadmin/web-add.sh
}
is_pack_samba(){
test -e /usr/share/scripts/add.pl
}
is_installed(){
for pkg in "$@"; do
dpkg -l "$pkg" 2> /dev/null | grep -q -E '^(i|h)i' || return 1
done
}
# logging
failed() {
check_name=$1
shift
check_comments=$*
RC=1
if [ "${QUIET}" != 1 ]; then
if [ -n "${check_comments}" ] && [ "${VERBOSE}" = 1 ]; then
printf "%s FAILED! %s\n" "${check_name}" "${check_comments}" >> "${main_output_file}"
else
printf "%s FAILED!\n" "${check_name}" >> "${main_output_file}"
fi
fi
}
# check functions
check_lsbrelease(){
if [ -x "${LSB_RELEASE_BIN}" ]; then
## only the major version matters
lhs=$(${LSB_RELEASE_BIN} --release --short | cut -d "." -f 1)
rhs=$(cut -d "." -f 1 < /etc/debian_version)
test "$lhs" = "$rhs" || failed "IS_LSBRELEASE" "release is not consistent between lsb_release (${lhs}) and /etc/debian_version (${rhs})"
else
failed "IS_LSBRELEASE" "lsb_release is missing or not executable"
fi
}
# Verifying check_mailq in Nagios NRPE config file. (Option "-M postfix" need to be set if the MTA is Postfix)
check_nrpepostfix() {
if is_installed postfix; then
{ test -e /etc/nagios/nrpe.cfg \
&& grep -qr "^command.*check_mailq -M postfix" /etc/nagios/nrpe.*;
} || failed "IS_NRPEPOSTFIX" "NRPE \"check_mailq\" for postfix is missing"
fi
}
# Check if mod-security config file is present
check_customsudoers() {
grep -E -qr "umask=0077" /etc/sudoers* || failed "IS_CUSTOMSUDOERS" "missing umask=0077 in sudoers file"
}
check_vartmpfs() {
FINDMNT_BIN=$(command -v findmnt)
if [ -x "${FINDMNT_BIN}" ]; then
${FINDMNT_BIN} /var/tmp --type tmpfs --noheadings > /dev/null || failed "IS_VARTMPFS" "/var/tmp is not a tmpfs"
else
df /var/tmp | grep -q tmpfs || failed "IS_VARTMPFS" "/var/tmp is not a tmpfs"
fi
}
check_serveurbase() {
is_installed serveur-base || failed "IS_SERVEURBASE" "serveur-base package is not installed"
}
check_logrotateconf() {
test -e /etc/logrotate.d/zsyslog || failed "IS_LOGROTATECONF" "missing zsyslog in logrotate.d"
}
check_syslogconf() {
grep -q "^# Syslog for Pack Evolix serveur" /etc/*syslog.conf \
|| failed "IS_SYSLOGCONF" "syslog evolix config file missing"
}
check_debiansecurity() {
# Look for enabled "Debian-Security" sources from the "Debian" origin
apt-cache policy | grep "\bl=Debian-Security\b" | grep "\bo=Debian\b" | grep --quiet "\bc=main\b"
test $? -eq 0 || failed "IS_DEBIANSECURITY" "missing Debian-Security repository"
}
check_aptitude() {
test -e /usr/bin/aptitude && failed "IS_APTITUDE" "aptitude may not be installed on Debian >=8"
}
check_aptgetbak() {
test -e /usr/bin/apt-get.bak && failed "IS_APTGETBAK" "prohibit the installation of apt-get.bak with dpkg-divert(1)"
}
check_usrro() {
grep /usr /etc/fstab | grep -qE "\bro\b" || failed "IS_USRRO" "missing ro directive on fstab for /usr"
}
check_tmpnoexec() {
FINDMNT_BIN=$(command -v findmnt)
if [ -x "${FINDMNT_BIN}" ]; then
options=$(${FINDMNT_BIN} --noheadings --first-only --output OPTIONS /tmp)
echo "${options}" | grep -qE "\bnoexec\b" || failed "IS_TMPNOEXEC" "/tmp is not mounted with 'noexec'"
else
mount | grep "on /tmp" | grep -qE "\bnoexec\b" || failed "IS_TMPNOEXEC" "/tmp is not mounted with 'noexec' (WARNING: findmnt(8) is not found)"
fi
}
check_mountfstab() {
# Test if lsblk available, if not skip this test...
LSBLK_BIN=$(command -v lsblk)
if test -x "${LSBLK_BIN}"; then
for mountPoint in $(${LSBLK_BIN} -o MOUNTPOINT -l -n | grep '/'); do
grep -Eq "$mountPoint\W" /etc/fstab \
|| failed "IS_MOUNT_FSTAB" "partition(s) detected mounted but no presence in fstab"
done
fi
}
check_listchangesconf() {
if [ -e "/etc/apt/listchanges.conf" ]; then
lines=$(grep -cE "(which=both|confirm=1)" /etc/apt/listchanges.conf)
if [ "$lines" != 2 ]; then
failed "IS_LISTCHANGESCONF" "apt-listchanges config is incorrect"
fi
else
failed "IS_LISTCHANGESCONF" "apt-listchanges config is missing"
fi
}
check_customcrontab() {
found_lines=$(grep -c -E "^(17 \*|25 6|47 6|52 6)" /etc/crontab)
test "$found_lines" = 4 && failed "IS_CUSTOMCRONTAB" "missing custom field in crontab"
}
check_sshallowusers() {
grep -E -qir "(AllowUsers|AllowGroups)" /etc/ssh/sshd_config /etc/ssh/sshd_config.d \
|| failed "IS_SSHALLOWUSERS" "missing AllowUsers or AllowGroups directive in sshd_config"
}
check_diskperf() {
perfFile="/root/disk-perf.txt"
test -e $perfFile || failed "IS_DISKPERF" "missing ${perfFile}"
}
check_tmoutprofile() {
grep -sq "TMOUT=" /etc/profile /etc/profile.d/evolinux.sh || failed "IS_TMOUTPROFILE" "TMOUT is not set"
}
check_alert5boot() {
if [ -n "$(find /etc/rc2.d/ -name 'S*alert5')" ]; then
grep -q "^date" /etc/rc2.d/S*alert5 || failed "IS_ALERT5BOOT" "boot mail is not sent by alert5 init script"
elif [ -n "$(find /etc/init.d/ -name 'alert5')" ]; then
grep -q "^date" /etc/init.d/alert5 || failed "IS_ALERT5BOOT" "boot mail is not sent by alert5 int script"
else
failed "IS_ALERT5BOOT" "alert5 init script is missing"
fi
}
check_alert5minifw() {
if [ -n "$(find /etc/rc2.d/ -name 'S*alert5')" ]; then
grep -q "^/etc/init.d/minifirewall" /etc/rc2.d/S*alert5 \
|| failed "IS_ALERT5MINIFW" "Minifirewall is not started by alert5 init script"
elif [ -n "$(find /etc/init.d/ -name 'alert5')" ]; then
grep -q "^/etc/init.d/minifirewall" /etc/init.d/alert5 \
|| failed "IS_ALERT5MINIFW" "Minifirewall is not started by alert5 init script"
else
failed "IS_ALERT5MINIFW" "alert5 init script is missing"
fi
}
check_minifw() {
/sbin/iptables -L -n | grep -q -E "^ACCEPT\s*all\s*--\s*31\.170\.8\.4\s*0\.0\.0\.0/0\s*$" \
|| failed "IS_MINIFW" "minifirewall seems not started"
}
check_nrpeperms() {
if [ -d /etc/nagios ]; then
nagiosDir="/etc/nagios"
actual=$(stat --format "%a" $nagiosDir)
expected="750"
test "$expected" = "$actual" || failed "IS_NRPEPERMS" "${nagiosDir} must be ${expected}"
fi
}
check_minifwperms() {
if [ -f "/etc/default/minifirewall" ]; then
actual=$(stat --format "%a" "/etc/default/minifirewall")
expected="600"
test "$expected" = "$actual" || failed "IS_MINIFWPERMS" "/etc/default/minifirewall must be ${expected}"
fi
}
check_nrpedisks() {
NRPEDISKS=$(grep command.check_disk /etc/nagios/nrpe.cfg | grep "^command.check_disk[0-9]" | sed -e "s/^command.check_disk\([0-9]\+\).*/\1/" | sort -n | tail -1)
DFDISKS=$(df -Pl | grep -c -E -v "(^Filesystem|/lib/init/rw|/dev/shm|udev|rpc_pipefs)")
test "$NRPEDISKS" = "$DFDISKS" || failed "IS_NRPEDISKS" "there must be $DFDISKS check_disk in nrpe.cfg"
}
check_nrpepid() {
{ test -e /etc/nagios/nrpe.cfg \
&& grep -q "^pid_file=/var/run/nagios/nrpe.pid" /etc/nagios/nrpe.cfg;
} || failed "IS_NRPEPID" "missing or wrong pid_file directive in nrpe.cfg"
}
check_grsecprocs() {
if uname -a | grep -q grsec; then
{ grep -q "^command.check_total_procs..sudo" /etc/nagios/nrpe.cfg \
&& grep -A1 "^\[processes\]" /etc/munin/plugin-conf.d/munin-node | grep -q "^user root";
} || failed "IS_GRSECPROCS" "missing munin's plugin processes directive for grsec"
fi
}
check_apachemunin() {
if test -e /etc/apache2/apache2.conf; then
pattern="/server-status-[[:alnum:]]{4,}"
{ grep -r -q -s -E "^env.url.*${pattern}" /etc/munin/plugin-conf.d \
&& { grep -q -s -E "${pattern}" /etc/apache2/apache2.conf \
|| grep -q -s -E "${pattern}" /etc/apache2/mods-enabled/status.conf;
};
} || failed "IS_APACHEMUNIN" "server status is not properly configured"
fi
}
# Verification mytop + Munin si MySQL
check_mysqlutils() {
MYSQL_ADMIN=${MYSQL_ADMIN:-mysqladmin}
if is_installed mysql-server; then
# You can configure MYSQL_ADMIN in evocheck.cf
if ! grep -qs "^user *= *${MYSQL_ADMIN}" /root/.my.cnf; then
failed "IS_MYSQLUTILS" "${MYSQL_ADMIN} missing in /root/.my.cnf"
fi
if ! test -x /usr/bin/mytop; then
if ! test -x /usr/local/bin/mytop; then
failed "IS_MYSQLUTILS" "mytop binary missing"
fi
fi
if ! grep -qs '^user *=' /root/.mytop; then
failed "IS_MYSQLUTILS" "credentials missing in /root/.mytop"
fi
fi
}
# Verification de la configuration du raid soft (mdadm)
check_raidsoft() {
if test -e /proc/mdstat && grep -q md /proc/mdstat; then
{ grep -q "^AUTOCHECK=true" /etc/default/mdadm \
&& grep -q "^START_DAEMON=true" /etc/default/mdadm \
&& grep -qv "^MAILADDR ___MAIL___" /etc/mdadm/mdadm.conf;
} || failed "IS_RAIDSOFT" "missing or wrong config for mdadm"
fi
}
# Verification du LogFormat de AWStats
check_awstatslogformat() {
if is_installed apache2 awstats; then
awstatsFile="/etc/awstats/awstats.conf.local"
grep -qE '^LogFormat=1' $awstatsFile \
|| failed "IS_AWSTATSLOGFORMAT" "missing or wrong LogFormat directive in $awstatsFile"
fi
}
# Verification de la présence de la config logrotate pour Munin
check_muninlogrotate() {
{ test -e /etc/logrotate.d/munin-node \
&& test -e /etc/logrotate.d/munin;
} || failed "IS_MUNINLOGROTATE" "missing lorotate file for munin"
}
# Verification de l'activation de Squid dans le cas d'un pack mail
check_squid() {
squidconffile="/etc/squid*/squid.conf"
if is_pack_web && (is_installed squid || is_installed squid3); then
host=$(hostname -i)
# shellcheck disable=SC2086
http_port=$(grep -E "^http_port\s+[0-9]+" $squidconffile | awk '{ print $2 }')
{ grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -m owner --uid-owner proxy -j ACCEPT" "/etc/default/minifirewall" \
&& grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -d $host -j ACCEPT" "/etc/default/minifirewall" \
&& grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -d 127.0.0.(1|0/8) -j ACCEPT" "/etc/default/minifirewall" \
&& grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-port.* $http_port" "/etc/default/minifirewall";
} || grep -qE "^PROXY='?on'?" "/etc/default/minifirewall" \
|| failed "IS_SQUID" "missing squid rules in minifirewall"
fi
}
check_evomaintenance_fw() {
if [ -f "/etc/default/minifirewall" ]; then
hook_db=$(grep -E '^\s*HOOK_DB' /etc/evomaintenance.cf | tr -d ' ' | cut -d= -f2)
rulesNumber=$(grep -c "/sbin/iptables -A INPUT -p tcp --sport 5432 --dport 1024:65535 -s .* -m state --state ESTABLISHED,RELATED -j ACCEPT" "/etc/default/minifirewall")
if [ "$hook_db" = "1" ] && [ "$rulesNumber" -lt 2 ]; then
failed "IS_EVOMAINTENANCE_FW" "HOOK_DB is enabled but missing evomaintenance rules in minifirewall"
fi
fi
}
# Verification de la conf et de l'activation de mod-deflate
check_moddeflate() {
f=/etc/apache2/mods-enabled/deflate.conf
if is_installed apache2.2; then
{ test -e $f && grep -q "AddOutputFilterByType DEFLATE text/html text/plain text/xml" $f \
&& grep -q "AddOutputFilterByType DEFLATE text/css" $f \
&& grep -q "AddOutputFilterByType DEFLATE application/x-javascript application/javascript" $f;
} || failed "IS_MODDEFLATE" "missing AddOutputFilterByType directive for apache mod deflate"
fi
}
# Verification de la conf log2mail
check_log2mailrunning() {
if is_pack_web && is_installed log2mail; then
pgrep log2mail >/dev/null || failed "IS_LOG2MAILRUNNING" "log2mail is not running"
fi
}
check_log2mailapache() {
conf=/etc/log2mail/config/default
if is_pack_web && is_installed log2mail; then
grep -s -q "^file = /var/log/apache2/error.log" $conf \
|| failed "IS_LOG2MAILAPACHE" "missing log2mail directive for apache"
fi
}
check_log2mailmysql() {
if is_pack_web && is_installed log2mail; then
grep -s -q "^file = /var/log/syslog" /etc/log2mail/config/{default,mysql,mysql.conf} \
|| failed "IS_LOG2MAILMYSQL" "missing log2mail directive for mysql"
fi
}
check_log2mailsquid() {
if is_pack_web && is_installed log2mail; then
grep -s -q "^file = /var/log/squid.*/access.log" /etc/log2mail/config/* \
|| failed "IS_LOG2MAILSQUID" "missing log2mail directive for squid"
fi
}
# Verification si bind est chroote
check_bindchroot() {
if is_installed bind9; then
if netstat -utpln | grep "/named" | grep :53 | grep -qvE "(127.0.0.1|::1)"; then
if grep -q '^OPTIONS=".*-t' /etc/default/bind9 && grep -q '^OPTIONS=".*-u' /etc/default/bind9; then
md5_original=$(md5sum /usr/sbin/named | cut -f 1 -d ' ')
md5_chrooted=$(md5sum /var/chroot-bind/usr/sbin/named | cut -f 1 -d ' ')
if [ "$md5_original" != "$md5_chrooted" ]; then
failed "IS_BINDCHROOT" "the chrooted bind binary is different than the original binary"
fi
else
failed "IS_BINDCHROOT" "bind process is not chrooted"
fi
fi
fi
}
# /etc/network/interfaces should be present, we don't manage systemd-network yet
check_network_interfaces() {
if ! test -f /etc/network/interfaces; then
IS_AUTOIF=0
IS_INTERFACESGW=0
failed "IS_NETWORK_INTERFACES" "systemd network configuration is not supported yet"
fi
}
# Verify if all if are in auto
check_autoif() {
interfaces=$(/sbin/ifconfig -s | tail -n +2 | grep -E -v "^(lo|vnet|docker|veth|tun|tap|macvtap|vrrp)" | cut -d " " -f 1 |tr "\n" " ")
for interface in $interfaces; do
if grep -Rq "^iface $interface" /etc/network/interfaces* && ! grep -Rq "^auto $interface" /etc/network/interfaces*; then
failed "IS_AUTOIF" "Network interface \`${interface}' is statically defined but not set to auto"
test "${VERBOSE}" = 1 || break
fi
done
}
# Network conf verification
check_interfacesgw() {
number=$(grep -Ec "^[^#]*gateway [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" /etc/network/interfaces)
test "$number" -gt 1 && failed "IS_INTERFACESGW" "there is more than 1 IPv4 gateway"
number=$(grep -Ec "^[^#]*gateway [0-9a-fA-F]+:" /etc/network/interfaces)
test "$number" -gt 1 && failed "IS_INTERFACESGW" "there is more than 1 IPv6 gateway"
}
# Verification de la mise en place d'evobackup
check_evobackup() {
evobackup_found=$(find /etc/cron* -name '*evobackup*' | wc -l)
test "$evobackup_found" -gt 0 || failed "IS_EVOBACKUP" "missing evobackup cron"
}
# Vérification de l'exclusion des montages (NFS) dans les sauvegardes
check_evobackup_exclude_mount() {
excludes_file=$(mktemp --tmpdir="${TMPDIR:-/tmp}" "evocheck.evobackup_exclude_mount.XXXXX")
files_to_cleanup="${files_to_cleanup} ${excludes_file}"
# shellcheck disable=SC2044
for evobackup_file in $(find /etc/cron* -name '*evobackup*' | grep -v -E ".disabled$"); do
# if the file seems to be a backup script, with an Rsync invocation
if grep -q "^\s*rsync" "${evobackup_file}"; then
# If rsync is not limited by "one-file-system"
# then we verify that every mount is excluded
if ! grep -q -- "^\s*--one-file-system" "${evobackup_file}"; then
grep -- "--exclude " "${evobackup_file}" | grep -E -o "\"[^\"]+\"" | tr -d '"' > "${excludes_file}"
not_excluded=$(findmnt --type nfs,nfs4,fuse.sshfs, -o target --noheadings | grep -v -f "${excludes_file}")
for mount in ${not_excluded}; do
failed "IS_EVOBACKUP_EXCLUDE_MOUNT" "${mount} is not excluded from ${evobackup_file} backup script"
done
fi
fi
done
}
# Verification de la presence du userlogrotate
check_userlogrotate() {
if is_pack_web; then
test -x /etc/cron.weekly/userlogrotate || failed "IS_USERLOGROTATE" "missing userlogrotate cron"
fi
}
# Verification de la syntaxe de la conf d'Apache
check_apachectl() {
if is_installed apache2; then
/usr/sbin/apache2ctl configtest 2>&1 | grep -q "^Syntax OK$" \
|| failed "IS_APACHECTL" "apache errors detected, run a configtest"
fi
}
# Check if there is regular files in Apache sites-enabled.
check_apachesymlink() {
if is_installed apache2; then
apacheFind=$(find /etc/apache2/sites-enabled ! -type l -type f -print)
nbApacheFind=$(wc -m <<< "$apacheFind")
if [[ $nbApacheFind -gt 1 ]]; then
if [[ $VERBOSE == 1 ]]; then
while read -r line; do
failed "IS_APACHESYMLINK" "Not a symlink: $line"
done <<< "$apacheFind"
else
failed "IS_APACHESYMLINK"
fi
fi
fi
}
# Check if there is real IP addresses in Allow/Deny directives (no trailing space, inline comments or so).
check_apacheipinallow() {
# Note: Replace "exit 1" by "print" in Perl code to debug it.
if is_installed apache2; then
grep -IrE "^[^#] *(Allow|Deny) from" /etc/apache2/ \
| grep -iv "from all" \
| grep -iv "env=" \
| perl -ne 'exit 1 unless (/from( [\da-f:.\/]+)+$/i)' \
|| failed "IS_APACHEIPINALLOW" "bad (Allow|Deny) directives in apache"
fi
}
# Check if default Apache configuration file for munin is absent (or empty or commented).
check_muninapacheconf() {
muninconf="/etc/apache2/conf-available/munin.conf"
if is_installed apache2; then
test -e $muninconf && grep -vEq "^( |\t)*#" "$muninconf" \
&& failed "IS_MUNINAPACHECONF" "default munin configuration may be commented or disabled"
fi
}
# Check if default Apache configuration file for phpMyAdmin is absent (or empty or commented).
check_phpmyadminapacheconf() {
phpmyadminconf0="/etc/apache2/conf-available/phpmyadmin.conf"
phpmyadminconf1="/etc/apache2/conf-enabled/phpmyadmin.conf"
if is_installed apache2; then
test -e $phpmyadminconf0 && grep -vEq "^( |\t)*#" "$phpmyadminconf0" \
&& failed "IS_PHPMYADMINAPACHECONF" "default phpmyadmin configuration ($phpmyadminconf0) may be commented or disabled"
test -e $phpmyadminconf1 && grep -vEq "^( |\t)*#" "$phpmyadminconf1" \
&& failed "IS_PHPMYADMINAPACHECONF" "default phpmyadmin configuration ($phpmyadminconf1) may be commented or disabled"
fi
}
# Verification si le système doit redémarrer suite màj kernel.
check_kerneluptodate() {
if is_installed linux-image*; then
# shellcheck disable=SC2012
kernel_installed_at=$(date -d "$(ls --full-time -lcrt /boot | tail -n1 | awk '{print $6}')" +%s)
last_reboot_at=$(($(date +%s) - $(cut -f1 -d '.' /proc/uptime)))
if [ "$kernel_installed_at" -gt "$last_reboot_at" ]; then
failed "IS_KERNELUPTODATE" "machine is running an outdated kernel, reboot advised"
fi
fi
}
# Check if the server is running for more than a year.
check_uptime() {
if is_installed linux-image*; then
limit=$(date -d "now - 2 year" +%s)
last_reboot_at=$(($(date +%s) - $(cut -f1 -d '.' /proc/uptime)))
if [ "$limit" -gt "$last_reboot_at" ]; then
failed "IS_UPTIME" "machine has an uptime of more than 2 years, reboot on new kernel advised"
fi
fi
}
# Check if munin-node running and RRD files are up to date.
check_muninrunning() {
if ! pgrep munin-node >/dev/null; then
failed "IS_MUNINRUNNING" "Munin is not running"
elif [ -d "/var/lib/munin/" ] && [ -d "/var/cache/munin/" ]; then
limit=$(date +"%s" -d "now - 10 minutes")
if [ -n "$(find /var/lib/munin/ -name '*load-g.rrd')" ]; then
updated_at=$(stat -c "%Y" /var/lib/munin/*/*load-g.rrd |sort |tail -1)
[ "$limit" -gt "$updated_at" ] && failed "IS_MUNINRUNNING" "Munin load RRD has not been updated in the last 10 minutes"
else
failed "IS_MUNINRUNNING" "Munin is not installed properly (load RRD not found)"
fi
if [ -n "$(find /var/cache/munin/www/ -name 'load-day.png')" ]; then
updated_at=$(stat -c "%Y" /var/cache/munin/www/*/*/load-day.png |sort |tail -1)
grep -sq "^graph_strategy cron" /etc/munin/munin.conf && [ "$limit" -gt "$updated_at" ] && failed "IS_MUNINRUNNING" "Munin load PNG has not been updated in the last 10 minutes"
else
failed "IS_MUNINRUNNING" "Munin is not installed properly (load PNG not found)"
fi
else
failed "IS_MUNINRUNNING" "Munin is not installed properly (main directories are missing)"
fi
}
# Check if files in /home/backup/ are up-to-date
check_backupuptodate() {
backup_dir="/home/backup"
if [ -d "${backup_dir}" ]; then
if [ -n "$(ls -A ${backup_dir})" ]; then
find "${backup_dir}" -maxdepth 1 -type f | while read -r file; do
limit=$(date +"%s" -d "now - 2 day")
updated_at=$(stat -c "%Y" "$file")
if [ "$limit" -gt "$updated_at" ]; then
failed "IS_BACKUPUPTODATE" "$file has not been backed up"
test "${VERBOSE}" = 1 || break;
fi
done
else
failed "IS_BACKUPUPTODATE" "${backup_dir}/ is empty"
fi
else
failed "IS_BACKUPUPTODATE" "${backup_dir}/ is missing"
fi
}
check_etcgit() {
export GIT_DIR="/etc/.git" GIT_WORK_TREE="/etc"
git rev-parse --is-inside-work-tree > /dev/null 2>&1 \
|| failed "IS_ETCGIT" "/etc is not a git repository"
}
# Check if /etc/.git/ has read/write permissions for root only.
check_gitperms() {
GIT_DIR="/etc/.git"
if test -d $GIT_DIR; then
expected="700"
actual=$(stat -c "%a" $GIT_DIR)
[ "$expected" = "$actual" ] || failed "IS_GITPERMS" "$GIT_DIR must be $expected"
fi
}
# Check if no package has been upgraded since $limit.
check_notupgraded() {
last_upgrade=0
upgraded=false
for log in /var/log/dpkg.log*; do
if zgrep -qsm1 upgrade "$log"; then
# There is at least one upgrade
upgraded=true
break
fi
done
if $upgraded; then
last_upgrade=$(date +%s -d "$(zgrep -h upgrade /var/log/dpkg.log* | sort -n | tail -1 | cut -f1 -d ' ')")
fi
if grep -qs '^mailto="listupgrade-todo@' /etc/evolinux/listupgrade.cnf \
|| grep -qs -E '^[[:digit:]]+[[:space:]]+[[:digit:]]+[[:space:]]+[^\*]' /etc/cron.d/listupgrade; then
# Manual upgrade process
limit=$(date +%s -d "now - 180 days")
else
# Regular process
limit=$(date +%s -d "now - 90 days")
fi
install_date=0
if [ -d /var/log/installer ]; then
install_date=$(stat -c %Z /var/log/installer)
fi
# Check install_date if the system never received an upgrade
if [ "$last_upgrade" -eq 0 ]; then
[ "$install_date" -lt "$limit" ] && failed "IS_NOTUPGRADED" "The system has never been updated"
else
[ "$last_upgrade" -lt "$limit" ] && failed "IS_NOTUPGRADED" "The system hasn't been updated for too long"
fi
}
# Check if reserved blocks for root is at least 5% on every mounted partitions.
check_tune2fs_m5() {
min=5
parts=$(grep -E "ext(3|4)" /proc/mounts | cut -d ' ' -f1 | tr -s '\n' ' ')
FINDMNT_BIN=$(command -v findmnt)
for part in $parts; do
blockCount=$(dumpe2fs -h "$part" 2>/dev/null | grep -e "Block count:" | grep -Eo "[0-9]+")
# If buggy partition, skip it.
if [ -z "$blockCount" ]; then
continue
fi
reservedBlockCount=$(dumpe2fs -h "$part" 2>/dev/null | grep -e "Reserved block count:" | grep -Eo "[0-9]+")
# Use awk to have a rounded percentage
# python is slow, bash is unable and bc rounds weirdly
percentage=$(awk "BEGIN { pc=100*${reservedBlockCount}/${blockCount}; i=int(pc); print (pc-i<0.5)?i:i+1 }")
if [ "$percentage" -lt "${min}" ]; then
if [ -x "${FINDMNT_BIN}" ]; then
mount=$(${FINDMNT_BIN} --noheadings --first-only --output TARGET "${part}")
else
mount="unknown mount point"
fi
failed "IS_TUNE2FS_M5" "Partition ${part} (${mount}) has less than ${min}% reserved blocks (${percentage}%)"
fi
done
}
check_broadcomfirmware() {
LSPCI_BIN=$(command -v lspci)
if [ -x "${LSPCI_BIN}" ]; then
if ${LSPCI_BIN} | grep -q 'NetXtreme II'; then
{ is_installed firmware-bnx2 \
&& grep -q "^deb http://mirror.evolix.org/debian.* non-free" /etc/apt/sources.list;
} || failed "IS_BROADCOMFIRMWARE" "missing non-free repository"
fi
else
failed "IS_BROADCOMFIRMWARE" "lspci not found in ${PATH}"
fi
}
check_hardwareraidtool() {
LSPCI_BIN=$(command -v lspci)
if [ -x "${LSPCI_BIN}" ]; then
if ${LSPCI_BIN} | grep -q 'MegaRAID'; then
# shellcheck disable=SC2015
is_installed megacli && { is_installed megaclisas-status || is_installed megaraidsas-status; } \
|| failed "IS_HARDWARERAIDTOOL" "Mega tools not found"
fi
if ${LSPCI_BIN} | grep -q 'Hewlett-Packard Company Smart Array'; then
is_installed cciss-vol-status || failed "IS_HARDWARERAIDTOOL" "cciss-vol-status not installed"
fi
else
failed "IS_HARDWARERAIDTOOL" "lspci not found in ${PATH}"
fi
}
check_listupgrade() {
test -f /etc/cron.d/listupgrade \
|| failed "IS_LISTUPGRADE" "missing listupgrade cron"
test -x /usr/share/scripts/listupgrade.sh \
|| failed "IS_LISTUPGRADE" "missing listupgrade script or not executable"
}
check_sql_backup() {
if (is_installed "mysql-server" || is_installed "mariadb-server"); then
# You could change the default path in /etc/evocheck.cf
SQL_BACKUP_PATH=${SQL_BACKUP_PATH:-"/home/backup/mysql.bak.gz"}
for backup_path in ${SQL_BACKUP_PATH}; do
if [ ! -f "${backup_path}" ]; then
failed "IS_SQL_BACKUP" "MySQL dump is missing (${backup_path})"
test "${VERBOSE}" = 1 || break
fi
done
fi
}
check_postgres_backup() {
if is_installed "postgresql-9*" || is_installed "postgresql-1*"; then
# If you use something like barman, you should disable this check
# You could change the default path in /etc/evocheck.cf
POSTGRES_BACKUP_PATH=${POSTGRES_BACKUP_PATH:-"/home/backup/pg.dump.bak*"}
for backup_path in ${POSTGRES_BACKUP_PATH}; do
if [ ! -f "${backup_path}" ]; then
failed "IS_POSTGRES_BACKUP" "PostgreSQL dump is missing (${backup_path})"
test "${VERBOSE}" = 1 || break
fi
done
fi
}
check_mongo_backup() {
if is_installed "mongodb-org-server"; then
# You could change the default path in /etc/evocheck.cf
MONGO_BACKUP_PATH=${MONGO_BACKUP_PATH:-"/home/backup/mongodump"}
if [ -d "$MONGO_BACKUP_PATH" ]; then
for file in "${MONGO_BACKUP_PATH}"/*/*.{json,bson}*; do
# Skip indexes file.
if ! [[ "$file" =~ indexes ]]; then
limit=$(date +"%s" -d "now - 2 day")
updated_at=$(stat -c "%Y" "$file")
if [ -f "$file" ] && [ "$limit" -gt "$updated_at" ]; then
failed "IS_MONGO_BACKUP" "MongoDB hasn't been dumped for more than 2 days"
break
fi
fi
done
else
failed "IS_MONGO_BACKUP" "MongoDB dump directory is missing (${MONGO_BACKUP_PATH})"
fi
fi
}
check_ldap_backup() {
if is_installed slapd; then
# You could change the default path in /etc/evocheck.cf
LDAP_BACKUP_PATH=${LDAP_BACKUP_PATH:-"/home/backup/ldap.bak"}
test -f "$LDAP_BACKUP_PATH" || failed "IS_LDAP_BACKUP" "LDAP dump is missing (${LDAP_BACKUP_PATH})"
fi
}
check_redis_backup() {
if is_installed redis-server; then
# You could change the default path in /etc/evocheck.cf
# REDIS_BACKUP_PATH may contain space-separated paths, example:
# REDIS_BACKUP_PATH='/home/backup/redis-instance1/dump.rdb /home/backup/redis-instance2/dump.rdb'
REDIS_BACKUP_PATH=${REDIS_BACKUP_PATH:-"/home/backup/redis/dump.rdb"}
for file in ${REDIS_BACKUP_PATH}; do
test -f "${file}" || failed "IS_REDIS_BACKUP" "Redis dump is missing (${file})"
done
fi
}
check_elastic_backup() {
if is_installed elasticsearch; then
# You could change the default path in /etc/evocheck.cf
ELASTIC_BACKUP_PATH=${ELASTIC_BACKUP_PATH:-"/home/backup-elasticsearch"}
test -d "$ELASTIC_BACKUP_PATH" || failed "IS_ELASTIC_BACKUP" "Elastic snapshot is missing (${ELASTIC_BACKUP_PATH})"
fi
}
check_duplicate_fs_label() {
# Do it only if thereis blkid binary
BLKID_BIN=$(command -v blkid)
if [ -n "$BLKID_BIN" ]; then
tmpFile=$(mktemp --tmpdir="${TMPDIR:-/tmp}" "evocheck.duplicate_fs_label.XXXXX")
files_to_cleanup="${files_to_cleanup} ${tmpFile}"
parts=$($BLKID_BIN -c /dev/null | grep -ve raid_member -e EFI_SYSPART | grep -Eo ' LABEL=".*"' | cut -d'"' -f2)
for part in $parts; do
echo "$part" >> "$tmpFile"
done
tmpOutput=$(sort < "$tmpFile" | uniq -d)
# If there is no duplicate, uniq will have no output
# So, if $tmpOutput is not null, there is a duplicate
if [ -n "$tmpOutput" ]; then
# shellcheck disable=SC2086
labels=$(echo -n $tmpOutput | tr '\n' ' ')
failed "IS_DUPLICATE_FS_LABEL" "Duplicate labels: $labels"
fi
else
failed "IS_DUPLICATE_FS_LABEL" "blkid not found in ${PATH}"
fi
}
check_evolix_user() {
grep -q -E "^evolix:" /etc/passwd \
&& failed "IS_EVOLIX_USER" "evolix user should be deleted, used only for install"
}
check_evoacme_cron() {
if [ -f "/usr/local/sbin/evoacme" ]; then
# Old cron file, should be deleted
test -f /etc/cron.daily/certbot && failed "IS_EVOACME_CRON" "certbot cron is incompatible with evoacme"
# evoacme cron file should be present
test -f /etc/cron.daily/evoacme || failed "IS_EVOACME_CRON" "evoacme cron is missing"
fi
}
check_evoacme_livelinks() {
EVOACME_BIN=$(command -v evoacme)
if [ -x "$EVOACME_BIN" ]; then
# Sometimes evoacme is installed but no certificates has been generated
numberOfLinks=$(find /etc/letsencrypt/ -type l | wc -l)
if [ "$numberOfLinks" -gt 0 ]; then
for live in /etc/letsencrypt/*/live; do
actualLink=$(readlink -f "$live")
actualVersion=$(basename "$actualLink")
certDir=$(dirname "$live")
certName=$(basename "$certDir")
# shellcheck disable=SC2012
lastCertDir=$(ls -ds "${certDir}"/[0-9]* | tail -1)
lastVersion=$(basename "$lastCertDir")
if [[ "$lastVersion" != "$actualVersion" ]]; then
failed "IS_EVOACME_LIVELINKS" "Certificate \`$certName' hasn't been updated"
test "${VERBOSE}" = 1 || break
fi
done
fi
fi
}
check_apache_confenabled() {
# Starting from Jessie and Apache 2.4, /etc/apache2/conf.d/
# must be replaced by conf-available/ and config files symlinked
# to conf-enabled/
if [ -f /etc/apache2/apache2.conf ]; then
test -d /etc/apache2/conf.d/ \
&& failed "IS_APACHE_CONFENABLED" "apache's conf.d directory must not exists"
grep -q 'Include conf.d' /etc/apache2/apache2.conf \
&& failed "IS_APACHE_CONFENABLED" "apache2.conf must not Include conf.d"
fi
}
check_meltdown_spectre() {
# For Jessie this is quite complicated to verify and we need to use kernel config file
if grep -q "BOOT_IMAGE=" /proc/cmdline; then
kernelPath=$(grep -Eo 'BOOT_IMAGE=[^ ]+' /proc/cmdline | cut -d= -f2)
kernelVer=${kernelPath##*/vmlinuz-}
kernelConfig="config-${kernelVer}"
# Sometimes autodetection of kernel config file fail, so we test if the file really exists.
if [ -f "/boot/${kernelConfig}" ]; then
grep -Eq '^CONFIG_PAGE_TABLE_ISOLATION=y' "/boot/$kernelConfig" \
|| failed "IS_MELTDOWN_SPECTRE" \
"PAGE_TABLE_ISOLATION must be enabled in kernel, outdated kernel?"
grep -Eq '^CONFIG_RETPOLINE=y' "/boot/$kernelConfig" \
|| failed "IS_MELTDOWN_SPECTRE" \
"RETPOLINE must be enabled in kernel, outdated kernel?"
fi
fi
}
check_old_home_dir() {
homeDir=${homeDir:-/home}
for dir in "$homeDir"/*; do
statResult=$(stat -c "%n has owner %u resolved as %U" "$dir" \
| grep -Eve '.bak' -e '\.[0-9]{2}-[0-9]{2}-[0-9]{4}' \
| grep "UNKNOWN")
# There is at least one dir matching
if [[ -n "$statResult" ]]; then
failed "IS_OLD_HOME_DIR" "$statResult"
test "${VERBOSE}" = 1 || break
fi
done
}
check_tmp_1777() {
actual=$(stat --format "%a" /tmp)
expected="1777"
test "$expected" = "$actual" || failed "IS_TMP_1777" "/tmp must be $expected"
}
check_root_0700() {
actual=$(stat --format "%a" /root)
expected="700"
test "$expected" = "$actual" || failed "IS_ROOT_0700" "/root must be $expected"
}
check_usrsharescripts() {
actual=$(stat --format "%a" /usr/share/scripts)
expected="700"
test "$expected" = "$actual" || failed "IS_USRSHARESCRIPTS" "/usr/share/scripts must be $expected"
}
check_sshpermitrootno() {
sshd_args="-C addr=,user=,host=,laddr=,lport=0"
# shellcheck disable=SC2086
if ! (sshd -T ${sshd_args} 2> /dev/null | grep -qi 'permitrootlogin no'); then
failed "IS_SSHPERMITROOTNO" "PermitRoot should be set to no"
fi
}
check_evomaintenanceusers() {
if [ -f /etc/sudoers.d/evolinux ]; then
sudoers="/etc/sudoers.d/evolinux"
else
sudoers="/etc/sudoers"
fi
# combine users from User_Alias and sudo group
users=$({ grep "^User_Alias *ADMIN" $sudoers | cut -d= -f2 | tr -d " "; grep "^sudo" /etc/group | cut -d: -f 4; } | tr "," "\n" | sort -u)
for user in $users; do
user_home=$(getent passwd "$user" | cut -d: -f6)
if [ -n "$user_home" ] && [ -d "$user_home" ]; then
if ! grep -qs "^trap.*sudo.*evomaintenance.sh" "${user_home}"/.*profile; then
failed "IS_EVOMAINTENANCEUSERS" "${user} doesn't have an evomaintenance trap"
test "${VERBOSE}" = 1 || break
fi
fi
done
}
check_evomaintenanceconf() {
f=/etc/evomaintenance.cf
if [ -e "$f" ]; then
perms=$(stat -c "%a" $f)
test "$perms" = "600" || failed "IS_EVOMAINTENANCECONF" "Wrong permissions on \`$f' ($perms instead of 600)"
{ grep "^export PGPASSWORD" $f | grep -qv "your-passwd" \
&& grep "^PGDB" $f | grep -qv "your-db" \
&& grep "^PGTABLE" $f | grep -qv "your-table" \
&& grep "^PGHOST" $f | grep -qv "your-pg-host" \
&& grep "^FROM" $f | grep -qv "jdoe@example.com" \
&& grep "^FULLFROM" $f | grep -qv "John Doe <jdoe@example.com>" \
&& grep "^URGENCYFROM" $f | grep -qv "mama.doe@example.com" \
&& grep "^URGENCYTEL" $f | grep -qv "06.00.00.00.00" \
&& grep "^REALM" $f | grep -qv "example.com"
} || failed "IS_EVOMAINTENANCECONF" "evomaintenance is not correctly configured"
else
failed "IS_EVOMAINTENANCECONF" "Configuration file \`$f' is missing"
fi
}
check_privatekeyworldreadable() {
# a simple globbing fails if directory is empty
if [ -n "$(ls -A /etc/ssl/private/)" ]; then
for f in /etc/ssl/private/*; do
perms=$(stat -L -c "%a" "$f")
if [ "${perms: -1}" != 0 ]; then
failed "IS_PRIVKEYWOLRDREADABLE" "$f is world-readable"
test "${VERBOSE}" = 1 || break
fi
done
fi
}
check_evobackup_incs() {
if is_installed bkctld; then
bkctld_cron_file=${bkctld_cron_file:-/etc/cron.d/bkctld}
if [ -f "${bkctld_cron_file}" ]; then
root_crontab=$(grep -v "^#" "${bkctld_cron_file}")
echo "${root_crontab}" | grep -q "bkctld inc" || failed "IS_EVOBACKUP_INCS" "\`bkctld inc' is missing in ${bkctld_cron_file}"
echo "${root_crontab}" | grep -qE "(check-incs.sh|bkctld check-incs)" || failed "IS_EVOBACKUP_INCS" "\`check-incs.sh' is missing in ${bkctld_cron_file}"
else
failed "IS_EVOBACKUP_INCS" "Crontab \`${bkctld_cron_file}' is missing"
fi
fi
}
check_osprober() {
if is_installed os-prober qemu-kvm; then
failed "IS_OSPROBER" \
"Removal of os-prober package is recommended as it can cause serious issue on KVM server"
fi
}
check_jessie_backports() {
jessieBackports=$(grep -hs "jessie-backports" /etc/apt/sources.list /etc/apt/sources.list.d/*)
if test -n "$jessieBackports"; then
if ! grep -q "archive.debian.org" <<< "$jessieBackports"; then
failed "IS_JESSIE_BACKPORTS" "You must use deb http://archive.debian.org/debian/ jessie-backports main"
fi
fi
}
check_apt_valid_until() {
aptvalidFile="/etc/apt/apt.conf.d/99no-check-valid-until"
aptvalidText="Acquire::Check-Valid-Until no;"
if grep -qs "archive.debian.org" /etc/apt/sources.list /etc/apt/sources.list.d/*; then
if ! grep -qs "$aptvalidText" /etc/apt/apt.conf.d/*; then
failed "IS_APT_VALID_UNTIL" \
"As you use archive.mirror.org you need ${aptvalidFile}: ${aptvalidText}"
fi
fi
}
check_chrooted_binary_uptodate() {
# list of processes to check
process_list="sshd"
for process_name in ${process_list}; do
# what is the binary path?
original_bin=$(command -v "${process_name}")
for pid in $(pgrep ${process_name}); do
process_bin=$(realpath "/proc/${pid}/exe")
# Is the process chrooted?
real_root=$(realpath "/proc/${pid}/root")
if [ "${real_root}" != "/" ]; then
chrooted_md5=$(md5sum "${process_bin}" | cut -f 1 -d ' ')
original_md5=$(md5sum "${original_bin}" | cut -f 1 -d ' ')
# compare md5 checksums
if [ "$original_md5" != "$chrooted_md5" ]; then
failed "IS_CHROOTED_BINARY_UPTODATE" "${process_bin} (${pid}) is different than ${original_bin}."
test "${VERBOSE}" = 1 || break
fi
fi
done
done
}
check_nginx_letsencrypt_uptodate() {
if [ -d /etc/nginx ]; then
snippets=$(find /etc/nginx -type f -name "letsencrypt.conf")
if [ -n "${snippets}" ]; then
while read -r snippet; do
if ! grep -qE "^\s*alias\s+/.+/\.well-known/acme-challenge" "${snippet}"; then
failed "IS_NGINX_LETSENCRYPT_UPTODATE" "Nginx snippet ${snippet} is not compatible with Nginx on Debian 8."
fi
done <<< "${snippets}"
fi
fi
}
check_lxc_container_resolv_conf() {
if is_installed lxc; then
container_list=$(lxc-ls)
current_resolvers=$(grep nameserver /etc/resolv.conf | sed 's/nameserver//g' )
for container in $container_list; do
if [ -f "/var/lib/lxc/${container}/rootfs/etc/resolv.conf" ]; then
while read -r resolver; do
if ! grep -qE "^nameserver\s+${resolver}" "/var/lib/lxc/${container}/rootfs/etc/resolv.conf"; then
failed "IS_LXC_CONTAINER_RESOLV_CONF" "resolv.conf miss-match beween host and container : missing nameserver ${resolver} in container ${container} resolv.conf"
fi
done <<< "${current_resolvers}"
else
failed "IS_LXC_CONTAINER_RESOLV_CONF" "resolv.conf missing in container ${container}"
fi
done
fi
}
download_versions() {
local file
file=${1:-}
## The file is supposed to list programs : each on a line, then its latest version number
## Examples:
# evoacme 21.06
# evomaintenance 0.6.4
versions_url="https://upgrades.evolix.org/versions-${DEBIAN_RELEASE}"
# fetch timeout, in seconds
timeout=10
if command -v curl > /dev/null; then
curl --max-time ${timeout} --fail --silent --output "${versions_file}" "${versions_url}"
elif command -v wget > /dev/null; then
wget --timeout=${timeout} --quiet "${versions_url}" -O "${versions_file}"
elif command -v GET; then
GET -t ${timeout}s "${versions_url}" > "${versions_file}"
else
failed "IS_CHECK_VERSIONS" "failed to find curl, wget or GET"
fi
test "$?" -eq 0 || failed "IS_CHECK_VERSIONS" "failed to download ${versions_url} to ${versions_file}"
}
get_command() {
local program
program=${1:-}
case "${program}" in
## Special cases where the program name is different than the command name
evocheck) echo "${0}" ;;
evomaintenance) command -v "evomaintenance.sh" ;;
listupgrade) command -v "evolistupgrade.sh" ;;
old-kernel-autoremoval) command -v "old-kernel-autoremoval.sh" ;;
mysql-queries-killer) command -v "mysql-queries-killer.sh" ;;
minifirewall) echo "/etc/init.d/minifirewall" ;;
## General case, where the program name is the same as the command name
*) command -v "${program}" ;;
esac
}
get_version() {
local program
local command
program=${1:-}
command=${2:-}
case "${program}" in
## Special case if `command --version => 'command` is not the standard way to get the version
# my_command)
# /path/to/my_command --get-version
# ;;
add-vm)
grep '^VERSION=' "${command}" | head -1 | cut -d '=' -f 2
;;
minifirewall)
${command} version | head -1 | cut -d ' ' -f 3
;;
## Let's try the --version flag before falling back to grep for the constant
kvmstats)
if ${command} --version > /dev/null 2> /dev/null; then
${command} --version 2> /dev/null | head -1 | cut -d ' ' -f 3
else
grep '^VERSION=' "${command}" | head -1 | cut -d '=' -f 2
fi
;;
## General case to get the version
*) ${command} --version 2> /dev/null | head -1 | cut -d ' ' -f 3 ;;
esac
}
check_version() {
local program
local expected_version
program=${1:-}
expected_version=${2:-}
command=$(get_command "${program}")
if [ -n "${command}" ]; then
# shellcheck disable=SC2086
actual_version=$(get_version "${program}" "${command}")
# printf "program:%s expected:%s actual:%s\n" "${program}" "${expected_version}" "${actual_version}"
if [ -z "${actual_version}" ]; then
failed "IS_CHECK_VERSIONS" "failed to lookup actual version of ${program}"
elif dpkg --compare-versions "${actual_version}" lt "${expected_version}"; then
failed "IS_CHECK_VERSIONS" "${program} version ${actual_version} is older than expected version ${expected_version}"
elif dpkg --compare-versions "${actual_version}" gt "${expected_version}"; then
failed "IS_CHECK_VERSIONS" "${program} version ${actual_version} is newer than expected version ${expected_version}, you should update your index."
else
: # Version check OK
fi
fi
}
add_to_path() {
local new_path
new_path=${1:-}
echo "$PATH" | grep -qF "${new_path}" || export PATH="${PATH}:${new_path}"
}
check_versions() {
versions_file=$(mktemp --tmpdir="${TMPDIR:-/tmp}" "evocheck.versions.XXXXX")
files_to_cleanup="${files_to_cleanup} ${versions_file}"
download_versions "${versions_file}"
add_to_path "/usr/share/scripts"
grep -v '^ *#' < "${versions_file}" | while IFS= read -r line; do
local program
local version
program=$(echo "${line}" | cut -d ' ' -f 1)
version=$(echo "${line}" | cut -d ' ' -f 2)
if [ -n "${program}" ]; then
if [ -n "${version}" ]; then
check_version "${program}" "${version}"
else
failed "IS_CHECK_VERSIONS" "failed to lookup expected version for ${program}"
fi
fi
done
}
main() {
# Default return code : 0 = no error
RC=0
# Detect operating system name, version and release
detect_os
main_output_file=$(mktemp --tmpdir="${TMPDIR:-/tmp}" "evocheck.main.XXXXX")
files_to_cleanup="${files_to_cleanup} ${main_output_file}"
test "${IS_TMP_1777:=1}" = 1 && check_tmp_1777
test "${IS_ROOT_0700:=1}" = 1 && check_root_0700
test "${IS_USRSHARESCRIPTS:=1}" = 1 && check_usrsharescripts
test "${IS_SSHPERMITROOTNO:=1}" = 1 && check_sshpermitrootno
test "${IS_EVOMAINTENANCEUSERS:=1}" = 1 && check_evomaintenanceusers
# Verification de la configuration d'evomaintenance
test "${IS_EVOMAINTENANCECONF:=1}" = 1 && check_evomaintenanceconf
test "${IS_PRIVKEYWOLRDREADABLE:=1}" = 1 && check_privatekeyworldreadable
test "${IS_LSBRELEASE:=1}" = 1 && check_lsbrelease
test "${IS_NRPEPOSTFIX:=1}" = 1 && check_nrpepostfix
test "${IS_CUSTOMSUDOERS:=1}" = 1 && check_customsudoers
test "${IS_VARTMPFS:=1}" = 1 && check_vartmpfs
test "${IS_SERVEURBASE:=1}" = 1 && check_serveurbase
test "${IS_LOGROTATECONF:=1}" = 1 && check_logrotateconf
test "${IS_SYSLOGCONF:=1}" = 1 && check_syslogconf
test "${IS_DEBIANSECURITY:=1}" = 1 && check_debiansecurity
test "${IS_APTITUDE:=1}" = 1 && check_aptitude
test "${IS_APTGETBAK:=1}" = 1 && check_aptgetbak
test "${IS_USRRO:=1}" = 1 && check_usrro
test "${IS_TMPNOEXEC:=1}" = 1 && check_tmpnoexec
test "${IS_MOUNT_FSTAB:=1}" = 1 && check_mountfstab
test "${IS_LISTCHANGESCONF:=1}" = 1 && check_listchangesconf
test "${IS_CUSTOMCRONTAB:=1}" = 1 && check_customcrontab
test "${IS_SSHALLOWUSERS:=1}" = 1 && check_sshallowusers
test "${IS_DISKPERF:=0}" = 1 && check_diskperf
test "${IS_TMOUTPROFILE:=1}" = 1 && check_tmoutprofile
test "${IS_ALERT5BOOT:=1}" = 1 && check_alert5boot
test "${IS_ALERT5MINIFW:=1}" = 1 && check_alert5minifw
test "${IS_ALERT5MINIFW:=1}" = 1 && test "${IS_MINIFW:=1}" = 1 && check_minifw
test "${IS_NRPEPERMS:=1}" = 1 && check_nrpeperms
test "${IS_MINIFWPERMS:=1}" = 1 && check_minifwperms
test "${IS_NRPEDISKS:=0}" = 1 && check_nrpedisks
test "${IS_NRPEPID:=1}" = 1 && check_nrpepid
test "${IS_GRSECPROCS:=1}" = 1 && check_grsecprocs
test "${IS_APACHEMUNIN:=1}" = 1 && check_apachemunin
test "${IS_MYSQLUTILS:=1}" = 1 && check_mysqlutils
test "${IS_RAIDSOFT:=1}" = 1 && check_raidsoft
test "${IS_AWSTATSLOGFORMAT:=1}" = 1 && check_awstatslogformat
test "${IS_MUNINLOGROTATE:=1}" = 1 && check_muninlogrotate
test "${IS_SQUID:=1}" = 1 && check_squid
test "${IS_EVOMAINTENANCE_FW:=1}" = 1 && check_evomaintenance_fw
test "${IS_MODDEFLATE:=1}" = 1 && check_moddeflate
test "${IS_LOG2MAILRUNNING:=1}" = 1 && check_log2mailrunning
test "${IS_LOG2MAILAPACHE:=1}" = 1 && check_log2mailapache
test "${IS_LOG2MAILMYSQL:=1}" = 1 && check_log2mailmysql
test "${IS_LOG2MAILSQUID:=1}" = 1 && check_log2mailsquid
test "${IS_BINDCHROOT:=1}" = 1 && check_bindchroot
test "${IS_NETWORK_INTERFACES:=1}" = 1 && check_network_interfaces
test "${IS_AUTOIF:=1}" = 1 && check_autoif
test "${IS_INTERFACESGW:=1}" = 1 && check_interfacesgw
test "${IS_EVOBACKUP:=1}" = 1 && check_evobackup
test "${IS_EVOBACKUP_EXCLUDE_MOUNT:=1}" = 1 && check_evobackup_exclude_mount
test "${IS_USERLOGROTATE:=1}" = 1 && check_userlogrotate
test "${IS_APACHECTL:=1}" = 1 && check_apachectl
test "${IS_APACHESYMLINK:=1}" = 1 && check_apachesymlink
test "${IS_APACHEIPINALLOW:=1}" = 1 && check_apacheipinallow
test "${IS_MUNINAPACHECONF:=1}" = 1 && check_muninapacheconf
test "${IS_PHPMYADMINAPACHECONF:=1}" = 1 && check_phpmyadminapacheconf
test "${IS_KERNELUPTODATE:=1}" = 1 && check_kerneluptodate
test "${IS_UPTIME:=1}" = 1 && check_uptime
test "${IS_MUNINRUNNING:=1}" = 1 && check_muninrunning
test "${IS_BACKUPUPTODATE:=1}" = 1 && check_backupuptodate
test "${IS_ETCGIT:=1}" = 1 && check_etcgit
test "${IS_GITPERMS:=1}" = 1 && check_gitperms
test "${IS_NOTUPGRADED:=1}" = 1 && check_notupgraded
test "${IS_TUNE2FS_M5:=1}" = 1 && check_tune2fs_m5
test "${IS_BROADCOMFIRMWARE:=1}" = 1 && check_broadcomfirmware
test "${IS_HARDWARERAIDTOOL:=1}" = 1 && check_hardwareraidtool
test "${IS_LISTUPGRADE:=1}" = 1 && check_listupgrade
test "${IS_SQL_BACKUP:=1}" = 1 && check_sql_backup
test "${IS_POSTGRES_BACKUP:=1}" = 1 && check_postgres_backup
test "${IS_MONGO_BACKUP:=1}" = 1 && check_mongo_backup
test "${IS_LDAP_BACKUP:=1}" = 1 && check_ldap_backup
test "${IS_REDIS_BACKUP:=1}" = 1 && check_redis_backup
test "${IS_ELASTIC_BACKUP:=1}" = 1 && check_elastic_backup
test "${IS_DUPLICATE_FS_LABEL:=1}" = 1 && check_duplicate_fs_label
test "${IS_EVOLIX_USER:=1}" = 1 && check_evolix_user
test "${IS_EVOACME_CRON:=1}" = 1 && check_evoacme_cron
test "${IS_EVOACME_LIVELINKS:=1}" = 1 && check_evoacme_livelinks
test "${IS_APACHE_CONFENABLED:=1}" = 1 && check_apache_confenabled
test "${IS_MELTDOWN_SPECTRE:=1}" = 1 && check_meltdown_spectre
test "${IS_OLD_HOME_DIR:=0}" = 1 && check_old_home_dir
test "${IS_EVOBACKUP_INCS:=1}" = 1 && check_evobackup_incs
test "${IS_OSPROBER:=1}" = 1 && check_osprober
test "${IS_JESSIE_BACKPORTS:=1}" = 1 && check_jessie_backports
test "${IS_APT_VALID_UNTIL:=1}" = 1 && check_apt_valid_until
test "${IS_CHROOTED_BINARY_UPTODATE:=1}" = 1 && check_chrooted_binary_uptodate
test "${IS_NGINX_LETSENCRYPT_UPTODATE:=1}" = 1 && check_nginx_letsencrypt_uptodate
test "${IS_LXC_CONTAINER_RESOLV_CONF:=1}" = 1 && check_lxc_container_resolv_conf
test "${IS_CHECK_VERSIONS:=1}" = 1 && check_versions
if [ -f "${main_output_file}" ]; then
lines_found=$(wc -l < "${main_output_file}")
# shellcheck disable=SC2086
if [ ${lines_found} -gt 0 ]; then
cat "${main_output_file}" 2>&1
fi
fi
exit ${RC}
}
cleanup_temp_files() {
# shellcheck disable=SC2086
rm -f ${files_to_cleanup}
}
PROGNAME=$(basename "$0")
# shellcheck disable=SC2034
readonly PROGNAME
# shellcheck disable=SC2124
ARGS=$@
readonly ARGS
# Disable LANG*
export LANG=C
export LANGUAGE=C
files_to_cleanup=""
# shellcheck disable=SC2064
trap cleanup_temp_files 0
# Source configuration file
# shellcheck disable=SC1091
test -f /etc/evocheck.cf && . /etc/evocheck.cf
# Parse options
# based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
while :; do
case $1 in
-h|-\?|--help)
show_help
exit 0
;;
--version)
show_version
exit 0
;;
--cron)
IS_KERNELUPTODATE=0
IS_UPTIME=0
IS_MELTDOWN_SPECTRE=0
IS_CHECK_VERSIONS=0
IS_NETWORKING_SERVICE=0
;;
-v|--verbose)
VERBOSE=1
;;
-q|--quiet)
QUIET=1
VERBOSE=0
;;
--)
# End of all options.
shift
break
;;
-?*|[[:alnum:]]*)
# ignore unknown options
if [ "${QUIET}" != 1 ]; then
printf 'WARN: Unknown option (ignored): %s\n' "$1" >&2
fi
;;
*)
# Default case: If no more options then break out of the loop.
break
;;
esac
shift
done
# shellcheck disable=SC2086
main ${ARGS}

View File

@ -4,7 +4,7 @@
# Script to verify compliance of a Linux (Debian) server # Script to verify compliance of a Linux (Debian) server
# powered by Evolix # powered by Evolix
VERSION="22.09" VERSION="22.11"
readonly VERSION readonly VERSION
# base functions # base functions
@ -52,16 +52,19 @@ detect_os() {
LSB_RELEASE_BIN=$(command -v lsb_release) LSB_RELEASE_BIN=$(command -v lsb_release)
if [ -e /etc/debian_version ]; then if [ -e /etc/debian_version ]; then
DEBIAN_VERSION=$(cut -d "." -f 1 < /etc/debian_version) DEBIAN_MAIN_VERSION=$(cut -d "." -f 1 < /etc/debian_version)
if [ "${DEBIAN_MAIN_VERSION}" -lt "9" ]; then
echo "Debian ${DEBIAN_MAIN_VERSION} is incompatible with this version of evocheck." >&2
echo "This version is built for Debian 9 and later." >&2
exit
fi
if [ -x "${LSB_RELEASE_BIN}" ]; then if [ -x "${LSB_RELEASE_BIN}" ]; then
DEBIAN_RELEASE=$(${LSB_RELEASE_BIN} --codename --short) DEBIAN_RELEASE=$(${LSB_RELEASE_BIN} --codename --short)
else else
case ${DEBIAN_VERSION} in case ${DEBIAN_MAIN_VERSION} in
5) DEBIAN_RELEASE="lenny";; 9) DEBIAN_RELEASE="stretch";;
6) DEBIAN_RELEASE="squeeze";;
7) DEBIAN_RELEASE="wheezy";;
8) DEBIAN_RELEASE="jessie";;
9) DEBIAN_RELEASE="stretch";;
10) DEBIAN_RELEASE="buster";; 10) DEBIAN_RELEASE="buster";;
11) DEBIAN_RELEASE="bullseye";; 11) DEBIAN_RELEASE="bullseye";;
12) DEBIAN_RELEASE="bookworm";; 12) DEBIAN_RELEASE="bookworm";;
@ -70,21 +73,6 @@ detect_os() {
fi fi
} }
is_debian() {
test -n "${DEBIAN_RELEASE}"
}
is_debian_lenny() {
test "${DEBIAN_RELEASE}" = "lenny"
}
is_debian_squeeze() {
test "${DEBIAN_RELEASE}" = "squeeze"
}
is_debian_wheezy() {
test "${DEBIAN_RELEASE}" = "wheezy"
}
is_debian_jessie() {
test "${DEBIAN_RELEASE}" = "jessie"
}
is_debian_stretch() { is_debian_stretch() {
test "${DEBIAN_RELEASE}" = "stretch" test "${DEBIAN_RELEASE}" = "stretch"
} }
@ -97,12 +85,6 @@ is_debian_bullseye() {
is_debian_bookworm() { is_debian_bookworm() {
test "${DEBIAN_RELEASE}" = "bookworm" test "${DEBIAN_RELEASE}" = "bookworm"
} }
debian_release() {
printf "%s" "${DEBIAN_RELEASE}"
}
debian_version() {
printf "%s" "${DEBIAN_VERSION}"
}
is_pack_web(){ is_pack_web(){
test -e /usr/share/scripts/web-add.sh || test -e /usr/share/scripts/evoadmin/web-add.sh test -e /usr/share/scripts/web-add.sh || test -e /usr/share/scripts/evoadmin/web-add.sh
@ -115,16 +97,6 @@ is_installed(){
dpkg -l "$pkg" 2> /dev/null | grep -q -E '^(i|h)i' || return 1 dpkg -l "$pkg" 2> /dev/null | grep -q -E '^(i|h)i' || return 1
done done
} }
minifirewall_file() {
case ${DEBIAN_RELEASE} in
lenny) echo "/etc/firewall.rc" ;;
squeeze) echo "/etc/firewall.rc" ;;
wheezy) echo "/etc/firewall.rc" ;;
jessie) echo "/etc/default/minifirewall" ;;
stretch) echo "/etc/default/minifirewall" ;;
*) echo "/etc/default/minifirewall" ;;
esac
}
# logging # logging
@ -156,54 +128,18 @@ check_lsbrelease(){
fi fi
} }
check_dpkgwarning() { check_dpkgwarning() {
if is_debian_squeeze; then test -e /etc/apt/apt.conf.d/z-evolinux.conf \
if [ "$IS_USRRO" = 1 ] || [ "$IS_TMPNOEXEC" = 1 ]; then || failed "IS_DPKGWARNING" "/etc/apt/apt.conf.d/z-evolinux.conf is missing"
count=$(grep -c -E -i "(Pre-Invoke ..echo Are you sure to have rw on|Post-Invoke ..echo Dont forget to mount -o remount)" /etc/apt/apt.conf)
test "$count" = 2 || failed "IS_DPKGWARNING" "Pre/Post-Invoke are missing."
fi
elif is_debian_wheezy; then
if [ "$IS_USRRO" = 1 ] || [ "$IS_TMPNOEXEC" = 1 ]; then
test -e /etc/apt/apt.conf.d/80evolinux \
|| failed "IS_DPKGWARNING" "/etc/apt/apt.conf.d/80evolinux is missing"
test -e /etc/apt/apt.conf \
&& failed "IS_DPKGWARNING" "/etc/apt/apt.conf is missing"
fi
elif is_debian_stretch || is_debian_buster || is_debian_bullseye; then
test -e /etc/apt/apt.conf.d/z-evolinux.conf \
|| failed "IS_DPKGWARNING" "/etc/apt/apt.conf.d/z-evolinux.conf is missing"
fi
}
check_umasksudoers(){
if is_debian_squeeze; then
grep -q "^Defaults.*umask=0077" /etc/sudoers \
|| failed "IS_UMASKSUDOERS" "sudoers must set umask to 0077"
fi
} }
# Verifying check_mailq in Nagios NRPE config file. (Option "-M postfix" need to be set if the MTA is Postfix) # Verifying check_mailq in Nagios NRPE config file. (Option "-M postfix" need to be set if the MTA is Postfix)
check_nrpepostfix() { check_nrpepostfix() {
if is_installed postfix; then if is_installed postfix; then
if is_debian_squeeze; then { test -e /etc/nagios/nrpe.cfg \
grep -q "^command.*check_mailq -M postfix" /etc/nagios/nrpe.cfg \ && grep -qr "^command.*check_mailq -M postfix" /etc/nagios/nrpe.*;
|| failed "IS_NRPEPOSTFIX" "NRPE \"check_mailq\" for postfix is missing" } || failed "IS_NRPEPOSTFIX" "NRPE \"check_mailq\" for postfix is missing"
else
{ test -e /etc/nagios/nrpe.cfg \
&& grep -qr "^command.*check_mailq -M postfix" /etc/nagios/nrpe.*;
} || failed "IS_NRPEPOSTFIX" "NRPE \"check_mailq\" for postfix is missing"
fi
fi fi
} }
# Check if mod-security config file is present # Check if mod-security config file is present
check_modsecurity() {
if is_debian_squeeze; then
if is_installed libapache-mod-security; then
test -e /etc/apache2/conf.d/mod-security2.conf || failed "IS_MODSECURITY" "missing configuration file"
fi
elif is_debian_wheezy; then
if is_installed libapache2-modsecurity; then
test -e /etc/apache2/conf.d/mod-security2.conf || failed "IS_MODSECURITY" "missing configuration file"
fi
fi
}
check_customsudoers() { check_customsudoers() {
grep -E -qr "umask=0077" /etc/sudoers* || failed "IS_CUSTOMSUDOERS" "missing umask=0077 in sudoers file" grep -E -qr "umask=0077" /etc/sudoers* || failed "IS_CUSTOMSUDOERS" "missing umask=0077 in sudoers file"
} }
@ -226,46 +162,15 @@ check_syslogconf() {
|| failed "IS_SYSLOGCONF" "syslog evolix config file missing" || failed "IS_SYSLOGCONF" "syslog evolix config file missing"
} }
check_debiansecurity() { check_debiansecurity() {
if is_debian_bullseye; then # Look for enabled "Debian-Security" sources from the "Debian" origin
# https://www.debian.org/releases/bullseye/amd64/release-notes/ch-information.html#security-archive apt-cache policy | grep "\bl=Debian-Security\b" | grep "\bo=Debian\b" | grep --quiet "\bc=main\b"
# https://www.debian.org/security/ test $? -eq 0 || failed "IS_DEBIANSECURITY" "missing Debian-Security repository"
pattern="^deb ?(\[.*\])? ?http://security\.debian\.org/debian-security/? bullseye-security main"
elif is_debian_buster; then
pattern="^deb ?(\[.*\])? ?http://security\.debian\.org/debian-security/? buster/updates main"
elif is_debian_stretch; then
pattern="^deb ?(\[.*\])? ?http://security\.debian\.org/debian-security/? stretch/updates main"
else
pattern="^deb.*security"
fi
source_file="/etc/apt/sources.list"
grep -qE "${pattern}" "${source_file}" || failed "IS_DEBIANSECURITY" "missing debian security repository"
}
check_aptitudeonly() {
if is_debian_squeeze || is_debian_wheezy; then
test -e /usr/bin/apt-get && failed "IS_APTITUDEONLY" \
"only aptitude may be enabled on Debian <=7, apt-get should be disabled"
fi
} }
check_aptitude() { check_aptitude() {
if is_debian_jessie || is_debian_stretch || is_debian_buster || is_debian_bullseye; then test -e /usr/bin/aptitude && failed "IS_APTITUDE" "aptitude may not be installed on Debian >=8"
test -e /usr/bin/aptitude && failed "IS_APTITUDE" "aptitude may not be installed on Debian >=8"
fi
} }
check_aptgetbak() { check_aptgetbak() {
if is_debian_jessie || is_debian_stretch || is_debian_buster || is_debian_bullseye; then test -e /usr/bin/apt-get.bak && failed "IS_APTGETBAK" "prohibit the installation of apt-get.bak with dpkg-divert(1)"
test -e /usr/bin/apt-get.bak && failed "IS_APTGETBAK" "prohibit the installation of apt-get.bak with dpkg-divert(1)"
fi
}
check_apticron() {
status="OK"
test -e /etc/cron.d/apticron || status="fail"
test -e /etc/cron.daily/apticron && status="fail"
test "$status" = "fail" || test -e /usr/bin/apt-get.bak || status="fail"
if is_debian_squeeze || is_debian_wheezy; then
test "$status" = "fail" && failed "IS_APTICRON" "apticron must be in cron.d not cron.daily"
fi
} }
check_usrro() { check_usrro() {
grep /usr /etc/fstab | grep -qE "\bro\b" || failed "IS_USRRO" "missing ro directive on fstab for /usr" grep /usr /etc/fstab | grep -qE "\bro\b" || failed "IS_USRRO" "missing ro directive on fstab for /usr"
@ -290,19 +195,8 @@ check_mountfstab() {
fi fi
} }
check_listchangesconf() { check_listchangesconf() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then if is_installed apt-listchanges; then
if is_installed apt-listchanges; then failed "IS_LISTCHANGESCONF" "apt-listchanges must not be installed on Debian >=9"
failed "IS_LISTCHANGESCONF" "apt-listchanges must not be installed on Debian >=9"
fi
else
if [ -e "/etc/apt/listchanges.conf" ]; then
lines=$(grep -cE "(which=both|confirm=1)" /etc/apt/listchanges.conf)
if [ "$lines" != 2 ]; then
failed "IS_LISTCHANGESCONF" "apt-listchanges config is incorrect"
fi
else
failed "IS_LISTCHANGESCONF" "apt-listchanges config is missing"
fi
fi fi
} }
check_customcrontab() { check_customcrontab() {
@ -321,14 +215,7 @@ check_tmoutprofile() {
grep -sq "TMOUT=" /etc/profile /etc/profile.d/evolinux.sh || failed "IS_TMOUTPROFILE" "TMOUT is not set" grep -sq "TMOUT=" /etc/profile /etc/profile.d/evolinux.sh || failed "IS_TMOUTPROFILE" "TMOUT is not set"
} }
check_alert5boot() { check_alert5boot() {
if is_debian_buster || is_debian_bullseye; then if is_debian_stretch; then
grep -qs "^date" /usr/share/scripts/alert5.sh || failed "IS_ALERT5BOOT" "boot mail is not sent by alert5 init script"
if [ -f /etc/systemd/system/alert5.service ]; then
systemctl is-enabled alert5.service -q || failed "IS_ALERT5BOOT" "alert5 unit is not enabled"
else
failed "IS_ALERT5BOOT" "alert5 unit file is missing"
fi
else
if [ -n "$(find /etc/rc2.d/ -name 'S*alert5')" ]; then if [ -n "$(find /etc/rc2.d/ -name 'S*alert5')" ]; then
grep -q "^date" /etc/rc2.d/S*alert5 || failed "IS_ALERT5BOOT" "boot mail is not sent by alert5 init script" grep -q "^date" /etc/rc2.d/S*alert5 || failed "IS_ALERT5BOOT" "boot mail is not sent by alert5 init script"
elif [ -n "$(find /etc/init.d/ -name 'alert5')" ]; then elif [ -n "$(find /etc/init.d/ -name 'alert5')" ]; then
@ -336,13 +223,17 @@ check_alert5boot() {
else else
failed "IS_ALERT5BOOT" "alert5 init script is missing" failed "IS_ALERT5BOOT" "alert5 init script is missing"
fi fi
else
grep -qs "^date" /usr/share/scripts/alert5.sh || failed "IS_ALERT5BOOT" "boot mail is not sent by alert5 init script"
if [ -f /etc/systemd/system/alert5.service ]; then
systemctl is-enabled alert5.service -q || failed "IS_ALERT5BOOT" "alert5 unit is not enabled"
else
failed "IS_ALERT5BOOT" "alert5 unit file is missing"
fi
fi fi
} }
check_alert5minifw() { check_alert5minifw() {
if is_debian_buster || is_debian_bullseye; then if is_debian_stretch; then
grep -qs "^/etc/init.d/minifirewall" /usr/share/scripts/alert5.sh \
|| failed "IS_ALERT5MINIFW" "Minifirewall is not started by alert5 script or script is missing"
else
if [ -n "$(find /etc/rc2.d/ -name 'S*alert5')" ]; then if [ -n "$(find /etc/rc2.d/ -name 'S*alert5')" ]; then
grep -q "^/etc/init.d/minifirewall" /etc/rc2.d/S*alert5 \ grep -q "^/etc/init.d/minifirewall" /etc/rc2.d/S*alert5 \
|| failed "IS_ALERT5MINIFW" "Minifirewall is not started by alert5 init script" || failed "IS_ALERT5MINIFW" "Minifirewall is not started by alert5 init script"
@ -352,6 +243,9 @@ check_alert5minifw() {
else else
failed "IS_ALERT5MINIFW" "alert5 init script is missing" failed "IS_ALERT5MINIFW" "alert5 init script is missing"
fi fi
else
grep -qs "^/etc/init.d/minifirewall" /usr/share/scripts/alert5.sh \
|| failed "IS_ALERT5MINIFW" "Minifirewall is not started by alert5 script or script is missing"
fi fi
} }
check_minifw() { check_minifw() {
@ -360,8 +254,8 @@ check_minifw() {
} }
check_minifw_includes() { check_minifw_includes() {
if is_debian_bullseye; then if is_debian_bullseye; then
if grep -q -e '/sbin/iptables' -e '/sbin/ip6tables' "${MINIFW_FILE}"; then if grep -q -e '/sbin/iptables' -e '/sbin/ip6tables' "/etc/default/minifirewall"; then
failed "IS_MINIFWINCLUDES" "minifirewall has direct iptables invocations in ${MINIFW_FILE} that should go in /etc/minifirewall.d/" failed "IS_MINIFWINCLUDES" "minifirewall has direct iptables invocations in /etc/default/minifirewall that should go in /etc/minifirewall.d/"
fi fi
fi fi
} }
@ -374,10 +268,10 @@ check_nrpeperms() {
fi fi
} }
check_minifwperms() { check_minifwperms() {
if [ -f "$MINIFW_FILE" ]; then if [ -f "/etc/default/minifirewall" ]; then
actual=$(stat --format "%a" "$MINIFW_FILE") actual=$(stat --format "%a" "/etc/default/minifirewall")
expected="600" expected="600"
test "$expected" = "$actual" || failed "IS_MINIFWPERMS" "${MINIFW_FILE} must be ${expected}" test "$expected" = "$actual" || failed "IS_MINIFWPERMS" "/etc/default/minifirewall must be ${expected}"
fi fi
} }
check_nrpedisks() { check_nrpedisks() {
@ -390,7 +284,7 @@ check_nrpepid() {
{ test -e /etc/nagios/nrpe.cfg \ { test -e /etc/nagios/nrpe.cfg \
&& grep -q "^pid_file=/run/nagios/nrpe.pid" /etc/nagios/nrpe.cfg; && grep -q "^pid_file=/run/nagios/nrpe.pid" /etc/nagios/nrpe.cfg;
} || failed "IS_NRPEPID" "missing or wrong pid_file directive in nrpe.cfg" } || failed "IS_NRPEPID" "missing or wrong pid_file directive in nrpe.cfg"
elif ! is_debian_squeeze; then else
{ test -e /etc/nagios/nrpe.cfg \ { test -e /etc/nagios/nrpe.cfg \
&& grep -q "^pid_file=/var/run/nagios/nrpe.pid" /etc/nagios/nrpe.cfg; && grep -q "^pid_file=/var/run/nagios/nrpe.pid" /etc/nagios/nrpe.cfg;
} || failed "IS_NRPEPID" "missing or wrong pid_file directive in nrpe.cfg" } || failed "IS_NRPEPID" "missing or wrong pid_file directive in nrpe.cfg"
@ -405,20 +299,11 @@ check_grsecprocs() {
} }
check_apachemunin() { check_apachemunin() {
if test -e /etc/apache2/apache2.conf; then if test -e /etc/apache2/apache2.conf; then
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then { test -h /etc/apache2/mods-enabled/status.load \
{ test -h /etc/apache2/mods-enabled/status.load \ && test -h /etc/munin/plugins/apache_accesses \
&& test -h /etc/munin/plugins/apache_accesses \ && test -h /etc/munin/plugins/apache_processes \
&& test -h /etc/munin/plugins/apache_processes \ && test -h /etc/munin/plugins/apache_volume;
&& test -h /etc/munin/plugins/apache_volume; } || failed "IS_APACHEMUNIN" "missing munin plugins for Apache"
} || failed "IS_APACHEMUNIN" "missing munin plugins for Apache"
else
pattern="/server-status-[[:alnum:]]{4,}"
{ grep -r -q -s -E "^env.url.*${pattern}" /etc/munin/plugin-conf.d \
&& { grep -q -s -E "${pattern}" /etc/apache2/apache2.conf \
|| grep -q -s -E "${pattern}" /etc/apache2/mods-enabled/status.conf;
};
} || failed "IS_APACHEMUNIN" "server status is not properly configured"
fi
fi fi
} }
# Verification mytop + Munin si MySQL # Verification mytop + Munin si MySQL
@ -426,7 +311,7 @@ check_mysqlutils() {
MYSQL_ADMIN=${MYSQL_ADMIN:-mysqladmin} MYSQL_ADMIN=${MYSQL_ADMIN:-mysqladmin}
if is_installed mysql-server; then if is_installed mysql-server; then
# With Debian 11 and later, root can connect to MariaDB with the socket # With Debian 11 and later, root can connect to MariaDB with the socket
if is_debian_wheezy || is_debian_jessie || is_debian_stretch || is_debian_buster; then if is_debian_stretch || is_debian_buster; then
# You can configure MYSQL_ADMIN in evocheck.cf # You can configure MYSQL_ADMIN in evocheck.cf
if ! grep -qs "^user *= *${MYSQL_ADMIN}" /root/.my.cnf; then if ! grep -qs "^user *= *${MYSQL_ADMIN}" /root/.my.cnf; then
failed "IS_MYSQLUTILS" "${MYSQL_ADMIN} missing in /root/.my.cnf" failed "IS_MYSQLUTILS" "${MYSQL_ADMIN} missing in /root/.my.cnf"
@ -467,27 +352,23 @@ check_muninlogrotate() {
} }
# Verification de l'activation de Squid dans le cas d'un pack mail # Verification de l'activation de Squid dans le cas d'un pack mail
check_squid() { check_squid() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then squidconffile="/etc/squid/evolinux-custom.conf"
squidconffile="/etc/squid/evolinux-custom.conf"
else
squidconffile="/etc/squid*/squid.conf"
fi
if is_pack_web && (is_installed squid || is_installed squid3); then if is_pack_web && (is_installed squid || is_installed squid3); then
host=$(hostname -i) host=$(hostname -i)
# shellcheck disable=SC2086 # shellcheck disable=SC2086
http_port=$(grep -E "^http_port\s+[0-9]+" $squidconffile | awk '{ print $2 }') http_port=$(grep -E "^http_port\s+[0-9]+" $squidconffile | awk '{ print $2 }')
{ grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -m owner --uid-owner proxy -j ACCEPT" "$MINIFW_FILE" \ { grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -m owner --uid-owner proxy -j ACCEPT" "/etc/default/minifirewall" \
&& grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -d $host -j ACCEPT" "$MINIFW_FILE" \ && grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -d $host -j ACCEPT" "/etc/default/minifirewall" \
&& grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -d 127.0.0.(1|0/8) -j ACCEPT" "$MINIFW_FILE" \ && grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -d 127.0.0.(1|0/8) -j ACCEPT" "/etc/default/minifirewall" \
&& grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-port.* $http_port" "$MINIFW_FILE"; && grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-port.* $http_port" "/etc/default/minifirewall";
} || grep -qE "^PROXY='?on'?" "$MINIFW_FILE" \ } || grep -qE "^PROXY='?on'?" "/etc/default/minifirewall" \
|| failed "IS_SQUID" "missing squid rules in minifirewall" || failed "IS_SQUID" "missing squid rules in minifirewall"
fi fi
} }
check_evomaintenance_fw() { check_evomaintenance_fw() {
if [ -f "$MINIFW_FILE" ]; then if [ -f "/etc/default/minifirewall" ]; then
hook_db=$(grep -E '^\s*HOOK_DB' /etc/evomaintenance.cf | tr -d ' ' | cut -d= -f2) hook_db=$(grep -E '^\s*HOOK_DB' /etc/evomaintenance.cf | tr -d ' ' | cut -d= -f2)
rulesNumber=$(grep -c "/sbin/iptables -A INPUT -p tcp --sport 5432 --dport 1024:65535 -s .* -m state --state ESTABLISHED,RELATED -j ACCEPT" "$MINIFW_FILE") rulesNumber=$(grep -c "/sbin/iptables -A INPUT -p tcp --sport 5432 --dport 1024:65535 -s .* -m state --state ESTABLISHED,RELATED -j ACCEPT" "/etc/default/minifirewall")
if [ "$hook_db" = "1" ] && [ "$rulesNumber" -lt 2 ]; then if [ "$hook_db" = "1" ] && [ "$rulesNumber" -lt 2 ]; then
failed "IS_EVOMAINTENANCE_FW" "HOOK_DB is enabled but missing evomaintenance rules in minifirewall" failed "IS_EVOMAINTENANCE_FW" "HOOK_DB is enabled but missing evomaintenance rules in minifirewall"
fi fi
@ -510,11 +391,7 @@ check_log2mailrunning() {
fi fi
} }
check_log2mailapache() { check_log2mailapache() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then conf=/etc/log2mail/config/Apache
conf=/etc/log2mail/config/apache
else
conf=/etc/log2mail/config/default
fi
if is_pack_web && is_installed log2mail; then if is_pack_web && is_installed log2mail; then
grep -s -q "^file = /var/log/apache2/error.log" $conf \ grep -s -q "^file = /var/log/apache2/error.log" $conf \
|| failed "IS_LOG2MAILAPACHE" "missing log2mail directive for apache" || failed "IS_LOG2MAILAPACHE" "missing log2mail directive for apache"
@ -548,17 +425,6 @@ check_bindchroot() {
fi fi
fi fi
} }
# Verification de la présence du depot volatile
check_repvolatile() {
if is_debian_lenny; then
grep -qE "^deb http://volatile.debian.org/debian-volatile" /etc/apt/sources.list \
|| failed "IS_REPVOLATILE" "missing debian-volatile repository"
fi
if is_debian_squeeze; then
grep -qE "^deb.*squeeze-updates" /etc/apt/sources.list \
|| failed "IS_REPVOLATILE" "missing squeeze-updates repository"
fi
}
# /etc/network/interfaces should be present, we don't manage systemd-network yet # /etc/network/interfaces should be present, we don't manage systemd-network yet
check_network_interfaces() { check_network_interfaces() {
if ! test -f /etc/network/interfaces; then if ! test -f /etc/network/interfaces; then
@ -569,11 +435,7 @@ check_network_interfaces() {
} }
# Verify if all if are in auto # Verify if all if are in auto
check_autoif() { check_autoif() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then interfaces=$(/sbin/ip address show up | grep "^[0-9]*:" | grep -E -v "(lo|vnet|docker|veth|tun|tap|macvtap|vrrp|lxcbr|wg)" | cut -d " " -f 2 | tr -d : | cut -d@ -f1 | tr "\n" " ")
interfaces=$(/sbin/ip address show up | grep "^[0-9]*:" | grep -E -v "(lo|vnet|docker|veth|tun|tap|macvtap|vrrp|lxcbr|wg)" | cut -d " " -f 2 | tr -d : | cut -d@ -f1 | tr "\n" " ")
else
interfaces=$(/sbin/ifconfig -s | tail -n +2 | grep -E -v "^(lo|vnet|docker|veth|tun|tap|macvtap|vrrp)" | cut -d " " -f 1 |tr "\n" " ")
fi
for interface in $interfaces; do for interface in $interfaces; do
if grep -Rq "^iface $interface" /etc/network/interfaces* && ! grep -Rq "^auto $interface" /etc/network/interfaces*; then if grep -Rq "^iface $interface" /etc/network/interfaces* && ! grep -Rq "^auto $interface" /etc/network/interfaces*; then
failed "IS_AUTOIF" "Network interface \`${interface}' is statically defined but not set to auto" failed "IS_AUTOIF" "Network interface \`${interface}' is statically defined but not set to auto"
@ -590,11 +452,9 @@ check_interfacesgw() {
} }
# Verification de létat du service networking # Verification de létat du service networking
check_networking_service() { check_networking_service() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then if systemctl is-enabled networking.service > /dev/null; then
if systemctl is-enabled networking.service > /dev/null; then if ! systemctl is-active networking.service > /dev/null; then
if ! systemctl is-active networking.service > /dev/null; then failed "IS_NETWORKING_SERVICE" "networking.service is not active"
failed "IS_NETWORKING_SERVICE" "networking.service is not active"
fi
fi fi
fi fi
} }
@ -674,23 +534,21 @@ check_apacheipinallow() {
} }
# Check if default Apache configuration file for munin is absent (or empty or commented). # Check if default Apache configuration file for munin is absent (or empty or commented).
check_muninapacheconf() { check_muninapacheconf() {
if is_debian_squeeze || is_debian_wheezy; then muninconf="/etc/apache2/conf-available/munin.conf"
muninconf="/etc/apache2/conf.d/munin"
else
muninconf="/etc/apache2/conf-available/munin.conf"
fi
if is_installed apache2; then if is_installed apache2; then
test -e $muninconf && grep -vEq "^( |\t)*#" "$muninconf" \ test -e $muninconf && grep -vEq "^( |\t)*#" "$muninconf" \
&& failed "IS_MUNINAPACHECONF" "default munin configuration may be commented or disabled" && failed "IS_MUNINAPACHECONF" "default munin configuration may be commented or disabled"
fi fi
} }
# Verification de la priorité du package samba si les backports sont utilisés # Check if default Apache configuration file for phpMyAdmin is absent (or empty or commented).
check_sambainpriority() { check_phpmyadminapacheconf() {
if is_debian_lenny && is_pack_samba; then phpmyadminconf0="/etc/apache2/conf-available/phpmyadmin.conf"
if grep -qrE "^[^#].*backport" /etc/apt/sources.list{,.d}; then phpmyadminconf1="/etc/apache2/conf-enabled/phpmyadmin.conf"
priority=$(grep -E -A2 "^Package:.*samba" /etc/apt/preferences | grep -A1 "^Pin: release a=lenny-backports" | grep "^Pin-Priority:" | cut -f2 -d" ") if is_installed apache2; then
test "$priority" -gt 500 || failed "IS_SAMBAPINPRIORITY" "bad pinning priority for samba" test -e $phpmyadminconf0 && grep -vEq "^( |\t)*#" "$phpmyadminconf0" \
fi && failed "IS_PHPMYADMINAPACHECONF" "default phpmyadmin configuration ($phpmyadminconf0) may be commented or disabled"
test -e $phpmyadminconf1 && grep -vEq "^( |\t)*#" "$phpmyadminconf1" \
&& failed "IS_PHPMYADMINAPACHECONF" "default phpmyadmin configuration ($phpmyadminconf1) may be commented or disabled"
fi fi
} }
# Verification si le système doit redémarrer suite màj kernel. # Verification si le système doit redémarrer suite màj kernel.
@ -833,60 +691,48 @@ check_tune2fs_m5() {
done done
} }
check_evolinuxsudogroup() { check_evolinuxsudogroup() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then if grep -q "^evolinux-sudo:" /etc/group; then
if grep -q "^evolinux-sudo:" /etc/group; then if [ -f /etc/sudoers.d/evolinux ]; then
if [ -f /etc/sudoers.d/evolinux ]; then grep -qE '^%evolinux-sudo +ALL ?= ?\(ALL:ALL\) ALL' /etc/sudoers.d/evolinux \
grep -qE '^%evolinux-sudo +ALL ?= ?\(ALL:ALL\) ALL' /etc/sudoers.d/evolinux \ || failed "IS_EVOLINUXSUDOGROUP" "missing evolinux-sudo directive in sudoers file"
|| failed "IS_EVOLINUXSUDOGROUP" "missing evolinux-sudo directive in sudoers file"
fi
fi fi
fi fi
} }
check_userinadmgroup() { check_userinadmgroup() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then users=$(grep "^evolinux-sudo:" /etc/group | awk -F: '{print $4}' | tr ',' ' ')
users=$(grep "^evolinux-sudo:" /etc/group | awk -F: '{print $4}' | tr ',' ' ') for user in $users; do
for user in $users; do if ! groups "$user" | grep -q adm; then
if ! groups "$user" | grep -q adm; then failed "IS_USERINADMGROUP" "User $user doesn't belong to \`adm' group"
failed "IS_USERINADMGROUP" "User $user doesn't belong to \`adm' group" test "${VERBOSE}" = 1 || break
test "${VERBOSE}" = 1 || break fi
fi done
done
fi
} }
check_apache2evolinuxconf() { check_apache2evolinuxconf() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then if is_installed apache2; then
if is_installed apache2; then { test -L /etc/apache2/conf-enabled/z-evolinux-defaults.conf \
{ test -L /etc/apache2/conf-enabled/z-evolinux-defaults.conf \ && test -L /etc/apache2/conf-enabled/zzz-evolinux-custom.conf \
&& test -L /etc/apache2/conf-enabled/zzz-evolinux-custom.conf \ && test -f /etc/apache2/ipaddr_whitelist.conf;
&& test -f /etc/apache2/ipaddr_whitelist.conf; } || failed "IS_APACHE2EVOLINUXCONF" "missing custom evolinux apache config"
} || failed "IS_APACHE2EVOLINUXCONF" "missing custom evolinux apache config"
fi
fi fi
} }
check_backportsconf() { check_backportsconf() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then grep -qsE "^[^#].*backports" /etc/apt/sources.list \
grep -qsE "^[^#].*backports" /etc/apt/sources.list \ && failed "IS_BACKPORTSCONF" "backports can't be in main sources list"
&& failed "IS_BACKPORTSCONF" "backports can't be in main sources list" if grep -qsE "^[^#].*backports" /etc/apt/sources.list.d/*.list; then
if grep -qsE "^[^#].*backports" /etc/apt/sources.list.d/*.list; then grep -qsE "^[^#].*backports" /etc/apt/preferences.d/* \
grep -qsE "^[^#].*backports" /etc/apt/preferences.d/* \ || failed "IS_BACKPORTSCONF" "backports must have preferences"
|| failed "IS_BACKPORTSCONF" "backports must have preferences"
fi
fi fi
} }
check_bind9munin() { check_bind9munin() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then if is_installed bind9; then
if is_installed bind9; then { test -L /etc/munin/plugins/bind9 \
{ test -L /etc/munin/plugins/bind9 \ && test -e /etc/munin/plugin-conf.d/bind9;
&& test -e /etc/munin/plugin-conf.d/bind9; } || failed "IS_BIND9MUNIN" "missing bind plugin for munin"
} || failed "IS_BIND9MUNIN" "missing bind plugin for munin"
fi
fi fi
} }
check_bind9logrotate() { check_bind9logrotate() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then if is_installed bind9; then
if is_installed bind9; then test -e /etc/logrotate.d/bind9 || failed "IS_BIND9LOGROTATE" "missing bind logrotate file"
test -e /etc/logrotate.d/bind9 || failed "IS_BIND9LOGROTATE" "missing bind logrotate file"
fi
fi fi
} }
check_broadcomfirmware() { check_broadcomfirmware() {
@ -917,14 +763,12 @@ check_hardwareraidtool() {
fi fi
} }
check_log2mailsystemdunit() { check_log2mailsystemdunit() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then systemctl -q is-active log2mail.service \
systemctl -q is-active log2mail.service \ || failed "IS_LOG2MAILSYSTEMDUNIT" "log2mail unit not running"
|| failed "IS_LOG2MAILSYSTEMDUNIT" "log2mail unit not running" test -f /etc/systemd/system/log2mail.service \
test -f /etc/systemd/system/log2mail.service \ || failed "IS_LOG2MAILSYSTEMDUNIT" "missing log2mail unit file"
|| failed "IS_LOG2MAILSYSTEMDUNIT" "missing log2mail unit file" test -f /etc/init.d/log2mail \
test -f /etc/init.d/log2mail \ && failed "IS_LOG2MAILSYSTEMDUNIT" "/etc/init.d/log2mail may be deleted (use systemd unit)"
&& failed "IS_LOG2MAILSYSTEMDUNIT" "/etc/init.d/log2mail may be deleted (use systemd unit)"
fi
} }
check_listupgrade() { check_listupgrade() {
test -f /etc/cron.d/listupgrade \ test -f /etc/cron.d/listupgrade \
@ -933,13 +777,11 @@ check_listupgrade() {
|| failed "IS_LISTUPGRADE" "missing listupgrade script or not executable" || failed "IS_LISTUPGRADE" "missing listupgrade script or not executable"
} }
check_mariadbevolinuxconf() { check_mariadbevolinuxconf() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then if is_installed mariadb-server; then
if is_installed mariadb-server; then { test -f /etc/mysql/mariadb.conf.d/z-evolinux-defaults.cnf \
{ test -f /etc/mysql/mariadb.conf.d/z-evolinux-defaults.cnf \ && test -f /etc/mysql/mariadb.conf.d/zzz-evolinux-custom.cnf;
&& test -f /etc/mysql/mariadb.conf.d/zzz-evolinux-custom.cnf; } || failed "IS_MARIADBEVOLINUXCONF" "missing mariadb custom config"
} || failed "IS_MARIADBEVOLINUXCONF" "missing mariadb custom config"
fi fi
fi
} }
check_sql_backup() { check_sql_backup() {
if (is_installed "mysql-server" || is_installed "mariadb-server"); then if (is_installed "mysql-server" || is_installed "mariadb-server"); then
@ -997,8 +839,12 @@ check_ldap_backup() {
check_redis_backup() { check_redis_backup() {
if is_installed redis-server; then if is_installed redis-server; then
# You could change the default path in /etc/evocheck.cf # You could change the default path in /etc/evocheck.cf
REDIS_BACKUP_PATH=${REDIS_BACKUP_PATH:-"/home/backup/dump.rdb"} # REDIS_BACKUP_PATH may contain space-separated paths, example:
test -f "$REDIS_BACKUP_PATH" || failed "IS_REDIS_BACKUP" "Redis dump is missing (${REDIS_BACKUP_PATH})" # REDIS_BACKUP_PATH='/home/backup/redis-instance1/dump.rdb /home/backup/redis-instance2/dump.rdb'
REDIS_BACKUP_PATH=${REDIS_BACKUP_PATH:-"/home/backup/redis/dump.rdb"}
for file in ${REDIS_BACKUP_PATH}; do
test -f "${file}" || failed "IS_REDIS_BACKUP" "Redis dump is missing (${file})"
done
fi fi
} }
check_elastic_backup() { check_elastic_backup() {
@ -1020,73 +866,63 @@ check_mariadbsystemdunit() {
fi fi
} }
check_mysqlmunin() { check_mysqlmunin() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then if is_installed mariadb-server; then
if is_installed mariadb-server; then for file in mysql_bytes mysql_queries mysql_slowqueries \
for file in mysql_bytes mysql_queries mysql_slowqueries \ mysql_threads mysql_connections mysql_files_tables \
mysql_threads mysql_connections mysql_files_tables \ mysql_innodb_bpool mysql_innodb_bpool_act mysql_innodb_io \
mysql_innodb_bpool mysql_innodb_bpool_act mysql_innodb_io \ mysql_innodb_log mysql_innodb_rows mysql_innodb_semaphores \
mysql_innodb_log mysql_innodb_rows mysql_innodb_semaphores \ mysql_myisam_indexes mysql_qcache mysql_qcache_mem \
mysql_myisam_indexes mysql_qcache mysql_qcache_mem \ mysql_sorts mysql_tmp_tables; do
mysql_sorts mysql_tmp_tables; do
if [[ ! -L /etc/munin/plugins/$file ]]; then if [[ ! -L /etc/munin/plugins/$file ]]; then
failed "IS_MYSQLMUNIN" "missing munin plugin '$file'" failed "IS_MYSQLMUNIN" "missing munin plugin '$file'"
test "${VERBOSE}" = 1 || break test "${VERBOSE}" = 1 || break
fi fi
done done
munin-run mysql_commands 2> /dev/null > /dev/null munin-run mysql_commands 2> /dev/null > /dev/null
test $? -eq 0 || failed "IS_MYSQLMUNIN" "Munin plugin mysql_commands returned an error" test $? -eq 0 || failed "IS_MYSQLMUNIN" "Munin plugin mysql_commands returned an error"
fi
fi fi
} }
check_mysqlnrpe() { check_mysqlnrpe() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then if is_installed mariadb-server; then
if is_installed mariadb-server; then nagios_file=~nagios/.my.cnf
nagios_file=~nagios/.my.cnf if ! test -f ${nagios_file}; then
if ! test -f ${nagios_file}; then failed "IS_MYSQLNRPE" "${nagios_file} is missing"
failed "IS_MYSQLNRPE" "${nagios_file} is missing" elif [ "$(stat -c %U ${nagios_file})" != "nagios" ] \
elif [ "$(stat -c %U ${nagios_file})" != "nagios" ] \ || [ "$(stat -c %a ${nagios_file})" != "600" ]; then
|| [ "$(stat -c %a ${nagios_file})" != "600" ]; then failed "IS_MYSQLNRPE" "${nagios_file} has wrong permissions"
failed "IS_MYSQLNRPE" "${nagios_file} has wrong permissions" else
else grep -q -F "command[check_mysql]=/usr/lib/nagios/plugins/check_mysql" /etc/nagios/nrpe.d/evolix.cfg \
grep -q -F "command[check_mysql]=/usr/lib/nagios/plugins/check_mysql" /etc/nagios/nrpe.d/evolix.cfg \ || failed "IS_MYSQLNRPE" "check_mysql is missing"
|| failed "IS_MYSQLNRPE" "check_mysql is missing" fi
fi
fi fi
fi
} }
check_phpevolinuxconf() { check_phpevolinuxconf() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then is_debian_stretch && phpVersion="7.0"
is_debian_stretch && phpVersion="7.0" is_debian_buster && phpVersion="7.3"
is_debian_buster && phpVersion="7.3" is_debian_bullseye && phpVersion="7.4"
is_debian_bullseye && phpVersion="7.4" if is_installed php; then
if is_installed php; then { test -f /etc/php/${phpVersion}/cli/conf.d/z-evolinux-defaults.ini \
{ test -f /etc/php/${phpVersion}/cli/conf.d/z-evolinux-defaults.ini \ && test -f /etc/php/${phpVersion}/cli/conf.d/zzz-evolinux-custom.ini
&& test -f /etc/php/${phpVersion}/cli/conf.d/zzz-evolinux-custom.ini } || failed "IS_PHPEVOLINUXCONF" "missing php evolinux config"
} || failed "IS_PHPEVOLINUXCONF" "missing php evolinux config"
fi
fi fi
} }
check_squidlogrotate() { check_squidlogrotate() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then if is_installed squid; then
if is_installed squid; then grep -q -e monthly -e daily /etc/logrotate.d/squid \
grep -q -e monthly -e daily /etc/logrotate.d/squid \ || failed "IS_SQUIDLOGROTATE" "missing squid logrotate file"
|| failed "IS_SQUIDLOGROTATE" "missing squid logrotate file"
fi
fi fi
} }
check_squidevolinuxconf() { check_squidevolinuxconf() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then if is_installed squid; then
if is_installed squid; then { grep -qs "^CONFIG=/etc/squid/evolinux-defaults.conf$" /etc/default/squid \
{ grep -qs "^CONFIG=/etc/squid/evolinux-defaults.conf$" /etc/default/squid \ && test -f /etc/squid/evolinux-defaults.conf \
&& test -f /etc/squid/evolinux-defaults.conf \ && test -f /etc/squid/evolinux-whitelist-defaults.conf \
&& test -f /etc/squid/evolinux-whitelist-defaults.conf \ && test -f /etc/squid/evolinux-whitelist-custom.conf \
&& test -f /etc/squid/evolinux-whitelist-custom.conf \ && test -f /etc/squid/evolinux-acl.conf \
&& test -f /etc/squid/evolinux-acl.conf \ && test -f /etc/squid/evolinux-httpaccess.conf \
&& test -f /etc/squid/evolinux-httpaccess.conf \ && test -f /etc/squid/evolinux-custom.conf;
&& test -f /etc/squid/evolinux-custom.conf; } || failed "IS_SQUIDEVOLINUXCONF" "missing squid evolinux config"
} || failed "IS_SQUIDEVOLINUXCONF" "missing squid evolinux config"
fi
fi fi
} }
check_duplicate_fs_label() { check_duplicate_fs_label() {
@ -1152,41 +988,20 @@ check_apache_confenabled() {
# Starting from Jessie and Apache 2.4, /etc/apache2/conf.d/ # Starting from Jessie and Apache 2.4, /etc/apache2/conf.d/
# must be replaced by conf-available/ and config files symlinked # must be replaced by conf-available/ and config files symlinked
# to conf-enabled/ # to conf-enabled/
if is_debian_jessie || is_debian_stretch || is_debian_buster || is_debian_bullseye; then if [ -f /etc/apache2/apache2.conf ]; then
if [ -f /etc/apache2/apache2.conf ]; then test -d /etc/apache2/conf.d/ \
test -d /etc/apache2/conf.d/ \ && failed "IS_APACHE_CONFENABLED" "apache's conf.d directory must not exists"
&& failed "IS_APACHE_CONFENABLED" "apache's conf.d directory must not exists" grep -q 'Include conf.d' /etc/apache2/apache2.conf \
grep -q 'Include conf.d' /etc/apache2/apache2.conf \ && failed "IS_APACHE_CONFENABLED" "apache2.conf must not Include conf.d"
&& failed "IS_APACHE_CONFENABLED" "apache2.conf must not Include conf.d"
fi
fi fi
} }
check_meltdown_spectre() { check_meltdown_spectre() {
# For Stretch, detection is easy as the kernel use
# /sys/devices/system/cpu/vulnerabilities/ # /sys/devices/system/cpu/vulnerabilities/
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then for vuln in meltdown spectre_v1 spectre_v2; do
for vuln in meltdown spectre_v1 spectre_v2; do test -f "/sys/devices/system/cpu/vulnerabilities/$vuln" \
test -f "/sys/devices/system/cpu/vulnerabilities/$vuln" \ || failed "IS_MELTDOWN_SPECTRE" "vulnerable to $vuln"
|| failed "IS_MELTDOWN_SPECTRE" "vulnerable to $vuln" test "${VERBOSE}" = 1 || break
test "${VERBOSE}" = 1 || break done
done
# For Jessie this is quite complicated to verify and we need to use kernel config file
elif is_debian_jessie; then
if grep -q "BOOT_IMAGE=" /proc/cmdline; then
kernelPath=$(grep -Eo 'BOOT_IMAGE=[^ ]+' /proc/cmdline | cut -d= -f2)
kernelVer=${kernelPath##*/vmlinuz-}
kernelConfig="config-${kernelVer}"
# Sometimes autodetection of kernel config file fail, so we test if the file really exists.
if [ -f "/boot/${kernelConfig}" ]; then
grep -Eq '^CONFIG_PAGE_TABLE_ISOLATION=y' "/boot/$kernelConfig" \
|| failed "IS_MELTDOWN_SPECTRE" \
"PAGE_TABLE_ISOLATION must be enabled in kernel, outdated kernel?"
grep -Eq '^CONFIG_RETPOLINE=y' "/boot/$kernelConfig" \
|| failed "IS_MELTDOWN_SPECTRE" \
"RETPOLINE must be enabled in kernel, outdated kernel?"
fi
fi
fi
} }
check_old_home_dir() { check_old_home_dir() {
homeDir=${homeDir:-/home} homeDir=${homeDir:-/home}
@ -1218,7 +1033,7 @@ check_usrsharescripts() {
} }
check_sshpermitrootno() { check_sshpermitrootno() {
sshd_args="-C addr=,user=,host=,laddr=,lport=0" sshd_args="-C addr=,user=,host=,laddr=,lport=0"
if is_debian_jessie || is_debian_stretch; then if is_debian_stretch; then
# Noop, we'll use the default $sshd_args # Noop, we'll use the default $sshd_args
: :
elif is_debian_buster; then elif is_debian_buster; then
@ -1234,17 +1049,7 @@ check_sshpermitrootno() {
fi fi
} }
check_evomaintenanceusers() { check_evomaintenanceusers() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then users=$(getent group evolinux-sudo | cut -d':' -f4 | tr ',' ' ')
users=$(getent group evolinux-sudo | cut -d':' -f4 | tr ',' ' ')
else
if [ -f /etc/sudoers.d/evolinux ]; then
sudoers="/etc/sudoers.d/evolinux"
else
sudoers="/etc/sudoers"
fi
# combine users from User_Alias and sudo group
users=$({ grep "^User_Alias *ADMIN" $sudoers | cut -d= -f2 | tr -d " "; grep "^sudo" /etc/group | cut -d: -f 4; } | tr "," "\n" | sort -u)
fi
for user in $users; do for user in $users; do
user_home=$(getent passwd "$user" | cut -d: -f6) user_home=$(getent passwd "$user" | cut -d: -f6)
if [ -n "$user_home" ] && [ -d "$user_home" ]; then if [ -n "$user_home" ] && [ -d "$user_home" ]; then
@ -1307,17 +1112,6 @@ check_osprober() {
fi fi
} }
check_jessie_backports() {
if is_debian_jessie; then
jessieBackports=$(grep -hs "jessie-backports" /etc/apt/sources.list /etc/apt/sources.list.d/*)
if test -n "$jessieBackports"; then
if ! grep -q "archive.debian.org" <<< "$jessieBackports"; then
failed "IS_JESSIE_BACKPORTS" "You must use deb http://archive.debian.org/debian/ jessie-backports main"
fi
fi
fi
}
check_apt_valid_until() { check_apt_valid_until() {
aptvalidFile="/etc/apt/apt.conf.d/99no-check-valid-until" aptvalidFile="/etc/apt/apt.conf.d/99no-check-valid-until"
aptvalidText="Acquire::Check-Valid-Until no;" aptvalidText="Acquire::Check-Valid-Until no;"
@ -1356,14 +1150,8 @@ check_nginx_letsencrypt_uptodate() {
snippets=$(find /etc/nginx -type f -name "letsencrypt.conf") snippets=$(find /etc/nginx -type f -name "letsencrypt.conf")
if [ -n "${snippets}" ]; then if [ -n "${snippets}" ]; then
while read -r snippet; do while read -r snippet; do
if is_debian_jessie; then if grep -qE "^\s*alias\s+/.+/\.well-known/acme-challenge" "${snippet}"; then
if ! grep -qE "^\s*alias\s+/.+/\.well-known/acme-challenge" "${snippet}"; then failed "IS_NGINX_LETSENCRYPT_UPTODATE" "Nginx snippet ${snippet} is not compatible with Nginx on Debian 9+."
failed "IS_NGINX_LETSENCRYPT_UPTODATE" "Nginx snippet ${snippet} is not compatible with Nginx on Debian 8."
fi
else
if grep -qE "^\s*alias\s+/.+/\.well-known/acme-challenge" "${snippet}"; then
failed "IS_NGINX_LETSENCRYPT_UPTODATE" "Nginx snippet ${snippet} is not compatible with Nginx on Debian 9+."
fi
fi fi
done <<< "${snippets}" done <<< "${snippets}"
fi fi
@ -1399,11 +1187,7 @@ download_versions() {
# evoacme 21.06 # evoacme 21.06
# evomaintenance 0.6.4 # evomaintenance 0.6.4
if is_debian; then versions_url="https://upgrades.evolix.org/versions-${DEBIAN_RELEASE}"
versions_url="https://upgrades.evolix.org/versions-${DEBIAN_RELEASE}"
else
failed "IS_CHECK_VERSIONS" "error determining os release"
fi
# fetch timeout, in seconds # fetch timeout, in seconds
timeout=10 timeout=10
@ -1527,8 +1311,6 @@ main() {
main_output_file=$(mktemp --tmpdir="${TMPDIR:-/tmp}" "evocheck.main.XXXXX") main_output_file=$(mktemp --tmpdir="${TMPDIR:-/tmp}" "evocheck.main.XXXXX")
files_to_cleanup="${files_to_cleanup} ${main_output_file}" files_to_cleanup="${files_to_cleanup} ${main_output_file}"
MINIFW_FILE=$(minifirewall_file)
test "${IS_TMP_1777:=1}" = 1 && check_tmp_1777 test "${IS_TMP_1777:=1}" = 1 && check_tmp_1777
test "${IS_ROOT_0700:=1}" = 1 && check_root_0700 test "${IS_ROOT_0700:=1}" = 1 && check_root_0700
test "${IS_USRSHARESCRIPTS:=1}" = 1 && check_usrsharescripts test "${IS_USRSHARESCRIPTS:=1}" = 1 && check_usrsharescripts
@ -1540,19 +1322,15 @@ main() {
test "${IS_LSBRELEASE:=1}" = 1 && check_lsbrelease test "${IS_LSBRELEASE:=1}" = 1 && check_lsbrelease
test "${IS_DPKGWARNING:=1}" = 1 && check_dpkgwarning test "${IS_DPKGWARNING:=1}" = 1 && check_dpkgwarning
test "${IS_UMASKSUDOERS:=1}" = 1 && check_umasksudoers
test "${IS_NRPEPOSTFIX:=1}" = 1 && check_nrpepostfix test "${IS_NRPEPOSTFIX:=1}" = 1 && check_nrpepostfix
test "${IS_MODSECURITY:=1}" = 1 && check_modsecurity
test "${IS_CUSTOMSUDOERS:=1}" = 1 && check_customsudoers test "${IS_CUSTOMSUDOERS:=1}" = 1 && check_customsudoers
test "${IS_VARTMPFS:=1}" = 1 && check_vartmpfs test "${IS_VARTMPFS:=1}" = 1 && check_vartmpfs
test "${IS_SERVEURBASE:=1}" = 1 && check_serveurbase test "${IS_SERVEURBASE:=1}" = 1 && check_serveurbase
test "${IS_LOGROTATECONF:=1}" = 1 && check_logrotateconf test "${IS_LOGROTATECONF:=1}" = 1 && check_logrotateconf
test "${IS_SYSLOGCONF:=1}" = 1 && check_syslogconf test "${IS_SYSLOGCONF:=1}" = 1 && check_syslogconf
test "${IS_DEBIANSECURITY:=1}" = 1 && check_debiansecurity test "${IS_DEBIANSECURITY:=1}" = 1 && check_debiansecurity
test "${IS_APTITUDEONLY:=1}" = 1 && check_aptitudeonly
test "${IS_APTITUDE:=1}" = 1 && check_aptitude test "${IS_APTITUDE:=1}" = 1 && check_aptitude
test "${IS_APTGETBAK:=1}" = 1 && check_aptgetbak test "${IS_APTGETBAK:=1}" = 1 && check_aptgetbak
test "${IS_APTICRON:=0}" = 1 && check_apticron
test "${IS_USRRO:=1}" = 1 && check_usrro test "${IS_USRRO:=1}" = 1 && check_usrro
test "${IS_TMPNOEXEC:=1}" = 1 && check_tmpnoexec test "${IS_TMPNOEXEC:=1}" = 1 && check_tmpnoexec
test "${IS_MOUNT_FSTAB:=1}" = 1 && check_mountfstab test "${IS_MOUNT_FSTAB:=1}" = 1 && check_mountfstab
@ -1584,7 +1362,6 @@ main() {
test "${IS_LOG2MAILMYSQL:=1}" = 1 && check_log2mailmysql test "${IS_LOG2MAILMYSQL:=1}" = 1 && check_log2mailmysql
test "${IS_LOG2MAILSQUID:=1}" = 1 && check_log2mailsquid test "${IS_LOG2MAILSQUID:=1}" = 1 && check_log2mailsquid
test "${IS_BINDCHROOT:=1}" = 1 && check_bindchroot test "${IS_BINDCHROOT:=1}" = 1 && check_bindchroot
test "${IS_REPVOLATILE:=1}" = 1 && check_repvolatile
test "${IS_NETWORK_INTERFACES:=1}" = 1 && check_network_interfaces test "${IS_NETWORK_INTERFACES:=1}" = 1 && check_network_interfaces
test "${IS_AUTOIF:=1}" = 1 && check_autoif test "${IS_AUTOIF:=1}" = 1 && check_autoif
test "${IS_INTERFACESGW:=1}" = 1 && check_interfacesgw test "${IS_INTERFACESGW:=1}" = 1 && check_interfacesgw
@ -1596,7 +1373,7 @@ main() {
test "${IS_APACHESYMLINK:=1}" = 1 && check_apachesymlink test "${IS_APACHESYMLINK:=1}" = 1 && check_apachesymlink
test "${IS_APACHEIPINALLOW:=1}" = 1 && check_apacheipinallow test "${IS_APACHEIPINALLOW:=1}" = 1 && check_apacheipinallow
test "${IS_MUNINAPACHECONF:=1}" = 1 && check_muninapacheconf test "${IS_MUNINAPACHECONF:=1}" = 1 && check_muninapacheconf
test "${IS_SAMBAPINPRIORITY:=1}" = 1 && check_sambainpriority test "${IS_PHPMYADMINAPACHECONF:=1}" = 1 && check_phpmyadminapacheconf
test "${IS_KERNELUPTODATE:=1}" = 1 && check_kerneluptodate test "${IS_KERNELUPTODATE:=1}" = 1 && check_kerneluptodate
test "${IS_UPTIME:=1}" = 1 && check_uptime test "${IS_UPTIME:=1}" = 1 && check_uptime
test "${IS_MUNINRUNNING:=1}" = 1 && check_muninrunning test "${IS_MUNINRUNNING:=1}" = 1 && check_muninrunning
@ -1637,7 +1414,6 @@ main() {
test "${IS_OLD_HOME_DIR:=0}" = 1 && check_old_home_dir test "${IS_OLD_HOME_DIR:=0}" = 1 && check_old_home_dir
test "${IS_EVOBACKUP_INCS:=1}" = 1 && check_evobackup_incs test "${IS_EVOBACKUP_INCS:=1}" = 1 && check_evobackup_incs
test "${IS_OSPROBER:=1}" = 1 && check_osprober test "${IS_OSPROBER:=1}" = 1 && check_osprober
test "${IS_JESSIE_BACKPORTS:=1}" = 1 && check_jessie_backports
test "${IS_APT_VALID_UNTIL:=1}" = 1 && check_apt_valid_until test "${IS_APT_VALID_UNTIL:=1}" = 1 && check_apt_valid_until
test "${IS_CHROOTED_BINARY_UPTODATE:=1}" = 1 && check_chrooted_binary_uptodate test "${IS_CHROOTED_BINARY_UPTODATE:=1}" = 1 && check_chrooted_binary_uptodate
test "${IS_NGINX_LETSENCRYPT_UPTODATE:=1}" = 1 && check_nginx_letsencrypt_uptodate test "${IS_NGINX_LETSENCRYPT_UPTODATE:=1}" = 1 && check_nginx_letsencrypt_uptodate

1252
evocheck/files/evocheck.wheezy.sh Executable file
View File

@ -0,0 +1,1252 @@
#!/bin/bash
# EvoCheck
# Script to verify compliance of a Linux (Debian) server
# powered by Evolix
VERSION="22.11"
readonly VERSION
# base functions
show_version() {
cat <<END
evocheck version ${VERSION} (Wheezy)
Copyright 2009-2022 Evolix <info@evolix.fr>,
Romain Dessort <rdessort@evolix.fr>,
Benoit Série <bserie@evolix.fr>,
Gregory Colpart <reg@evolix.fr>,
Jérémy Lecour <jlecour@evolix.fr>,
Tristan Pilat <tpilat@evolix.fr>,
Victor Laborie <vlaborie@evolix.fr>,
Alexis Ben Miloud--Josselin <abenmiloud@evolix.fr>,
and others.
evocheck comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
See the GNU General Public License v3.0 for details.
END
}
show_help() {
cat <<END
evocheck is a script that verifies Evolix conventions on Linux (Debian) servers.
Usage: evocheck
or evocheck --cron
or evocheck --quiet
or evocheck --verbose
Options
--cron disable a few checks
-v, --verbose increase verbosity of checks
-q, --quiet nothing is printed on stdout nor stderr
-h, --help print this message and exit
--version print version and exit
END
}
detect_os() {
# OS detection
DEBIAN_RELEASE=""
LSB_RELEASE_BIN=$(command -v lsb_release)
if [ -e /etc/debian_version ]; then
DEBIAN_MAIN_VERSION=$(cut -d "." -f 1 < /etc/debian_version)
if [ "${DEBIAN_MAIN_VERSION}" -ne "7" ]; then
echo "Debian ${DEBIAN_MAIN_VERSION} is incompatible with this version of evocheck." >&2
echo "This version is built for Debian 7 only." >&2
exit
fi
if [ -x "${LSB_RELEASE_BIN}" ]; then
DEBIAN_RELEASE=$(${LSB_RELEASE_BIN} --codename --short)
else
case ${DEBIAN_MAIN_VERSION} in
5) DEBIAN_RELEASE="lenny";;
6) DEBIAN_RELEASE="squeeze";;
7) DEBIAN_RELEASE="wheezy";;
esac
fi
fi
}
is_debian_lenny() {
test "${DEBIAN_RELEASE}" = "lenny"
}
is_debian_squeeze() {
test "${DEBIAN_RELEASE}" = "squeeze"
}
is_debian_wheezy() {
test "${DEBIAN_RELEASE}" = "wheezy"
}
is_pack_web(){
test -e /usr/share/scripts/web-add.sh || test -e /usr/share/scripts/evoadmin/web-add.sh
}
is_pack_samba(){
test -e /usr/share/scripts/add.pl
}
is_installed(){
for pkg in "$@"; do
dpkg -l "$pkg" 2> /dev/null | grep -q -E '^(i|h)i' || return 1
done
}
# logging
failed() {
check_name=$1
shift
check_comments=$*
RC=1
if [ "${QUIET}" != 1 ]; then
if [ -n "${check_comments}" ] && [ "${VERBOSE}" = 1 ]; then
printf "%s FAILED! %s\n" "${check_name}" "${check_comments}" >> "${main_output_file}"
else
printf "%s FAILED!\n" "${check_name}" >> "${main_output_file}"
fi
fi
}
# check functions
check_lsbrelease(){
if [ -x "${LSB_RELEASE_BIN}" ]; then
## only the major version matters
lhs=$(${LSB_RELEASE_BIN} --release --short | cut -d "." -f 1)
rhs=$(cut -d "." -f 1 < /etc/debian_version)
test "$lhs" = "$rhs" || failed "IS_LSBRELEASE" "release is not consistent between lsb_release (${lhs}) and /etc/debian_version (${rhs})"
else
failed "IS_LSBRELEASE" "lsb_release is missing or not executable"
fi
}
check_dpkgwarning() {
if [ "$IS_USRRO" = 1 ] || [ "$IS_TMPNOEXEC" = 1 ]; then
test -e /etc/apt/apt.conf.d/80evolinux \
|| failed "IS_DPKGWARNING" "/etc/apt/apt.conf.d/80evolinux is missing"
test -e /etc/apt/apt.conf \
&& failed "IS_DPKGWARNING" "/etc/apt/apt.conf is missing"
fi
}
# Verifying check_mailq in Nagios NRPE config file. (Option "-M postfix" need to be set if the MTA is Postfix)
check_nrpepostfix() {
if is_installed postfix; then
{ test -e /etc/nagios/nrpe.cfg \
&& grep -qr "^command.*check_mailq -M postfix" /etc/nagios/nrpe.*;
} || failed "IS_NRPEPOSTFIX" "NRPE \"check_mailq\" for postfix is missing"
fi
}
# Check if mod-security config file is present
check_modsecurity() {
if is_installed libapache2-modsecurity; then
test -e /etc/apache2/conf.d/mod-security2.conf || failed "IS_MODSECURITY" "missing configuration file"
fi
}
check_customsudoers() {
grep -E -qr "umask=0077" /etc/sudoers* || failed "IS_CUSTOMSUDOERS" "missing umask=0077 in sudoers file"
}
check_vartmpfs() {
FINDMNT_BIN=$(command -v findmnt)
if [ -x "${FINDMNT_BIN}" ]; then
${FINDMNT_BIN} /var/tmp --type tmpfs --noheadings > /dev/null || failed "IS_VARTMPFS" "/var/tmp is not a tmpfs"
else
df /var/tmp | grep -q tmpfs || failed "IS_VARTMPFS" "/var/tmp is not a tmpfs"
fi
}
check_serveurbase() {
is_installed serveur-base || failed "IS_SERVEURBASE" "serveur-base package is not installed"
}
check_logrotateconf() {
test -e /etc/logrotate.d/zsyslog || failed "IS_LOGROTATECONF" "missing zsyslog in logrotate.d"
}
check_syslogconf() {
grep -q "^# Syslog for Pack Evolix serveur" /etc/*syslog.conf \
|| failed "IS_SYSLOGCONF" "syslog evolix config file missing"
}
check_debiansecurity() {
# Look for enabled "Debian-Security" sources from the "Debian" origin
apt-cache policy | grep "\bl=Debian-Security\b" | grep "\bo=Debian\b" | grep --quiet "\bc=main\b"
test $? -eq 0 || failed "IS_DEBIANSECURITY" "missing Debian-Security repository"
}
check_aptitudeonly() {
test -e /usr/bin/apt-get && failed "IS_APTITUDEONLY" \
"only aptitude may be enabled on Debian <=7, apt-get should be disabled"
}
check_apticron() {
status="OK"
test -e /etc/cron.d/apticron || status="fail"
test -e /etc/cron.daily/apticron && status="fail"
test "$status" = "fail" || test -e /usr/bin/apt-get.bak || status="fail"
test "$status" = "fail" && failed "IS_APTICRON" "apticron must be in cron.d not cron.daily"
}
check_usrro() {
grep /usr /etc/fstab | grep -qE "\bro\b" || failed "IS_USRRO" "missing ro directive on fstab for /usr"
}
check_tmpnoexec() {
FINDMNT_BIN=$(command -v findmnt)
if [ -x "${FINDMNT_BIN}" ]; then
options=$(${FINDMNT_BIN} --noheadings --first-only --output OPTIONS /tmp)
echo "${options}" | grep -qE "\bnoexec\b" || failed "IS_TMPNOEXEC" "/tmp is not mounted with 'noexec'"
else
mount | grep "on /tmp" | grep -qE "\bnoexec\b" || failed "IS_TMPNOEXEC" "/tmp is not mounted with 'noexec' (WARNING: findmnt(8) is not found)"
fi
}
check_mountfstab() {
# Test if lsblk available, if not skip this test...
LSBLK_BIN=$(command -v lsblk)
if test -x "${LSBLK_BIN}"; then
for mountPoint in $(${LSBLK_BIN} -o MOUNTPOINT -l -n | grep '/'); do
grep -Eq "$mountPoint\W" /etc/fstab \
|| failed "IS_MOUNT_FSTAB" "partition(s) detected mounted but no presence in fstab"
done
fi
}
check_listchangesconf() {
if [ -e "/etc/apt/listchanges.conf" ]; then
lines=$(grep -cE "(which=both|confirm=1)" /etc/apt/listchanges.conf)
if [ "$lines" != 2 ]; then
failed "IS_LISTCHANGESCONF" "apt-listchanges config is incorrect"
fi
else
failed "IS_LISTCHANGESCONF" "apt-listchanges config is missing"
fi
}
check_customcrontab() {
found_lines=$(grep -c -E "^(17 \*|25 6|47 6|52 6)" /etc/crontab)
test "$found_lines" = 4 && failed "IS_CUSTOMCRONTAB" "missing custom field in crontab"
}
check_sshallowusers() {
grep -E -qir "(AllowUsers|AllowGroups)" /etc/ssh/sshd_config /etc/ssh/sshd_config.d \
|| failed "IS_SSHALLOWUSERS" "missing AllowUsers or AllowGroups directive in sshd_config"
}
check_diskperf() {
perfFile="/root/disk-perf.txt"
test -e $perfFile || failed "IS_DISKPERF" "missing ${perfFile}"
}
check_tmoutprofile() {
grep -sq "TMOUT=" /etc/profile /etc/profile.d/evolinux.sh || failed "IS_TMOUTPROFILE" "TMOUT is not set"
}
check_alert5boot() {
if [ -n "$(find /etc/rc2.d/ -name 'S*alert5')" ]; then
grep -q "^date" /etc/rc2.d/S*alert5 || failed "IS_ALERT5BOOT" "boot mail is not sent by alert5 init script"
elif [ -n "$(find /etc/init.d/ -name 'alert5')" ]; then
grep -q "^date" /etc/init.d/alert5 || failed "IS_ALERT5BOOT" "boot mail is not sent by alert5 int script"
else
failed "IS_ALERT5BOOT" "alert5 init script is missing"
fi
}
check_alert5minifw() {
if [ -n "$(find /etc/rc2.d/ -name 'S*alert5')" ]; then
grep -q "^/etc/init.d/minifirewall" /etc/rc2.d/S*alert5 \
|| failed "IS_ALERT5MINIFW" "Minifirewall is not started by alert5 init script"
elif [ -n "$(find /etc/init.d/ -name 'alert5')" ]; then
grep -q "^/etc/init.d/minifirewall" /etc/init.d/alert5 \
|| failed "IS_ALERT5MINIFW" "Minifirewall is not started by alert5 init script"
else
failed "IS_ALERT5MINIFW" "alert5 init script is missing"
fi
}
check_minifw() {
/sbin/iptables -L -n | grep -q -E "^ACCEPT\s*all\s*--\s*31\.170\.8\.4\s*0\.0\.0\.0/0\s*$" \
|| failed "IS_MINIFW" "minifirewall seems not started"
}
check_nrpeperms() {
if [ -d /etc/nagios ]; then
nagiosDir="/etc/nagios"
actual=$(stat --format "%a" $nagiosDir)
expected="750"
test "$expected" = "$actual" || failed "IS_NRPEPERMS" "${nagiosDir} must be ${expected}"
fi
}
check_minifwperms() {
if [ -f "/etc/firewall.rc" ]; then
actual=$(stat --format "%a" "/etc/firewall.rc")
expected="600"
test "$expected" = "$actual" || failed "IS_MINIFWPERMS" "/etc/firewall.rc must be ${expected}"
fi
}
check_nrpedisks() {
NRPEDISKS=$(grep command.check_disk /etc/nagios/nrpe.cfg | grep "^command.check_disk[0-9]" | sed -e "s/^command.check_disk\([0-9]\+\).*/\1/" | sort -n | tail -1)
DFDISKS=$(df -Pl | grep -c -E -v "(^Filesystem|/lib/init/rw|/dev/shm|udev|rpc_pipefs)")
test "$NRPEDISKS" = "$DFDISKS" || failed "IS_NRPEDISKS" "there must be $DFDISKS check_disk in nrpe.cfg"
}
check_nrpepid() {
{ test -e /etc/nagios/nrpe.cfg \
&& grep -q "^pid_file=/var/run/nagios/nrpe.pid" /etc/nagios/nrpe.cfg;
} || failed "IS_NRPEPID" "missing or wrong pid_file directive in nrpe.cfg"
}
check_grsecprocs() {
if uname -a | grep -q grsec; then
{ grep -q "^command.check_total_procs..sudo" /etc/nagios/nrpe.cfg \
&& grep -A1 "^\[processes\]" /etc/munin/plugin-conf.d/munin-node | grep -q "^user root";
} || failed "IS_GRSECPROCS" "missing munin's plugin processes directive for grsec"
fi
}
check_apachemunin() {
if test -e /etc/apache2/apache2.conf; then
pattern="/server-status-[[:alnum:]]{4,}"
{ grep -r -q -s -E "^env.url.*${pattern}" /etc/munin/plugin-conf.d \
&& { grep -q -s -E "${pattern}" /etc/apache2/apache2.conf \
|| grep -q -s -E "${pattern}" /etc/apache2/mods-enabled/status.conf;
};
} || failed "IS_APACHEMUNIN" "server status is not properly configured"
fi
}
# Verification mytop + Munin si MySQL
check_mysqlutils() {
MYSQL_ADMIN=${MYSQL_ADMIN:-mysqladmin}
if is_installed mysql-server; then
# You can configure MYSQL_ADMIN in evocheck.cf
if ! grep -qs "^user *= *${MYSQL_ADMIN}" /root/.my.cnf; then
failed "IS_MYSQLUTILS" "${MYSQL_ADMIN} missing in /root/.my.cnf"
fi
if ! test -x /usr/bin/mytop; then
if ! test -x /usr/local/bin/mytop; then
failed "IS_MYSQLUTILS" "mytop binary missing"
fi
fi
if ! grep -qs '^user *=' /root/.mytop; then
failed "IS_MYSQLUTILS" "credentials missing in /root/.mytop"
fi
fi
}
# Verification de la configuration du raid soft (mdadm)
check_raidsoft() {
if test -e /proc/mdstat && grep -q md /proc/mdstat; then
{ grep -q "^AUTOCHECK=true" /etc/default/mdadm \
&& grep -q "^START_DAEMON=true" /etc/default/mdadm \
&& grep -qv "^MAILADDR ___MAIL___" /etc/mdadm/mdadm.conf;
} || failed "IS_RAIDSOFT" "missing or wrong config for mdadm"
fi
}
# Verification du LogFormat de AWStats
check_awstatslogformat() {
if is_installed apache2 awstats; then
awstatsFile="/etc/awstats/awstats.conf.local"
grep -qE '^LogFormat=1' $awstatsFile \
|| failed "IS_AWSTATSLOGFORMAT" "missing or wrong LogFormat directive in $awstatsFile"
fi
}
# Verification de la présence de la config logrotate pour Munin
check_muninlogrotate() {
{ test -e /etc/logrotate.d/munin-node \
&& test -e /etc/logrotate.d/munin;
} || failed "IS_MUNINLOGROTATE" "missing lorotate file for munin"
}
# Verification de l'activation de Squid dans le cas d'un pack mail
check_squid() {
squidconffile="/etc/squid*/squid.conf"
if is_pack_web && (is_installed squid || is_installed squid3); then
host=$(hostname -i)
# shellcheck disable=SC2086
http_port=$(grep -E "^http_port\s+[0-9]+" $squidconffile | awk '{ print $2 }')
{ grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -m owner --uid-owner proxy -j ACCEPT" "/etc/firewall.rc" \
&& grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -d $host -j ACCEPT" "/etc/firewall.rc" \
&& grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -d 127.0.0.(1|0/8) -j ACCEPT" "/etc/firewall.rc" \
&& grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-port.* $http_port" "/etc/firewall.rc";
} || grep -qE "^PROXY='?on'?" "/etc/firewall.rc" \
|| failed "IS_SQUID" "missing squid rules in minifirewall"
fi
}
check_evomaintenance_fw() {
if [ -f "/etc/firewall.rc" ]; then
hook_db=$(grep -E '^\s*HOOK_DB' /etc/evomaintenance.cf | tr -d ' ' | cut -d= -f2)
rulesNumber=$(grep -c "/sbin/iptables -A INPUT -p tcp --sport 5432 --dport 1024:65535 -s .* -m state --state ESTABLISHED,RELATED -j ACCEPT" "/etc/firewall.rc")
if [ "$hook_db" = "1" ] && [ "$rulesNumber" -lt 2 ]; then
failed "IS_EVOMAINTENANCE_FW" "HOOK_DB is enabled but missing evomaintenance rules in minifirewall"
fi
fi
}
# Verification de la conf et de l'activation de mod-deflate
check_moddeflate() {
f=/etc/apache2/mods-enabled/deflate.conf
if is_installed apache2.2; then
{ test -e $f && grep -q "AddOutputFilterByType DEFLATE text/html text/plain text/xml" $f \
&& grep -q "AddOutputFilterByType DEFLATE text/css" $f \
&& grep -q "AddOutputFilterByType DEFLATE application/x-javascript application/javascript" $f;
} || failed "IS_MODDEFLATE" "missing AddOutputFilterByType directive for apache mod deflate"
fi
}
# Verification de la conf log2mail
check_log2mailrunning() {
if is_pack_web && is_installed log2mail; then
pgrep log2mail >/dev/null || failed "IS_LOG2MAILRUNNING" "log2mail is not running"
fi
}
check_log2mailapache() {
conf=/etc/log2mail/config/default
if is_pack_web && is_installed log2mail; then
grep -s -q "^file = /var/log/apache2/error.log" $conf \
|| failed "IS_LOG2MAILAPACHE" "missing log2mail directive for apache"
fi
}
check_log2mailmysql() {
if is_pack_web && is_installed log2mail; then
grep -s -q "^file = /var/log/syslog" /etc/log2mail/config/{default,mysql,mysql.conf} \
|| failed "IS_LOG2MAILMYSQL" "missing log2mail directive for mysql"
fi
}
check_log2mailsquid() {
if is_pack_web && is_installed log2mail; then
grep -s -q "^file = /var/log/squid.*/access.log" /etc/log2mail/config/* \
|| failed "IS_LOG2MAILSQUID" "missing log2mail directive for squid"
fi
}
# Verification si bind est chroote
check_bindchroot() {
if is_installed bind9; then
if netstat -utpln | grep "/named" | grep :53 | grep -qvE "(127.0.0.1|::1)"; then
if grep -q '^OPTIONS=".*-t' /etc/default/bind9 && grep -q '^OPTIONS=".*-u' /etc/default/bind9; then
md5_original=$(md5sum /usr/sbin/named | cut -f 1 -d ' ')
md5_chrooted=$(md5sum /var/chroot-bind/usr/sbin/named | cut -f 1 -d ' ')
if [ "$md5_original" != "$md5_chrooted" ]; then
failed "IS_BINDCHROOT" "the chrooted bind binary is different than the original binary"
fi
else
failed "IS_BINDCHROOT" "bind process is not chrooted"
fi
fi
fi
}
# /etc/network/interfaces should be present, we don't manage systemd-network yet
check_network_interfaces() {
if ! test -f /etc/network/interfaces; then
IS_AUTOIF=0
IS_INTERFACESGW=0
failed "IS_NETWORK_INTERFACES" "systemd network configuration is not supported yet"
fi
}
# Verify if all if are in auto
check_autoif() {
interfaces=$(/sbin/ifconfig -s | tail -n +2 | grep -E -v "^(lo|vnet|docker|veth|tun|tap|macvtap|vrrp)" | cut -d " " -f 1 |tr "\n" " ")
for interface in $interfaces; do
if grep -Rq "^iface $interface" /etc/network/interfaces* && ! grep -Rq "^auto $interface" /etc/network/interfaces*; then
failed "IS_AUTOIF" "Network interface \`${interface}' is statically defined but not set to auto"
test "${VERBOSE}" = 1 || break
fi
done
}
# Network conf verification
check_interfacesgw() {
number=$(grep -Ec "^[^#]*gateway [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" /etc/network/interfaces)
test "$number" -gt 1 && failed "IS_INTERFACESGW" "there is more than 1 IPv4 gateway"
number=$(grep -Ec "^[^#]*gateway [0-9a-fA-F]+:" /etc/network/interfaces)
test "$number" -gt 1 && failed "IS_INTERFACESGW" "there is more than 1 IPv6 gateway"
}
# Verification de la mise en place d'evobackup
check_evobackup() {
evobackup_found=$(find /etc/cron* -name '*evobackup*' | wc -l)
test "$evobackup_found" -gt 0 || failed "IS_EVOBACKUP" "missing evobackup cron"
}
# Vérification de l'exclusion des montages (NFS) dans les sauvegardes
check_evobackup_exclude_mount() {
excludes_file=$(mktemp --tmpdir="${TMPDIR:-/tmp}" "evocheck.evobackup_exclude_mount.XXXXX")
files_to_cleanup="${files_to_cleanup} ${excludes_file}"
# shellcheck disable=SC2044
for evobackup_file in $(find /etc/cron* -name '*evobackup*' | grep -v -E ".disabled$"); do
# if the file seems to be a backup script, with an Rsync invocation
if grep -q "^\s*rsync" "${evobackup_file}"; then
# If rsync is not limited by "one-file-system"
# then we verify that every mount is excluded
if ! grep -q -- "^\s*--one-file-system" "${evobackup_file}"; then
grep -- "--exclude " "${evobackup_file}" | grep -E -o "\"[^\"]+\"" | tr -d '"' > "${excludes_file}"
not_excluded=$(findmnt --type nfs,nfs4,fuse.sshfs, -o target --noheadings | grep -v -f "${excludes_file}")
for mount in ${not_excluded}; do
failed "IS_EVOBACKUP_EXCLUDE_MOUNT" "${mount} is not excluded from ${evobackup_file} backup script"
done
fi
fi
done
}
# Verification de la presence du userlogrotate
check_userlogrotate() {
if is_pack_web; then
test -x /etc/cron.weekly/userlogrotate || failed "IS_USERLOGROTATE" "missing userlogrotate cron"
fi
}
# Verification de la syntaxe de la conf d'Apache
check_apachectl() {
if is_installed apache2; then
/usr/sbin/apache2ctl configtest 2>&1 | grep -q "^Syntax OK$" \
|| failed "IS_APACHECTL" "apache errors detected, run a configtest"
fi
}
# Check if there is regular files in Apache sites-enabled.
check_apachesymlink() {
if is_installed apache2; then
apacheFind=$(find /etc/apache2/sites-enabled ! -type l -type f -print)
nbApacheFind=$(wc -m <<< "$apacheFind")
if [[ $nbApacheFind -gt 1 ]]; then
if [[ $VERBOSE == 1 ]]; then
while read -r line; do
failed "IS_APACHESYMLINK" "Not a symlink: $line"
done <<< "$apacheFind"
else
failed "IS_APACHESYMLINK"
fi
fi
fi
}
# Check if there is real IP addresses in Allow/Deny directives (no trailing space, inline comments or so).
check_apacheipinallow() {
# Note: Replace "exit 1" by "print" in Perl code to debug it.
if is_installed apache2; then
grep -IrE "^[^#] *(Allow|Deny) from" /etc/apache2/ \
| grep -iv "from all" \
| grep -iv "env=" \
| perl -ne 'exit 1 unless (/from( [\da-f:.\/]+)+$/i)' \
|| failed "IS_APACHEIPINALLOW" "bad (Allow|Deny) directives in apache"
fi
}
# Check if default Apache configuration file for munin is absent (or empty or commented).
check_muninapacheconf() {
muninconf="/etc/apache2/conf.d/munin"
if is_installed apache2; then
test -e $muninconf && grep -vEq "^( |\t)*#" "$muninconf" \
&& failed "IS_MUNINAPACHECONF" "default munin configuration may be commented or disabled"
fi
}
# Check if default Apache configuration file for phpMyAdmin is absent (or empty or commented).
check_phpmyadminapacheconf() {
phpmyadminconf0="/etc/apache2/conf-available/phpmyadmin.conf"
phpmyadminconf1="/etc/apache2/conf-enabled/phpmyadmin.conf"
if is_installed apache2; then
test -e $phpmyadminconf0 && grep -vEq "^( |\t)*#" "$phpmyadminconf0" \
&& failed "IS_PHPMYADMINAPACHECONF" "default phpmyadmin configuration ($phpmyadminconf0) may be commented or disabled"
test -e $phpmyadminconf1 && grep -vEq "^( |\t)*#" "$phpmyadminconf1" \
&& failed "IS_PHPMYADMINAPACHECONF" "default phpmyadmin configuration ($phpmyadminconf1) may be commented or disabled"
fi
}
# Verification si le système doit redémarrer suite màj kernel.
check_kerneluptodate() {
if is_installed linux-image*; then
# shellcheck disable=SC2012
kernel_installed_at=$(date -d "$(ls --full-time -lcrt /boot | tail -n1 | awk '{print $6}')" +%s)
last_reboot_at=$(($(date +%s) - $(cut -f1 -d '.' /proc/uptime)))
if [ "$kernel_installed_at" -gt "$last_reboot_at" ]; then
failed "IS_KERNELUPTODATE" "machine is running an outdated kernel, reboot advised"
fi
fi
}
# Check if the server is running for more than a year.
check_uptime() {
if is_installed linux-image*; then
limit=$(date -d "now - 2 year" +%s)
last_reboot_at=$(($(date +%s) - $(cut -f1 -d '.' /proc/uptime)))
if [ "$limit" -gt "$last_reboot_at" ]; then
failed "IS_UPTIME" "machine has an uptime of more than 2 years, reboot on new kernel advised"
fi
fi
}
# Check if munin-node running and RRD files are up to date.
check_muninrunning() {
if ! pgrep munin-node >/dev/null; then
failed "IS_MUNINRUNNING" "Munin is not running"
elif [ -d "/var/lib/munin/" ] && [ -d "/var/cache/munin/" ]; then
limit=$(date +"%s" -d "now - 10 minutes")
if [ -n "$(find /var/lib/munin/ -name '*load-g.rrd')" ]; then
updated_at=$(stat -c "%Y" /var/lib/munin/*/*load-g.rrd |sort |tail -1)
[ "$limit" -gt "$updated_at" ] && failed "IS_MUNINRUNNING" "Munin load RRD has not been updated in the last 10 minutes"
else
failed "IS_MUNINRUNNING" "Munin is not installed properly (load RRD not found)"
fi
if [ -n "$(find /var/cache/munin/www/ -name 'load-day.png')" ]; then
updated_at=$(stat -c "%Y" /var/cache/munin/www/*/*/load-day.png |sort |tail -1)
grep -sq "^graph_strategy cron" /etc/munin/munin.conf && [ "$limit" -gt "$updated_at" ] && failed "IS_MUNINRUNNING" "Munin load PNG has not been updated in the last 10 minutes"
else
failed "IS_MUNINRUNNING" "Munin is not installed properly (load PNG not found)"
fi
else
failed "IS_MUNINRUNNING" "Munin is not installed properly (main directories are missing)"
fi
}
# Check if files in /home/backup/ are up-to-date
check_backupuptodate() {
backup_dir="/home/backup"
if [ -d "${backup_dir}" ]; then
if [ -n "$(ls -A ${backup_dir})" ]; then
find "${backup_dir}" -maxdepth 1 -type f | while read -r file; do
limit=$(date +"%s" -d "now - 2 day")
updated_at=$(stat -c "%Y" "$file")
if [ "$limit" -gt "$updated_at" ]; then
failed "IS_BACKUPUPTODATE" "$file has not been backed up"
test "${VERBOSE}" = 1 || break;
fi
done
else
failed "IS_BACKUPUPTODATE" "${backup_dir}/ is empty"
fi
else
failed "IS_BACKUPUPTODATE" "${backup_dir}/ is missing"
fi
}
check_etcgit() {
export GIT_DIR="/etc/.git" GIT_WORK_TREE="/etc"
git rev-parse --is-inside-work-tree > /dev/null 2>&1 \
|| failed "IS_ETCGIT" "/etc is not a git repository"
}
# Check if /etc/.git/ has read/write permissions for root only.
check_gitperms() {
GIT_DIR="/etc/.git"
if test -d $GIT_DIR; then
expected="700"
actual=$(stat -c "%a" $GIT_DIR)
[ "$expected" = "$actual" ] || failed "IS_GITPERMS" "$GIT_DIR must be $expected"
fi
}
# Check if no package has been upgraded since $limit.
check_notupgraded() {
last_upgrade=0
upgraded=false
for log in /var/log/dpkg.log*; do
if zgrep -qsm1 upgrade "$log"; then
# There is at least one upgrade
upgraded=true
break
fi
done
if $upgraded; then
last_upgrade=$(date +%s -d "$(zgrep -h upgrade /var/log/dpkg.log* | sort -n | tail -1 | cut -f1 -d ' ')")
fi
if grep -qs '^mailto="listupgrade-todo@' /etc/evolinux/listupgrade.cnf \
|| grep -qs -E '^[[:digit:]]+[[:space:]]+[[:digit:]]+[[:space:]]+[^\*]' /etc/cron.d/listupgrade; then
# Manual upgrade process
limit=$(date +%s -d "now - 180 days")
else
# Regular process
limit=$(date +%s -d "now - 90 days")
fi
install_date=0
if [ -d /var/log/installer ]; then
install_date=$(stat -c %Z /var/log/installer)
fi
# Check install_date if the system never received an upgrade
if [ "$last_upgrade" -eq 0 ]; then
[ "$install_date" -lt "$limit" ] && failed "IS_NOTUPGRADED" "The system has never been updated"
else
[ "$last_upgrade" -lt "$limit" ] && failed "IS_NOTUPGRADED" "The system hasn't been updated for too long"
fi
}
# Check if reserved blocks for root is at least 5% on every mounted partitions.
check_tune2fs_m5() {
min=5
parts=$(grep -E "ext(3|4)" /proc/mounts | cut -d ' ' -f1 | tr -s '\n' ' ')
FINDMNT_BIN=$(command -v findmnt)
for part in $parts; do
blockCount=$(dumpe2fs -h "$part" 2>/dev/null | grep -e "Block count:" | grep -Eo "[0-9]+")
# If buggy partition, skip it.
if [ -z "$blockCount" ]; then
continue
fi
reservedBlockCount=$(dumpe2fs -h "$part" 2>/dev/null | grep -e "Reserved block count:" | grep -Eo "[0-9]+")
# Use awk to have a rounded percentage
# python is slow, bash is unable and bc rounds weirdly
percentage=$(awk "BEGIN { pc=100*${reservedBlockCount}/${blockCount}; i=int(pc); print (pc-i<0.5)?i:i+1 }")
if [ "$percentage" -lt "${min}" ]; then
if [ -x "${FINDMNT_BIN}" ]; then
mount=$(${FINDMNT_BIN} --noheadings --first-only --output TARGET "${part}")
else
mount="unknown mount point"
fi
failed "IS_TUNE2FS_M5" "Partition ${part} (${mount}) has less than ${min}% reserved blocks (${percentage}%)"
fi
done
}
check_broadcomfirmware() {
LSPCI_BIN=$(command -v lspci)
if [ -x "${LSPCI_BIN}" ]; then
if ${LSPCI_BIN} | grep -q 'NetXtreme II'; then
{ is_installed firmware-bnx2 \
&& grep -q "^deb http://mirror.evolix.org/debian.* non-free" /etc/apt/sources.list;
} || failed "IS_BROADCOMFIRMWARE" "missing non-free repository"
fi
else
failed "IS_BROADCOMFIRMWARE" "lspci not found in ${PATH}"
fi
}
check_hardwareraidtool() {
LSPCI_BIN=$(command -v lspci)
if [ -x "${LSPCI_BIN}" ]; then
if ${LSPCI_BIN} | grep -q 'MegaRAID'; then
# shellcheck disable=SC2015
is_installed megacli && { is_installed megaclisas-status || is_installed megaraidsas-status; } \
|| failed "IS_HARDWARERAIDTOOL" "Mega tools not found"
fi
if ${LSPCI_BIN} | grep -q 'Hewlett-Packard Company Smart Array'; then
is_installed cciss-vol-status || failed "IS_HARDWARERAIDTOOL" "cciss-vol-status not installed"
fi
else
failed "IS_HARDWARERAIDTOOL" "lspci not found in ${PATH}"
fi
}
check_sql_backup() {
if (is_installed "mysql-server" || is_installed "mariadb-server"); then
# You could change the default path in /etc/evocheck.cf
SQL_BACKUP_PATH=${SQL_BACKUP_PATH:-"/home/backup/mysql.bak.gz"}
for backup_path in ${SQL_BACKUP_PATH}; do
if [ ! -f "${backup_path}" ]; then
failed "IS_SQL_BACKUP" "MySQL dump is missing (${backup_path})"
test "${VERBOSE}" = 1 || break
fi
done
fi
}
check_postgres_backup() {
if is_installed "postgresql-9*" || is_installed "postgresql-1*"; then
# If you use something like barman, you should disable this check
# You could change the default path in /etc/evocheck.cf
POSTGRES_BACKUP_PATH=${POSTGRES_BACKUP_PATH:-"/home/backup/pg.dump.bak*"}
for backup_path in ${POSTGRES_BACKUP_PATH}; do
if [ ! -f "${backup_path}" ]; then
failed "IS_POSTGRES_BACKUP" "PostgreSQL dump is missing (${backup_path})"
test "${VERBOSE}" = 1 || break
fi
done
fi
}
check_mongo_backup() {
if is_installed "mongodb-org-server"; then
# You could change the default path in /etc/evocheck.cf
MONGO_BACKUP_PATH=${MONGO_BACKUP_PATH:-"/home/backup/mongodump"}
if [ -d "$MONGO_BACKUP_PATH" ]; then
for file in "${MONGO_BACKUP_PATH}"/*/*.{json,bson}*; do
# Skip indexes file.
if ! [[ "$file" =~ indexes ]]; then
limit=$(date +"%s" -d "now - 2 day")
updated_at=$(stat -c "%Y" "$file")
if [ -f "$file" ] && [ "$limit" -gt "$updated_at" ]; then
failed "IS_MONGO_BACKUP" "MongoDB hasn't been dumped for more than 2 days"
break
fi
fi
done
else
failed "IS_MONGO_BACKUP" "MongoDB dump directory is missing (${MONGO_BACKUP_PATH})"
fi
fi
}
check_ldap_backup() {
if is_installed slapd; then
# You could change the default path in /etc/evocheck.cf
LDAP_BACKUP_PATH=${LDAP_BACKUP_PATH:-"/home/backup/ldap.bak"}
test -f "$LDAP_BACKUP_PATH" || failed "IS_LDAP_BACKUP" "LDAP dump is missing (${LDAP_BACKUP_PATH})"
fi
}
check_redis_backup() {
if is_installed redis-server; then
# You could change the default path in /etc/evocheck.cf
# REDIS_BACKUP_PATH may contain space-separated paths, example:
# REDIS_BACKUP_PATH='/home/backup/redis-instance1/dump.rdb /home/backup/redis-instance2/dump.rdb'
REDIS_BACKUP_PATH=${REDIS_BACKUP_PATH:-"/home/backup/redis/dump.rdb"}
for file in ${REDIS_BACKUP_PATH}; do
test -f "${file}" || failed "IS_REDIS_BACKUP" "Redis dump is missing (${file})"
done
fi
}
check_elastic_backup() {
if is_installed elasticsearch; then
# You could change the default path in /etc/evocheck.cf
ELASTIC_BACKUP_PATH=${ELASTIC_BACKUP_PATH:-"/home/backup-elasticsearch"}
test -d "$ELASTIC_BACKUP_PATH" || failed "IS_ELASTIC_BACKUP" "Elastic snapshot is missing (${ELASTIC_BACKUP_PATH})"
fi
}
check_duplicate_fs_label() {
# Do it only if thereis blkid binary
BLKID_BIN=$(command -v blkid)
if [ -n "$BLKID_BIN" ]; then
tmpFile=$(mktemp --tmpdir="${TMPDIR:-/tmp}" "evocheck.duplicate_fs_label.XXXXX")
files_to_cleanup="${files_to_cleanup} ${tmpFile}"
parts=$($BLKID_BIN -c /dev/null | grep -ve raid_member -e EFI_SYSPART | grep -Eo ' LABEL=".*"' | cut -d'"' -f2)
for part in $parts; do
echo "$part" >> "$tmpFile"
done
tmpOutput=$(sort < "$tmpFile" | uniq -d)
# If there is no duplicate, uniq will have no output
# So, if $tmpOutput is not null, there is a duplicate
if [ -n "$tmpOutput" ]; then
# shellcheck disable=SC2086
labels=$(echo -n $tmpOutput | tr '\n' ' ')
failed "IS_DUPLICATE_FS_LABEL" "Duplicate labels: $labels"
fi
else
failed "IS_DUPLICATE_FS_LABEL" "blkid not found in ${PATH}"
fi
}
check_evolix_user() {
grep -q -E "^evolix:" /etc/passwd \
&& failed "IS_EVOLIX_USER" "evolix user should be deleted, used only for install"
}
check_old_home_dir() {
homeDir=${homeDir:-/home}
for dir in "$homeDir"/*; do
statResult=$(stat -c "%n has owner %u resolved as %U" "$dir" \
| grep -Eve '.bak' -e '\.[0-9]{2}-[0-9]{2}-[0-9]{4}' \
| grep "UNKNOWN")
# There is at least one dir matching
if [[ -n "$statResult" ]]; then
failed "IS_OLD_HOME_DIR" "$statResult"
test "${VERBOSE}" = 1 || break
fi
done
}
check_tmp_1777() {
actual=$(stat --format "%a" /tmp)
expected="1777"
test "$expected" = "$actual" || failed "IS_TMP_1777" "/tmp must be $expected"
}
check_root_0700() {
actual=$(stat --format "%a" /root)
expected="700"
test "$expected" = "$actual" || failed "IS_ROOT_0700" "/root must be $expected"
}
check_usrsharescripts() {
actual=$(stat --format "%a" /usr/share/scripts)
expected="700"
test "$expected" = "$actual" || failed "IS_USRSHARESCRIPTS" "/usr/share/scripts must be $expected"
}
check_sshpermitrootno() {
# shellcheck disable=SC2086
if ! (sshd -T 2> /dev/null | grep -qi 'permitrootlogin no'); then
failed "IS_SSHPERMITROOTNO" "PermitRoot should be set to no"
fi
}
check_evomaintenanceusers() {
if [ -f /etc/sudoers.d/evolinux ]; then
sudoers="/etc/sudoers.d/evolinux"
else
sudoers="/etc/sudoers"
fi
# combine users from User_Alias and sudo group
users=$({ grep "^User_Alias *ADMIN" $sudoers | cut -d= -f2 | tr -d " "; grep "^sudo" /etc/group | cut -d: -f 4; } | tr "," "\n" | sort -u)
for user in $users; do
user_home=$(getent passwd "$user" | cut -d: -f6)
if [ -n "$user_home" ] && [ -d "$user_home" ]; then
if ! grep -qs "^trap.*sudo.*evomaintenance.sh" "${user_home}"/.*profile; then
failed "IS_EVOMAINTENANCEUSERS" "${user} doesn't have an evomaintenance trap"
test "${VERBOSE}" = 1 || break
fi
fi
done
}
check_evomaintenanceconf() {
f=/etc/evomaintenance.cf
if [ -e "$f" ]; then
perms=$(stat -c "%a" $f)
test "$perms" = "600" || failed "IS_EVOMAINTENANCECONF" "Wrong permissions on \`$f' ($perms instead of 600)"
{ grep "^export PGPASSWORD" $f | grep -qv "your-passwd" \
&& grep "^PGDB" $f | grep -qv "your-db" \
&& grep "^PGTABLE" $f | grep -qv "your-table" \
&& grep "^PGHOST" $f | grep -qv "your-pg-host" \
&& grep "^FROM" $f | grep -qv "jdoe@example.com" \
&& grep "^FULLFROM" $f | grep -qv "John Doe <jdoe@example.com>" \
&& grep "^URGENCYFROM" $f | grep -qv "mama.doe@example.com" \
&& grep "^URGENCYTEL" $f | grep -qv "06.00.00.00.00" \
&& grep "^REALM" $f | grep -qv "example.com"
} || failed "IS_EVOMAINTENANCECONF" "evomaintenance is not correctly configured"
else
failed "IS_EVOMAINTENANCECONF" "Configuration file \`$f' is missing"
fi
}
check_privatekeyworldreadable() {
# a simple globbing fails if directory is empty
if [ -n "$(ls -A /etc/ssl/private/)" ]; then
for f in /etc/ssl/private/*; do
perms=$(stat -L -c "%a" "$f")
if [ "${perms: -1}" != 0 ]; then
failed "IS_PRIVKEYWOLRDREADABLE" "$f is world-readable"
test "${VERBOSE}" = 1 || break
fi
done
fi
}
check_evobackup_incs() {
if is_installed bkctld; then
bkctld_cron_file=${bkctld_cron_file:-/etc/cron.d/bkctld}
if [ -f "${bkctld_cron_file}" ]; then
root_crontab=$(grep -v "^#" "${bkctld_cron_file}")
echo "${root_crontab}" | grep -q "bkctld inc" || failed "IS_EVOBACKUP_INCS" "\`bkctld inc' is missing in ${bkctld_cron_file}"
echo "${root_crontab}" | grep -qE "(check-incs.sh|bkctld check-incs)" || failed "IS_EVOBACKUP_INCS" "\`check-incs.sh' is missing in ${bkctld_cron_file}"
else
failed "IS_EVOBACKUP_INCS" "Crontab \`${bkctld_cron_file}' is missing"
fi
fi
}
check_osprober() {
if is_installed os-prober qemu-kvm; then
failed "IS_OSPROBER" \
"Removal of os-prober package is recommended as it can cause serious issue on KVM server"
fi
}
check_apt_valid_until() {
aptvalidFile="/etc/apt/apt.conf.d/99no-check-valid-until"
aptvalidText="Acquire::Check-Valid-Until no;"
if grep -qs "archive.debian.org" /etc/apt/sources.list /etc/apt/sources.list.d/*; then
if ! grep -qs "$aptvalidText" /etc/apt/apt.conf.d/*; then
failed "IS_APT_VALID_UNTIL" \
"As you use archive.mirror.org you need ${aptvalidFile}: ${aptvalidText}"
fi
fi
}
check_chrooted_binary_uptodate() {
# list of processes to check
process_list="sshd"
for process_name in ${process_list}; do
# what is the binary path?
original_bin=$(command -v "${process_name}")
for pid in $(pgrep ${process_name}); do
process_bin=$(realpath "/proc/${pid}/exe")
# Is the process chrooted?
real_root=$(realpath "/proc/${pid}/root")
if [ "${real_root}" != "/" ]; then
chrooted_md5=$(md5sum "${process_bin}" | cut -f 1 -d ' ')
original_md5=$(md5sum "${original_bin}" | cut -f 1 -d ' ')
# compare md5 checksums
if [ "$original_md5" != "$chrooted_md5" ]; then
failed "IS_CHROOTED_BINARY_UPTODATE" "${process_bin} (${pid}) is different than ${original_bin}."
test "${VERBOSE}" = 1 || break
fi
fi
done
done
}
check_lxc_container_resolv_conf() {
if is_installed lxc; then
container_list=$(lxc-ls)
current_resolvers=$(grep nameserver /etc/resolv.conf | sed 's/nameserver//g' )
for container in $container_list; do
if [ -f "/var/lib/lxc/${container}/rootfs/etc/resolv.conf" ]; then
while read -r resolver; do
if ! grep -qE "^nameserver\s+${resolver}" "/var/lib/lxc/${container}/rootfs/etc/resolv.conf"; then
failed "IS_LXC_CONTAINER_RESOLV_CONF" "resolv.conf miss-match beween host and container : missing nameserver ${resolver} in container ${container} resolv.conf"
fi
done <<< "${current_resolvers}"
else
failed "IS_LXC_CONTAINER_RESOLV_CONF" "resolv.conf missing in container ${container}"
fi
done
fi
}
download_versions() {
local file
file=${1:-}
## The file is supposed to list programs : each on a line, then its latest version number
## Examples:
# evoacme 21.06
# evomaintenance 0.6.4
versions_url="https://upgrades.evolix.org/versions-${DEBIAN_RELEASE}"
# fetch timeout, in seconds
timeout=10
if command -v curl > /dev/null; then
curl --max-time ${timeout} --fail --silent --output "${versions_file}" "${versions_url}"
elif command -v wget > /dev/null; then
wget --timeout=${timeout} --quiet "${versions_url}" -O "${versions_file}"
elif command -v GET; then
GET -t ${timeout}s "${versions_url}" > "${versions_file}"
else
failed "IS_CHECK_VERSIONS" "failed to find curl, wget or GET"
fi
test "$?" -eq 0 || failed "IS_CHECK_VERSIONS" "failed to download ${versions_url} to ${versions_file}"
}
get_command() {
local program
program=${1:-}
case "${program}" in
## Special cases where the program name is different than the command name
evocheck) echo "${0}" ;;
evomaintenance) command -v "evomaintenance.sh" ;;
listupgrade) command -v "evolistupgrade.sh" ;;
old-kernel-autoremoval) command -v "old-kernel-autoremoval.sh" ;;
mysql-queries-killer) command -v "mysql-queries-killer.sh" ;;
minifirewall) echo "/etc/init.d/minifirewall" ;;
## General case, where the program name is the same as the command name
*) command -v "${program}" ;;
esac
}
get_version() {
local program
local command
program=${1:-}
command=${2:-}
case "${program}" in
## Special case if `command --version => 'command` is not the standard way to get the version
# my_command)
# /path/to/my_command --get-version
# ;;
add-vm)
grep '^VERSION=' "${command}" | head -1 | cut -d '=' -f 2
;;
minifirewall)
${command} version | head -1 | cut -d ' ' -f 3
;;
## Let's try the --version flag before falling back to grep for the constant
kvmstats)
if ${command} --version > /dev/null 2> /dev/null; then
${command} --version 2> /dev/null | head -1 | cut -d ' ' -f 3
else
grep '^VERSION=' "${command}" | head -1 | cut -d '=' -f 2
fi
;;
## General case to get the version
*) ${command} --version 2> /dev/null | head -1 | cut -d ' ' -f 3 ;;
esac
}
check_version() {
local program
local expected_version
program=${1:-}
expected_version=${2:-}
command=$(get_command "${program}")
if [ -n "${command}" ]; then
# shellcheck disable=SC2086
actual_version=$(get_version "${program}" "${command}")
# printf "program:%s expected:%s actual:%s\n" "${program}" "${expected_version}" "${actual_version}"
if [ -z "${actual_version}" ]; then
failed "IS_CHECK_VERSIONS" "failed to lookup actual version of ${program}"
elif dpkg --compare-versions "${actual_version}" lt "${expected_version}"; then
failed "IS_CHECK_VERSIONS" "${program} version ${actual_version} is older than expected version ${expected_version}"
elif dpkg --compare-versions "${actual_version}" gt "${expected_version}"; then
failed "IS_CHECK_VERSIONS" "${program} version ${actual_version} is newer than expected version ${expected_version}, you should update your index."
else
: # Version check OK
fi
fi
}
add_to_path() {
local new_path
new_path=${1:-}
echo "$PATH" | grep -qF "${new_path}" || export PATH="${PATH}:${new_path}"
}
check_versions() {
versions_file=$(mktemp --tmpdir="${TMPDIR:-/tmp}" "evocheck.versions.XXXXX")
files_to_cleanup="${files_to_cleanup} ${versions_file}"
download_versions "${versions_file}"
add_to_path "/usr/share/scripts"
grep -v '^ *#' < "${versions_file}" | while IFS= read -r line; do
local program
local version
program=$(echo "${line}" | cut -d ' ' -f 1)
version=$(echo "${line}" | cut -d ' ' -f 2)
if [ -n "${program}" ]; then
if [ -n "${version}" ]; then
check_version "${program}" "${version}"
else
failed "IS_CHECK_VERSIONS" "failed to lookup expected version for ${program}"
fi
fi
done
}
main() {
# Default return code : 0 = no error
RC=0
# Detect operating system name, version and release
detect_os
main_output_file=$(mktemp --tmpdir="${TMPDIR:-/tmp}" "evocheck.main.XXXXX")
files_to_cleanup="${files_to_cleanup} ${main_output_file}"
test "${IS_TMP_1777:=1}" = 1 && check_tmp_1777
test "${IS_ROOT_0700:=1}" = 1 && check_root_0700
test "${IS_USRSHARESCRIPTS:=1}" = 1 && check_usrsharescripts
test "${IS_SSHPERMITROOTNO:=1}" = 1 && check_sshpermitrootno
test "${IS_EVOMAINTENANCEUSERS:=1}" = 1 && check_evomaintenanceusers
# Verification de la configuration d'evomaintenance
test "${IS_EVOMAINTENANCECONF:=1}" = 1 && check_evomaintenanceconf
test "${IS_PRIVKEYWOLRDREADABLE:=1}" = 1 && check_privatekeyworldreadable
test "${IS_LSBRELEASE:=1}" = 1 && check_lsbrelease
test "${IS_DPKGWARNING:=1}" = 1 && check_dpkgwarning
test "${IS_NRPEPOSTFIX:=1}" = 1 && check_nrpepostfix
test "${IS_MODSECURITY:=1}" = 1 && check_modsecurity
test "${IS_CUSTOMSUDOERS:=1}" = 1 && check_customsudoers
test "${IS_VARTMPFS:=1}" = 1 && check_vartmpfs
test "${IS_SERVEURBASE:=1}" = 1 && check_serveurbase
test "${IS_LOGROTATECONF:=1}" = 1 && check_logrotateconf
test "${IS_SYSLOGCONF:=1}" = 1 && check_syslogconf
test "${IS_DEBIANSECURITY:=1}" = 1 && check_debiansecurity
test "${IS_APTITUDEONLY:=1}" = 1 && check_aptitudeonly
test "${IS_APTICRON:=0}" = 1 && check_apticron
test "${IS_USRRO:=1}" = 1 && check_usrro
test "${IS_TMPNOEXEC:=1}" = 1 && check_tmpnoexec
test "${IS_MOUNT_FSTAB:=1}" = 1 && check_mountfstab
test "${IS_LISTCHANGESCONF:=1}" = 1 && check_listchangesconf
test "${IS_CUSTOMCRONTAB:=1}" = 1 && check_customcrontab
test "${IS_SSHALLOWUSERS:=1}" = 1 && check_sshallowusers
test "${IS_DISKPERF:=0}" = 1 && check_diskperf
test "${IS_TMOUTPROFILE:=1}" = 1 && check_tmoutprofile
test "${IS_ALERT5BOOT:=1}" = 1 && check_alert5boot
test "${IS_ALERT5MINIFW:=1}" = 1 && check_alert5minifw
test "${IS_ALERT5MINIFW:=1}" = 1 && test "${IS_MINIFW:=1}" = 1 && check_minifw
test "${IS_NRPEPERMS:=1}" = 1 && check_nrpeperms
test "${IS_MINIFWPERMS:=1}" = 1 && check_minifwperms
test "${IS_NRPEDISKS:=0}" = 1 && check_nrpedisks
test "${IS_NRPEPID:=1}" = 1 && check_nrpepid
test "${IS_GRSECPROCS:=1}" = 1 && check_grsecprocs
test "${IS_APACHEMUNIN:=1}" = 1 && check_apachemunin
test "${IS_MYSQLUTILS:=1}" = 1 && check_mysqlutils
test "${IS_RAIDSOFT:=1}" = 1 && check_raidsoft
test "${IS_AWSTATSLOGFORMAT:=1}" = 1 && check_awstatslogformat
test "${IS_MUNINLOGROTATE:=1}" = 1 && check_muninlogrotate
test "${IS_SQUID:=1}" = 1 && check_squid
test "${IS_EVOMAINTENANCE_FW:=1}" = 1 && check_evomaintenance_fw
test "${IS_MODDEFLATE:=1}" = 1 && check_moddeflate
test "${IS_LOG2MAILRUNNING:=1}" = 1 && check_log2mailrunning
test "${IS_LOG2MAILAPACHE:=1}" = 1 && check_log2mailapache
test "${IS_LOG2MAILMYSQL:=1}" = 1 && check_log2mailmysql
test "${IS_LOG2MAILSQUID:=1}" = 1 && check_log2mailsquid
test "${IS_BINDCHROOT:=1}" = 1 && check_bindchroot
test "${IS_NETWORK_INTERFACES:=1}" = 1 && check_network_interfaces
test "${IS_AUTOIF:=1}" = 1 && check_autoif
test "${IS_INTERFACESGW:=1}" = 1 && check_interfacesgw
test "${IS_EVOBACKUP:=1}" = 1 && check_evobackup
test "${IS_EVOBACKUP_EXCLUDE_MOUNT:=1}" = 1 && check_evobackup_exclude_mount
test "${IS_USERLOGROTATE:=1}" = 1 && check_userlogrotate
test "${IS_APACHECTL:=1}" = 1 && check_apachectl
test "${IS_APACHESYMLINK:=1}" = 1 && check_apachesymlink
test "${IS_APACHEIPINALLOW:=1}" = 1 && check_apacheipinallow
test "${IS_MUNINAPACHECONF:=1}" = 1 && check_muninapacheconf
test "${IS_PHPMYADMINAPACHECONF:=1}" = 1 && check_phpmyadminapacheconf
test "${IS_KERNELUPTODATE:=1}" = 1 && check_kerneluptodate
test "${IS_UPTIME:=1}" = 1 && check_uptime
test "${IS_MUNINRUNNING:=1}" = 1 && check_muninrunning
test "${IS_BACKUPUPTODATE:=1}" = 1 && check_backupuptodate
test "${IS_ETCGIT:=1}" = 1 && check_etcgit
test "${IS_GITPERMS:=1}" = 1 && check_gitperms
test "${IS_NOTUPGRADED:=1}" = 1 && check_notupgraded
test "${IS_TUNE2FS_M5:=1}" = 1 && check_tune2fs_m5
test "${IS_BROADCOMFIRMWARE:=1}" = 1 && check_broadcomfirmware
test "${IS_HARDWARERAIDTOOL:=1}" = 1 && check_hardwareraidtool
test "${IS_SQL_BACKUP:=1}" = 1 && check_sql_backup
test "${IS_POSTGRES_BACKUP:=1}" = 1 && check_postgres_backup
test "${IS_MONGO_BACKUP:=1}" = 1 && check_mongo_backup
test "${IS_LDAP_BACKUP:=1}" = 1 && check_ldap_backup
test "${IS_REDIS_BACKUP:=1}" = 1 && check_redis_backup
test "${IS_ELASTIC_BACKUP:=1}" = 1 && check_elastic_backup
test "${IS_DUPLICATE_FS_LABEL:=1}" = 1 && check_duplicate_fs_label
test "${IS_EVOLIX_USER:=1}" = 1 && check_evolix_user
test "${IS_OLD_HOME_DIR:=0}" = 1 && check_old_home_dir
test "${IS_EVOBACKUP_INCS:=1}" = 1 && check_evobackup_incs
test "${IS_OSPROBER:=1}" = 1 && check_osprober
test "${IS_APT_VALID_UNTIL:=1}" = 1 && check_apt_valid_until
test "${IS_CHROOTED_BINARY_UPTODATE:=1}" = 1 && check_chrooted_binary_uptodate
test "${IS_CHECK_VERSIONS:=1}" = 1 && check_versions
if [ -f "${main_output_file}" ]; then
lines_found=$(wc -l < "${main_output_file}")
# shellcheck disable=SC2086
if [ ${lines_found} -gt 0 ]; then
cat "${main_output_file}" 2>&1
fi
fi
exit ${RC}
}
cleanup_temp_files() {
# shellcheck disable=SC2086
rm -f ${files_to_cleanup}
}
PROGNAME=$(basename "$0")
# shellcheck disable=SC2034
readonly PROGNAME
# shellcheck disable=SC2124
ARGS=$@
readonly ARGS
# Disable LANG*
export LANG=C
export LANGUAGE=C
files_to_cleanup=""
# shellcheck disable=SC2064
trap cleanup_temp_files 0
# Source configuration file
# shellcheck disable=SC1091
test -f /etc/evocheck.cf && . /etc/evocheck.cf
# Parse options
# based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
while :; do
case $1 in
-h|-\?|--help)
show_help
exit 0
;;
--version)
show_version
exit 0
;;
--cron)
IS_KERNELUPTODATE=0
IS_UPTIME=0
IS_MELTDOWN_SPECTRE=0
IS_CHECK_VERSIONS=0
IS_NETWORKING_SERVICE=0
;;
-v|--verbose)
VERBOSE=1
;;
-q|--quiet)
QUIET=1
VERBOSE=0
;;
--)
# End of all options.
shift
break
;;
-?*|[[:alnum:]]*)
# ignore unknown options
if [ "${QUIET}" != 1 ]; then
printf 'WARN: Unknown option (ignored): %s\n' "$1" >&2
fi
;;
*)
# Default case: If no more options then break out of the loop.
break
;;
esac
shift
done
# shellcheck disable=SC2086
main ${ARGS}

View File

@ -15,9 +15,24 @@
tags: tags:
- evocheck - evocheck
- name: Script for Debian 7 and earlier
set_fact:
evocheck_script_src: evocheck.wheezy.sh
when: ansible_distribution_major_version is version('7', '<=')
- name: Script for Debian 8
set_fact:
evocheck_script_src: evocheck.jessie.sh
when: ansible_distribution_major_version is version('8', '=')
- name: Script for Debian 9 and later
set_fact:
evocheck_script_src: evocheck.sh
when: ansible_distribution_major_version is version('9', '>=')
- name: Copy evocheck.sh - name: Copy evocheck.sh
copy: copy:
src: evocheck.sh src: "{{ evocheck_script_src }}"
dest: "{{ evocheck_bin_dir }}/evocheck.sh" dest: "{{ evocheck_bin_dir }}/evocheck.sh"
mode: "0700" mode: "0700"
owner: root owner: root

View File

@ -21,6 +21,8 @@ evolinux_apt_public_sources: True
evolinux_apt_upgrade: True evolinux_apt_upgrade: True
evolinux_apt_remove_aptitude: True evolinux_apt_remove_aptitude: True
apt_keyring_dir: "{{ ansible_distribution_major_version is version('12', '<') | ternary('/etc/apt/trusted.gpg.d', '/etc/apt/keyrings') }}"
# etc-evolinux # etc-evolinux
evolinux_etcevolinux_include: True evolinux_etcevolinux_include: True
@ -48,6 +50,7 @@ evolinux_internal_fqdn: "{{ evolinux_internal_hostname }}.{{ evolinux_intern
evolinux_kernel_include: True evolinux_kernel_include: True
evolinux_kernel_cloud_auto: True
evolinux_kernel_reboot_after_panic: True evolinux_kernel_reboot_after_panic: True
evolinux_kernel_disable_tcp_timestamps: True evolinux_kernel_disable_tcp_timestamps: True
evolinux_kernel_customize_swappiness: True evolinux_kernel_customize_swappiness: True
@ -224,3 +227,6 @@ evolinux_cron_checkhpraid_frequency: daily
# Motd # Motd
evolinux_motd_include: True evolinux_motd_include: True
# Utils
evolinux_utils_include: True

View File

@ -81,7 +81,7 @@
- name: HPE GPG key is installed - name: HPE GPG key is installed
copy: copy:
src: hpePublicKey2048_key1.asc src: hpePublicKey2048_key1.asc
dest: /etc/apt/trusted.gpg.d/hpePublicKey2048_key1.asc dest: "{{ apt_keyring_dir }}/hpePublicKey2048_key1.asc"
force: yes force: yes
mode: "0644" mode: "0644"
owner: root owner: root
@ -91,11 +91,18 @@
- name: Add HPE repository - name: Add HPE repository
apt_repository: apt_repository:
repo: 'deb https://downloads.linux.hpe.com/SDR/repo/mcp {{ ansible_distribution_release }}/current non-free' repo: 'deb [signed-by={{ apt_keyring_dir }}/hpePublicKey2048_key1.asc] https://downloads.linux.hpe.com/SDR/repo/mcp {{ ansible_distribution_release }}/current non-free'
state: present state: present
tags: tags:
- packages - packages
- name: Remove unsigned HPE repository
apt_repository:
repo: 'deb https://downloads.linux.hpe.com/SDR/repo/mcp {{ ansible_distribution_release }}/current non-free'
state: absent
tags:
- packages
- name: Install HPE Smart Storage Administrator (ssacli) - name: Install HPE Smart Storage Administrator (ssacli)
apt: apt:
name: ssacli name: ssacli
@ -208,7 +215,7 @@
- name: HWRaid GPG key is installed - name: HWRaid GPG key is installed
copy: copy:
src: hwraid.le-vert.net.asc src: hwraid.le-vert.net.asc
dest: /etc/apt/trusted.gpg.d/hwraid.le-vert.net.asc dest: "{{ apt_keyring_dir }}/hwraid.le-vert.net.asc"
force: yes force: yes
mode: "0644" mode: "0644"
owner: root owner: root
@ -219,11 +226,18 @@
- name: Add HW tool repository - name: Add HW tool repository
apt_repository: apt_repository:
repo: 'deb http://hwraid.le-vert.net/debian {{ ansible_distribution_release }} main' repo: 'deb [signed-by={{ apt_keyring_dir }}/hwraid.le-vert.net.asc] http://hwraid.le-vert.net/debian {{ ansible_distribution_release }} main'
state: present state: present
tags: tags:
- packages - packages
- name: Remove unsigned HW tool repository
apt_repository:
repo: 'deb http://hwraid.le-vert.net/debian {{ ansible_distribution_release }} main'
state: absent
tags:
- packages
- name: Install packages for DELL/LSI hardware - name: Install packages for DELL/LSI hardware
apt: apt:
name: name:

View File

@ -1,6 +0,0 @@
---
- name: Deploy htop configuration
copy:
src: htoprc
dest: /etc/htoprc
mode: "0644"

View File

@ -1,5 +1,23 @@
--- ---
- name: "Use Cloud kernel on virtual servers"
apt:
name: "linux-image-cloud-amd64"
state: present
when:
- ansible_machine == "x86_64"
- ansible_virtualization_role == "guest"
- evolinux_kernel_cloud_auto | bool
- name: "Remove non-Cloud kernel on virtual servers"
apt:
name: "linux-image-amd64"
state: absent
when:
- ansible_machine == "x86_64"
- ansible_virtualization_role == "guest"
- evolinux_kernel_cloud_auto | bool
- name: Reboot after panic - name: Reboot after panic
sysctl: sysctl:
name: "{{ item.name }}" name: "{{ item.name }}"

View File

@ -102,6 +102,7 @@
when: evolinux_motd_include | bool when: evolinux_motd_include | bool
- include: utils.yml - include: utils.yml
when: evolinux_utils_include | bool
- name: Munin - name: Munin
include_role: include_role:
@ -132,7 +133,3 @@
include_role: include_role:
name: evolix/generate-ldif name: evolix/generate-ldif
when: evolinux_generateldif_include | bool when: evolinux_generateldif_include | bool
- include: top.yml
- include: htop.yml

View File

@ -1,5 +0,0 @@
---
- name: Deploy top configuration file
file:
path: /etc/topdefaultrc
state: absent

View File

@ -37,4 +37,15 @@
# force: True # force: True
# owner: root # owner: root
# group: root # group: root
# mode: "0755" # mode: "0755"
- name: Deploy htop configuration
copy:
src: htoprc
dest: /etc/htoprc
mode: "0644"
- name: Deploy top configuration file
file:
path: /etc/topdefaultrc
state: absent

View File

@ -5,6 +5,7 @@
dest: /etc/evolinux dest: /etc/evolinux
mode: "0700" mode: "0700"
state: directory state: directory
when: ansible_distribution == "Debian"
- name: /etc/evolinux/todo.txt is present - name: /etc/evolinux/todo.txt is present
copy: copy:
@ -12,3 +13,4 @@
dest: /etc/evolinux/todo.txt dest: /etc/evolinux/todo.txt
mode: "0640" mode: "0640"
force: no force: no
when: ansible_distribution == "Debian"

View File

@ -12,7 +12,8 @@ nagios ALL = NOPASSWD: /usr/local/lib/nagios/plugins/check_phpfpm_multi
nagios ALL = NOPASSWD: /usr/local/lib/nagios/plugins/check_phpfpm_multi /var/lib/lxc/php70/rootfs/etc/php/7.0/fpm/pool.d/ nagios ALL = NOPASSWD: /usr/local/lib/nagios/plugins/check_phpfpm_multi /var/lib/lxc/php70/rootfs/etc/php/7.0/fpm/pool.d/
nagios ALL = NOPASSWD: /usr/local/lib/nagios/plugins/check_phpfpm_multi /var/lib/lxc/php73/rootfs/etc/php/7.3/fpm/pool.d/ nagios ALL = NOPASSWD: /usr/local/lib/nagios/plugins/check_phpfpm_multi /var/lib/lxc/php73/rootfs/etc/php/7.3/fpm/pool.d/
nagios ALL = NOPASSWD: /usr/local/lib/nagios/plugins/check_phpfpm_multi /var/lib/lxc/php74/rootfs/etc/php/7.4/fpm/pool.d/ nagios ALL = NOPASSWD: /usr/local/lib/nagios/plugins/check_phpfpm_multi /var/lib/lxc/php74/rootfs/etc/php/7.4/fpm/pool.d/
nagios ALL = NOPASSWD: /usr/local/lib/nagios/plugins/check_phpfpm_multi /var/lib/lxc/php74/rootfs/etc/php/8.0/fpm/pool.d/ nagios ALL = NOPASSWD: /usr/local/lib/nagios/plugins/check_phpfpm_multi /var/lib/lxc/php80/rootfs/etc/php/8.0/fpm/pool.d/
nagios ALL = NOPASSWD: /usr/local/lib/nagios/plugins/check_phpfpm_multi /var/lib/lxc/php81/rootfs/etc/php/8.1/fpm/pool.d/
nagios ALL = NOPASSWD: /usr/sbin/megaclisas-status --nagios nagios ALL = NOPASSWD: /usr/sbin/megaclisas-status --nagios
nagios ALL = NOPASSWD: /usr/lib/nagios/plugins/check_ipmi_sensor nagios ALL = NOPASSWD: /usr/lib/nagios/plugins/check_ipmi_sensor
nagios ALL = NOPASSWD: /sbin/dmsetup status --noflush nagios ALL = NOPASSWD: /sbin/dmsetup status --noflush

View File

@ -5,6 +5,7 @@
- evomaintenance_api_endpoint is not none - evomaintenance_api_endpoint is not none
- evomaintenance_api_key is not none - evomaintenance_api_key is not none
msg: evomaintenance api variables must be set msg: evomaintenance api variables must be set
when: evomaintenance_hook_api | bool
- name: Configuration is installed - name: Configuration is installed
template: template:

View File

@ -11,7 +11,7 @@ FULLFROM="{{ evomaintenance_full_from }}"
URGENCYFROM={{ evomaintenance_urgency_from }} URGENCYFROM={{ evomaintenance_urgency_from }}
URGENCYTEL="{{ evomaintenance_urgency_tel }}" URGENCYTEL="{{ evomaintenance_urgency_tel }}"
REALM="{{ evomaintenance_realm }}" REALM="{{ evomaintenance_realm }}"
API_ENDPOINT={{ evomaintenance_api_endpoint }} API_ENDPOINT={{ evomaintenance_api_endpoint }}
API_KEY={{ evomaintenance_api_key }} API_KEY={{ evomaintenance_api_key }}
HOOK_API={{ evomaintenance_hook_api | bool | ternary('1','0') }} HOOK_API={{ evomaintenance_hook_api | bool | ternary('1','0') }}

View File

@ -1,3 +1,13 @@
#!/bin/sh #!/bin/sh
# Juin 2022 : #64088 # Juin - Decembre 2022 : #64088
/usr/bin/sqlite3 /var/lib/fail2ban/fail2ban.sqlite3 "DELETE FROM bans WHERE date('now', '-{{ fail2ban_recidive_bantime | default(default_dbpurgeage.stdout) }}') > datetime(timeofban, 'unixepoch'); VACUUM;" # Purge pour Stretch et Buster
/usr/bin/ionice -c3 /usr/bin/sqlite3 /var/lib/fail2ban/fail2ban.sqlite3 "DELETE FROM bans WHERE datetime('now', '-{{ bantime.stdout }} second') > datetime(timeofban, 'unixepoch');"
place_dispo=$( df -h /var/lib/fail2ban/fail2ban.sqlite3 --output="avail" -h --block-size=1 |tail -n1 )
place_pris=$( echo $(("$(stat --format %s /var/lib/fail2ban/fail2ban.sqlite3 ) * 2" )) )
if [ $place_pris -lt $place_dispo ]
then
/usr/bin/ionice -c3 /usr/bin/sqlite3 /var/lib/fail2ban/fail2ban.sqlite3 "VACUUM;"
fi

View File

@ -38,7 +38,7 @@ bantime = {{ fail2ban_recidive_bantime }}
# Evolix custom jails # Evolix custom jails
[wordpress-hard] [wordpress-hard]
enabled = {{ fail2ban_wordpress_hard }} enabled = {{ fail2ban_wordpress_hard }}
port = http, https port = http, https
filter = wordpress-hard filter = wordpress-hard
logpath = /var/log/auth.log logpath = /var/log/auth.log
@ -47,7 +47,7 @@ findtime = {{ fail2ban_wordpress_hard_findtime }}
bantime = {{ fail2ban_wordpress_hard_bantime }} bantime = {{ fail2ban_wordpress_hard_bantime }}
[wordpress-soft] [wordpress-soft]
enabled = {{ fail2ban_wordpress_soft }} enabled = {{ fail2ban_wordpress_soft }}
port = http, https port = http, https
filter = wordpress-soft filter = wordpress-soft
logpath = /var/log/auth.log logpath = /var/log/auth.log
@ -56,7 +56,7 @@ findtime = {{ fail2ban_wordpress_soft_findtime }}
bantime = {{ fail2ban_wordpress_soft_bantime }} bantime = {{ fail2ban_wordpress_soft_bantime }}
[roundcube] [roundcube]
enabled = {{ fail2ban_roundcube }} enabled = {{ fail2ban_roundcube }}
port = http, https port = http, https
filter = roundcube filter = roundcube
logpath = /var/lib/roundcube/logs/errors logpath = /var/lib/roundcube/logs/errors

View File

@ -22,3 +22,5 @@ filebeat_use_config_template: False
filebeat_update_config: True filebeat_update_config: True
filebeat_force_config: True filebeat_force_config: True
filebeat_upgrade_package: False filebeat_upgrade_package: False
apt_keyring_dir: "{{ ansible_distribution_major_version is version('12', '<') | ternary('/etc/apt/trusted.gpg.d', '/etc/apt/keyrings') }}"

View File

@ -29,7 +29,7 @@
- name: Elastic GPG key is installed - name: Elastic GPG key is installed
copy: copy:
src: elastic.asc src: elastic.asc
dest: /etc/apt/trusted.gpg.d/elastic.asc dest: "{{ apt_keyring_dir }}/elastic.asc"
force: yes force: yes
mode: "0644" mode: "0644"
owner: root owner: root
@ -40,7 +40,7 @@
- name: Elastic sources list is available - name: Elastic sources list is available
apt_repository: apt_repository:
repo: "deb https://artifacts.elastic.co/packages/{{ elastic_stack_version | mandatory }}/apt stable main" repo: "deb [signed-by={{ apt_keyring_dir }}/elastic.asc] https://artifacts.elastic.co/packages/{{ elastic_stack_version | mandatory }}/apt stable main"
filename: elastic filename: elastic
state: present state: present
update_cache: yes update_cache: yes
@ -48,6 +48,16 @@
- filebeat - filebeat
- packages - packages
- name: Unsigned Elastic sources list is not available
apt_repository:
repo: "deb https://artifacts.elastic.co/packages/{{ elastic_stack_version | mandatory }}/apt stable main"
filename: elastic
state: absent
update_cache: yes
tags:
- filebeat
- packages
- name: Filebeat is installed - name: Filebeat is installed
apt: apt:
name: filebeat name: filebeat

View File

@ -10,3 +10,5 @@ fluentd_host_port:
fluentd_flush_interval: fluentd_flush_interval:
fluentd_heartbeat_type: fluentd_heartbeat_type:
apt_keyring_dir: "{{ ansible_distribution_major_version is version('12', '<') | ternary('/etc/apt/trusted.gpg.d', '/etc/apt/keyrings') }}"

View File

@ -21,7 +21,7 @@
- name: Add Fluentd GPG key - name: Add Fluentd GPG key
copy: copy:
src: fluentd.asc src: fluentd.asc
dest: /etc/apt/trusted.gpg.d/fluentd.asc dest: "{{ apt_keyring_dir }}/fluentd.asc"
force: yes force: yes
mode: "0644" mode: "0644"
owner: root owner: root
@ -32,7 +32,7 @@
- name: Fluentd sources list is available - name: Fluentd sources list is available
apt_repository: apt_repository:
repo: "deb http://packages.treasuredata.com/3/debian/{{ ansible_distribution_release }}/ {{ ansible_distribution_release }} contrib" repo: "deb [signed-by={{ apt_keyring_dir }}/fluentd.asc] http://packages.treasuredata.com/3/debian/{{ ansible_distribution_release }}/ {{ ansible_distribution_release }} contrib"
filename: treasuredata filename: treasuredata
update_cache: yes update_cache: yes
state: present state: present
@ -40,6 +40,16 @@
- packages - packages
- fluentd - fluentd
- name: Unsigned Fluentd sources list is not available
apt_repository:
repo: "deb http://packages.treasuredata.com/3/debian/{{ ansible_distribution_release }}/ {{ ansible_distribution_release }} contrib"
filename: treasuredata
update_cache: yes
state: absent
tags:
- packages
- fluentd
- name: Fluentd is installed. - name: Fluentd is installed.
apt: apt:
name: td-agent name: td-agent

View File

@ -1,4 +1,4 @@
--- ---
java_alternative: 'openjdk' java_alternative: 'openjdk'
java_version: 8 java_version: Null
java_default_alternative: True java_default_alternative: True

View File

@ -13,7 +13,17 @@
tags: tags:
- java - java
- name: Install openjdk package - name: Install default openjdk package
apt:
name: "default-jre-headless"
default_release: "{{ java_apt_release }}"
state: present
tags:
- java
- packages
when: java_version is none
- name: Install specific openjdk package
apt: apt:
name: "openjdk-{{ java_version}}-jre-headless" name: "openjdk-{{ java_version}}-jre-headless"
default_release: "{{ java_apt_release }}" default_release: "{{ java_apt_release }}"
@ -21,11 +31,14 @@
tags: tags:
- java - java
- packages - packages
when: java_version is not none
- name: This openjdk version is the default alternative - name: This openjdk version is the default alternative
alternatives: alternatives:
name: java name: java
path: "{{ java_bin_path[java_version] }}" path: "{{ java_bin_path[java_version] }}"
when: java_default_alternative | bool
tags: tags:
- java - java
when:
- java_default_alternative | bool
- java_version is not none

View File

@ -0,0 +1,3 @@
---
apt_keyring_dir: "{{ ansible_distribution_major_version is version('12', '<') | ternary('/etc/apt/trusted.gpg.d', '/etc/apt/keyrings') }}"

View File

@ -20,17 +20,24 @@
- name: Add Jenkins GPG key - name: Add Jenkins GPG key
copy: copy:
src: jenkins.asc src: jenkins.asc
dest: /etc/apt/trusted.gpg.d/jenkins.asc dest: "{{ apt_keyring_dir }}/jenkins.asc"
force: yes force: yes
mode: "0644" mode: "0644"
owner: root owner: root
group: root group: root
- name: Add jenkins APT repository - name: Add jenkins APT repository
apt_repository:
repo: deb [signed-by={{ apt_keyring_dir }}/jenkins.asc] http://pkg.jenkins-ci.org/debian-stable binary/
filename: jenkins
update_cache: yes
- name: Remove unsigned jenkins APT repository
apt_repository: apt_repository:
repo: deb http://pkg.jenkins-ci.org/debian-stable binary/ repo: deb http://pkg.jenkins-ci.org/debian-stable binary/
filename: jenkins filename: jenkins
update_cache: yes update_cache: yes
state: absent
- name: Install Jenkins - name: Install Jenkins
apt: apt:

View File

@ -18,35 +18,38 @@ MASTER='true'
# checking if there are alive keepalived processes so we can trust the content of the notify 'state' file # checking if there are alive keepalived processes so we can trust the content of the notify 'state' file
KEEPALIVENUM=`ps uax|grep '/usr/sbin/keepalived'|grep -v grep|wc -l|tr -d "\n"` KEEPALIVENUM=`ps uax|grep '/usr/sbin/keepalived'|grep -v grep|wc -l|tr -d "\n"`
if [ $KEEPALIVENUM -gt 0 ]; then if [ ${KEEPALIVENUM} -gt 0 ]; then
KEEPALIVESTATE=`cat /var/run/keepalive.state` KEEPALIVESTATE=`cat /var/run/keepalive.state`
if [ "$MASTER" == "true" ]; then if [ "${MASTER}" == "true" ]; then
if [[ $KEEPALIVESTATE == *"MASTER"* ]];then if [[ ${KEEPALIVESTATE} == *"MASTER"* ]];then
echo $KEEPALIVESTATE echo "OK - ${KEEPALIVESTATE}"
exit 0 exit 0
fi fi
if [[ $KEEPALIVESTATE == *"BACKUP"* ]];then if [[ ${KEEPALIVESTATE} == *"BACKUP"* ]];then
echo $KEEPALIVESTATE echo "WARNING - ${KEEPALIVESTATE}"
exit 2 exit 1
fi fi
else else
if [[ $KEEPALIVESTATE == *"BACKUP"* ]];then if [[ ${KEEPALIVESTATE} == *"BACKUP"* ]];then
echo $KEEPALIVESTATE echo "OK - ${KEEPALIVESTATE}"
exit 0 exit 0
fi fi
if [[ $KEEPALIVESTATE == *"MASTER"* ]];then if [[ ${KEEPALIVESTATE} == *"MASTER"* ]];then
echo $KEEPALIVESTATE echo "WARNING - ${KEEPALIVESTATE}"
exit 2 exit 1
fi fi
fi fi
else
echo "CRITICAL - keepalived is not running"
exit 2
fi fi
echo "Keepalived is in UNKNOWN state" echo "Keepalived is in UNKNOWN state"

View File

@ -9,3 +9,5 @@ kibana_proxy_nginx: False
kibana_proxy_domain: "kibana.{{ ansible_fqdn }}" kibana_proxy_domain: "kibana.{{ ansible_fqdn }}"
kibana_proxy_ssl_cert: "/etc/ssl/certs/{{ ansible_fqdn }}.crt" kibana_proxy_ssl_cert: "/etc/ssl/certs/{{ ansible_fqdn }}.crt"
kibana_proxy_ssl_key: "/etc/ssl/private/{{ ansible_fqdn }}.key" kibana_proxy_ssl_key: "/etc/ssl/private/{{ ansible_fqdn }}.key"
apt_keyring_dir: "{{ ansible_distribution_major_version is version('12', '<') | ternary('/etc/apt/trusted.gpg.d', '/etc/apt/keyrings') }}"

View File

@ -29,7 +29,7 @@
- name: Elastic GPG key is installed - name: Elastic GPG key is installed
copy: copy:
src: elastic.asc src: elastic.asc
dest: /etc/apt/trusted.gpg.d/elastic.asc dest: "{{ apt_keyring_dir }}/elastic.asc"
force: yes force: yes
mode: "0644" mode: "0644"
owner: root owner: root
@ -40,7 +40,7 @@
- name: Elastic sources list is available - name: Elastic sources list is available
apt_repository: apt_repository:
repo: "deb https://artifacts.elastic.co/packages/{{ elastic_stack_version | mandatory }}/apt stable main" repo: "deb [signed-by={{ apt_keyring_dir }}/elastic.asc] https://artifacts.elastic.co/packages/{{ elastic_stack_version | mandatory }}/apt stable main"
filename: elastic filename: elastic
state: present state: present
update_cache: yes update_cache: yes
@ -48,6 +48,16 @@
- kibana - kibana
- packages - packages
- name: Unsigned Elastic sources list is not available
apt_repository:
repo: "deb https://artifacts.elastic.co/packages/{{ elastic_stack_version | mandatory }}/apt stable main"
filename: elastic
state: absent
update_cache: yes
tags:
- kibana
- packages
- name: Kibana is installed - name: Kibana is installed
apt: apt:
name: kibana name: kibana

View File

@ -100,15 +100,15 @@ semaine prochaine.
Voici la listes de packages qui seront mis à jour : Voici la listes de packages qui seront mis à jour :
$(cat "${packages}") $(cat "${packages}" | sort | uniq)
Liste des packages dont la mise-à-jour a été manuellement suspendue : Liste des packages dont la mise-à-jour a été manuellement suspendue :
$(cat "${packagesHold}") $(cat "${packagesHold}" | sort | uniq)
Liste des services qui seront redémarrés : Liste des services qui seront redémarrés :
$(cat "${servicesToRestart}") $(cat "${servicesToRestart}" | sort | uniq)
N'hésitez pas à nous faire toute remarque sur ce créneau d'intervention le plus N'hésitez pas à nous faire toute remarque sur ce créneau d'intervention le plus
tôt possible. tôt possible.
@ -240,7 +240,7 @@ main() {
echo "MySQL" >>"${servicesToRestart}" echo "MySQL" >>"${servicesToRestart}"
elif echo "${pkg}" | grep -q "^mariadb-server"; then elif echo "${pkg}" | grep -q "^mariadb-server"; then
echo "MariaDB" >>"${servicesToRestart}" echo "MariaDB" >>"${servicesToRestart}"
elif echo "${pkg}" | grep -qE "^postgresql-[[:digit:]]+\.[[:digit:]]+$"; then elif echo "${pkg}" | grep -qE "^postgresql-[[:digit:]]+(\.[[:digit:]]+)?$"; then
echo "PostgreSQL" >>"${servicesToRestart}" echo "PostgreSQL" >>"${servicesToRestart}"
elif echo "${pkg}" | grep -qE "^tomcat[[:digit:]]+$"; then elif echo "${pkg}" | grep -qE "^tomcat[[:digit:]]+$"; then
echo "Tomcat" >>"${servicesToRestart}" echo "Tomcat" >>"${servicesToRestart}"

View File

@ -7,4 +7,6 @@ logstash_log_rotate_days: 365
logstash_custom_tmpdir: Null logstash_custom_tmpdir: Null
logstash_default_tmpdir: /var/lib/logstash/tmp logstash_default_tmpdir: /var/lib/logstash/tmp
logstash_log_syslog_enabled: True logstash_log_syslog_enabled: True
logstash_config_force: True logstash_config_force: True
apt_keyring_dir: "{{ ansible_distribution_major_version is version('12', '<') | ternary('/etc/apt/trusted.gpg.d', '/etc/apt/keyrings') }}"

View File

@ -29,7 +29,7 @@
- name: Elastic GPG key is installed - name: Elastic GPG key is installed
copy: copy:
src: elastic.asc src: elastic.asc
dest: /etc/apt/trusted.gpg.d/elastic.asc dest: "{{ apt_keyring_dir }}/elastic.asc"
force: yes force: yes
mode: "0644" mode: "0644"
owner: root owner: root
@ -40,7 +40,7 @@
- name: Elastic sources list is available - name: Elastic sources list is available
apt_repository: apt_repository:
repo: "deb https://artifacts.elastic.co/packages/{{ elastic_stack_version | mandatory }}/apt stable main" repo: "deb [signed-by={{ apt_keyring_dir }}/elastic.asc] https://artifacts.elastic.co/packages/{{ elastic_stack_version | mandatory }}/apt stable main"
filename: elastic filename: elastic
state: present state: present
update_cache: yes update_cache: yes
@ -48,6 +48,16 @@
- logstash - logstash
- packages - packages
- name: Unsigned Elastic sources list is not available
apt_repository:
repo: "deb https://artifacts.elastic.co/packages/{{ elastic_stack_version | mandatory }}/apt stable main"
filename: elastic
state: absent
update_cache: yes
tags:
- logstash
- packages
- name: Logstash is installed - name: Logstash is installed
apt: apt:
name: logstash name: logstash

View File

@ -21,3 +21,13 @@ lxc_php_container_releases:
php74: "bullseye" php74: "bullseye"
php80: "bullseye" php80: "bullseye"
php81: "bullseye" php81: "bullseye"
lxc_php_services:
php56: 'php5-fpm.service'
php70: 'php7.0-fpm.service'
php73: 'php7.3-fpm.service'
php74: 'php7.4-fpm.service'
php80: 'php8.0-fpm.service'
php81: 'php8.1-fpm.service'
apt_keyring_dir: "{{ ansible_distribution_major_version is version('12', '<') | ternary('/etc/apt/trusted.gpg.d', '/etc/apt/keyrings') }}"

View File

@ -1,4 +1,15 @@
--- ---
- name: Reload PHP-FPM
lxc_container:
name: "{{ lxc_php_version }}"
container_command: "systemctl reload {{ lxc_php_services[lxc_php_version] }}"
- name: Restart PHP-FPM
lxc_container:
name: "{{ lxc_php_version }}"
container_command: "systemctl restart {{ lxc_php_services[lxc_php_version] }}"
- name: Reload php81-fpm - name: Reload php81-fpm
lxc_container: lxc_container:
name: "{{ lxc_php_version }}" name: "{{ lxc_php_version }}"
@ -34,6 +45,11 @@
name: "{{ lxc_php_version }}" name: "{{ lxc_php_version }}"
container_command: "systemctl restart opensmtpd" container_command: "systemctl restart opensmtpd"
- name: Daemon reload
lxc_container:
name: "{{ lxc_php_version }}"
container_command: "systemctl daemon-reload"
- name: Restart container - name: Restart container
lxc_container: lxc_container:
name: "{{ lxc_php_version }}" name: "{{ lxc_php_version }}"

View File

@ -27,4 +27,6 @@
- include: "php81.yml" - include: "php81.yml"
when: lxc_php_version == "php81" when: lxc_php_version == "php81"
- include: "umask.yml"
- include: "misc.yml" - include: "misc.yml"

View File

@ -19,13 +19,13 @@
create: yes create: yes
mode: "0644" mode: "0644"
loop: loop:
- "deb https://packages.sury.org/php/ bullseye main" - "deb [signed-by={{ apt_keyring_dir }}/sury.gpg] https://packages.sury.org/php/ bullseye main"
- "deb http://pub.evolix.net/ bullseye-php80/" - "deb [signed-by={{ apt_keyring_dir }}/reg.asc] http://pub.evolix.net/ bullseye-php80/"
- name: copy pub.evolix.net GPG key - name: copy pub.evolix.net GPG key
copy: copy:
src: reg.asc src: reg.asc
dest: /var/lib/lxc/{{ lxc_php_version }}/rootfs/etc/apt/trusted.gpg.d/reg.asc dest: /var/lib/lxc/{{ lxc_php_version }}/rootfs{{ apt_keyring_dir }}/reg.asc
mode: "0644" mode: "0644"
owner: root owner: root
group: root group: root
@ -33,7 +33,7 @@
- name: copy packages.sury.org GPG Key - name: copy packages.sury.org GPG Key
copy: copy:
src: sury.gpg src: sury.gpg
dest: /var/lib/lxc/{{ lxc_php_version }}/rootfs/etc/apt/trusted.gpg.d/sury.gpg dest: /var/lib/lxc/{{ lxc_php_version }}/rootfs{{ apt_keyring_dir }}/sury.gpg
mode: "0644" mode: "0644"
owner: root owner: root
group: root group: root

View File

@ -19,13 +19,13 @@
create: yes create: yes
mode: "0644" mode: "0644"
loop: loop:
- "deb https://packages.sury.org/php/ bullseye main" - "deb [signed-by={{ apt_keyring_dir }}/sury.gpg] https://packages.sury.org/php/ bullseye main"
- "deb http://pub.evolix.net/ bullseye-php81/" - "deb [signed-by={{ apt_keyring_dir }}/reg.asc] http://pub.evolix.net/ bullseye-php81/"
- name: copy pub.evolix.net GPG key - name: copy pub.evolix.net GPG key
copy: copy:
src: reg.asc src: reg.asc
dest: /var/lib/lxc/{{ lxc_php_version }}/rootfs/etc/apt/trusted.gpg.d/reg.asc dest: /var/lib/lxc/{{ lxc_php_version }}/rootfs{{ apt_keyring_dir }}/reg.asc
mode: "0644" mode: "0644"
owner: root owner: root
group: root group: root
@ -33,7 +33,7 @@
- name: copy packages.sury.org GPG Key - name: copy packages.sury.org GPG Key
copy: copy:
src: sury.gpg src: sury.gpg
dest: /var/lib/lxc/{{ lxc_php_version }}/rootfs/etc/apt/trusted.gpg.d/sury.gpg dest: /var/lib/lxc/{{ lxc_php_version }}/rootfs{{ apt_keyring_dir }}/sury.gpg
mode: "0644" mode: "0644"
owner: root owner: root
group: root group: root

32
lxc-php/tasks/umask.yml Normal file
View File

@ -0,0 +1,32 @@
# Ajoute UMask=0007 à l'unité systemd PHP-FPM du conteneur LXC
# dans /etc/systemd/system/phpX.X-fpm.service.d/evolinux.conf
---
- name: "Définis le chemin du système de fichiers du conteneur LXC."
set_fact:
lxc_rootfs_path: "/var/lib/lxc/{{ lxc_php_version }}/rootfs"
- name: "Crée des répertoires (si absents) pour surcharger la config des services PHP dans les conteneurs LXC."
ansible.builtin.file:
path: "{{ lxc_rootfs_path }}/etc/systemd/system/{{ lxc_php_services[lxc_php_version] }}.d"
state: directory
register: systemd_path
- name: "[Service] est présent dans la surchage des services PHP-FPM des conteneurs LXC."
ansible.builtin.lineinfile:
path: "{{ systemd_path.path }}/evolinux.conf"
regex: "\\[Service\\]"
line: "[Service]"
create: yes
- name: "UMask=0007 est présent dans la surchage des services PHP-FPM des conteneurs LXC."
ansible.builtin.lineinfile:
path: "{{ systemd_path.path }}/evolinux.conf"
regex: "^UMask="
line: "UMask=0007"
insertafter: "\\[Service\\]"
when: not ansible_check_mode
notify:
- "Daemon reload"
- "Restart PHP-FPM"

View File

@ -14,5 +14,9 @@
# release: stretch # release: stretch
# solr_version: 8.4.1 # solr_version: 8.4.1
# solr_port: 8985 # solr_port: 8985
# - name: solr9
# release: bullseye
# solr_version: 9.0.0
# solr_port: 8985
lxc_containers: [] lxc_containers: []

View File

@ -10,5 +10,9 @@
mode: '0755' mode: '0755'
loop: "{{ lxc_containers }}" loop: "{{ lxc_containers }}"
- include: "solr.yml name={{item.name}} solr_version={{item.solr_version}} solr_port={{item.solr_port}}" - include: solr.yml
args:
name: "{{ item.name }}"
solr_version: "{{ item.solr_version }}"
solr_port: "{{ item.solr_port }}"
loop: "{{ lxc_containers }}" loop: "{{ lxc_containers }}"

View File

@ -1,42 +1,42 @@
--- ---
- name: Install openjdk-8-jre-headless and lsof packages
command: "lxc-attach -n {{name}} -- apt-get install -y openjdk-8-jre-headless lsof" - name: "Set values for Solr < 9.0.0"
set_fact:
tarball_url: https://archive.apache.org/dist/lucene/solr/{{ solr_version }}/solr-{{ solr_version }}.tgz
tarball_path: /var/lib/lxc/{{ name }}/rootfs/root/solr-{{ solr_version }}.tgz
start_command: "/etc/init.d/solr start"
stop_command: "/etc/init.d/solr stop"
when: "solr_version is version('9.0.0', '<')"
- name: "Set values for Solr >= 9.0.0"
set_fact:
tarball_url: https://archive.apache.org/dist/solr/solr/{{ solr_version }}/solr-{{ solr_version }}.tgz
tarball_path: /var/lib/lxc/{{ name }}/rootfs/root/solr-{{ solr_version }}.tgz
start_command: "systemctl start solr"
stop_command: "systemctl stop solr"
when: "solr_version is version('9.0.0', '>=')"
- name: Install java and lsof packages
command: "lxc-attach -n {{ name }} -- apt-get install -y default-jre-headless lsof"
- name: "Download Solr {{ solr_version }}" - name: "Download Solr {{ solr_version }}"
get_url: get_url:
url: "https://archive.apache.org/dist/lucene/solr/{{ solr_version }}/solr-{{ solr_version }}.tgz" url: "{{ tarball_url }}"
dest: "/var/lib/lxc/{{ name }}/rootfs/root/solr-{{ solr_version }}.tgz" dest: "{{ tarball_path }}"
mode: '0644' mode: '0644'
- name: "Extract solr-{{ solr_version }}.tgz" - name: "Extract solr-{{ solr_version }}.tgz"
unarchive: unarchive:
src: /var/lib/lxc/{{ name }}/rootfs/root/solr-{{ solr_version }}.tgz src: "{{ tarball_path }}"
dest: /var/lib/lxc/{{ name }}/rootfs/root/ dest: /var/lib/lxc/{{ name }}/rootfs/root/
remote_src: yes remote_src: yes
- name: "Install Solr {{ solr_version }}"
command: "lxc-attach -n {{name}} -- /root/solr-{{ solr_version }}/bin/install_solr_service.sh /root/solr-{{ solr_version }}.tgz"
- name: "Stop Solr"
command: "lxc-attach -n {{name}} -- /etc/init.d/solr stop"
ignore_errors: True
- name: "Make sure /home/solr exists" - name: "Make sure /home/solr exists"
file: file:
path: /home/solr path: /home/solr/{{ name }}
recurse: yes
state: directory state: directory
mode: '0755' mode: '0755'
- name: "Move Solr data directory to /home/solr/{{name}}" - name: "Install Solr {{ solr_version }}"
command: "lxc-attach -n {{name}} -- mv /var/solr /home/solr/{{name}}" command: "lxc-attach -n {{name}} -- /root/solr-{{ solr_version }}/bin/install_solr_service.sh /root/solr-{{ solr_version }}.tgz -d /home/solr/{{name}} -p {{ solr_port }}"
- name: "Create a symbolic link to /home/solr/{{name}}"
command: "lxc-attach -n {{name}} -- ln -s /home/solr/{{name}} /var/solr"
- name: "Set Solr port to {{ solr_port }}"
lineinfile:
dest: /var/lib/lxc/{{ name }}/rootfs/etc/default/solr.in.sh
line: "SOLR_PORT={{ solr_port }}"
- name: "Start Solr"
command: "lxc-attach -n {{name}} -- /etc/init.d/solr start"

View File

@ -15,4 +15,6 @@ lxc_mount_part: "/home"
# release: jessie # release: jessie
# - name: php70 # - name: php70
# release: stretch # release: stretch
# - name: php81
# release: bullseye
lxc_containers: [] lxc_containers: []

View File

@ -43,11 +43,19 @@
- lxc_unprivilegied_containers | bool - lxc_unprivilegied_containers | bool
- root_subuids.rc != 0 - root_subuids.rc != 0
- name: Check if /var has not mount options or nosuid or nodev or noexec - name: Get filesystem options
shell: findmnt | grep -E "/var[^/]" | grep -e nodev -e noexec -e nosuid command: findmnt --noheadings --target /var/lib/lxc --output OPTIONS
register: check_var
changed_when: false changed_when: false
failed_when: "check_var.rc == 0" check_mode: no
register: check_fs_options
- name: Check if options are correct
assert:
that:
- "'nodev' not in check_fs_options.stdout"
- "'noexec' not in check_fs_options.stdout"
- "'nosuid' not in check_fs_options.stdout"
msg: "LXC directory is in a filesystem with incompatible options"
- name: Create containers - name: Create containers
include: create-container.yml include: create-container.yml

View File

@ -28,3 +28,5 @@ metricbeat_tags: Null
# metricbeat_fields: # metricbeat_fields:
# - "env: staging" # - "env: staging"
metricbeat_fields: Null metricbeat_fields: Null
apt_keyring_dir: "{{ ansible_distribution_major_version is version('12', '<') | ternary('/etc/apt/trusted.gpg.d', '/etc/apt/keyrings') }}"

View File

@ -29,7 +29,7 @@
- name: Elastic GPG key is installed - name: Elastic GPG key is installed
copy: copy:
src: elastic.asc src: elastic.asc
dest: /etc/apt/trusted.gpg.d/elastic.asc dest: "{{ apt_keyring_dir }}/elastic.asc"
force: yes force: yes
mode: "0644" mode: "0644"
owner: root owner: root
@ -40,7 +40,7 @@
- name: Elastic sources list is available - name: Elastic sources list is available
apt_repository: apt_repository:
repo: "deb https://artifacts.elastic.co/packages/{{ elastic_stack_version | mandatory }}/apt stable main" repo: "deb [signed-by={{ apt_keyring_dir }}/elastic.asc] https://artifacts.elastic.co/packages/{{ elastic_stack_version | mandatory }}/apt stable main"
filename: elastic filename: elastic
state: present state: present
update_cache: yes update_cache: yes
@ -48,6 +48,16 @@
- metricbeat - metricbeat
- packages - packages
- name: Elastic sources list is available
apt_repository:
repo: "deb https://artifacts.elastic.co/packages/{{ elastic_stack_version | mandatory }}/apt stable main"
filename: elastic
state: absent
update_cache: yes
tags:
- metricbeat
- packages
- name: Metricbeat is installed - name: Metricbeat is installed
apt: apt:
name: metricbeat name: metricbeat

View File

@ -55,7 +55,7 @@ DNSSERVEURS='0.0.0.0/0'
# HTTP authorizations # HTTP authorizations
# (you can use DNS names but set cron to reload minifirewall regularly) # (you can use DNS names but set cron to reload minifirewall regularly)
# (if you have HTTP proxy, set 0.0.0.0/0) # (if you have HTTP proxy, set 0.0.0.0/0)
# HTTPSITES='security.debian.org pub.evolix.net security-cdn.debian.org mirror.evolix.org backports.debian.org hwraid.le-vert.net antispam00.evolix.org spamassassin.apache.org sa-update.space-pro.be sa-update.secnap.net www.sa-update.pccc.com sa-update.dnswl.org ocsp.int-x3.letsencrypt.org' # HTTPSITES='security.debian.org pub.evolix.net security-cdn.debian.org mirror.evolix.org backports.debian.org hwraid.le-vert.net antispam00.evolix.org spamassassin.apache.org sa-update.space-pro.be sa-update.secnap.net www.sa-update.pccc.com sa-update.dnswl.org ocsp.int-x3.letsencrypt.org deb.freexian.com'
HTTPSITES='0.0.0.0/0' HTTPSITES='0.0.0.0/0'
# HTTPS authorizations # HTTPS authorizations

View File

@ -7,4 +7,6 @@ mongodb_bind: 127.0.0.1
# otherwise it can disable important settings, like authorization :/ # otherwise it can disable important settings, like authorization :/
mongodb_force_config: False mongodb_force_config: False
mongodb_version: 4.4 mongodb_version: 4.4
apt_keyring_dir: "{{ ansible_distribution_major_version is version('12', '<') | ternary('/etc/apt/trusted.gpg.d', '/etc/apt/keyrings') }}"

View File

@ -4,8 +4,12 @@
msg: Not compatible with Debian 11 (Bullseye) msg: Not compatible with Debian 11 (Bullseye)
when: when:
- ansible_distribution_release == "bullseye" - ansible_distribution_release == "bullseye"
- mongodb_version is version('5.0', '<=') - mongodb_version is version('5.0', '<')
- name: Look for legacy apt keyring
stat:
path: /etc/apt/trusted.gpg
register: _trusted_gpg_keyring
- name: MongoDB embedded GPG key is absent - name: MongoDB embedded GPG key is absent
apt_key: apt_key:
@ -17,19 +21,26 @@
- name: Add MongoDB GPG key - name: Add MongoDB GPG key
copy: copy:
src: "server-{{mongodb_version}}.asc" src: "server-{{mongodb_version}}.asc"
dest: "/etc/apt/trusted.gpg.d/mongodb-server-{{mongodb_version}}.asc" dest: "{{ apt_keyring_dir }}/mongodb-server-{{mongodb_version}}.asc"
force: yes force: yes
mode: "0644" mode: "0644"
owner: root owner: root
group: root group: root
- name: enable APT sources list - name: Enable APT sources list
apt_repository: apt_repository:
repo: "deb http://repo.mongodb.org/apt/debian buster/mongodb-org/{{mongodb_version}} main" repo: "deb [signed-by={{ apt_keyring_dir }}/mongodb-server-{{mongodb_version}}.asc] http://repo.mongodb.org/apt/debian bullseye/mongodb-org/{{mongodb_version}} main"
state: present state: present
filename: "mongodb-org-{{mongodb_version}}" filename: "mongodb-org-{{mongodb_version}}"
update_cache: yes update_cache: yes
- name: Disable unsigned APT sources list
apt_repository:
repo: "deb http://repo.mongodb.org/apt/debian bullseye/mongodb-org/{{mongodb_version}} main"
state: absent
filename: "mongodb-org-{{mongodb_version}}"
update_cache: yes
- name: Install packages - name: Install packages
apt: apt:
name: mongodb-org name: mongodb-org
@ -46,19 +57,19 @@
- name: install dependency for monitoring - name: install dependency for monitoring
apt: apt:
name: python-pymongo name: python3-pymongo
state: present state: present
- name: Custom configuration - name: Custom configuration
template: template:
src: mongodb_buster.conf.j2 src: mongodb_bullseye.conf.j2
dest: "/etc/mongod.conf" dest: "/etc/mongod.conf"
force: "{{ mongodb_force_config | bool | ternary('yes', 'no') }}" force: "{{ mongodb_force_config | bool | ternary('yes', 'no') }}"
notify: restart mongod notify: restart mongod
- name: Configure logrotate - name: Configure logrotate
template: template:
src: logrotate_buster.j2 src: logrotate_bullseye.j2
dest: /etc/logrotate.d/mongodb dest: /etc/logrotate.d/mongodb
force: yes force: yes
backup: no backup: no

View File

@ -15,19 +15,26 @@
- name: Add MongoDB GPG key - name: Add MongoDB GPG key
copy: copy:
src: "server-{{mongodb_version}}.asc" src: "server-{{mongodb_version}}.asc"
dest: "/etc/apt/trusted.gpg.d/mongodb-server-{{mongodb_version}}.asc" dest: "{{ apt_keyring_dir }}/mongodb-server-{{ mongodb_version }}.asc"
force: yes force: yes
mode: "0644" mode: "0644"
owner: root owner: root
group: root group: root
- name: enable APT sources list - name: Enable APT sources list
apt_repository: apt_repository:
repo: "deb http://repo.mongodb.org/apt/debian buster/mongodb-org/{{mongodb_version}} main" repo: "deb [signed-by={{ apt_keyring_dir }}/mongodb-server-{{ mongodb_version }}.asc] http://repo.mongodb.org/apt/debian buster/mongodb-org/{{ mongodb_version }} main"
state: present state: present
filename: "mongodb-org-{{mongodb_version}}" filename: "mongodb-org-{{mongodb_version}}"
update_cache: yes update_cache: yes
- name: Disable unsigned APT sources list
apt_repository:
repo: "deb http://repo.mongodb.org/apt/debian buster/mongodb-org/{{ mongodb_version }} main"
state: absent
filename: "mongodb-org-{{mongodb_version}}"
update_cache: yes
- name: Install packages - name: Install packages
apt: apt:
name: mongodb-org name: mongodb-org

View File

@ -1,15 +1,38 @@
--- ---
- name: MongoDB public GPG Key - name: Look for legacy apt keyring
apt_key: stat:
# url: https://www.mongodb.org/static/pgp/server-3.4.asc path: /etc/apt/trusted.gpg
data: "{{ lookup('file', 'server-3.4.asc') }}" register: _trusted_gpg_keyring
- name: enable APT sources list - name: MongoDB embedded GPG key is absent
apt_key:
id: "B8612B5D"
keyring: /etc/apt/trusted.gpg
state: absent
when: _trusted_gpg_keyring.stat.exists
- name: Add MongoDB GPG key
copy:
src: "server-{{mongodb_version}}.asc"
dest: "/etc/apt/trusted.gpg.d/mongodb-server-{{mongodb_version}}.asc"
force: yes
mode: "0644"
owner: root
group: root
- name: Enable APT sources list
apt_repository: apt_repository:
repo: deb http://repo.mongodb.org/apt/debian jessie/mongodb-org/3.4 main repo: "deb http://repo.mongodb.org/apt/debian jessie/mongodb-org/{{mongodb_version}} main"
state: present state: present
filename: mongodb filename: "mongodb-org-{{mongodb_version}}"
update_cache: yes
- name: Disable APT sources list
apt_repository:
repo: "deb http://repo.mongodb.org/apt/debian jessie/mongodb-org/{{mongodb_version}} main"
state: absent
filename: "mongodb-org-{{mongodb_version}}"
update_cache: yes update_cache: yes
- name: Install packages - name: Install packages

View File

@ -4,44 +4,44 @@
set_fact: set_fact:
mysql_restart_handler_name: "{{ mysql_restart_if_needed | bool | ternary('restart mysql', 'restart mysql (noop)') }}" mysql_restart_handler_name: "{{ mysql_restart_if_needed | bool | ternary('restart mysql', 'restart mysql (noop)') }}"
- include: packages_stretch.yml - include_tasks: packages_stretch.yml
when: ansible_distribution_major_version is version('9', '>=') when: ansible_distribution_major_version is version('9', '>=')
- include: packages_jessie.yml - include_tasks: packages_jessie.yml
when: ansible_distribution_release == "jessie" when: ansible_distribution_release == "jessie"
## There is nothing to do with users on Debian 11 - yet we need a /root/.my.cnf for compatibility ## There is nothing to do with users on Debian 11+ - yet we need a /root/.my.cnf for compatibility
- include: users_bullseye.yml - include_tasks: users_bullseye.yml
when: ansible_distribution_release == "bullseye" when: ansible_distribution_major_version is version('11', '>=')
- include: users_buster.yml - include_tasks: users_buster.yml
when: ansible_distribution_release == "buster" when: ansible_distribution_release == "buster"
- include: users_stretch.yml - include_tasks: users_stretch.yml
when: ansible_distribution_release == "stretch" when: ansible_distribution_release == "stretch"
- include: users_jessie.yml - include_tasks: users_jessie.yml
when: ansible_distribution_release == "jessie" when: ansible_distribution_release == "jessie"
- include: config_stretch.yml - include_tasks: config_stretch.yml
when: ansible_distribution_major_version is version('9', '>=') when: ansible_distribution_major_version is version('9', '>=')
- include: config_jessie.yml - include_tasks: config_jessie.yml
when: ansible_distribution_release == "jessie" when: ansible_distribution_release == "jessie"
- include: replication.yml - include_tasks: replication.yml
when: mysql_replication | bool when: mysql_replication | bool
- include: datadir.yml - include_tasks: datadir.yml
- include: logdir.yml - include_tasks: logdir.yml
- include: tmpdir.yml - include_tasks: tmpdir.yml
- include: nrpe.yml - include_tasks: nrpe.yml
- include: munin.yml - include_tasks: munin.yml
- include: log2mail.yml - include_tasks: log2mail.yml
- include: utils.yml - include_tasks: utils.yml

View File

@ -17,7 +17,7 @@
# mytop # mytop
- name: "Install mytop (Debian 9)" - name: "Install mytop (Debian 8)"
apt: apt:
name: mytop name: mytop
state: present state: present
@ -43,14 +43,23 @@
- libterm-readkey-perl - libterm-readkey-perl
when: ansible_distribution_release == "buster" when: ansible_distribution_release == "buster"
- name: "Install dependencies for mytop (Debian 11 or later)" - name: "Install dependencies for mytop (Debian 11)"
apt: apt:
name: name:
- mariadb-client-10.5 - mariadb-client-10.5
- libconfig-inifiles-perl - libconfig-inifiles-perl
- libterm-readkey-perl - libterm-readkey-perl
- libdbd-mariadb-perl - libdbd-mariadb-perl
when: ansible_distribution_major_version is version('11', '>=') when: ansible_distribution_release == "bullseye"
- name: "Install dependencies for mytop (Debian 12 or later)"
apt:
name:
- mariadb-client-10.6
- libconfig-inifiles-perl
- libterm-readkey-perl
- libdbd-mariadb-perl
when: ansible_distribution_major_version is version('12', '=')
- name: Read debian-sys-maint password (Debian < 11) - name: Read debian-sys-maint password (Debian < 11)
shell: 'cat /etc/mysql/debian.cnf | grep -m1 "password = .*" | cut -d" " -f3' shell: 'cat /etc/mysql/debian.cnf | grep -m1 "password = .*" | cut -d" " -f3'

View File

@ -0,0 +1,232 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2013 SWITCH http://www.switch.ch
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from __future__ import print_function
import argparse
import os
import subprocess
import sys
__version__ = '1.7.1'
# default ceph values
CEPH_COMMAND = '/usr/bin/ceph'
# nagios exit code
STATUS_OK = 0
STATUS_WARNING = 1
STATUS_ERROR = 2
STATUS_UNKNOWN = 3
def main():
# parse args
parser = argparse.ArgumentParser(description="'ceph df' nagios plugin.")
parser.add_argument('-e','--exe', help='ceph executable [%s]' % CEPH_COMMAND)
parser.add_argument('-c','--conf', help='alternative ceph conf file')
parser.add_argument('-m','--monaddress', help='ceph monitor address[:port]')
parser.add_argument('-i','--id', help='ceph client id')
parser.add_argument('-n','--name', help='ceph client name')
parser.add_argument('-k','--keyring', help='ceph client keyring file')
parser.add_argument('-p','--pool', help='ceph pool name')
parser.add_argument('-d','--detail', help="show pool details on warn and critical", action='store_true')
parser.add_argument('-W','--warn', help="warn above this percent RAW USED", type=float)
parser.add_argument('-C','--critical', help="critical alert above this percent RAW USED", type=float)
parser.add_argument('-V','--version', help='show version and exit', action='store_true')
args = parser.parse_args()
# validate args
ceph_exec = args.exe if args.exe else CEPH_COMMAND
if not os.path.exists(ceph_exec):
print("ERROR: ceph executable '%s' doesn't exist" % ceph_exec)
return STATUS_UNKNOWN
if args.version:
print('version %s' % __version__)
return STATUS_OK
if args.conf and not os.path.exists(args.conf):
print("ERROR: ceph conf file '%s' doesn't exist" % args.conf)
return STATUS_UNKNOWN
if args.keyring and not os.path.exists(args.keyring):
print("ERROR: keyring file '%s' doesn't exist" % args.keyring)
return STATUS_UNKNOWN
if not args.warn or not args.critical or args.warn > args.critical:
print("ERROR: warn and critical level must be set and critical must be greater than warn")
return STATUS_UNKNOWN
# build command
ceph_df = [ceph_exec]
if args.monaddress:
ceph_df.append('-m')
ceph_df.append(args.monaddress)
if args.conf:
ceph_df.append('-c')
ceph_df.append(args.conf)
if args.id:
ceph_df.append('--id')
ceph_df.append(args.id)
if args.name:
ceph_df.append('--name')
ceph_df.append(args.name)
if args.keyring:
ceph_df.append('--keyring')
ceph_df.append(args.keyring)
ceph_df.append('df')
#print ceph_df
# exec command
p = subprocess.Popen(ceph_df,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
output, err = p.communicate()
# parse output
# print "DEBUG: output:", output
# print "DEBUG: err:", err
if output:
output = output.decode('utf-8')
# parse output
# if detail switch was not set only show global values and compare to warning and critical
# otherwise show space for pools too
result=output.splitlines()
# values for GLOBAL are in 3rd line of output
globalline = result[2]
globalvals = globalline.split()
# Luminous vs Minic output (27.3TiB vs 27.3 TiB)
if len(globalvals) == 7:
gv = []
gv.append("{}{}".format(globalvals[0], globalvals[1]))
gv.append("{}{}".format(globalvals[2], globalvals[3]))
gv.append("{}{}".format(globalvals[4], globalvals[5]))
gv.append(globalvals[6])
globalvals = gv
#print "XXX: globalvals: {} {}".format(len(globalvals), globalvals)
# Nautilus output
if len(globalvals) == 10:
gv = []
gv.append("{}{}".format(globalvals[1], globalvals[2]))
gv.append("{}{}".format(globalvals[3], globalvals[4]))
gv.append("{}{}".format(globalvals[5], globalvals[6]))
gv.append(globalvals[9])
globalvals = gv
#print "XXX: globalvals: {} {}".format(len(globalvals), globalvals)
# prepare pool values
# pool output starts in line 4 with the bare word POOLS: followed by the output
poollines = result[3:]
if args.pool:
for line in poollines:
if args.pool in line:
poolvals = line.split()
# Luminous vs Minic output (27.3TiB vs 27.3 TiB)
if len(poolvals) == 8:
pv = []
pv.append(poolvals[0]) # NAME
pv.append(poolvals[1]) # ID
pv.append("{}{}".format(poolvals[2], poolvals[3])) # USED 27.3 TiB
pv.append(poolvals[4]) # %USED
pv.append("{}{}".format(poolvals[5], poolvals[6])) # MAX AVAIL 27.3 TiB
# pv.append(poolvals[7]) # OBJECTS
poolvals = pv
#print "XXX: poolvals: {} {}".format(len(poolvals), poolvals)
# Nautilus output
if len(poolvals) == 10:
pv = []
pv.append(poolvals[0]) # NAME
pv.append(poolvals[1]) # ID
pv.append("{}{}".format(poolvals[2], poolvals[3])) # USED 27.3 TiB
pv.append(poolvals[7]) # %USED
pv.append("{}{}".format(poolvals[8], poolvals[9])) # MAX AVAIL 27.3 TiB
# pv.append(poolvals[7]) # OBJECTS, not used
poolvals = pv
#print "XXX: poolvals: {} {}".format(len(poolvals), poolvals)
# Octopus >= v15.2.8 (pgs added to ceph-df)
if len(poolvals) == 11:
pv = []
pv.append(poolvals[0]) # NAME
pv.append(poolvals[1]) # ID
#pv.append(poolvals[2]) # PGS, not used
pv.append("{}{}".format(poolvals[3], poolvals[4])) # USED 27.3 TiB
pv.append(poolvals[8]) # %USED
pv.append("{}{}".format(poolvals[9], poolvals[10])) # MAX AVAIL 27.3 TiB
# pv.append(poolvals[7]) # OBJECTS, not used
poolvals = pv
#print "XXX: poolvals: {} {}".format(len(poolvals), poolvals)
pool_used = poolvals[2]
pool_usage_percent = float(poolvals[3])
pool_available_space = poolvals[4]
# pool_objects = float(poolvals[5]) # not used
if pool_usage_percent > args.critical:
print('CRITICAL: %s%% usage in Pool \'%s\' is above %s%% (%s used) | Usage=%s%%;%s;%s;;' % (pool_usage_percent, args.pool, args.critical, pool_used, pool_usage_percent, args.warn, args.critical))
return STATUS_ERROR
if pool_usage_percent > args.warn:
print('WARNING: %s%% usage in Pool \'%s\' is above %s%% (%s used) | Usage=%s%%;%s;%s;;' % (pool_usage_percent, args.pool, args.warn, pool_used, pool_usage_percent, args.warn, args.critical))
return STATUS_WARNING
else:
print('%s%% usage in Pool \'%s\' | Usage=%s%%;%s;%s;;' % (pool_usage_percent, args.pool, pool_usage_percent, args.warn, args.critical))
return STATUS_OK
else:
# print 'DEBUG:', globalvals
# finally 4th element contains percentual value
# print 'DEBUG USAGE:', globalvals[3]
global_usage_percent = float(globalvals[3])
global_available_space = globalvals[1]
global_total_space = globalvals[0]
# print 'DEBUG WARNLEVEL:', args.warn
# print 'DEBUG CRITICALLEVEL:', args.critical
if global_usage_percent > args.critical:
if args.detail:
poollines.insert(0, '\n')
poolout = '\n '.join(poollines)
else:
poolout = ''
print('CRITICAL: global RAW usage of %s%% is above %s%% (%s of %s free)%s | Usage=%s%%;%s;%s;;' % (global_usage_percent, args.critical, global_available_space, global_total_space, poolout, global_usage_percent, args.warn, args.critical))
return STATUS_ERROR
elif global_usage_percent > args.warn:
if args.detail:
poollines.insert(0, '\n')
poolout = '\n '.join(poollines)
else:
poolout = ''
print('WARNING: global RAW usage of %s%% is above %s%% (%s of %s free)%s | Usage=%s%%;%s;%s;;' % (global_usage_percent, args.warn, global_available_space, global_total_space, poolout, global_usage_percent, args.warn, args.critical))
return STATUS_WARNING
else:
print('RAW usage %s%% | Usage=%s%%;%s;%s;;' % (global_usage_percent, global_usage_percent, args.warn, args.critical))
return STATUS_OK
#for
elif err:
# read only first line of error
one_line = err.split('\n')[0]
if '-1 ' in one_line:
idx = one_line.rfind('-1 ')
print('ERROR: %s: %s' % (ceph_exec, one_line[idx+len('-1 '):]))
else:
print(one_line)
return STATUS_UNKNOWN
if __name__ == "__main__":
sys.exit(main())

View File

@ -0,0 +1,200 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2013-2016 SWITCH http://www.switch.ch
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from __future__ import print_function
import argparse
import os
import subprocess
import sys
import re
import json
__version__ = '1.7.0'
# default ceph values
CEPH_ADM_COMMAND = '/usr/sbin/cephadm'
CEPH_COMMAND = '/usr/bin/ceph'
# nagios exit code
STATUS_OK = 0
STATUS_WARNING = 1
STATUS_ERROR = 2
STATUS_UNKNOWN = 3
def main():
# parse args
parser = argparse.ArgumentParser(description="'ceph health' nagios plugin.")
parser.add_argument('-e','--exe', help='ceph executable [%s]' % CEPH_COMMAND)
parser.add_argument('-A','--admexe', help='cephadm executable [%s]' % CEPH_ADM_COMMAND)
parser.add_argument('--cluster', help='ceph cluster name')
parser.add_argument('-c','--conf', help='alternative ceph conf file')
parser.add_argument('-m','--monaddress', help='ceph monitor address[:port]')
parser.add_argument('-i','--id', help='ceph client id')
parser.add_argument('-n','--name', help='ceph client name')
parser.add_argument('-k','--keyring', help='ceph client keyring file')
parser.add_argument('--check', help='regexp of which check(s) to check (luminous+) '
"Can be inverted, e.g. '^((?!(PG_DEGRADED|OBJECT_MISPLACED)$).)*$'")
parser.add_argument('-w','--whitelist', help='whitelist regexp for ceph health warnings')
parser.add_argument('-d','--detail', help="exec 'ceph health detail'", action='store_true')
parser.add_argument('-V','--version', help='show version and exit', action='store_true')
parser.add_argument('-a','--cephadm', help='uses cephadm to execute the command', action='store_true')
parser.add_argument('-s','--skip-muted', help='skip muted checks', action='store_true')
args = parser.parse_args()
# validate args
cephadm_exec = args.admexe if args.admexe else CEPH_ADM_COMMAND
ceph_exec = args.exe if args.exe else CEPH_COMMAND
if args.cephadm:
if not os.path.exists(cephadm_exec):
print("ERROR: cephadm executable '%s' doesn't exist" % cephadm_exec)
return STATUS_UNKNOWN
else:
if not os.path.exists(ceph_exec):
print("ERROR: ceph executable '%s' doesn't exist" % ceph_exec)
return STATUS_UNKNOWN
if args.version:
print('version %s' % __version__)
return STATUS_OK
if args.conf and not os.path.exists(args.conf):
print("ERROR: ceph conf file '%s' doesn't exist" % args.conf)
return STATUS_UNKNOWN
if args.keyring and not os.path.exists(args.keyring):
print("ERROR: keyring file '%s' doesn't exist" % args.keyring)
return STATUS_UNKNOWN
# build command
ceph_health = [ceph_exec]
if args.cephadm:
# Prepend the command with the cephadm binary and the shell command
ceph_health = [cephadm_exec, 'shell'] + ceph_health
if args.monaddress:
ceph_health.append('-m')
ceph_health.append(args.monaddress)
if args.cluster:
ceph_health.append('--cluster')
ceph_health.append(args.cluster)
if args.conf:
ceph_health.append('-c')
ceph_health.append(args.conf)
if args.id:
ceph_health.append('--id')
ceph_health.append(args.id)
if args.name:
ceph_health.append('--name')
ceph_health.append(args.name)
if args.keyring:
ceph_health.append('--keyring')
ceph_health.append(args.keyring)
ceph_health.append('health')
if args.detail:
ceph_health.append('detail')
ceph_health.append('--format')
ceph_health.append('json')
#print(ceph_health)
# exec command
p = subprocess.Popen(ceph_health,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
output, err = p.communicate()
try:
output = json.loads(output)
except ValueError:
output = dict()
# parse output
# print "output:", output
#print "err:", err
if output:
ret = STATUS_OK
msg = ""
extended = []
if 'checks' in output:
#luminous
for check,status in output['checks'].items():
# skip check if not selected
if args.check and not re.search(args.check, check):
continue
if args.skip_muted and ('muted' in status and status['muted']):
continue
check_detail = "%s( %s )" % (check, status['summary']['message'])
if status["severity"] == "HEALTH_ERR":
extended.append(msg)
msg = "CRITICAL: %s" % check_detail
ret = STATUS_ERROR
continue
if args.whitelist and re.search(args.whitelist,status['summary']['message']):
continue
check_msg = "WARNING: %s" % check_detail
if not msg:
msg = check_msg
ret = STATUS_WARNING
else:
extended.append(check_msg)
else:
#pre-luminous
for status in output["summary"]:
if status != "HEALTH_OK":
if status == "HEALTH_ERROR":
msg = "CRITICAL: %s" % status['summary']
ret = STATUS_ERROR
continue
if args.whitelist and re.search(args.whitelist,status['summary']):
continue
if not msg:
msg = "WARNING: %s" % status['summary']
ret = STATUS_WARNING
else:
extended.append("WARNING: %s" % status['summary'])
if msg:
print(msg)
else:
print("HEALTH OK")
if extended: print('\n'.join(extended))
return ret
elif err:
# read only first line of error
one_line = err.split('\n')[0]
if '-1 ' in one_line:
idx = one_line.rfind('-1 ')
print('ERROR: %s: %s' % (ceph_exec, one_line[idx+len('-1 '):]))
else:
print(one_line)
return STATUS_UNKNOWN
if __name__ == "__main__":
sys.exit(main())

View File

@ -0,0 +1,188 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2013 Catalyst IT http://www.catalyst.net.nz
# Copyright (c) 2015 SWITCH http://www.switch.ch
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import print_function
import argparse
import socket
import os
import re
import subprocess
import sys
import json
__version__ = '1.6.0'
# default ceph values
CEPH_EXEC = '/usr/bin/ceph'
CEPH_COMMAND = 'mds stat -f json'
# nagios exit code
STATUS_OK = 0
STATUS_WARNING = 1
STATUS_ERROR = 2
STATUS_UNKNOWN = 3
def main():
# parse args
parser = argparse.ArgumentParser(description="'ceph mds stat' nagios plugin.")
parser.add_argument('-e','--exe', help='ceph executable [%s]' % CEPH_EXEC)
parser.add_argument('-c','--conf', help='alternative ceph conf file')
parser.add_argument('-m','--monaddress', help='ceph monitor to use for queries (address[:port])')
parser.add_argument('-i','--id', help='ceph client id')
parser.add_argument('-k','--keyring', help='ceph client keyring file')
parser.add_argument('-V','--version', help='show version and exit', action='store_true')
parser.add_argument('-n','--name', help='mds daemon name', required=True)
parser.add_argument('-f','--filesystem', help='mds filesystem name', required=True)
args = parser.parse_args()
if args.version:
print('version %s' % __version__)
return STATUS_OK
# validate args
ceph_exec = args.exe if args.exe else CEPH_EXEC
if not os.path.exists(ceph_exec):
print("MDS ERROR: ceph executable '%s' doesn't exist" % ceph_exec)
return STATUS_UNKNOWN
if args.conf and not os.path.exists(args.conf):
print("MDS ERROR: ceph conf file '%s' doesn't exist" % args.conf)
return STATUS_UNKNOWN
if args.keyring and not os.path.exists(args.keyring):
print("MDS ERROR: keyring file '%s' doesn't exist" % args.keyring)
return STATUS_UNKNOWN
# build command
ceph_cmd = [ceph_exec]
if args.monaddress:
ceph_cmd.append('-m')
ceph_cmd.append(args.monaddress)
if args.conf:
ceph_cmd.append('-c')
ceph_cmd.append(args.conf)
if args.id:
ceph_cmd.append('--id')
ceph_cmd.append(args.id)
if args.keyring:
ceph_cmd.append('--keyring')
ceph_cmd.append(args.keyring)
ceph_cmd.extend(CEPH_COMMAND.split(' '))
# exec command
p = subprocess.Popen(ceph_cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
output, err = p.communicate()
if p.returncode != 0 or not output:
print("MDS ERROR: %s" % err)
return STATUS_ERROR
# load json output and parse
mds_stat = None
try:
mds_stat = json.loads(output)
except Exception as e:
print("MDS ERROR: could not parse '%s' output: %s: %s" % (CEPH_COMMAND,output,e))
return STATUS_UNKNOWN
return check_target_mds(mds_stat, args.filesystem, args.name)
def check_target_mds(mds_stat, fs_name, name):
# find mds from standby list
standby_mdss = _get_standby_mds(mds_stat)
for mds in standby_mdss:
if mds.get_name() == name:
print("MDS OK: %s" % (mds))
return STATUS_OK
# find mds from active list
active_mdss = _get_active_mds(mds_stat, fs_name)
if active_mdss:
for mds in active_mdss:
if mds.get_name() != name:
continue
# target mds in active list
print("MDS %s: %s" % ("WARN" if mds.is_laggy() else "OK", mds))
return STATUS_WARNING if mds.is_laggy() else STATUS_OK
# mds not found
print("MDS ERROR: MDS '%s' is not found (offline?)" % (name))
return STATUS_ERROR
else:
# fs not found in map, perhaps user input error
print("MDS ERROR: FS '%s' is not found in fsmap" % (fs_name))
return STATUS_ERROR
def _get_standby_mds(mds_stat):
mds_array = []
for mds in mds_stat['fsmap']['standbys']:
name = mds['name']
state = mds['state']
laggy_since = mds['laggy_since'] if 'laggy_since' in mds else None
mds_array.append(MDS(name, state))
return mds_array
def _get_active_mds(mds_stat, fs_name):
mds_fs = mds_stat['fsmap']['filesystems']
# find filesystem in stat
for i in range(len(mds_fs)):
mdsmap = mds_fs[i]['mdsmap']
if mdsmap['fs_name'] != fs_name:
continue
# put mds to array
mds_array = []
infos = mds_stat['fsmap']['filesystems'][i]['mdsmap']['info']
for gid in infos:
name = infos[gid]['name']
state = infos[gid]['state']
laggy_since = infos[gid]['laggy_since'] if 'laggy_since' in infos[gid] else None
mds_array.append(MDS(name, state, laggy_since))
return mds_array
# no fs found
return None
class MDS(object):
def __init__(self, name, state, laggy_since=None):
self.name = name
self.state = state
self.laggy_since = laggy_since
def get_name(self):
return self.name
def get_state(self):
return self.state
def is_laggy(self):
return self.laggy_since is not None
def __str__(self):
msg = "MDS '%s' is %s" % (self.name, self.state)
if self.laggy_since is not None:
msg += " (laggy or crashed)"
return msg
# main
if __name__ == "__main__":
sys.exit(main())

View File

@ -0,0 +1,188 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2018 SWITCH http://www.switch.ch
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from __future__ import print_function
import argparse
import os
import subprocess
import sys
import json
__version__ = '1.0.0'
# default ceph values
CEPH_EXEC = '/usr/bin/ceph'
CEPH_COMMAND = 'mgr dump -f json'
CEPH_MGR_DUMP_EXAMPLE = '''
$ ceph --version
ceph version 12.2.7 (3ec878d1e53e1aeb47a9f619c49d9e7c0aa384d5) luminous (stable)
$ ceph mgr dump -f json|jq .
{
"epoch": 165,
"active_gid": 248001409,
"active_name": "zhdk0013",
"active_addr": "10.10.10.9:6800/810408",
"available": true,
"standbys": [
{
"gid": 247991934,
"name": "zhdk0009",
"available_modules": [
"balancer",
"dashboard",
"influx",
"localpool",
"prometheus",
"restful",
"selftest",
"status",
"zabbix"
]
},
{
"gid": 248011196,
"name": "zhdk0025",
"available_modules": [
"balancer",
"dashboard",
"influx",
"localpool",
"prometheus",
"restful",
"selftest",
"status",
"zabbix"
]
}
],
"modules": [
"balancer",
"restful",
"status"
],
"available_modules": [
"balancer",
"dashboard",
"influx",
"localpool",
"prometheus",
"restful",
"selftest",
"status",
"zabbix"
],
"services": {}
}
'''
# nagios exit code
STATUS_OK = 0
STATUS_WARNING = 1
STATUS_ERROR = 2
STATUS_UNKNOWN = 3
def main():
# parse args
parser = argparse.ArgumentParser(description="'ceph mgr dump' nagios plugin.")
parser.add_argument('-e', '--exe', help='ceph executable [%s]' % CEPH_EXEC)
parser.add_argument('-c', '--conf', help='alternative ceph conf file')
parser.add_argument('-m', '--monaddress', help='ceph monitor to use for queries (address[:port])')
parser.add_argument('-i', '--id', help='ceph client id')
parser.add_argument('-n', '--name', help='ceph client name')
parser.add_argument('-k', '--keyring', help='ceph client keyring file')
parser.add_argument('-V', '--version', help='show version and exit', action='store_true')
args = parser.parse_args()
if args.version:
print("version {}".format(__version__))
return STATUS_OK
# validate args
ceph_exec = args.exe if args.exe else CEPH_EXEC
if not os.path.exists(ceph_exec):
print("MGR ERROR: ceph executable '{}' doesn't exist".format(ceph_exec))
return STATUS_UNKNOWN
if args.conf and not os.path.exists(args.conf):
print("MGR ERROR: ceph conf file '{}' doesn't exist".format(args.conf))
return STATUS_UNKNOWN
if args.keyring and not os.path.exists(args.keyring):
print("MGR ERROR: keyring file '{}' doesn't exist".format(args.keyring))
return STATUS_UNKNOWN
# build command
ceph_cmd = [ceph_exec]
if args.monaddress:
ceph_cmd.append('-m')
ceph_cmd.append(args.monaddress)
if args.conf:
ceph_cmd.append('-c')
ceph_cmd.append(args.conf)
if args.id:
ceph_cmd.append('--id')
ceph_cmd.append(args.id)
if args.name:
ceph_cmd.append('--name')
ceph_cmd.append(args.name)
if args.keyring:
ceph_cmd.append('--keyring')
ceph_cmd.append(args.keyring)
ceph_cmd.extend(CEPH_COMMAND.split(' '))
# exec command
p = subprocess.Popen(ceph_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, err = p.communicate()
if p.returncode != 0 or not output:
print("MGR ERROR: {}".format(err))
return STATUS_UNKNOWN
# load json output and parse
mgr_dump = None
try:
mgr_dump = json.loads(output)
except Exception as e:
print("MGR ERROR: could not parse '{}' output: {}: {}".format(ceph_cmd, output, e))
return STATUS_UNKNOWN
# check active
if 'active_name' not in mgr_dump:
print("MGR CRITICAL: not active mgr found")
print("JSON: {}".format(json.dumps(mgr_dump)))
return STATUS_ERROR
active_mgr_name = mgr_dump['active_name']
# check standby
standby_mgr_names = []
for standby_mgr in mgr_dump['standbys']:
standby_mgr_names.append(standby_mgr['name'])
if len(standby_mgr_names) <= 0:
print("MGR WARN: active: {} but no standbys".format(active_mgr_name))
return STATUS_WARNING
else:
print("MGR OK: active: {}, standbys: {}".format(active_mgr_name,
", ".join(standby_mgr_names)))
return STATUS_OK
# main
if __name__ == "__main__":
sys.exit(main())

View File

@ -0,0 +1,163 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2013 Catalyst IT http://www.catalyst.net.nz
# Copyright (c) 2015 SWITCH http://www.switch.ch
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from __future__ import print_function
import argparse
import socket
import os
import re
import subprocess
import sys
import json
__version__ = '1.5.0'
# default ceph values
CEPH_EXEC = '/usr/bin/ceph'
CEPH_COMMAND = 'quorum_status'
# nagios exit code
STATUS_OK = 0
STATUS_WARNING = 1
STATUS_ERROR = 2
STATUS_UNKNOWN = 3
##
# ceph quorum_status output example
##
ceph_quorum_status_output_example = '''{
"quorum_leader_name" : "s0001",
"monmap" : {
"mons" : [
{
"name" : "s0001",
"addr" : "[2001:620:5ca1:8000::1001]:6789/0",
"rank" : 0
},
{
"name" : "s0003",
"addr" : "[2001:620:5ca1:8000::1003]:6789/0",
"rank" : 1
}
],
"created" : "2014-12-15 08:28:35.153650",
"epoch" : 2,
"modified" : "2014-12-15 08:28:40.371878",
"fsid" : "22348d2b-b69d-46cc-9a79-ca93cd6bae84"
},
"quorum_names" : [
"s0001",
"s0003"
],
"quorum" : [
0,
1
],
"election_epoch" : 24
}'''
def main():
# parse args
parser = argparse.ArgumentParser(description="'ceph quorum_status' nagios plugin.")
parser.add_argument('-e','--exe', help='ceph executable [%s]' % CEPH_EXEC)
parser.add_argument('-c','--conf', help='alternative ceph conf file')
parser.add_argument('-m','--monaddress', help='ceph monitor to use for queries (address[:port])')
parser.add_argument('-i','--id', help='ceph client id')
parser.add_argument('-k','--keyring', help='ceph client keyring file')
parser.add_argument('-V','--version', help='show version and exit', action='store_true')
parser.add_argument('-I','--monid', help='mon ID to be checked for availability')
args = parser.parse_args()
if args.version:
print('version %s' % __version__)
return STATUS_OK
# validate args
ceph_exec = args.exe if args.exe else CEPH_EXEC
if not os.path.exists(ceph_exec):
print("MON ERROR: ceph executable '%s' doesn't exist" % ceph_exec)
return STATUS_UNKNOWN
if args.conf and not os.path.exists(args.conf):
print("MON ERROR: ceph conf file '%s' doesn't exist" % args.conf)
return STATUS_UNKNOWN
if args.keyring and not os.path.exists(args.keyring):
print("MON ERROR: keyring file '%s' doesn't exist" % args.keyring)
return STATUS_UNKNOWN
if not args.monid:
print("MON ERROR: no MON ID given, use -I/--monid parameter")
return STATUS_UNKNOWN
# build command
ceph_cmd = [ceph_exec]
if args.monaddress:
ceph_cmd.append('-m')
ceph_cmd.append(args.monaddress)
if args.conf:
ceph_cmd.append('-c')
ceph_cmd.append(args.conf)
if args.id:
ceph_cmd.append('--id')
ceph_cmd.append(args.id)
if args.keyring:
ceph_cmd.append('--keyring')
ceph_cmd.append(args.keyring)
ceph_cmd.append(CEPH_COMMAND)
# exec command
p = subprocess.Popen(ceph_cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
output, err = p.communicate()
if p.returncode != 0 or not output:
print("MON ERROR: %s" % err)
return STATUS_ERROR
# load json output and parse
quorum_status = False
try:
quorum_status = json.loads(output)
except Exception as e:
print("MON ERROR: could not parse '%s' output: %s: %s" % (CEPH_COMMAND,output,e))
return STATUS_UNKNOWN
#print "XXX: quorum_status['quorum_names']:", quorum_status['quorum_names']
# do our checks
is_monitor = False
for mon in quorum_status['monmap']['mons']:
if mon['name'] == args.monid:
is_monitor = True
if not is_monitor:
print("MON WARN: mon '%s' is not in monmap: %s" % (args.monid,quorum_status['monmap']['mons']))
return STATUS_WARNING
in_quorum = args.monid in quorum_status['quorum_names']
if in_quorum:
print("MON OK")
return STATUS_OK
else:
print("MON WARN: no MON '%s' found in quorum" % args.monid)
return STATUS_WARNING
# main
if __name__ == "__main__":
sys.exit(main())

View File

@ -0,0 +1,154 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2013 Catalyst IT http://www.catalyst.net.nz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# 1.5.2 (2019-06-16) Martin Seener: fixed regex to work with Ceph Nautilus (14.2.x)
from __future__ import print_function
import argparse
import os
import re
import subprocess
import sys
import socket
__version__ = '1.5.2'
# default ceph values
CEPH_COMMAND = '/usr/bin/ceph'
# nagios exit code
STATUS_OK = 0
STATUS_WARNING = 1
STATUS_ERROR = 2
STATUS_UNKNOWN = 3
def main():
# parse args
parser = argparse.ArgumentParser(description="'ceph osd' nagios plugin.")
parser.add_argument('-e','--exe', help='ceph executable [%s]' % CEPH_COMMAND)
parser.add_argument('-c','--conf', help='alternative ceph conf file')
parser.add_argument('-m','--monaddress', help='ceph monitor address[:port]')
parser.add_argument('-i','--id', help='ceph client id')
parser.add_argument('-k','--keyring', help='ceph client keyring file')
parser.add_argument('-V','--version', help='show version and exit', action='store_true')
parser.add_argument('-H','--host', help='osd host', required=True)
parser.add_argument('-I','--osdid', help='osd id', required=False)
parser.add_argument('-C','--crit', help='Number of failed OSDs to trigger critical (default=2)',type=int,default=2, required=False)
parser.add_argument('-o','--out', help='check osds that are set OUT', default=False, action='store_true', required=False)
args = parser.parse_args()
# validate args
ceph_exec = args.exe if args.exe else CEPH_COMMAND
if not os.path.exists(ceph_exec):
print("OSD ERROR: ceph executable '%s' doesn't exist" % ceph_exec)
return STATUS_UNKNOWN
if args.version:
print('version %s' % __version__)
return STATUS_OK
if args.conf and not os.path.exists(args.conf):
print("OSD ERROR: ceph conf file '%s' doesn't exist" % args.conf)
return STATUS_UNKNOWN
if args.keyring and not os.path.exists(args.keyring):
print("OSD ERROR: keyring file '%s' doesn't exist" % args.keyring)
return STATUS_UNKNOWN
if not args.osdid:
args.osdid = '[^ ]*'
if not args.host:
print("OSD ERROR: no OSD hostname given")
return STATUS_UNKNOWN
try:
addrinfo = socket.getaddrinfo(args.host, None, 0, socket.SOCK_STREAM)
args.host = addrinfo[0][-1][0]
if addrinfo[0][0] == socket.AF_INET6:
args.host = "[%s]" % args.host
except:
print('OSD ERROR: could not resolve %s' % args.host)
return STATUS_UNKNOWN
# build command
ceph_cmd = [ceph_exec]
if args.monaddress:
ceph_cmd.append('-m')
ceph_cmd.append(args.monaddress)
if args.conf:
ceph_cmd.append('-c')
ceph_cmd.append(args.conf)
if args.id:
ceph_cmd.append('--id')
ceph_cmd.append(args.id)
if args.keyring:
ceph_cmd.append('--keyring')
ceph_cmd.append(args.keyring)
ceph_cmd.append('osd')
ceph_cmd.append('dump')
# exec command
p = subprocess.Popen(ceph_cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
output, err = p.communicate()
output = output.decode('utf8')
if err or not output:
print("OSD ERROR: %s" % err)
return STATUS_ERROR
# escape IPv4 host address
osd_host = args.host.replace('.', '\.')
# escape IPv6 host address
osd_host = osd_host.replace('[', '\[')
osd_host = osd_host.replace(']', '\]')
up = re.findall(r"^(osd\.%s) up.*%s:" % (args.osdid, osd_host), output, re.MULTILINE)
if args.out:
down = re.findall(r"^(osd\.%s) down.*%s:" % (args.osdid, osd_host), output, re.MULTILINE)
down_in = re.findall(r"^(osd\.%s) down[ ]+in.*%s:" % (args.osdid, osd_host), output, re.MULTILINE)
down_out = re.findall(r"^(osd\.%s) down[ ]+out.*%s:" % (args.osdid, osd_host), output, re.MULTILINE)
else:
down = re.findall(r"^(osd\.%s) down[ ]+in.*%s:" % (args.osdid, osd_host), output, re.MULTILINE)
down_in = down
down_out = re.findall(r"^(osd\.%s) down[ ]+out.*%s:" % (args.osdid, osd_host), output, re.MULTILINE)
if down:
print("OSD %s: Down OSD%s on %s: %s" % ('CRITICAL' if len(down)>=args.crit else 'WARNING' ,'s' if len(down)>1 else '', args.host, " ".join(down)))
print("Up OSDs: " + " ".join(up))
print("Down+In OSDs: " + " ".join(down_in))
print("Down+Out OSDs: " + " ".join(down_out))
print("| 'osd_up'=%d 'osd_down_in'=%d;;%d 'osd_down_out'=%d;;%d" % (len(up), len(down_in), args.crit, len(down_out), args.crit))
if len(down)>=args.crit:
return STATUS_ERROR
else:
return STATUS_WARNING
if up:
print("OSD OK")
print("Up OSDs: " + " ".join(up))
print("Down+In OSDs: " + " ".join(down_in))
print("Down+Out OSDs: " + " ".join(down_out))
print("| 'osd_up'=%d 'osd_down_in'=%d;;%d 'osd_down_out'=%d;;%d" % (len(up), len(down_in), args.crit, len(down_out), args.crit))
return STATUS_OK
print("OSD WARN: no OSD.%s found on host %s" % (args.osdid, args.host))
return STATUS_WARNING
if __name__ == "__main__":
sys.exit(main())

View File

@ -0,0 +1,152 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2020 Binero AB https://binero.com
# Copyright (c) 2013 Catalyst IT http://www.catalyst.net.nz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import argparse
import os
import re
import subprocess
import sys
import socket
import json
CEPH_COMMAND = '/usr/bin/ceph'
STATUS_OK = 0
STATUS_CRITICAL = 2
STATUS_UNKNOWN = 3
def main():
parser = argparse.ArgumentParser(description="'ceph osd' nagios plugin.")
parser.add_argument('-e','--exe', help='ceph executable [%s]' % CEPH_COMMAND)
parser.add_argument('-c','--conf', help='alternative ceph conf file')
parser.add_argument('-m','--monaddress', help='ceph monitor address[:port]')
parser.add_argument('-i','--id', help='ceph client id')
parser.add_argument('-k','--keyring', help='ceph client keyring file')
parser.add_argument('-H','--host', help='osd host', required=True)
parser.add_argument('-C','--critical', help='critical threshold', default=60)
args = parser.parse_args()
ceph_exec = args.exe if args.exe else CEPH_COMMAND
if not os.path.exists(ceph_exec):
print("UNKNOWN: ceph executable '%s' doesn't exist" % ceph_exec)
return STATUS_UNKNOWN
if args.conf and not os.path.exists(args.conf):
print("UNKNOWN: ceph conf file '%s' doesn't exist" % args.conf)
return STATUS_UNKNOWN
if args.keyring and not os.path.exists(args.keyring):
print("UNKNOWN: keyring file '%s' doesn't exist" % args.keyring)
return STATUS_UNKNOWN
if not args.host:
print("UNKNOWN: no OSD hostname given")
return STATUS_UNKNOWN
try:
addrinfo = socket.getaddrinfo(args.host, None, 0, socket.SOCK_STREAM)
args.host = addrinfo[0][-1][0]
if addrinfo[0][0] == socket.AF_INET6:
args.host = "[%s]" % args.host
except Exception:
print('UNKNOWN: could not resolve %s' % args.host)
return STATUS_UNKNOWN
ceph_cmd = [ceph_exec]
if args.monaddress:
ceph_cmd.append('-m')
ceph_cmd.append(args.monaddress)
if args.conf:
ceph_cmd.append('-c')
ceph_cmd.append(args.conf)
if args.id:
ceph_cmd.append('--id')
ceph_cmd.append(args.id)
if args.keyring:
ceph_cmd.append('--keyring')
ceph_cmd.append(args.keyring)
ceph_cmd.append('osd')
ceph_cmd.append('dump')
p = subprocess.Popen(ceph_cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
output, err = p.communicate()
if err or not output:
print("CRITICAL: %s" % err)
return STATUS_CRITICAL
# escape IPv4 host address
osd_host = args.host.replace('.', '\.')
# escape IPv6 host address
osd_host = osd_host.replace('[', '\[')
osd_host = osd_host.replace(']', '\]')
osds_up = re.findall(r"^(osd\.[^ ]*) up.*%s:" % (osd_host), output, re.MULTILINE)
final_status = STATUS_OK
lines = []
for osd in osds_up:
daemon_ceph_cmd = [ceph_exec, '--format', 'json']
daemon_ceph_cmd.append('daemon')
daemon_ceph_cmd.append(osd)
daemon_ceph_cmd.append('perf')
daemon_ceph_cmd.append('dump')
p = subprocess.Popen(daemon_ceph_cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
output, err = p.communicate()
if err or not output:
print("CRITICAL: %s" % err)
return STATUS_CRITICAL
try:
data = json.loads(output)
except Exception:
print("CRITICAL: failed to load json")
return STATUS_CRITICAL
bluefs = data.get('bluefs', None)
if not bluefs:
continue
db_total_bytes = bluefs.get('db_total_bytes')
db_used_bytes = bluefs.get('db_used_bytes')
perc = (float(db_used_bytes) / float(db_total_bytes) * 100)
if perc >= args.critical and final_status == STATUS_OK:
final_status = STATUS_CRITICAL
lines.append("%s=%.2f%%" % (osd, perc))
if final_status == STATUS_OK:
print("OK: %s" % (' '.join(lines)))
else:
print("CRITICAL: %s" % (' '.join(lines)))
return final_status
if __name__ == "__main__":
sys.exit(main())

View File

@ -0,0 +1,153 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# check_ceph_osd_df - Check OSD DF output
# Copyright (c) 2020 noris network AG https://www.noris.de
#
# This plugin will not output perfdata as there is likely a lot of output
# which should be gathered using other tools.
#
# Parts based on code from check_ceph_df which is
# Copyright (c) 2013 SWITCH http://www.switch.ch
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from __future__ import print_function
import argparse
import os
import subprocess
import sys
import json
from operator import itemgetter
# Semver
__version__ = '1.0.0'
# default ceph values
CEPH_COMMAND = '/usr/bin/ceph'
# nagios exit code
STATUS_OK = 0
STATUS_WARNING = 1
STATUS_ERROR = 2
STATUS_UNKNOWN = 3
def main():
# parse args
parser = argparse.ArgumentParser(description="'ceph osd df' nagios plugin.")
parser.add_argument('-e','--exe', help='ceph executable [%s]' % CEPH_COMMAND)
parser.add_argument('-c','--conf', help='alternative ceph conf file')
parser.add_argument('-m','--monaddress', help='ceph monitor address[:port]')
parser.add_argument('-i','--id', help='ceph client id')
parser.add_argument('-n','--name', help='ceph client name')
parser.add_argument('-k','--keyring', help='ceph client keyring file')
parser.add_argument('-W','--warn', help="warn above this percent USED", type=float)
parser.add_argument('-C','--critical', help="critical alert above this percent USED", type=float)
parser.add_argument('-V','--version', help='show version and exit', action='store_true')
args = parser.parse_args()
# validate args
ceph_exec = args.exe if args.exe else CEPH_COMMAND
if not os.path.exists(ceph_exec):
print("ERROR: ceph executable '%s' doesn't exist" % ceph_exec)
return STATUS_UNKNOWN
if args.version:
print('version %s' % __version__)
return STATUS_OK
if args.conf and not os.path.exists(args.conf):
print("ERROR: ceph conf file '%s' doesn't exist" % args.conf)
return STATUS_UNKNOWN
if args.keyring and not os.path.exists(args.keyring):
print("ERROR: keyring file '%s' doesn't exist" % args.keyring)
return STATUS_UNKNOWN
if not args.warn or not args.critical or args.warn > args.critical:
print("ERROR: warn and critical level must be set and critical must be greater than warn")
return STATUS_UNKNOWN
# build command
ceph_osd_df = [ceph_exec]
if args.monaddress:
ceph_osd_df.append('-m')
ceph_osd_df.append(args.monaddress)
if args.conf:
ceph_osd_df.append('-c')
ceph_osd_df.append(args.conf)
if args.id:
ceph_osd_df.append('--id')
ceph_osd_df.append(args.id)
if args.name:
ceph_osd_df.append('--name')
ceph_osd_df.append(args.name)
if args.keyring:
ceph_osd_df.append('--keyring')
ceph_osd_df.append(args.keyring)
ceph_osd_df.append('osd')
ceph_osd_df.append('df')
ceph_osd_df.append('--format=json')
# exec command
p = subprocess.Popen(ceph_osd_df,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
output, err = p.communicate()
# parse output
# print "DEBUG: output:", output
# print "DEBUG: err:", err
if output:
# parse output
try:
result = json.loads(output)
check_return_value = STATUS_OK
nodes_sorted = sorted(result["nodes"], key=itemgetter('utilization','id'))
warn_crit_osds = []
for node in reversed(nodes_sorted):
if node["utilization"] >= args.warn and check_return_value is not STATUS_ERROR:
check_return_value = STATUS_WARNING
warn_crit_osds.append("{}={:04.2f}".format(node["name"], node["utilization"]))
if node["utilization"] >= args.critical:
check_return_value = STATUS_ERROR
warn_crit_osds.append("{}={:04.2f}".format(node["name"], node["utilization"]))
if check_return_value == STATUS_OK:
print("OK: All OSDs within limits")
return STATUS_OK
elif check_return_value == STATUS_WARNING:
print("WARNING: OSD usage above warn threshold: {:.4054}".format(", ".join(warn_crit_osds)))
return STATUS_WARNING
elif check_return_value == STATUS_ERROR:
print("CRITICAL: OSD usage above critical or warn threshold: {:.4041}".format(", ".join(warn_crit_osds)))
return STATUS_ERROR
except:
print("ERROR: {}".format(sys.exc_info()[0]))
return STATUS_UNKNOWN
elif err:
# read only first line of error
one_line = err.split('\n')[0]
if '-1 ' in one_line:
idx = one_line.rfind('-1 ')
print('ERROR: %s: %s' % (ceph_exec, one_line[idx+len('-1 '):]))
else:
print(one_line)
return STATUS_UNKNOWN
if __name__ == "__main__":
sys.exit(main())

View File

@ -0,0 +1,118 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2014 Catalyst IT http://www.catalyst.net.nz
# Copyright (c) 2015 SWITCH http://www.switch.ch
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import print_function
import argparse
import os
import re
import subprocess
import sys
import json
__version__ = '1.5.1'
# default ceph values
RGW_COMMAND = '/usr/bin/radosgw-admin'
# nagios exit code
STATUS_OK = 0
STATUS_WARNING = 1
STATUS_ERROR = 2
STATUS_UNKNOWN = 3
def main():
# parse args
parser = argparse.ArgumentParser(description="'radosgw-admin bucket stats' nagios plugin.")
parser.add_argument('-d','--detail', help='output perf data for all buckets', action='store_true')
parser.add_argument('-B','--byte', help='output perf data in Byte instead of KB', action='store_true')
parser.add_argument('-e','--exe', help='radosgw-admin executable [%s]' % RGW_COMMAND)
parser.add_argument('-c','--conf', help='alternative ceph conf file')
parser.add_argument('-i','--id', help='ceph client id')
parser.add_argument('-n','--name', help='ceph client name (type.id)')
parser.add_argument('-V','--version', help='show version and exit', action='store_true')
args = parser.parse_args()
# validate args
rgw_exec = args.exe if args.exe else RGW_COMMAND
if not os.path.exists(rgw_exec):
print("RGW ERROR: radosgw-admin executable '%s' doesn't exist" % rgw_exec)
return STATUS_UNKNOWN
if args.version:
print('version %s' % __version__)
return STATUS_OK
if args.conf and not os.path.exists(args.conf):
print("RGW ERROR: ceph conf file '%s' doesn't exist" % args.conf)
return STATUS_UNKNOWN
# build command
rgw_cmd = [rgw_exec]
if args.conf:
rgw_cmd.append('-c')
rgw_cmd.append(args.conf)
if args.id:
rgw_cmd.append('--id')
rgw_cmd.append(args.id)
if args.name:
rgw_cmd.append('-n')
rgw_cmd.append(args.name)
rgw_cmd.append('bucket')
rgw_cmd.append('stats')
# exec command
p = subprocess.Popen(rgw_cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
output, err = p.communicate()
if p.returncode != 0 or not output:
print("RGW ERROR: %s :: %s" % (output, err))
return STATUS_ERROR
bucket_stats = json.loads(output)
#print bucket_stats
buckets = []
for i in bucket_stats:
if type(i) is dict:
bucket_name = i['bucket']
usage_dict = i['usage']
if usage_dict and 'rgw.main' in usage_dict:
bucket_usage_kb = usage_dict['rgw.main']['size_kb_actual']
else:
bucket_usage_kb = 0
buckets.append((bucket_name, bucket_usage_kb))
buckets_total_kb = sum([b[1] for b in buckets])
if args.byte:
status = "RGW OK: {} buckets, {} KB total | /={}B ".format(len(buckets),buckets_total_kb,buckets_total_kb*1024)
else:
status = "RGW OK: {} buckets, {} KB total | /={}KB ".format(len(buckets),buckets_total_kb,buckets_total_kb)
#print buckets
if buckets and args.detail:
if args.byte:
status = status + " ".join(["{}={}B".format(b[0],b[1]*1024) for b in buckets])
else:
status = status + " ".join(["{}={}KB".format(b[0],b[1]) for b in buckets])
print(status)
return STATUS_OK
if __name__ == "__main__":
sys.exit(main())

View File

@ -0,0 +1,116 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2014 Catalyst IT http://www.catalyst.net.nz
# Copyright (c) 2015 SWITCH http://www.switch.ch
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import print_function
import requests
import warnings
import json
import argparse
import sys
from awsauth import S3Auth
__version__ = '1.7.2'
# nagios exit code
STATUS_OK = 0
STATUS_WARNING = 1
STATUS_CRITICAL = 2
STATUS_UNKNOWN = 3
def main():
# parse args
parser = argparse.ArgumentParser(description="'radosgw api bucket stats' nagios plugin.")
parser.add_argument('-H', '--host', help="Server URL for the radosgw api (example: http://objects.dreamhost.com/)", required=True)
parser.add_argument('-k', '--insecure', help="Allow insecure server connections when using SSL", action="store_false")
parser.add_argument('-e', '--admin_entry', help="The entry point for an admin request URL [default is '%(default)s']", default="admin")
parser.add_argument('-a', '--access_key', help="S3 access key", required=True)
parser.add_argument('-s', '--secret_key', help="S3 secret key", required=True)
parser.add_argument('-d', '--detail', help="output perf data for all buckets", action="store_true")
parser.add_argument('-b', '--byte', help="output perf data in Byte instead of KB", action="store_true")
parser.add_argument('-v', '--version', help='show version and exit', action="store_true")
args = parser.parse_args()
if args.version:
print("version {0}".format(__version__))
return STATUS_OK
# helpers for default schema
if not args.host.startswith("http"):
args.host = "http://{0}".format(args.host)
# and for request_uri
if not args.host.endswith("/"):
args.host = "{0}/".format(args.host)
url = "{0}{1}/bucket?format=json&stats=True".format(args.host,
args.admin_entry)
try:
# Inversion of condition, when '--insecure' is defined we disable
# requests warning about certificate hostname mismatch.
if not args.insecure:
warnings.filterwarnings('ignore', message='Unverified HTTPS request')
response = requests.get(url, verify=args.insecure,
auth=S3Auth(args.access_key, args.secret_key,
args.host))
if response.status_code == requests.codes.ok:
bucket_stats = response.json()
else:
# no usage caps or wrong admin entry
print("RGW ERROR [{0}]: {1}".format(response.status_code,
response.content.decode('utf-8')))
return STATUS_WARNING
# DNS, connection errors, etc
except requests.exceptions.RequestException as e:
print("RGW ERROR: {0}".format(e))
return STATUS_UNKNOWN
#print(bucket_stats)
buckets = []
for i in bucket_stats:
if type(i) is dict:
bucket_name = i['bucket']
usage_dict = i['usage']
if usage_dict and 'rgw.main' in usage_dict:
bucket_usage_kb = usage_dict['rgw.main']['size_kb_actual']
else:
bucket_usage_kb = 0
buckets.append((bucket_name, bucket_usage_kb))
buckets_total_kb = sum([b[1] for b in buckets])
status = "RGW OK: {0} buckets, {1} KB total | /={2}{3} "
if args.byte:
status = status.format(len(buckets), buckets_total_kb, buckets_total_kb*1024, "B")
else:
status = status.format(len(buckets), buckets_total_kb, buckets_total_kb, "KB")
#print(buckets)
if buckets and args.detail:
if args.byte:
status = status + " ".join(["{}={}B".format(b[0], b[1]*1024) for b in buckets])
else:
status = status + " ".join(["{}={}KB".format(b[0], b[1]) for b in buckets])
print(status)
return STATUS_OK
if __name__ == "__main__":
sys.exit(main())

View File

@ -5,6 +5,7 @@
# Copyright (C) 2012, Giacomo Montagner <giacomo@entirelyunlike.net> # Copyright (C) 2012, Giacomo Montagner <giacomo@entirelyunlike.net>
# 2015, Yann Fertat, Romain Dessort, Jeff Palmer, # 2015, Yann Fertat, Romain Dessort, Jeff Palmer,
# Christophe Drevet-Droguet <dr4ke@dr4ke.net> # Christophe Drevet-Droguet <dr4ke@dr4ke.net>
# 2022, Jérémy Lecour <jlecour@evolix.fr>
# #
# This program is free software; you can redistribute it and/or modify it # This program is free software; you can redistribute it and/or modify it
# under the same terms as Perl 5.10.1. # under the same terms as Perl 5.10.1.
@ -15,7 +16,7 @@
# warranty of merchantability or fitness for a particular purpose. # warranty of merchantability or fitness for a particular purpose.
# #
our $VERSION = "1.2.0"; our $VERSION = "1.3.1";
open(STDERR, ">&STDOUT"); open(STDERR, ">&STDOUT");
@ -29,6 +30,8 @@ open(STDERR, ">&STDOUT");
# 1.1.0 - support for HTTP interface # 1.1.0 - support for HTTP interface
# 1.1.1 - drop perl 5.10 requirement # 1.1.1 - drop perl 5.10 requirement
# 1.2.0 - add an option for ignore NOLB # 1.2.0 - add an option for ignore NOLB
# 1.3.0 - add an option for ignore DRAIN
# 1.3.1 - support DRAIN/MAINT when set by agent
use strict; use strict;
use warnings; use warnings;
@ -64,6 +67,8 @@ DESCRIPTION
Assume servers in MAINT state to be ok. Assume servers in MAINT state to be ok.
-n, --ignore-nolb -n, --ignore-nolb
Assume servers in NOLB state to be ok. Assume servers in NOLB state to be ok.
--ignore-drain
Assume servers in DRAIN state to be ok.
-p, --proxy -p, --proxy
Check only named proxies, not every one. Use comma to separate proxies Check only named proxies, not every one. Use comma to separate proxies
in list. in list.
@ -132,6 +137,7 @@ my $pass = '';
my $dump; my $dump;
my $ignore_maint; my $ignore_maint;
my $ignore_nolb; my $ignore_nolb;
my $ignore_drain;
my $proxy; my $proxy;
my $no_proxy; my $no_proxy;
my $help; my $help;
@ -143,7 +149,8 @@ GetOptions (
"d|dump" => \$dump, "d|dump" => \$dump,
"h|help" => \$help, "h|help" => \$help,
"m|ignore-maint" => \$ignore_maint, "m|ignore-maint" => \$ignore_maint,
"n|ignore-nolb" => \$ignore_nolb, "n|ignore-nolb" => \$ignore_nolb,
"ignore-drain" => \$ignore_drain,
"p|proxy=s" => \$proxy, "p|proxy=s" => \$proxy,
"P|no-proxy=s" => \$no_proxy, "P|no-proxy=s" => \$no_proxy,
"s|sock|socket=s" => \$sock, "s|sock|socket=s" => \$sock,
@ -267,8 +274,9 @@ foreach (@hastats) {
# Check of servers # Check of servers
} else { } else {
if ($data[$status] ne 'UP') { if ($data[$status] ne 'UP') {
next if ($ignore_maint && $data[$status] eq 'MAINT'); next if ($ignore_maint && ($data[$status] eq 'MAINT' || $data[$status] eq 'MAINT (agent)'));
next if ($ignore_nolb && $data[$status] eq 'NOLB'); next if ($ignore_nolb && $data[$status] eq 'NOLB');
next if ($ignore_drain && ($data[$status] eq 'DRAIN' || $data[$status] eq 'DRAIN (agent)'));
next if $data[$status] eq 'no check'; # Ignore server if no check is configured to be run next if $data[$status] eq 'no check'; # Ignore server if no check is configured to be run
next if $data[$svname] eq 'sock-1'; next if $data[$svname] eq 'sock-1';
$exitcode = 2; $exitcode = 2;

View File

@ -51,7 +51,7 @@ command[check_ssl]=/usr/lib/nagios/plugins/check_http -f follow -I 127.0.0.1 -S
command[check_ssl_local]={{ nagios_plugins_directory }}/check_ssl_local command[check_ssl_local]={{ nagios_plugins_directory }}/check_ssl_local
command[check_elasticsearch]=/usr/lib/nagios/plugins/check_http -I 127.0.0.1 -u /_cat/health?h=st -p 9200 -r 'red' --invert-regex command[check_elasticsearch]=/usr/lib/nagios/plugins/check_http -I 127.0.0.1 -u /_cat/health?h=st -p 9200 -r 'red' --invert-regex
command[check_memcached]=/usr/lib/nagios/plugins/check_tcp -H 127.0.0.1 -p 11211 command[check_memcached]=/usr/lib/nagios/plugins/check_tcp -H 127.0.0.1 -p 11211
command[check_opendkim]=/usr/lib/nagios/plugins/check_tcp -H 127.0.0.1 -p 54321 command[check_opendkim]=/usr/lib/nagios/plugins/check_tcp -H 127.0.0.1 -p 8891
command[check_bkctld_setup]=sudo /usr/sbin/bkctld check-setup command[check_bkctld_setup]=sudo /usr/sbin/bkctld check-setup
command[check_bkctld_jails]=sudo /usr/sbin/bkctld check-jails command[check_bkctld_jails]=sudo /usr/sbin/bkctld check-jails
# "check_bkctld" is here as backward compatibility, but is replaced by "check_bkctld_jails" # "check_bkctld" is here as backward compatibility, but is replaced by "check_bkctld_jails"
@ -72,7 +72,7 @@ command[check_mongodb_connect]={{ nagios_plugins_directory }}/check_mongodb -H l
command[check_glusterfs]={{ nagios_plugins_directory }}/check_glusterfs -v all -n 0 command[check_glusterfs]={{ nagios_plugins_directory }}/check_glusterfs -v all -n 0
command[check_supervisord_status]={{ nagios_plugins_directory }}/check_supervisord command[check_supervisord_status]={{ nagios_plugins_directory }}/check_supervisord
command[check_varnish]={{ nagios_plugins_directory }}/check_varnish_health -i 127.0.0.1 -p 6082 -s /etc/varnish/secret -w 2 -c 4 command[check_varnish]={{ nagios_plugins_directory }}/check_varnish_health -i 127.0.0.1 -p 6082 -s /etc/varnish/secret -w 2 -c 4
command[check_haproxy]=sudo {{ nagios_plugins_directory }}/check_haproxy_stats -s /run/haproxy/admin.sock -w 80 -c 90 --ignore-maint --ignore-nolb command[check_haproxy]=sudo {{ nagios_plugins_directory }}/check_haproxy_stats -s /run/haproxy/admin.sock -w 80 -c 90 --ignore-maint --ignore-nolb --ignore-drain
command[check_minifirewall]=sudo {{ nagios_plugins_directory }}/check_minifirewall command[check_minifirewall]=sudo {{ nagios_plugins_directory }}/check_minifirewall
command[check_redis_instances]={{ nagios_plugins_directory }}/check_redis_instances command[check_redis_instances]={{ nagios_plugins_directory }}/check_redis_instances
command[check_hpraid]={{ nagios_plugins_directory }}/check_hpraid command[check_hpraid]={{ nagios_plugins_directory }}/check_hpraid

View File

@ -5,3 +5,5 @@ newrelic_php: False
newrelic_license: "" newrelic_license: ""
newrelic_appname: "" newrelic_appname: ""
apt_keyring_dir: "{{ ansible_distribution_major_version is version('12', '<') | ternary('/etc/apt/trusted.gpg.d', '/etc/apt/keyrings') }}"

View File

@ -15,7 +15,7 @@
- name: Add NewRelic GPG key - name: Add NewRelic GPG key
copy: copy:
src: newrelic.asc src: newrelic.asc
dest: /etc/apt/trusted.gpg.d/newrelic.asc dest: "{{ apt_keyring_dir }}/newrelic.asc"
force: yes force: yes
mode: "0644" mode: "0644"
owner: root owner: root
@ -23,7 +23,14 @@
- name: Install NewRelic repository - name: Install NewRelic repository
apt_repository: apt_repository:
repo: "deb http://apt.newrelic.com/debian/ newrelic non-free" repo: "deb [signed-by={{ apt_keyring_dir }}/newrelic.asc] http://apt.newrelic.com/debian/ newrelic non-free"
state: present state: present
filename: newrelic filename: newrelic
update_cache: yes update_cache: yes
- name: Desinstall unsigned NewRelic repository
apt_repository:
repo: "deb http://apt.newrelic.com/debian/ newrelic non-free"
state: absent
filename: newrelic
update_cache: yes

View File

@ -4,3 +4,5 @@
nodejs_apt_version: 'node_16.x' nodejs_apt_version: 'node_16.x'
nodejs_install_yarn: False nodejs_install_yarn: False
apt_keyring_dir: "{{ ansible_distribution_major_version is version('12', '<') | ternary('/etc/apt/trusted.gpg.d', '/etc/apt/keyrings') }}"

View File

@ -32,7 +32,7 @@
- name: NodeJS GPG key is installed - name: NodeJS GPG key is installed
copy: copy:
src: nodesource.asc src: nodesource.asc
dest: /etc/apt/trusted.gpg.d/nodesource.asc dest: "{{ apt_keyring_dir }}/nodesource.asc"
mode: "0644" mode: "0644"
owner: root owner: root
group: root group: root
@ -43,7 +43,7 @@
- name: NodeJS sources list ({{ nodejs_apt_version }}) is available - name: NodeJS sources list ({{ nodejs_apt_version }}) is available
apt_repository: apt_repository:
repo: "deb https://deb.nodesource.com/{{ nodejs_apt_version }} {{ ansible_distribution_release }} main" repo: "deb [signed-by={{ apt_keyring_dir }}/nodesource.asc] https://deb.nodesource.com/{{ nodejs_apt_version }} {{ ansible_distribution_release }} main"
filename: nodesource filename: nodesource
update_cache: yes update_cache: yes
state: present state: present
@ -52,6 +52,17 @@
- packages - packages
- nodejs - nodejs
- name: Unsigned NodeJS sources list ({{ nodejs_apt_version }}) is not available
apt_repository:
repo: "deb https://deb.nodesource.com/{{ nodejs_apt_version }} {{ ansible_distribution_release }} main"
filename: nodesource
update_cache: yes
state: absent
tags:
- system
- packages
- nodejs
- name: NodeJS is installed - name: NodeJS is installed
apt: apt:
name: nodejs name: nodejs

View File

@ -25,7 +25,7 @@
- name: Yarn GPG key is installed - name: Yarn GPG key is installed
copy: copy:
src: yarn.asc src: yarn.asc
dest: /etc/apt/trusted.gpg.d/yarn.asc dest: "{{ apt_keyring_dir }}/yarn.asc"
mode: "0644" mode: "0644"
owner: root owner: root
group: root group: root
@ -37,7 +37,7 @@
- name: Yarn sources list is available - name: Yarn sources list is available
apt_repository: apt_repository:
repo: "deb https://dl.yarnpkg.com/debian/ stable main" repo: "deb [signed-by={{ apt_keyring_dir }}/yarn.asc] https://dl.yarnpkg.com/debian/ stable main"
filename: yarn filename: yarn
update_cache: yes update_cache: yes
state: present state: present
@ -47,6 +47,18 @@
- nodejs - nodejs
- yarn - yarn
- name: Unsigned Yarn sources list is not available
apt_repository:
repo: "deb https://dl.yarnpkg.com/debian/ stable main"
filename: yarn
update_cache: yes
state: absent
tags:
- system
- packages
- nodejs
- yarn
- name: Yarn is installed - name: Yarn is installed
apt: apt:
name: yarn name: yarn

View File

@ -1,26 +1,126 @@
#!/bin/sh #!/bin/sh
carp=$(/sbin/ifconfig carp0 2>/dev/null | grep 'status' | cut -d' ' -f2) VERSION="22.12.1"
if [ "$carp" = "backup" ]; then show_version() {
exit 0 cat <<END
fi cert-expirations.sh version ${VERSION}
echo "Warning : all times are in UTC !\n" Copyright 2020-2022 Evolix <info@evolix.fr>,
Jérémy Lecour <jlecour@evolix.fr>,
Jérémy Dubois <jdubois@evolix.fr>
and others.
echo "CA certificate:" cert-expirations.sh comes with ABSOLUTELY NO WARRANTY. This is free software,
openssl x509 -enddate -noout -in /etc/shellpki/cacert.pem \ and you are welcome to redistribute it under certain conditions.
| cut -d '=' -f 2 \ See the MIT Licence for details.
| sed -e "s/^\(.*\)\ \(20..\).*/- \2 \1/" END
}
echo "" show_usage() {
cat <<END
Usage: ${0} [--version]
END
}
echo "Client certificates:" check_carp_state() {
cat /etc/shellpki/index.txt \ if [ "${SYSTEM}" = "openbsd" ]; then
| grep ^V \ carp=$(/sbin/ifconfig carp0 2>/dev/null | grep 'status' | cut -d' ' -f2)
| awk -F "/" '{print $1,$5}' \
| awk '{print $2,$5}' \ if [ "$carp" = "backup" ]; then
| sed 's/CN=//' \ exit 0
| sed -E 's/([[:digit:]]{2})([[:digit:]]{2})([[:digit:]]{2})([[:digit:]]{2})([[:digit:]]{2})([[:digit:]]{2})Z (.*)/- 20\1 \2 \3 \4:\5:\6 \7/' \ fi
| awk '{if ($3 == "01") $3="Jan"; else if ($3 == "02") $3="Feb"; else if ($3 == "03") $3="Mar"; else if ($3 == "04") $3="Apr"; else if ($3 == "05") $3="May"; else if ($3 == "06") $3="Jun"; else if ($3 == "07") $3="Jul"; else if ($3 == "08") $3="Aug"; else if ($3 == "09") $3="Sep"; else if ($3 == "10") $3="Oct"; else if ($3 == "11") $3="Nov"; else if ($3 == "12") $3="Dec"; print $0;}' \ fi
| sort -n -k 2 -k 3M -k 4 }
check_ca_expiration() {
echo "CA certificate:"
openssl x509 -enddate -noout -in ${cacert_path} \
| cut -d '=' -f 2 \
| sed -e "s/^\(.*\)\ \(20..\).*/- \2 \1/"
}
check_certs_expiration() {
# Syntax "cmd | { while read line; do var="foo"; done echo $var }" needed, otherwise $var is empty at the end of while loop
grep ^V ${index_path} \
| awk -F "/" '{print $1,$5}' \
| awk '{print $2,$5}' \
| sed 's/CN=//' \
| sed -E 's/([[:digit:]]{2})([[:digit:]]{2})([[:digit:]]{2})([[:digit:]]{2})([[:digit:]]{2})([[:digit:]]{2})Z (.*)/- 20\1 \2 \3 \4:\5:\6 \7/' \
| awk '{if ($3 == "01") $3="Jan"; else if ($3 == "02") $3="Feb"; else if ($3 == "03") $3="Mar"; else if ($3 == "04") $3="Apr"; else if ($3 == "05") $3="May"; else if ($3 == "06") $3="Jun"; else if ($3 == "07") $3="Jul"; else if ($3 == "08") $3="Aug"; else if ($3 == "09") $3="Sep"; else if ($3 == "10") $3="Oct"; else if ($3 == "11") $3="Nov"; else if ($3 == "12") $3="Dec"; print $0;}' \
| sort -n -k 2 -k 3M -k 4 | {
while read -r line; do
# Predicting expirations - OpenBSD case (date is not the same than in Linux)
if [ "${SYSTEM}" = "openbsd" ]; then
# Already expired if expiration date is before now
if [ "$(TZ=:Zulu date -jf "%Y %b %d %H:%M:%S" "$(echo "$line" | awk '{print $2,$3,$4,$5}')" +%s)" -le "$(date +%s)" ]; then
expired_certs="${expired_certs}$line\n"
# Expiring soon if expiration date is after now and before now + $somedays days
elif [ "$(TZ=:Zulu date -jf "%Y %b %d %H:%M:%S" "$(echo "$line" | awk '{print $2,$3,$4,$5}')" +%s)" -gt "$(date +%s)" ] && [ "$(TZ=:Zulu date -jf "%Y %b %d %H:%M:%S" "$(echo "$line" | awk '{print $2,$3,$4,$5}')" +%s)" -lt "$(($(date +%s) + somedays))" ]; then
expiring_soon_certs="${expiring_soon_certs}$line\n"
# Still valid for a time if expiration date is after now + $somedays days
elif [ "$(TZ=:Zulu date -jf "%Y %b %d %H:%M:%S" "$(echo "$line" | awk '{print $2,$3,$4,$5}')" +%s)" -ge "$(($(date +%s) + somedays))" ]; then
still_valid_certs="${still_valid_certs}$line\n"
fi
# Non OpenBSD cases
else
# Already expired if expiration date is before now
if [ "$(TZ=:Zulu date -d "$(echo "$line" | awk '{print $3,$4,$2,$5}')" +%s)" -le "$(date +%s)" ]; then
expired_certs="${expired_certs}$line\n"
# Expiring soon if expiration date is after now and before now + $somedays days
elif [ "$(TZ=:Zulu date -d "$(echo "$line" | awk '{print $3,$4,$2,$5}')" +%s)" -gt "$(date +%s)" ] && [ "$(TZ=:Zulu date -d "$(echo "$line" | awk '{print $3,$4,$2,$5}')" +%s)" -lt "$(($(date +%s) + somedays))" ]; then
expiring_soon_certs="${expiring_soon_certs}$line\n"
# Still valid for a time if expiration date is after now + $somedays days
elif [ "$(TZ=:Zulu date -d "$(echo "$line" | awk '{print $3,$4,$2,$5}')" +%s)" -ge "$(($(date +%s) + somedays))" ]; then
still_valid_certs="${still_valid_certs}$line\n"
fi
fi
done
echo "Expired client certificates:"
echo "${expired_certs}"
echo "Valid client certificates expiring soon (in less than $((somedays / 60 / 60 / 24)) days):"
echo "${expiring_soon_certs}"
echo "Valid client certificates expiring later (in more than $((somedays / 60 / 60 / 24)) days):"
echo "${still_valid_certs}"
}
}
main() {
SYSTEM=$(uname | tr '[:upper:]' '[:lower:]')
cacert_path="/etc/shellpki/cacert.pem"
index_path="/etc/shellpki/index.txt"
somedays="3456000" # 40 days currently
expired_certs=""
expiring_soon_certs=""
still_valid_certs=""
case "$1" in
version|--version)
show_version
exit 0
;;
help|--help)
show_usage
exit 0
;;
"")
check_carp_state
echo "Warning : all times are in UTC !"
echo ""
check_ca_expiration
echo ""
check_certs_expiration
;;
*)
show_usage >&2
exit 1
;;
esac
}
main "$@"

View File

@ -1,3 +1,5 @@
# VERSION="22.12.2"
[ ca ] [ ca ]
default_ca = CA_default default_ca = CA_default
@ -12,7 +14,7 @@ crl = $dir/crl.pem
private_key = $dir/cakey.key private_key = $dir/cakey.key
RANDFILE = $dir/.rand RANDFILE = $dir/.rand
default_days = 365 default_days = 365
default_crl_days= 365 default_crl_days= 730
default_md = sha256 default_md = sha256
preserve = no preserve = no
policy = policy_match policy = policy_match

View File

@ -5,7 +5,7 @@
set -u set -u
VERSION="22.04" VERSION="22.12.2"
show_version() { show_version() {
cat <<END cat <<END
@ -137,14 +137,14 @@ warning() {
} }
verify_ca_password() { verify_ca_password() {
"${OPENSSL_BIN}" rsa \ "${OPENSSL_BIN}" pkey \
-in "${CA_KEY}" \ -in "${CA_KEY}" \
-passin pass:"${CA_PASSWORD}" \ -passin pass:"${CA_PASSWORD}" \
>/dev/null 2>&1 >/dev/null 2>&1
} }
get_real_path() { get_real_path() {
# --canonicalize is supported on Linux # --canonicalize is supported on Linux
# -f is supported on Linux and OpenBSD # -f is supported on Linux and OpenBSD
readlink -f -- "${1}" readlink -f -- "${1}"
} }
@ -224,9 +224,10 @@ replace_existing_or_abort() {
init() { init() {
umask 0177 umask 0177
[ -d "${CA_DIR}" ] || mkdir -m 0750 "${CA_DIR}" [ -d "${CA_DIR}" ] || mkdir -m 0751 "${CA_DIR}"
[ -d "${CRT_DIR}" ] || mkdir -m 0750 "${CRT_DIR}" [ -d "${CRT_DIR}" ] || mkdir -m 0750 "${CRT_DIR}"
[ -f "${INDEX_FILE}" ] || touch "${INDEX_FILE}" [ -f "${INDEX_FILE}" ] || touch "${INDEX_FILE}"
[ -f "${INDEX_FILE}.attr" ] || touch "${INDEX_FILE}.attr"
[ -f "${CRL}" ] || touch "${CRL}" [ -f "${CRL}" ] || touch "${CRL}"
[ -f "${SERIAL}" ] || echo "01" > "${SERIAL}" [ -f "${SERIAL}" ] || echo "01" > "${SERIAL}"
@ -278,17 +279,18 @@ init() {
passout_arg="" passout_arg=""
if [ -n "${CA_PASSWORD:-}" ]; then if [ -n "${CA_PASSWORD:-}" ]; then
passout_arg="-passout pass:${CA_PASSWORD}" passout_arg="-pass pass:${CA_PASSWORD}"
elif [ "${non_interactive}" -eq 1 ]; then elif [ "${non_interactive}" -eq 1 ]; then
error "In non-interactive mode, you must pass CA_PASSWORD as environment variable." error "In non-interactive mode, you must pass CA_PASSWORD as environment variable."
fi fi
if [ ! -f "${CA_KEY}" ]; then if [ ! -f "${CA_KEY}" ]; then
"${OPENSSL_BIN}" genrsa \ "${OPENSSL_BIN}" genpkey \
-algorithm RSA \
-out "${CA_KEY}" \ -out "${CA_KEY}" \
${passout_arg} \ ${passout_arg} \
-aes256 \ -aes256 \
"${CA_KEY_LENGTH}" \ -pkeyopt "rsa_keygen_bits:${CA_KEY_LENGTH}" \
>/dev/null 2>&1 >/dev/null 2>&1
# shellcheck disable=SC2181 # shellcheck disable=SC2181
if [ "$?" -ne 0 ]; then if [ "$?" -ne 0 ]; then
@ -355,9 +357,10 @@ ocsp() {
port=$(echo "${ocsp_uri}" | cut -d':' -f2) port=$(echo "${ocsp_uri}" | cut -d':' -f2)
if [ ! -f "${OCSP_KEY}" ]; then if [ ! -f "${OCSP_KEY}" ]; then
"${OPENSSL_BIN}" genrsa \ "${OPENSSL_BIN}" genpkey \
-algorithm RSA \
-out "${OCSP_KEY}" \ -out "${OCSP_KEY}" \
"${KEY_LENGTH}" \ -pkeyopt "rsa_keygen_bits:${KEY_LENGTH}" \
>/dev/null 2>&1 >/dev/null 2>&1
# shellcheck disable=SC2181 # shellcheck disable=SC2181
if [ "$?" -ne 0 ]; then if [ "$?" -ne 0 ]; then
@ -680,17 +683,19 @@ create() {
# generate private key # generate private key
pass_args="" pass_args=""
if [ -n "${password_file:-}" ]; then if [ -n "${password_file:-}" ]; then
pass_args="-aes256 -passout file:${password_file}" pass_args="-aes256 -pass file:${password_file}"
elif [ -n "${PASSWORD:-}" ]; then elif [ -n "${PASSWORD:-}" ]; then
pass_args="-aes256 -passout pass:${PASSWORD}" pass_args="-aes256 -pass pass:${PASSWORD}"
fi fi
"${OPENSSL_BIN}" genrsa \ "${OPENSSL_BIN}" genpkey \
-algorithm RSA \
-out "${key_file}" \ -out "${key_file}" \
${pass_args} \ ${pass_args} \
"${KEY_LENGTH}" \ -pkeyopt "rsa_keygen_bits:${KEY_LENGTH}" \
>/dev/null 2>&1 >/dev/null 2>&1
# shellcheck disable=SC2181 # shellcheck disable=SC2181
if [ "$?" -eq 0 ]; then if [ "$?" -eq 0 ]; then
chmod 600 "${key_file}"
echo "The KEY file is available at \`${key_file}'" echo "The KEY file is available at \`${key_file}'"
else else
error "Error generating the private key" error "Error generating the private key"
@ -1098,9 +1103,11 @@ main() {
# fix right # fix right
chown -R "${PKI_USER}":"${PKI_USER}" "${CA_DIR}" chown -R "${PKI_USER}":"${PKI_USER}" "${CA_DIR}"
chmod 750 "${CA_DIR}" "${CRT_DIR}" "${KEY_DIR}" "${CSR_DIR}" "${PKCS12_DIR}" "${OVPN_DIR}" "${TMP_DIR}" chmod 750 "${CRT_DIR}" "${KEY_DIR}" "${CSR_DIR}" "${PKCS12_DIR}" "${OVPN_DIR}" "${TMP_DIR}"
chmod 600 "${INDEX_FILE}"* "${SERIAL}"* "${CA_KEY}" "${CRL}" chmod 600 "${INDEX_FILE}"* "${SERIAL}"* "${CA_KEY}"
chmod 640 "${CA_CERT}" chmod 640 "${CA_CERT}"
chmod 604 "${CRL}"
chmod 751 "${CA_DIR}"
} }
main "$@" main "$@"

View File

@ -48,7 +48,7 @@
group: "{{ item.group }}" group: "{{ item.group }}"
with_items: with_items:
- { source: "openssl.cnf", destination: "/etc/shellpki/openssl.cnf", mode: "0640", owner: "shellpki", group: "shellpki" } - { source: "openssl.cnf", destination: "/etc/shellpki/openssl.cnf", mode: "0640", owner: "shellpki", group: "shellpki" }
- { source: "shellpki", destination: "/usr/local/sbin/shellpki", mode: "0755", owner: "root", group: "root" } - { source: "shellpki", destination: "/usr/local/sbin/shellpki", mode: "0750", owner: "root", group: "root" }
- name: Add sudo rights - name: Add sudo rights
lineinfile: lineinfile:
@ -77,16 +77,6 @@
- include_role: - include_role:
name: evolix/remount-usr 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 604 /etc/shellpki/crl.pem$', line: " chmod 604 /etc/shellpki/crl.pem", insertafter: '^ chmod 640 "\${CACERT}"$' }
- { regexp: '^ chmod 751 /etc/shellpki/$', line: " chmod 751 /etc/shellpki/", insertafter: '^ chmod 604 /etc/shellpki/crl.pem$' }
- name: Deploy OpenVPN server config - name: Deploy OpenVPN server config
template: template:
src: "server.conf.j2" src: "server.conf.j2"
@ -261,7 +251,7 @@
cron: cron:
name: "OpenVPN certificates expiration" name: "OpenVPN certificates expiration"
special_time: monthly special_time: monthly
job: '/usr/share/scripts/cert-expirations.sh | mail -E -s "PKI VPN {{ ansible_hostname }} : recapitulatif expirations" {{ client_email }}' job: '/usr/share/scripts/cert-expirations.sh | mail -E -s "PKI OpenVPN {{ ansible_hostname }} : recapitulatif expirations" {{ client_email }}'
- name: Generate the CA password - name: Generate the CA password
set_fact: set_fact:

View File

@ -38,7 +38,7 @@
group: "{{ item.group }}" group: "{{ item.group }}"
with_items: with_items:
- { source: "openssl.cnf", destination: "/etc/shellpki/openssl.cnf", mode: "0640", owner: "_shellpki", group: "_shellpki" } - { source: "openssl.cnf", destination: "/etc/shellpki/openssl.cnf", mode: "0640", owner: "_shellpki", group: "_shellpki" }
- { source: "shellpki", destination: "/usr/local/sbin/shellpki", mode: "0755", owner: "root", group: "wheel" } - { source: "shellpki", destination: "/usr/local/sbin/shellpki", mode: "0750", owner: "root", group: "wheel" }
- name: Add sudo rights - name: Add sudo rights
lineinfile: lineinfile:
@ -60,16 +60,6 @@
path: /etc/shellpki/dh2048.pem path: /etc/shellpki/dh2048.pem
size: 2048 size: 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 604 /etc/shellpki/crl.pem$', line: " chmod 604 /etc/shellpki/crl.pem", insertafter: '^ chmod 640 "\${CACERT}"$' }
- { regexp: '^ chmod 751 /etc/shellpki/$', line: " chmod 751 /etc/shellpki/", insertafter: '^ chmod 604 /etc/shellpki/crl.pem$' }
- name: Deploy OpenVPN server config - name: Deploy OpenVPN server config
template: template:
src: "server.conf.j2" src: "server.conf.j2"
@ -189,7 +179,7 @@
cron: cron:
name: "OpenVPN certificates expiration" name: "OpenVPN certificates expiration"
special_time: monthly special_time: monthly
job: '/usr/share/scripts/cert-expirations.sh | mail -E -s "PKI VPN {{ ansible_hostname }} : recapitulatif expirations" {{ client_email }}' job: '/usr/share/scripts/cert-expirations.sh | mail -E -s "PKI OpenVPN {{ ansible_hostname }} : recapitulatif expirations" {{ client_email }}'
- name: Generate the CA password - name: Generate the CA password
set_fact: set_fact:

View File

@ -26,18 +26,5 @@ galaxy_info:
allow_duplicates: true allow_duplicates: true
dependencies: dependencies: []
- { role: evolix/apache }
- { role: evolix/php, php_apache_enable: True, when: packweb_apache_modphp }
- { role: evolix/php, php_fpm_enable: True, when: packweb_apache_fpm }
- { role: evolix/squid, squid_localproxy_enable: True }
- { role: evolix/mysql, when: packweb_mysql_variant == "debian" }
- { role: evolix/mysql-oracle, when: packweb_mysql_variant == "oracle" }
- { role: evolix/lxc-php, lxc_php_version: php56, lxc_php_create_mysql_link: True, when: "'php56' in packweb_multiphp_versions" }
- { role: evolix/lxc-php, lxc_php_version: php70, lxc_php_create_mysql_link: True, when: "'php70' in packweb_multiphp_versions" }
- { 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 }

View File

@ -33,6 +33,7 @@
- include - include
- negotiation - negotiation
- alias - alias
- log_forensic
- name: Copy Apache settings for modules - name: Copy Apache settings for modules
copy: copy:

View File

@ -0,0 +1,80 @@
---
- import_role:
name: evolix/apache
- import_role:
name: evolix/php
vars:
php_apache_enable: True
when: packweb_apache_modphp
- import_role:
name: evolix/php
vars:
php_fpm_enable: True
when: packweb_apache_fpm
- import_role:
name: evolix/squid
vars:
squid_localproxy_enable: True
- import_role:
name: evolix/mysql
when: packweb_mysql_variant == "debian"
- import_role:
name: evolix/mysql-oracle
when: packweb_mysql_variant == "oracle"
- import_role:
name: evolix/lxc-php
vars:
lxc_php_version: php56
lxc_php_create_mysql_link: True
when: "'php56' in packweb_multiphp_versions"
- import_role:
name: evolix/lxc-php
vars:
lxc_php_version: php70
lxc_php_create_mysql_link: True
when: "'php70' in packweb_multiphp_versions"
- import_role:
name: evolix/lxc-php
vars:
lxc_php_version: php73
lxc_php_create_mysql_link: True
when: "'php73' in packweb_multiphp_versions"
- import_role:
name: evolix/lxc-php
vars:
lxc_php_version: php74
lxc_php_create_mysql_link: True
when: "'php74' in packweb_multiphp_versions"
- import_role:
name: evolix/lxc-php
vars:
lxc_php_version: php80
lxc_php_create_mysql_link: True
when: "'php80' in packweb_multiphp_versions"
- import_role:
name: evolix/lxc-php
vars:
lxc_php_version: php81
lxc_php_create_mysql_link: True
when: "'php81' in packweb_multiphp_versions"
- import_role:
name: evolix/webapps/evoadmin-web
vars:
evoadmin_enable_vhost: "{{ packweb_enable_evoadmin_vhost }}"
evoadmin_multiphp_versions: "{{ packweb_multiphp_versions }}"
- import_role:
name: evolix/evoacme

View File

@ -1,5 +1,8 @@
--- ---
- name: Dependencies are satisfied
include_tasks: dependencies.yml
- fail: - fail:
msg: only compatible with Debian >= 8 msg: only compatible with Debian >= 8
when: when:

View File

@ -9,7 +9,7 @@
- name: "Met-à-jour userlogrotate" - name: "Met-à-jour userlogrotate"
ansible.builtin.copy: ansible.builtin.copy:
src: userlogrotate src: userlogrotate
dest: "{{ item }}" dest: "{{ item }}"
mode: "0755" mode: "0755"
loop: "{{ find_logrotate.files }}" loop: "{{ find_logrotate.files }}"
when: find_logrotate.files | length>0 when: find_logrotate.files | length>0

View File

@ -2,3 +2,5 @@
percona__install_xtrabackup: True percona__install_xtrabackup: True
percona__xtrabackup_package_name: percona-xtrabackup-24 percona__xtrabackup_package_name: percona-xtrabackup-24
apt_keyring_dir: "{{ ansible_distribution_major_version is version('12', '<') | ternary('/etc/apt/trusted.gpg.d', '/etc/apt/keyrings') }}"

View File

@ -18,7 +18,7 @@
- name: Add Percona GPG key - name: Add Percona GPG key
copy: copy:
src: percona.asc src: percona.asc
dest: /etc/apt/trusted.gpg.d/percona.asc dest: "{{ apt_keyring_dir }}/percona.asc"
force: yes force: yes
mode: "0644" mode: "0644"
owner: root owner: root

View File

@ -8,3 +8,5 @@ php_symfony_requirements: False
php_modules_mysqlnd: False php_modules_mysqlnd: False
php_fpm_remove_default_pool: False php_fpm_remove_default_pool: False
apt_keyring_dir: "{{ ansible_distribution_major_version is version('12', '<') | ternary('/etc/apt/trusted.gpg.d', '/etc/apt/keyrings') }}"

View File

@ -19,3 +19,8 @@
service: service:
name: php7.4-fpm name: php7.4-fpm
state: restarted state: restarted
- name: restart php8.1-fpm
service:
name: php8.1-fpm
state: restarted

View File

@ -4,17 +4,20 @@
that: that:
- ansible_distribution == "Debian" - ansible_distribution == "Debian"
- ansible_distribution_major_version is version('8', '>=') - ansible_distribution_major_version is version('8', '>=')
- ansible_distribution_major_version is version('11', '<=') - ansible_distribution_major_version is version('12', '<=')
msg: This is only compatible with Debian 8 → 11 msg: This is only compatible with Debian 8 → 12
- include: main_jessie.yml - include_tasks: main_jessie.yml
when: ansible_distribution_release == "jessie" when: ansible_distribution_release == "jessie"
- include: main_stretch.yml - include_tasks: main_stretch.yml
when: ansible_distribution_release == "stretch" when: ansible_distribution_release == "stretch"
- include: main_buster.yml - include_tasks: main_buster.yml
when: ansible_distribution_release == "buster" when: ansible_distribution_release == "buster"
- include: main_bullseye.yml - include_tasks: main_bullseye.yml
when: ansible_distribution_release == "bullseye" when: ansible_distribution_release == "bullseye"
- include_tasks: main_bookworm.yml
when: ansible_distribution_release == "bookworm"

108
php/tasks/main_bookworm.yml Normal file
View File

@ -0,0 +1,108 @@
---
- name: "Set php version to 8.1 (Debian 12)"
set_fact:
php_version: "8.1"
- name: "Set php config directories (Debian 12)"
set_fact:
php_cli_conf_dir: "/etc/php/{{ php_version }}/cli/conf.d"
php_apache_conf_dir: "/etc/php/{{ php_version }}/apache2/conf.d"
php_fpm_conf_dir: "/etc/php/{{ php_version }}/fpm/conf.d"
php_fpm_pool_dir: "/etc/php/{{ php_version }}/fpm/pool.d"
- name: "Set php config files (Debian 12)"
set_fact:
php_cli_defaults_ini_file: "{{ php_cli_conf_dir }}/z-evolinux-defaults.ini"
php_cli_custom_ini_file: "{{ php_cli_conf_dir }}/zzz-evolinux-custom.ini"
php_apache_defaults_ini_file: "{{ php_apache_conf_dir }}/z-evolinux-defaults.ini"
php_apache_custom_ini_file: "{{ php_apache_conf_dir }}/zzz-evolinux-custom.ini"
php_fpm_defaults_ini_file: "{{ php_fpm_conf_dir }}/z-evolinux-defaults.ini"
php_fpm_custom_ini_file: "{{ php_fpm_conf_dir }}/zzz-evolinux-custom.ini"
php_fpm_debian_default_pool_file: "{{ php_fpm_pool_dir}}/www.conf"
php_fpm_default_pool_file: "{{ php_fpm_pool_dir}}/www-evolinux-defaults.conf"
php_fpm_default_pool_custom_file: "{{ php_fpm_pool_dir}}/www-evolinux-zcustom.conf"
php_fpm_default_pool_socket: "/var/run/php/php{{ php_version }}-fpm.sock"
php_fpm_service_name: "php{{ php_version }}-fpm"
# Packages
- name: "Set package list (Debian 12)"
set_fact:
php_stretch_packages:
- php-cli
- php-gd
- php-intl
- php-imap
- php-ldap
- php-mysql
# php-mcrypt is no longer packaged for PHP 7.2
- php-pgsql
- php-sqlite3
- php-curl
- php-ssh2
- php-xml
- php-zip
- composer
- libphp-phpmailer
- include: sury_pre.yml
when: php_sury_enable
- name: "Install PHP packages (Debian 12)"
apt:
name: '{{ php_stretch_packages }}'
state: present
- name: "Install mod_php packages (Debian 12)"
apt:
name:
- libapache2-mod-php
- php
state: present
when: php_apache_enable
- name: "Install PHP FPM packages (Debian 12)"
apt:
name:
- php-fpm
- php
state: present
when: php_fpm_enable
# Configuration
- name: "Enforce permissions on PHP directory (Debian 12)"
file:
dest: "{{ item }}"
mode: "0755"
with_items:
- /etc/php
- /etc/php/{{ php_version }}
- include: config_cli.yml
- name: "Enforce permissions on PHP cli directory (Debian 12)"
file:
dest: /etc/php/{{ php_version }}/cli
mode: "0755"
- include: config_fpm.yml
when: php_fpm_enable
- name: "Enforce permissions on PHP fpm directory (Debian 12)"
file:
dest: /etc/php/{{ php_version }}/fpm
mode: "0755"
when: php_fpm_enable
- include: config_apache.yml
when: php_apache_enable
- name: "Enforce permissions on PHP apache2 directory (Debian 12)"
file:
dest: /etc/php/{{ php_version }}/apache2
mode: "0755"
when: php_apache_enable
- include: sury_post.yml
when: php_sury_enable

View File

@ -3,7 +3,7 @@
- name: Setup deb.sury.org repository - Add GPG key - name: Setup deb.sury.org repository - Add GPG key
copy: copy:
src: sury.gpg src: sury.gpg
dest: /etc/apt/trusted.gpg.d/sury.gpg dest: "{{ apt_keyring_dir }}/sury.gpg"
mode: "0644" mode: "0644"
owner: root owner: root
group: root group: root
@ -20,10 +20,16 @@
- name: Setup deb.sury.org repository - Add source list - name: Setup deb.sury.org repository - Add source list
apt_repository: apt_repository:
repo: "deb https://packages.sury.org/php/ {{ ansible_distribution_release }} main" repo: "deb [signed-by={{ apt_keyring_dir }}/sury.gpg] https://packages.sury.org/php/ {{ ansible_distribution_release }} main"
filename: sury filename: sury
state: present state: present
- name: Setup deb.sury.org repository - Remove unsigned source list
apt_repository:
repo: "deb https://packages.sury.org/php/ {{ ansible_distribution_release }} main"
filename: sury
state: absent
- name: "Override package list for Sury (Debian 9 or later)" - name: "Override package list for Sury (Debian 9 or later)"
set_fact: set_fact:
php_stretch_packages: php_stretch_packages:

View File

@ -20,3 +20,5 @@ locales_default: fr_FR.UTF-8
# PostGIS # PostGIS
postgresql_install_postgis: False postgresql_install_postgis: False
apt_keyring_dir: "{{ ansible_distribution_major_version is version('12', '<') | ternary('/etc/apt/trusted.gpg.d', '/etc/apt/keyrings') }}"

View File

@ -0,0 +1,16 @@
---
- name: "Set variables (Debian 12)"
set_fact:
postgresql_version: '15'
when: postgresql_version is none or postgresql_version | length == 0
- include: pgdg-repo.yml
when: postgresql_version != '15'
- name: Install postgresql package
apt:
name:
- "postgresql-{{postgresql_version}}"
- pgtop
- libdbd-pg-perl

View File

@ -23,16 +23,22 @@
- name: Add PGDG GPG key - name: Add PGDG GPG key
copy: copy:
src: postgresql.asc src: postgresql.asc
dest: /etc/apt/trusted.gpg.d/postgresql.asc dest: "{{ apt_keyring_dir }}/postgresql.asc"
force: yes force: yes
mode: "0644" mode: "0644"
owner: root owner: root
group: root group: root
- name: Add PGDG repository - name: Add PGDG repository
apt_repository:
repo: "deb [signed-by={{ apt_keyring_dir }}/postgresql.asc] http://apt.postgresql.org/pub/repos/apt/ {{ansible_distribution_release}}-pgdg main"
update_cache: yes
- name: Remove unsigned PGDG repository
apt_repository: apt_repository:
repo: "deb http://apt.postgresql.org/pub/repos/apt/ {{ansible_distribution_release}}-pgdg main" repo: "deb http://apt.postgresql.org/pub/repos/apt/ {{ansible_distribution_release}}-pgdg main"
update_cache: yes update_cache: yes
state: absent
- name: Add APT preference file - name: Add APT preference file
template: template:

Some files were not shown because too many files have changed in this diff Show More