Merge pull request 'Release 22.05' (#155) from unstable into stable
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is failing

Reviewed-on: #155
This commit is contained in:
Jérémy Lecour 2022-05-10 17:01:15 +02:00
commit c273117c5f
72 changed files with 5519 additions and 1473 deletions

View file

@ -22,6 +22,44 @@ The **patch** part changes is incremented if multiple releases happen the same m
### Security
## [22.05] 2022-05-10
### Added
* etc-git: use "ansible-commit" to efficiently commit all available repositories (including /etc inside LXC) from Ansible
* minifirewall: compatibility with "legacy" version of minifirewall
* minifirewall: configure proxy/backup/sysctl values
* munin: Add possibility to install local plugins, and install dhcp_pool plugin
* nagios-nrpe: Add a check dhcp_pool
* redis: Activate overcommit sysctl
* redis: Add log2mail user to redis group
### Changed
* dump-server-state: upstream release 22.04.3
* evocheck: upstream release 22.04.1
* evolinux-base: Add non-free repos & install non-free firmware on dedicated hardware
* evolinux-base: rename backup-server-state to dump-server-state
* generate-ldif: Add services check for bkctld
* minifirewall: restore "force-restart" and fix "restart-if-needed"
* minifirewall: tail template follows symlinks
* minifirewall: upstream release 22.05
* opendkim : add generate opendkim-genkey in sha256 and key 4096
* openvpn: use a local copy of files instead of cloning an external git repository
* openvpn: use a subnet topology instead of the net30 default topology
* tomcat: Tomcat 9 by default with Debian 11
* vrrpd: Store sysctl values in specific file
### Fixed
* etc-git : Remount /usr in rw for git gc in in /usr/share/scripts/
* etc-git: Make evocommit fully compatible with OpenBSD
* generate-ldif: Correct generated entries for php-fpm in containers
* keepalived: repair broken role
* minifirewall: fix `failed_when` condition on restart
* postfix: Do not send mails through milters a second time after amavis (in packmail)
* redis: Remount /usr with RW before adding nagios plugin
## [22.03] 2022-03-02
### Added
@ -44,8 +82,6 @@ The **patch** part changes is incremented if multiple releases happen the same m
* lxc: Fail if /var is nosuid
* openvpn: make it compatible with OpenBSD and add some improvements
## [22.01.3] 2022-01-31
### Changed

View file

@ -8,3 +8,9 @@
service:
name: dovecot
state: reloaded
- name: restart log2mail
service:
name: log2mail
state: restarted

View file

@ -81,3 +81,25 @@
- include: munin.yml
tags:
- dovecot
- name: log2mail is installed
apt:
name: log2mail
state: present
tags: dovecot
- name: dovecot is configured in log2mail
blockinfile:
path: /etc/log2mail/config/mail.conf
create: true
owner: log2mail
group: adm
mode: "0640"
block: |
file = /var/log/mail.log
pattern = "Out of memory"
mailto = {{ log2mail_alert_email or general_alert_email | mandatory }}
template = /etc/log2mail/mail
notify: restart log2mail
tags: dovecot

View file

@ -4,3 +4,4 @@ etc_git_default_commit_message: Ansible run
etc_git_monitor_status: True
etc_git_purge_index_lock_enabled: True
etc_git_purge_index_lock_age: 86400
etc_git_config_repositories: True

View file

@ -0,0 +1,187 @@
#!/bin/sh
set -u
VERSION="22.05"
show_version() {
cat <<END
ansible-commit version ${VERSION}
Copyright 2022 Evolix <info@evolix.fr>,
Jérémy Lecour <jlecour@evolix.fr>
and others.
ansible-commit comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
See the GNU General Public Licence for details.
END
}
show_help() {
cat <<END
ansible-commit is a wrapper for evocommit, to be used with Ansible
END
show_usage
}
show_usage() {
cat <<END
Usage: ansible-commit --message "add new host"
Options
--message MESSAGE set the commit message
--no-lxc disable commit inside LXC containers
-V, --version print version number
-v, --verbose increase verbosity
-n, --dry-run actions are not executed
-h, --help print this message and exit
END
}
is_dry_run() {
test "${DRY_RUN}" = "1"
}
is_verbose() {
test "${VERBOSE}" = "1"
}
main() {
rc=0
common_args="--ansible"
if is_verbose; then
common_args="${common_args} --verbose"
fi
if is_dry_run; then
common_args="${common_args} --dry-run"
fi
if [ -d "/etc/.git" ]; then
# shellcheck disable=SC2086,SC2090
${evocommit_bin} ${common_args} --repository /etc --message "${MESSAGE}"
last_rc=$?
if [ ${last_rc} -ne 0 ]; then
rc=${last_rc}
fi
fi
if [ -d "/etc/bind/.git" ]; then
# shellcheck disable=SC2086,SC2090
${evocommit_bin} ${common_args} --repository /etc/bind --message "${MESSAGE}"
last_rc=$?
if [ ${last_rc} -ne 0 ]; then
rc=${last_rc}
fi
fi
if [ -d "/usr/share/scripts/.git" ]; then
# shellcheck disable=SC2086,SC2090
${evocommit_bin} ${common_args} --repository /usr/share/scripts --message "${MESSAGE}"
last_rc=$?
if [ ${last_rc} -ne 0 ]; then
rc=${last_rc}
fi
fi
if [ "${LXC}" = "1" ] && [ -n "${lxc_ls_bin}" ]; then
for container in $(${lxc_ls_bin} -1); do
if [ -n "${lxc_config_bin}" ]; then
# discovered path
etc_path="$(${lxc_config_bin} lxc.lxcpath)/${container}/rootfs/etc"
else
# fallback to default path
etc_path="/var/lib/lxc/${container}/rootfs/etc"
fi
if [ -d "${etc_path}/.git" ]; then
# shellcheck disable=SC2086,SC2090
${evocommit_bin} ${common_args} --repository "${etc_path}" --message "${MESSAGE}"
last_rc=$?
if [ ${last_rc} -ne 0 ]; then
rc=${last_rc}
fi
fi
done
fi
exit ${rc}
}
# Parse options
# based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
while :; do
case ${1:-''} in
-h|-\?|--help)
show_help
exit 0
;;
-V|--version)
show_version
exit 0
;;
--message)
# message options, with value speparated by space
if [ -n "$2" ]; then
MESSAGE=$2
shift
else
printf 'FAILED: "--message" requires a non-empty option argument.\n' >&2
exit 1
fi
;;
--message=?*)
# message options, with value speparated by =
MESSAGE=${1#*=}
;;
--message=)
# message options, without value
printf 'FAILED: "--message" requires a non-empty option argument.\n' >&2
exit 1
;;
--no-lxc)
LXC=0
;;
-n|--dry-run)
# disable actual commands
DRY_RUN=1
;;
-v|--verbose)
# print verbose information
VERBOSE=1
;;
--)
# End of all options.
shift
break
;;
-?*|[[:alnum:]]*)
# ignore unknown options
printf 'FAILED: Unknown option (ignored): %s\n' "$1" >&2
;;
*)
# Default case: If no more options then break out of the loop.
break
;;
esac
shift
done
if [ -z "${MESSAGE}" ]; then
echo "FAILED: missing message parameter" >&2
show_usage
exit 1
fi
DRY_RUN=${DRY_RUN:-0}
VERBOSE=${VERBOSE:-0}
LXC=${LXC:-1}
evocommit_bin=$(command -v evocommit)
if [ -z "${evocommit_bin}" ]; then
echo "FAILED: evocommit not found" >&2
exit 1
fi
lxc_ls_bin=$(command -v lxc-ls)
lxc_config_bin=$(command -v lxc-config)
main

View file

@ -6,6 +6,12 @@ repositories="/etc /etc/bind/ /usr/share/scripts"
for repository in ${repositories}; do
if [ -d "${repository}/.git" ]; then
if [ ${repository} = "/usr/share/scripts" ]; then
mount -o remount,rw /usr
fi
git --git-dir="${repository}/.git" gc --quiet
if [ ${repository} = "/usr/share/scripts" ]; then
mount -o remount /usr
fi
fi
done

View file

@ -2,13 +2,13 @@
set -u
VERSION="21.10"
VERSION="22.04"
show_version() {
cat <<END
evocommit version ${VERSION}
Copyright 2021 Evolix <info@evolix.fr>,
Copyright 2022 Evolix <info@evolix.fr>,
Jérémy Lecour <jlecour@evolix.fr>
and others.
@ -63,6 +63,7 @@ remount_repository_readwrite() {
if [ "$(get_system)" = "OpenBSD" ]; then
partition=$(stat -f '%Sd' $1)
mount -u -w /dev/${partition} 2>/dev/null
syslog "Re-mount ${mountpoint} as read-write to commit in repository $1"
else
mountpoint=$(stat -c '%m' $1)
mount -o remount,rw ${mountpoint}
@ -73,6 +74,7 @@ remount_repository_readonly() {
if [ "$(get_system)" = "OpenBSD" ]; then
partition=$(stat -f '%Sd' $1)
mount -u -r /dev/${partition} 2>/dev/null
syslog "Re-mount ${mountpoint} as read-only after commit to repository $1"
else
mountpoint=$(stat -c '%m' $1)
mount -o remount,ro ${mountpoint} 2>/dev/null
@ -92,8 +94,12 @@ main() {
rc=0
lock="${GIT_DIR}/index.lock"
if [ -f "${lock}" ]; then
limit=$(date +"%s" -d "now - 1 hour")
updated_at=$(stat -c "%Y" "${lock}")
limit=$(($(date +"%s") - (1 * 60 * 60)))
if [ "$(get_system)" = "OpenBSD" ]; then
updated_at=$(stat -f "%m" "${lock}")
else
updated_at=$(stat -c "%Y" "${lock}")
fi
if [ "$updated_at" -lt "$limit" ]; then
rm -f "${lock}"
fi
@ -262,4 +268,4 @@ if [ -d "${GIT_DIR}" ]; then
else
echo "There is no Git repository in '${REPOSITORY}'" >&2
exit 1
fi
fi

View file

@ -1,52 +1,9 @@
---
# /etc
- name: Is /etc a git repository
stat:
path: /etc/.git
register: _etc_git
- name: "evocommit /etc"
command: "/usr/local/bin/evocommit --ansible --repository /etc --message \"{{ commit_message | mandatory }}\""
- name: "Execute ansible-commit"
command: "/usr/local/bin/ansible-commit --verbose --message \"{{ commit_message | mandatory }}\""
changed_when:
- _etc_git_commit.stdout
- "'CHANGED:' in _etc_git_commit.stdout"
ignore_errors: yes
register: _etc_git_commit
when:
- _etc_git.stat.exists
- _etc_git.stat.isdir
# /etc/bind
- name: Is /etc/bind a git repository
stat:
path: /etc/bind/.git
register: _etc_bind_git
- name: "evocommit /etc/bind"
command: "/usr/local/bin/evocommit --ansible --repository /etc/bind --message \"{{ commit_message | mandatory }}\""
changed_when:
- _etc_bind_git_commit.stdout
- "'CHANGED:' in _etc_bind_git_commit.stdout"
ignore_errors: yes
register: _etc_bind_git_commit
when:
- _etc_bind_git.stat.exists
- _etc_bind_git.stat.isdir
# /usr/share/scripts
- name: Is /usr/share/scripts a git repository
stat:
path: /usr/share/scripts/.git
register: _usr_share_scripts_git
- name: "evocommit /usr/share/scripts"
command: "/usr/local/bin/evocommit --ansible --repository /usr/share/scripts --message \"{{ commit_message | mandatory }}\""
changed_when:
- _usr_share_scripts_git_commit.stdout
- "'CHANGED:' in _usr_share_scripts_git_commit.stdout"
ignore_errors: yes
register: _usr_share_scripts_git_commit
when:
- _usr_share_scripts_git.stat.exists
- _usr_share_scripts_git.stat.isdir
- _ansible_commit.stdout
- "'CHANGED:' in _ansible_commit.stdout"
ignore_errors: True
register: _ansible_commit

View file

@ -0,0 +1,35 @@
---
- name: "Assert that we have been called with `container` defined"
assert:
that:
- container is defined
- name: "Define path to /etc in {{ container }} container"
set_fact:
container_etc: "{{ ('/var/lib/lxc', container, 'rootfs/etc') | path_join }}"
- name: "Check if /etc is a git repository in {{ container }}"
stat:
path: "{{ (container_etc, '.git') | path_join }}"
get_attributes: no
get_checksum: no
get_mime: no
register: "container_etc_git"
- name: "Evocommit /etc of {{ container }}"
command:
argv:
- /usr/local/bin/evocommit
- '--ansible'
- '--repository'
- "{{ container_etc }}"
- '--message'
- "{{ commit_message | mandatory }}"
changed_when:
- "container_etc_git_commit.stdout"
- "'CHANGED:' in container_etc_git_commit.stdout"
ignore_errors: yes
register: "container_etc_git_commit"
when:
- "container_etc_git.stat.exists"
- "container_etc_git.stat.isdir"

View file

@ -6,109 +6,16 @@
state: present
tags:
- etc-git
when:
- ansible_distribution == "Debian"
- include_role:
name: evolix/remount-usr
- name: "evocommit script is installed"
copy:
src: evocommit
dest: /usr/local/bin/evocommit
mode: "0755"
force: yes
- name: Install and configure utilities
include: utils.yml
tags:
- etc-git
- include: repository.yml
vars:
repository_path: "/etc"
gitignore_items:
- "aliases.db"
- "*.swp"
- "postfix/sa-blacklist.access"
- "postfix/*.db"
- "postfix/spamd.cidr"
- "evobackup/.keep-*"
- "letsencrypt/.certbot.lock"
- name: verify /usr/share/scripts presence
stat:
path: /usr/share/scripts
register: _usr_share_scripts
- include: repository.yml
vars:
repository_path: "/usr/share/scripts"
gitignore_items: []
when:
- _usr_share_scripts.stat.isdir
- ansible_distribution_major_version is version('10', '>=')
- name: "etc-git-optimize script is installed"
copy:
src: etc-git-optimize
dest: /usr/share/scripts/etc-git-optimize
mode: "0755"
force: yes
- name: Configure repositories
include: repositories.yml
tags:
- etc-git
- name: "etc-git-status script is installed"
copy:
src: etc-git-status
dest: /usr/share/scripts/etc-git-status
mode: "0755"
force: yes
tags:
- etc-git
- name: Check if cron is installed
shell: "set -o pipefail && dpkg -l cron 2>/dev/null | grep -q -E '^(i|h)i'"
args:
executable: /bin/bash
failed_when: False
changed_when: False
check_mode: no
register: is_cron_installed
- block:
- name: Legacy cron jobs for /etc/.git status are absent
file:
dest: "{{ item }}"
state: absent
loop:
- /etc/cron.monthly/optimize-etc-git
- /etc/cron.d/etc-git-status
- name: Cron job for monthly git optimization
cron:
name: "Monthly optimization"
cron_file: etc-git
special_time: "monthly"
user: root
job: "/usr/share/scripts/etc-git-optimize"
- name: Cron job for hourly git status
cron:
name: "Hourly warning for unclean Git repository if nobody is connected"
cron_file: etc-git
special_time: "hourly"
user: root
job: "who > /dev/null || /usr/share/scripts/etc-git-status"
state: "{{ etc_git_monitor_status | bool | ternary('present','absent') }}"
- name: Cron job for daily git status
cron:
name: "Daily warning for unclean Git repository"
cron_file: etc-git
user: root
job: "/usr/share/scripts/etc-git-status"
minute: "21"
hour: "21"
weekday: "*"
day: "*"
month: "*"
state: "{{ etc_git_monitor_status | bool | ternary('present','absent') }}"
when: is_cron_installed.rc == 0
tags:
- etc-git
when: etc_git_config_repositories | bool

View file

@ -0,0 +1,37 @@
---
- include: repository.yml
vars:
repository_path: "/etc"
gitignore_items:
- "aliases.db"
- "*.swp"
- "postfix/sa-blacklist.access"
- "postfix/*.db"
- "postfix/spamd.cidr"
- "evobackup/.keep-*"
- "letsencrypt/.certbot.lock"
tags:
- etc-git
- name: verify /usr/share/scripts presence
stat:
path: /usr/share/scripts
register: _usr_share_scripts
tags:
- etc-git
- include_role:
name: evolix/remount-usr
when:
- _usr_share_scripts.stat.isdir
- include: repository.yml
vars:
repository_path: "/usr/share/scripts"
gitignore_items: []
when:
- _usr_share_scripts.stat.isdir
- ansible_distribution_major_version is version('10', '>=')
tags:
- etc-git

93
etc-git/tasks/utils.yml Normal file
View file

@ -0,0 +1,93 @@
---
- include_role:
name: evolix/remount-usr
tags:
- etc-git
- name: "evocommit script is installed"
copy:
src: evocommit
dest: /usr/local/bin/evocommit
mode: "0755"
force: yes
tags:
- etc-git
- name: "ansible-commit script is installed"
copy:
src: ansible-commit
dest: /usr/local/bin/ansible-commit
mode: "0755"
force: yes
tags:
- etc-git
- name: "etc-git-optimize script is installed"
copy:
src: etc-git-optimize
dest: /usr/share/scripts/etc-git-optimize
mode: "0755"
force: yes
tags:
- etc-git
- name: "etc-git-status script is installed"
copy:
src: etc-git-status
dest: /usr/share/scripts/etc-git-status
mode: "0755"
force: yes
tags:
- etc-git
- name: Check if cron is installed
shell: "set -o pipefail && dpkg -l cron 2>/dev/null | grep -q -E '^(i|h)i'"
args:
executable: /bin/bash
failed_when: False
changed_when: False
check_mode: no
register: is_cron_installed
- block:
- name: Legacy cron jobs for /etc/.git status are absent
file:
dest: "{{ item }}"
state: absent
loop:
- /etc/cron.monthly/optimize-etc-git
- /etc/cron.d/etc-git-status
- name: Cron job for monthly git optimization
cron:
name: "Monthly optimization"
cron_file: etc-git
special_time: "monthly"
user: root
job: "/usr/share/scripts/etc-git-optimize"
- name: Cron job for hourly git status
cron:
name: "Hourly warning for unclean Git repository if nobody is connected"
cron_file: etc-git
special_time: "hourly"
user: root
job: "who > /dev/null || /usr/share/scripts/etc-git-status"
state: "{{ etc_git_monitor_status | bool | ternary('present','absent') }}"
- name: Cron job for daily git status
cron:
name: "Daily warning for unclean Git repository"
cron_file: etc-git
user: root
job: "/usr/share/scripts/etc-git-status"
minute: "21"
hour: "21"
weekday: "*"
day: "*"
month: "*"
state: "{{ etc_git_monitor_status | bool | ternary('present','absent') }}"
when: is_cron_installed.rc == 0
tags:
- etc-git

View file

@ -2,8 +2,9 @@
- name: restart minifirewall
command: /etc/init.d/minifirewall restart
register: minifirewall_init_restart
failed_when: "'starting IPTables rules is now finish : OK' not in minifirewall_init_restart.stdout"
changed_when: "'starting IPTables rules is now finish : OK' in minifirewall_init_restart.stdout"
failed_when:
- "'starting IPTables rules is now finish : OK' not in minifirewall_init_restart.stdout"
- "'minifirewall started' not in minifirewall_init_restart.stdout"
- name: 'created new jail'
command: "bkctld restart {{ evolinux_hostname }}"

View file

@ -4,7 +4,7 @@
# Script to verify compliance of a Debian/OpenBSD server
# powered by Evolix
VERSION="21.10.4"
VERSION="22.04.1"
readonly VERSION
# base functions
@ -13,7 +13,7 @@ show_version() {
cat <<END
evocheck version ${VERSION}
Copyright 2009-2021 Evolix <info@evolix.fr>,
Copyright 2009-2022 Evolix <info@evolix.fr>,
Romain Dessort <rdessort@evolix.fr>,
Benoit Série <bserie@evolix.fr>,
Gregory Colpart <reg@evolix.fr>,
@ -142,9 +142,9 @@ failed() {
RC=1
if [ "${QUIET}" != 1 ]; then
if [ -n "${check_comments}" ] && [ "${VERBOSE}" = 1 ]; then
printf "%s FAILED! %s\n" "${check_name}" "${check_comments}" 2>&1
printf "%s FAILED! %s\n" "${check_name}" "${check_comments}" >> "${main_output_file}"
else
printf "%s FAILED!\n" "${check_name}" 2>&1
printf "%s FAILED!\n" "${check_name}" >> "${main_output_file}"
fi
fi
}
@ -234,7 +234,8 @@ check_syslogconf() {
check_debiansecurity() {
if is_debian_bullseye; then
# https://www.debian.org/releases/bullseye/amd64/release-notes/ch-information.html#security-archive
pattern="^deb https://deb\.debian\.org/debian-security/? bullseye-security main"
# https://www.debian.org/security/
pattern="^deb https://(deb|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
@ -328,8 +329,11 @@ check_tmoutprofile() {
check_alert5boot() {
if is_debian_buster || is_debian_bullseye; then
grep -qs "^date" /usr/share/scripts/alert5.sh || failed "IS_ALERT5BOOT" "boot mail is not sent by alert5 init script"
test -f /etc/systemd/system/alert5.service || failed "IS_ALERT5BOOT" "alert5 unit file is missing"
systemctl is-enabled alert5 -q || failed "IS_ALERT5BOOT" "alert5 unit is not enabled"
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
grep -q "^date" /etc/rc2.d/S*alert5 || failed "IS_ALERT5BOOT" "boot mail is not sent by alert5 init script"
@ -567,7 +571,7 @@ check_network_interfaces() {
# Verify if all if are in auto
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)" | 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)" | 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
@ -592,18 +596,21 @@ check_evobackup() {
}
# Vérification de l'exclusion des montages (NFS) dans les sauvegardes
check_evobackup_exclude_mount() {
excludes_file=$(mktemp)
# shellcheck disable=SC2064
trap "rm -f ${excludes_file}" 0
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
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
# 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
done
rm -rf "${excludes_file}"
}
# Verification de la presence du userlogrotate
check_userlogrotate() {
@ -809,8 +816,10 @@ check_tune2fs_m5() {
check_evolinuxsudogroup() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then
if grep -q "^evolinux-sudo:" /etc/group; then
grep -qE '^%evolinux-sudo +ALL ?= ?\(ALL:ALL\) ALL' /etc/sudoers.d/evolinux \
|| failed "IS_EVOLINUXSUDOGROUP" "missing evolinux-sudo directive in sudoers file"
if [ -f /etc/sudoers.d/evolinux ]; then
grep -qE '^%evolinux-sudo +ALL ?= ?\(ALL:ALL\) ALL' /etc/sudoers.d/evolinux \
|| failed "IS_EVOLINUXSUDOGROUP" "missing evolinux-sudo directive in sudoers file"
fi
fi
fi
}
@ -827,7 +836,7 @@ check_userinadmgroup() {
}
check_apache2evolinuxconf() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then
if test -d /etc/apache2; then
if is_installed apache2; then
{ test -L /etc/apache2/conf-enabled/z-evolinux-defaults.conf \
&& test -L /etc/apache2/conf-enabled/zzz-evolinux-custom.conf \
&& test -f /etc/apache2/ipaddr_whitelist.conf;
@ -1006,6 +1015,8 @@ check_mysqlmunin() {
test "${VERBOSE}" = 1 || break
fi
done
munin-run mysql_commands 2> /dev/null > /dev/null
test $? -eq 0 || failed "IS_MYSQLMUNIN" "Munin plugin mysql_commands returned an error"
fi
fi
}
@ -1062,8 +1073,10 @@ check_squidevolinuxconf() {
check_duplicate_fs_label() {
# Do it only if thereis blkid binary
BLKID_BIN=$(command -v blkid)
if [ -x "$BLKID_BIN" ]; then
tmpFile=$(mktemp -p /tmp)
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"
@ -1076,7 +1089,6 @@ check_duplicate_fs_label() {
labels=$(echo -n $tmpOutput | tr '\n' ' ')
failed "IS_DUPLICATE_FS_LABEL" "Duplicate labels: $labels"
fi
rm "$tmpFile"
else
failed "IS_DUPLICATE_FS_LABEL" "blkid not found in ${PATH}"
fi
@ -1367,7 +1379,7 @@ download_versions() {
elif is_openbsd; then
versions_url="https://upgrades.evolix.org/versions-${OPENBSD_RELEASE}"
else
failed "IS_VERSIONS_CHECK" "error determining os release"
failed "IS_CHECK_VERSIONS" "error determining os release"
fi
# fetch timeout, in seconds
@ -1380,9 +1392,9 @@ download_versions() {
elif command -v GET; then
GET -t ${timeout}s "${versions_url}" > "${versions_file}"
else
failed "IS_VERSIONS_CHECK" "failed to find curl, wget or GET"
failed "IS_CHECK_VERSIONS" "failed to find curl, wget or GET"
fi
test "$?" -eq 0 || failed "IS_VERSIONS_CHECK" "failed to download ${versions_url} to ${versions_file}"
test "$?" -eq 0 || failed "IS_CHECK_VERSIONS" "failed to download ${versions_url} to ${versions_file}"
}
get_command() {
local program
@ -1395,6 +1407,7 @@ get_command() {
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}" ;;
@ -1415,6 +1428,9 @@ get_version() {
add-vm)
grep '^VERSION=' "${command}" | head -1 | cut -d '=' -f 2
;;
minifirewall)
${command} status | 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
@ -1440,11 +1456,11 @@ check_version() {
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_VERSIONS_CHECK" "failed to lookup actual version of ${program}"
failed "IS_CHECK_VERSIONS" "failed to lookup actual version of ${program}"
elif dpkg --compare-versions "${actual_version}" lt "${expected_version}"; then
failed "IS_VERSIONS_CHECK" "${program} version ${actual_version} is older than expected version ${expected_version}"
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_VERSIONS_CHECK" "${program} version ${actual_version} is newer than expected version ${expected_version}, you should update tour index."
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
@ -1457,9 +1473,9 @@ add_to_path() {
echo "$PATH" | grep -qF "${new_path}" || export PATH="${PATH}:${new_path}"
}
check_versions() {
versions_file=$(mktemp --tmpdir=/tmp "evocheck-versions.XXXXX")
# shellcheck disable=SC2064
trap "rm -f ${versions_file}" 0
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"
@ -1473,12 +1489,10 @@ check_versions() {
if [ -n "${version}" ]; then
check_version "${program}" "${version}"
else
failed "IS_VERSIONS_CHECK" "failed to lookup expected version for ${program}"
failed "IS_CHECK_VERSIONS" "failed to lookup expected version for ${program}"
fi
fi
done
rm -f "${versions_file}"
}
main() {
@ -1487,6 +1501,9 @@ main() {
# 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}"
#-----------------------------------------------------------
# Tests communs à tous les systèmes
#-----------------------------------------------------------
@ -1715,8 +1732,21 @@ main() {
# - NRPEDISK et NRPEPOSTFIX
fi
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
@ -1730,6 +1760,10 @@ readonly ARGS
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

View file

@ -1,1019 +0,0 @@
#!/bin/sh
PROGNAME="backup-server-state"
VERSION="22.01.3"
readonly VERSION
backup_dir=
rc=0
# base functions
show_version() {
cat <<END
${PROGNAME} version ${VERSION}
Copyright 2018-2022 Evolix <info@evolix.fr>,
Jérémy Lecour <jlecour@evolix.fr>
and others.
${PROGNAME} 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
${PROGNAME} is making backup copies of information related to the state of the server.
Usage: ${PROGNAME} --backup-dir=/path/to/backup/directory [OPTIONS]
Options
-d, --backup-dir path to the directory where the backup will be stored
-f, --force keep existing backup directory and its content
--etc backup copy of /etc
--no-etc no backup copy of /etc (default)
--dpkg backup copy of /var/lib/dpkg
--no-dpkg no backup copy of /var/lib/dpkg (default)
--apt-states backup copy of apt extended states (default)
--no-apt-states no backup copy of apt extended states
--apt-config backup copy of apt configuration (default)
--no-apt-config no backup copy of apt configuration
--packages backup copy of dpkg selections (default)
--no-packages no backup copy of dpkg selections
--processes backup copy of process list (default)
--no-processes no backup copy of process list
--uptime backup of uptime value (default)
--no-uptime no backup of uptime value
--netstat backup copy of netstat (default)
--no-netstat no backup copy of netstat
--netcfg backup copy of network configuration (default)
--no-netcfg no backup copy of network configuration
--iptables backup copy of iptables (default)
--no-iptables no backup copy of iptables
--sysctl backup copy of sysctl values (default)
--no-sysctl no backup copy of sysctl values
--virsh backup copy of virsh list (default)
--no-virsh no backup copy of virsh list
--lxc backup copy of lxc list (default)
--no-lxc no backup copy of lxc list
--disks backup copy of MBR and partitions (default)
--no-disks no backup copy of MBR and partitions
--mount backup copy of mount points (default)
--no-mount no backup copy of mount points
--df backup copy of disk usage (default)
--no-df no backup copy of disk usage
--dmesg backup copy of dmesg (default)
--no-dmesg no backup copy of dmesg
--mysql backup copy of mysql processes (default)
--no-mysql no backup copy of mysql processes
--services backup copy of services states (default)
--no-services no backup copy of services states
-v, --verbose print details about backup steps
-V, --version print version and exit
-h, --help print this message and exit
END
}
debug() {
if [ "${VERBOSE}" = "1" ]; then
echo "$1"
fi
}
create_backup_dir() {
debug "Create ${backup_dir}"
last_result=$(mkdir -p "${backup_dir}" && chmod -R 755 "${backup_dir}")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* mkdir/chmod OK"
else
debug "* mkdir/chmod ERROR :"
debug "${last_result}"
rc=10
fi
}
backup_etc() {
debug "Backup /etc"
rsync_bin=$(command -v rsync)
if [ -n "${rsync_bin}" ]; then
last_result=$(${rsync_bin} -ah --itemize-changes --exclude=.git /etc "${backup_dir}/")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* rsync OK"
else
debug "* rsync ERROR :"
debug "${last_result}"
rc=10
fi
else
debug "* rsync not found"
last_result=$(cp -r /etc "${backup_dir}/ && rm -rf ${backup_dir}/etc/.git")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* cp OK"
else
debug "* cp ERROR :"
debug "${last_result}"
rc=10
fi
fi
}
backup_apt_states() {
apt_dir="/"
apt_dir_state="var/lib/apt"
apt_dir_state_extended_states="extended_states"
apt_config_bin=$(command -v apt-config)
if [ -n "${apt_config_bin}" ]; then
eval "$(${apt_config_bin} shell apt_dir Dir)"
eval "$(${apt_config_bin} shell apt_dir_state Dir::State)"
eval "$(${apt_config_bin} shell apt_dir_state_extended_states Dir::State::extended_states)"
fi
extended_states="${apt_dir}/${apt_dir_state}/${apt_dir_state_extended_states}"
if [ -f "${extended_states}" ]; then
debug "Backup APT states"
last_result=$(cp -r "${extended_states}" "${backup_dir}/apt-extended-states.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* cp OK"
else
debug "* cp ERROR :"
debug "${last_result}"
rc=10
fi
fi
}
backup_apt_config() {
debug "Backup APT config"
apt_config_bin=$(command -v apt-config)
if [ -n "${apt_config_bin}" ]; then
last_result=$(${apt_config_bin} dump > "${backup_dir}/apt-config.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* apt-config OK"
else
debug "* apt-config ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* apt-config is not found"
fi
}
backup_dpkg_full() {
debug "Backup DPkg full state"
dir_state_status="/var/lib/dpkg/status"
apt_config_bin=$(command -v apt-config)
if [ -n "${apt_config_bin}" ]; then
eval "$(${apt_config_bin} shell dir_state_status Dir::State::status)"
fi
dpkg_dir=$(dirname "${dir_state_status}")
last_result=$(mkdir -p "${backup_dir}${dpkg_dir}" && chmod -R 755 "${backup_dir}${dpkg_dir}")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* mkdir/chmod OK"
else
debug "* mkdir/chmod ERROR"
debug "${last_result}"
rc=10
fi
rsync_bin=$(command -v rsync)
if [ -n "${rsync_bin}" ]; then
last_result=$(${rsync_bin} -ah --itemize-changes --exclude='*-old' "${dpkg_dir}/" "${backup_dir}${dpkg_dir}/")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* rsync OK"
else
debug "* rsync ERROR :"
debug "${last_result}"
rc=10
fi
else
debug "* rsync not found"
last_result=$(cp -r "${dpkg_dir}/*" "${backup_dir}${dpkg_dir}/" && rm -rf "${backup_dir}${dpkg_dir}/*-old")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* cp OK"
else
debug "* cp ERROR :"
debug "${last_result}"
rc=10
fi
fi
}
backup_dpkg_status() {
debug "Backup DPkg status"
dir_state_status="/var/lib/dpkg/status"
apt_config_bin=$(command -v apt-config)
if [ -n "${apt_config_bin}" ]; then
eval "$(${apt_config_bin} shell dir_state_status Dir::State::status)"
fi
last_result=$(cp "${dir_state_status}" "${backup_dir}/dpkg-status.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* cp OK"
else
debug "* cp ERROR :"
debug "${last_result}"
rc=10
fi
}
backup_packages() {
debug "Backup list of installed package"
dpkg_bin=$(command -v dpkg)
if [ -n "${dpkg_bin}" ]; then
last_result=$(${dpkg_bin} --get-selections "*" > "${backup_dir}/current_packages.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* dpkg OK"
else
debug "* dpkg ERROR :"
debug "${last_result}"
rc=10
fi
else
debug "* dpkg not found"
fi
}
backup_uname() {
debug "Backup uname"
last_result=$(uname -a > "${backup_dir}/uname.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* uname OK"
else
debug "* uname ERROR"
debug "${last_result}"
rc=10
fi
}
backup_uptime() {
debug "Backup uptime"
last_result=$(uptime > "${backup_dir}/uptime.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* uptime OK"
else
debug "* uptime ERROR"
debug "${last_result}"
rc=10
fi
}
backup_processes() {
debug "Backup process list"
last_result=$(ps fauxw > "${backup_dir}/ps.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* ps OK"
else
debug "* ps ERROR"
debug "${last_result}"
rc=10
fi
pstree_bin=$(command -v pstree)
if [ -n "${pstree_bin}" ]; then
last_result=$(${pstree_bin} -pan > "${backup_dir}/pstree.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* pstree OK"
else
debug "* pstree ERROR"
debug "${last_result}"
rc=10
fi
fi
}
backup_netstat() {
debug "Backup network status"
ss_bin=$(command -v ss)
if [ -n "${ss_bin}" ]; then
last_result=$(${ss_bin} -tanpul > "${backup_dir}/netstat-ss.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* ss OK"
else
debug "* ss ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* ss not found"
fi
netstat_bin=$(command -v netstat)
if [ -n "${netstat_bin}" ]; then
last_result=$(netstat -laputen > "${backup_dir}/netstat-legacy.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* netstat OK"
else
debug "* netstat ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* netstat not found"
fi
}
backup_netcfg() {
debug "Backup network configuration"
ip_bin=$(command -v ip)
if [ -n "${ip_bin}" ]; then
last_result=$(${ip_bin} address show > "${backup_dir}/ip-address.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* ip address OK"
else
debug "* ip address ERROR"
debug "${last_result}"
rc=10
fi
last_result=$(${ip_bin} route show > "${backup_dir}/ip-route.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* ip route OK"
else
debug "* ip route ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* ip not found"
ifconfig_bin=$(command -v ifconfig)
if [ -n "${ifconfig_bin}" ]; then
last_result=$(${ifconfig_bin} > "${backup_dir}/ifconfig.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* ifconfig OK"
else
debug "* ifconfig ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* ifconfig not found"
fi
fi
}
backup_iptables() {
debug "Backup iptables"
iptables_bin=$(command -v iptables)
if [ -n "${iptables_bin}" ]; then
last_result=$({ ${iptables_bin} -L -n -v; ${iptables_bin} -t filter -L -n -v; } > "${backup_dir}/iptables.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* iptables OK"
else
debug "* iptables ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* iptables not found"
fi
iptables_save_bin=$(command -v iptables-save)
if [ -n "${iptables_save_bin}" ]; then
last_result=$(${iptables_save_bin} > "${backup_dir}/iptables-save.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* iptables-save OK"
else
debug "* iptables-save ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* iptables-save not found"
fi
}
backup_sysctl() {
debug "Backup sysctl values"
sysctl_bin=$(command -v sysctl)
if [ -n "${sysctl_bin}" ]; then
last_result=$(${sysctl_bin} -a | sort -h > "${backup_dir}/sysctl.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* sysctl OK"
else
debug "* sysctl ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* sysctl not found"
fi
}
backup_virsh() {
debug "Backup virsh list"
virsh_bin=$(command -v virsh)
if [ -n "${virsh_bin}" ]; then
last_result=$(${virsh_bin} list --all > "${backup_dir}/virsh-list.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* virsh list OK"
else
debug "* virsh list ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* virsh not found"
fi
}
backup_lxc() {
debug "Backup lxc list"
lxc_ls_bin=$(command -v lxc-ls)
if [ -n "${lxc_ls_bin}" ]; then
last_result=$(${lxc_ls_bin} --fancy > "${backup_dir}/lxc-list.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* lxc list OK"
else
debug "* lxc list ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* lxc-ls not found"
fi
}
backup_disks() {
debug "Backup disks"
lsblk_bin=$(command -v lsblk)
awk_bin=$(command -v awk)
if [ -n "${lsblk_bin}" ] && [ -n "${awk_bin}" ]; then
disks=$(${lsblk_bin} -l | grep disk | grep -v -E '(drbd|fd[0-9]+)' | ${awk_bin} '{print $1}')
for disk in ${disks}; do
dd_bin=$(command -v dd)
if [ -n "${dd_bin}" ]; then
last_result=$(${dd_bin} if="/dev/${disk}" of="${backup_dir}/MBR-${disk}" bs=512 count=1 2>&1)
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* dd ${disk} OK"
else
debug "* dd ${disk} ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* dd not found"
fi
fdisk_bin=$(command -v fdisk)
if [ -n "${fdisk_bin}" ]; then
last_result=$(${fdisk_bin} -l "/dev/${disk}" > "${backup_dir}/partitions-${disk}" 2>&1)
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* fdisk ${disk} OK"
else
debug "* fdisk ${disk} ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* fdisk not found"
fi
done
cat "${backup_dir}"/partitions-* > "${backup_dir}/partitions"
else
if [ -n "${lsblk_bin}" ]; then
debug "* lsblk not found"
fi
if [ -n "${awk_bin}" ]; then
debug "* awk not found"
fi
fi
}
backup_mount() {
debug "Backup mount points"
findmnt_bin=$(command -v findmnt)
if [ -n "${findmnt_bin}" ]; then
last_result=$(${findmnt_bin} > "${backup_dir}/mount.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* mount points OK"
else
debug "* mount points ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* findmnt not found"
mount_bin=$(command -v mount)
if [ -n "${mount_bin}" ]; then
last_result=$(${mount_bin} > "${backup_dir}/mount.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* mount points OK"
else
debug "* mount points ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* mount not found"
fi
fi
}
backup_df() {
debug "Backup df"
df_bin=$(command -v df)
if [ -n "${df_bin}" ]; then
last_result=$(${df_bin} --portability > "${backup_dir}/df.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* df OK"
else
debug "* df ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* df not found"
fi
}
backup_dmesg() {
debug "Backup dmesg"
dmesg_bin=$(command -v dmesg)
if [ -n "${dmesg_bin}" ]; then
last_result=$(${dmesg_bin} > "${backup_dir}/dmesg.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* dmesg OK"
else
debug "* dmesg ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* dmesg not found"
fi
}
backup_mysql_processes() {
debug "Backup mysql processes"
mysqladmin_bin=$(command -v mysqladmin)
if [ -n "${mysqladmin_bin}" ]; then
last_result=$(${mysqladmin_bin} --verbose processlist > "${backup_dir}/mysql-processlist.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* mysqladmin OK"
else
debug "* mysqladmin ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* mysqladmin not found"
fi
}
backup_systemctl() {
debug "Backup services"
systemctl_bin=$(command -v systemctl)
if [ -n "${systemctl_bin}" ]; then
last_result=$(${systemctl_bin} --no-legend --state=failed --type=service > "${backup_dir}/systemctl-failed-services.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* failed services OK"
else
debug "* failed services ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* systemctl not found"
fi
}
main() {
if [ -z "${backup_dir}" ]; then
echo "ERROR: You must provide the --backup-dir argument" >&2
exit 1
fi
if [ -d "${backup_dir}" ]; then
if [ "${FORCE}" != "1" ]; then
echo "ERROR: The backup directory ${backup_dir} already exists. Delete it first." >&2
exit 2
fi
else
create_backup_dir
fi
if [ "${DO_ETC}" -eq 1 ]; then
backup_etc
fi
if [ "${DO_DPKG_FULL}" -eq 1 ]; then
backup_dpkg_full
fi
if [ "${DO_DPKG_STATUS}" -eq 1 ]; then
backup_dpkg_status
fi
if [ "${DO_APT_STATES}" -eq 1 ]; then
backup_apt_states
fi
if [ "${DO_APT_CONFIG}" -eq 1 ]; then
backup_apt_config
fi
if [ "${DO_PACKAGES}" -eq 1 ]; then
backup_packages
fi
if [ "${DO_PROCESSES}" -eq 1 ]; then
backup_processes
fi
if [ "${DO_UPTIME}" -eq 1 ]; then
backup_uptime
fi
if [ "${DO_UNAME}" -eq 1 ]; then
backup_uname
fi
if [ "${DO_NETSTAT}" -eq 1 ]; then
backup_netstat
fi
if [ "${DO_NETCFG}" -eq 1 ]; then
backup_netcfg
fi
if [ "${DO_IPTABLES}" -eq 1 ]; then
backup_iptables
fi
if [ "${DO_SYSCTL}" -eq 1 ]; then
backup_sysctl
fi
if [ "${DO_VIRSH}" -eq 1 ]; then
backup_virsh
fi
if [ "${DO_LXC}" -eq 1 ]; then
backup_lxc
fi
if [ "${DO_DISKS}" -eq 1 ]; then
backup_disks
fi
if [ "${DO_MOUNT}" -eq 1 ]; then
backup_mount
fi
if [ "${DO_DF}" -eq 1 ]; then
backup_df
fi
if [ "${DO_DMESG}" -eq 1 ]; then
backup_dmesg
fi
if [ "${DO_MYSQL_PROCESSES}" -eq 1 ]; then
backup_mysql_processes
fi
if [ "${DO_SYSTEMCTL}" -eq 1 ]; then
backup_systemctl
fi
debug "=> Your backup is available at ${backup_dir}"
exit ${rc}
}
# parse options
# based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
while :; do
case $1 in
-h|-\?|--help)
show_help
exit 0
;;
-V|--version)
show_version
exit 0
;;
-v|--verbose)
VERBOSE=1
;;
-f|--force)
FORCE=1
;;
-d|--backup-dir)
# with value separated by space
if [ -n "$2" ]; then
backup_dir=$2
shift
else
printf 'ERROR: "-d|--backup-dir" requires a non-empty option argument.\n' >&2
exit 1
fi
;;
--backup-dir=?*)
# with value speparated by =
backup_dir=${1#*=}
;;
--backup-dir=)
# without value
printf 'ERROR: "--backup-dir" requires a non-empty option argument.\n' >&2
exit 1
;;
--etc)
DO_ETC=1
;;
--no-etc)
DO_ETC=0
;;
--dpkg-full)
DO_DPKG_FULL=1
;;
--no-dpkg-full)
DO_DPKG_FULL=0
;;
--dpkg-status)
DO_DPKG_STATUS=1
;;
--no-dpkg-status)
DO_DPKG_STATUS=0
;;
--apt-states)
DO_APT_STATES=1
;;
--no-apt-states)
DO_APT_STATES=0
;;
--apt-config)
DO_APT_CONFIG=1
;;
--no-apt-config)
DO_APT_CONFIG=0
;;
--packages)
DO_PACKAGES=1
;;
--no-packages)
DO_PACKAGES=0
;;
--processes)
DO_PROCESSES=1
;;
--no-processes)
DO_PROCESSES=0
;;
--uptime)
DO_UPTIME=1
;;
--no-uptime)
DO_UPTIME=0
;;
--uname)
DO_UNAME=1
;;
--no-uname)
DO_UNAME=0
;;
--netstat)
DO_NETSTAT=1
;;
--no-netstat)
DO_NETSTAT=0
;;
--netcfg)
DO_NETCFG=1
;;
--no-netcfg)
DO_NETCFG=0
;;
--iptables)
DO_IPTABLES=1
;;
--no-iptables)
DO_IPTABLES=0
;;
--sysctl)
DO_SYSCTL=1
;;
--no-sysctl)
DO_SYSCTL=0
;;
--virsh)
DO_VIRSH=1
;;
--no-virsh)
DO_VIRSH=0
;;
--lxc)
DO_LXC=1
;;
--no-lxc)
DO_LXC=0
;;
--disks)
DO_DISKS=1
;;
--no-disks)
DO_DISKS=0
;;
--mount)
DO_MOUNT=1
;;
--no-mount)
DO_MOUNT=0
;;
--df)
DO_DF=1
;;
--no-df)
DO_DF=0
;;
--dmesg)
DO_DMESG=1
;;
--no-dmesg)
DO_DMESG=0
;;
--mysql-processes)
DO_MYSQL_PROCESSES=1
;;
--no-mysql-processes)
DO_MYSQL_PROCESSES=0
;;
--systemctl)
DO_SYSTEMCTL=1
;;
--no-systemctl)
DO_SYSTEMCTL=0
;;
--)
# End of all options.
shift
break
;;
-?*)
# ignore unknown options
printf 'WARN: Unknown option : %s\n' "$1" >&2
exit 1
;;
*)
# Default case: If no more options then break out of the loop.
break
;;
esac
shift
done
# Default values
: "${VERBOSE:=0}"
: "${FORCE:=0}"
: "${DO_ETC:=0}"
: "${DO_DPKG_FULL:=0}"
: "${DO_DPKG_STATUS:=1}"
: "${DO_APT_STATES:=1}"
: "${DO_APT_CONFIG:=1}"
: "${DO_PACKAGES:=1}"
: "${DO_PROCESSES:=1}"
: "${DO_UNAME:=1}"
: "${DO_UPTIME:=1}"
: "${DO_NETSTAT:=1}"
: "${DO_NETCFG:=1}"
: "${DO_IPTABLES:=1}"
: "${DO_SYSCTL:=1}"
: "${DO_VIRSH:=1}"
: "${DO_LXC:=1}"
: "${DO_DISKS:=1}"
: "${DO_MOUNT:=1}"
: "${DO_DF:=1}"
: "${DO_DMESG:=1}"
: "${DO_MYSQL_PROCESSES:=1}"
: "${DO_SYSTEMCTL:=1}"
export LC_ALL=C
set -u
main

View file

@ -0,0 +1,1177 @@
#!/bin/sh
PROGNAME="dump-server-state"
REPOSITORY="https://gitea.evolix.org/evolix/dump-server-state"
VERSION="22.04.3"
readonly VERSION
dump_dir=
rc=0
# base functions
show_version() {
cat <<END
${PROGNAME} version ${VERSION}
Copyright 2018-2022 Evolix <info@evolix.fr>,
Jérémy Lecour <jlecour@evolix.fr>,
Éric Morino <emorino@evolix.fr>,
Brice Waegeneire <bwaegeneire@evolix.fr>
and others.
${REPOSITORY}
${PROGNAME} 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
${PROGNAME} is dumping information related to the state of the server.
Usage: ${PROGNAME} --dump-dir=/path/to/dump/directory [OPTIONS]
Main options
-d, --dump-dir path to the directory where data will be stored
--backup-dir legacy option for dump directory
-f, --force keep existing dump directory and its content
-v, --verbose print details about each task
-V, --version print version and exit
-h, --help print this message and exit
Tasks options
--all reset options to execute all tasks
--none reset options to execute no task
--[no-]etc copy of /etc (default: no)
--[no-]dpkg-full copy of /var/lib/dpkg (default: no)
--[no-]dpkg-status copy of /var/lib/dpkg/status (default: yes)
--[no-]apt-states copy of apt extended states (default: yes)
--[no-]apt-config copy of apt configuration (default: yes)
--[no-]packages copy of dpkg selections (default: yes)
--[no-]processes copy of process list (default: yes)
--[no-]uname copy of uname value (default: yes)
--[no-]uptime copy of uptime value (default: yes)
--[no-]netstat copy of netstat (default: yes)
--[no-]netcfg copy of network configuration (default: yes)
--[no-]iptables copy of iptables (default: yes)
--[no-]sysctl copy of sysctl values (default: yes)
--[no-]virsh copy of virsh list (default: yes)
--[no-]lxc copy of lxc list (default: yes)
--[no-]disks copy of MBR and partitions (default: yes)
--[no-]mount copy of mount points (default: yes)
--[no-]df copy of disk usage (default: yes)
--[no-]dmesg copy of dmesg (default: yes)
--[no-]mysql copy of mysql processes (default: yes)
--[no-]systemctl copy of systemd services states (default: yes)
Tasks options order matters. They are evaluated from left to right.
Examples :
* "[…] --none --uname" will do only the uname task
* "[…] --all --no-etc" will do everything but the etc task
* "[…] --etc --none --mysql" will do only the mysql task
END
}
debug() {
if [ "${VERBOSE}" = "1" ]; then
msg="${1:-$(cat /dev/stdin)}"
echo "${msg}"
fi
}
create_dump_dir() {
debug "Task: Create ${dump_dir}"
last_result=$(mkdir -p "${dump_dir}" && chmod -R 755 "${dump_dir}")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* mkdir/chmod OK"
else
debug "* mkdir/chmod ERROR :"
debug "${last_result}"
rc=10
fi
}
task_etc() {
debug "Task: /etc"
rsync_bin=$(command -v rsync)
if [ -n "${rsync_bin}" ]; then
last_result=$(${rsync_bin} -ah --itemize-changes --exclude=.git /etc "${dump_dir}/")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* rsync OK"
else
debug "* rsync ERROR :"
debug "${last_result}"
rc=10
fi
else
debug "* rsync not found"
last_result=$(cp -r /etc "${dump_dir}/ && rm -rf ${dump_dir}/etc/.git")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* cp OK"
else
debug "* cp ERROR :"
debug "${last_result}"
rc=10
fi
fi
}
task_apt_states() {
apt_dir="/"
apt_dir_state="var/lib/apt"
apt_dir_state_extended_states="extended_states"
apt_config_bin=$(command -v apt-config)
if [ -n "${apt_config_bin}" ]; then
eval "$(${apt_config_bin} shell apt_dir Dir)"
eval "$(${apt_config_bin} shell apt_dir_state Dir::State)"
eval "$(${apt_config_bin} shell apt_dir_state_extended_states Dir::State::extended_states)"
fi
extended_states="${apt_dir}/${apt_dir_state}/${apt_dir_state_extended_states}"
if [ -f "${extended_states}" ]; then
debug "Task: APT states"
last_result=$(cp -r "${extended_states}" "${dump_dir}/apt-extended-states.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* cp OK"
else
debug "* cp ERROR :"
debug "${last_result}"
rc=10
fi
fi
}
task_apt_config() {
debug "Task: APT config"
apt_config_bin=$(command -v apt-config)
if [ -n "${apt_config_bin}" ]; then
last_result=$(${apt_config_bin} dump > "${dump_dir}/apt-config.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* apt-config OK"
else
debug "* apt-config ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* apt-config is not found"
fi
}
task_dpkg_full() {
debug "Task: DPkg full state"
dir_state_status="/var/lib/dpkg/status"
apt_config_bin=$(command -v apt-config)
if [ -n "${apt_config_bin}" ]; then
eval "$(${apt_config_bin} shell dir_state_status Dir::State::status)"
fi
dpkg_dir=$(dirname "${dir_state_status}")
last_result=$(mkdir -p "${dump_dir}${dpkg_dir}" && chmod -R 755 "${dump_dir}${dpkg_dir}")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* mkdir/chmod OK"
else
debug "* mkdir/chmod ERROR"
debug "${last_result}"
rc=10
fi
rsync_bin=$(command -v rsync)
if [ -n "${rsync_bin}" ]; then
last_result=$(${rsync_bin} -ah --itemize-changes --exclude='*-old' "${dpkg_dir}/" "${dump_dir}${dpkg_dir}/")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* rsync OK"
else
debug "* rsync ERROR :"
debug "${last_result}"
rc=10
fi
else
debug "* rsync not found"
last_result=$(cp -r "${dpkg_dir}/*" "${dump_dir}${dpkg_dir}/" && rm -rf "${dump_dir}${dpkg_dir}/*-old")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* cp OK"
else
debug "* cp ERROR :"
debug "${last_result}"
rc=10
fi
fi
}
task_dpkg_status() {
debug "Task: DPkg status"
dir_state_status="/var/lib/dpkg/status"
apt_config_bin=$(command -v apt-config)
if [ -n "${apt_config_bin}" ]; then
eval "$(${apt_config_bin} shell dir_state_status Dir::State::status)"
fi
last_result=$(cp "${dir_state_status}" "${dump_dir}/dpkg-status.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* cp OK"
else
debug "* cp ERROR :"
debug "${last_result}"
rc=10
fi
}
task_packages() {
debug "Task: List of installed package"
dpkg_bin=$(command -v dpkg)
if [ -n "${dpkg_bin}" ]; then
last_result=$(${dpkg_bin} --get-selections "*" > "${dump_dir}/current_packages.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* dpkg OK"
else
debug "* dpkg ERROR :"
debug "${last_result}"
rc=10
fi
else
debug "* dpkg not found"
fi
}
task_uname() {
debug "Task: uname"
last_result=$(uname -a > "${dump_dir}/uname.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* uname OK"
else
debug "* uname ERROR"
debug "${last_result}"
rc=10
fi
}
task_uptime() {
debug "Task: uptime"
last_result=$(uptime > "${dump_dir}/uptime.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* uptime OK"
else
debug "* uptime ERROR"
debug "${last_result}"
rc=10
fi
}
task_processes() {
debug "Task: Process list"
last_result=$(ps fauxw > "${dump_dir}/ps.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* ps OK"
else
debug "* ps ERROR"
debug "${last_result}"
rc=10
fi
pstree_bin=$(command -v pstree)
if [ -n "${pstree_bin}" ]; then
last_result=$(${pstree_bin} -pan > "${dump_dir}/pstree.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* pstree OK"
else
debug "* pstree ERROR"
debug "${last_result}"
rc=10
fi
fi
}
task_netstat() {
debug "Task: Network status"
ss_bin=$(command -v ss)
if [ -n "${ss_bin}" ]; then
last_result=$(${ss_bin} -tanpul > "${dump_dir}/netstat-ss.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* ss OK"
else
debug "* ss ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* ss not found"
fi
netstat_bin=$(command -v netstat)
if [ -n "${netstat_bin}" ]; then
last_result=$(netstat -laputen > "${dump_dir}/netstat-legacy.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* netstat OK"
else
debug "* netstat ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* netstat not found"
fi
}
task_netcfg() {
debug "Task: Network configuration"
ip_bin=$(command -v ip)
if [ -n "${ip_bin}" ]; then
last_result=$(${ip_bin} address show > "${dump_dir}/ip-address.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* ip address OK"
else
debug "* ip address ERROR"
debug "${last_result}"
rc=10
fi
last_result=$(${ip_bin} route show > "${dump_dir}/ip-route.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* ip route OK"
else
debug "* ip route ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* ip not found"
ifconfig_bin=$(command -v ifconfig)
if [ -n "${ifconfig_bin}" ]; then
last_result=$(${ifconfig_bin} > "${dump_dir}/ifconfig.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* ifconfig OK"
else
debug "* ifconfig ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* ifconfig not found"
fi
fi
}
task_iptables() {
debug "Task: iptables"
iptables_bin=$(command -v iptables)
ip6tables_bin=$(command -v ip6tables)
if [ -n "${iptables_bin}" ]; then
last_result=$({
printf "#### iptables --list ###############################\n"
${iptables_bin} --list --numeric --verbose --line-numbers
printf "\n### iptables --table nat --list ####################\n"
${iptables_bin} --table nat --list --numeric --verbose --line-numbers
printf "\n#### iptables --table mangle --list ################\n"
${iptables_bin} --table mangle --list --numeric --verbose --line-numbers
if [ -n "${ip6tables_bin}" ]; then
printf "\n#### ip6tables --list ##############################\n"
${ip6tables_bin} --list --numeric --verbose --line-numbers
printf "\n#### ip6tables --table mangle --list ###############\n"
${ip6tables_bin} --table mangle --list --numeric --verbose --line-numbers
fi
} > "${dump_dir}/iptables-v.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* iptables -v OK"
else
debug "* iptables -v ERROR"
debug "${last_result}"
# Ignore errors because we don't know if this is nft related or a real error
# rc=10
fi
last_result=$({
printf "#### iptables --list ###############################\n"
${iptables_bin} --list --numeric
printf "\n### iptables --table nat --list ####################\n"
${iptables_bin} --table nat --list --numeric
printf "\n#### iptables --table mangle --list ################\n"
${iptables_bin} --table mangle --list --numeric
if [ -n "${ip6tables_bin}" ]; then
printf "\n#### ip6tables --list ##############################\n"
${ip6tables_bin} --list --numeric
printf "\n#### ip6tables --table mangle --list ###############\n"
${ip6tables_bin} --table mangle --list --numeric
fi
} > "${dump_dir}/iptables.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* iptables OK"
else
debug "* iptables ERROR"
debug "${last_result}"
# Ignore errors because we don't know if this is nft related or a real error
# rc=10
fi
else
debug "* iptables not found"
fi
iptables_save_bin=$(command -v iptables-save)
if [ -n "${iptables_save_bin}" ]; then
last_result=$(${iptables_save_bin} > "${dump_dir}/iptables-save.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* iptables-save OK"
else
debug "* iptables-save ERROR"
debug "${last_result}"
# Ignore errors because we don't know if this is nft related or a real error
# rc=10
fi
else
debug "* iptables-save not found"
fi
nft_bin=$(command -v nft)
if [ -n "${nft_bin}" ]; then
last_result=$(${nft_bin} list ruleset > "${dump_dir}/nft-ruleset.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* nft ruleset OK"
else
debug "* nft ruleset ERROR"
debug "${last_result}"
rc=10
fi
fi
}
task_sysctl() {
debug "Task: sysctl values"
sysctl_bin=$(command -v sysctl)
if [ -n "${sysctl_bin}" ]; then
last_result=$(${sysctl_bin} -a --ignore 2>/dev/null | sort -h > "${dump_dir}/sysctl.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* sysctl OK"
else
debug "* sysctl ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* sysctl not found"
fi
}
task_virsh() {
debug "Task: virsh list"
virsh_bin=$(command -v virsh)
if [ -n "${virsh_bin}" ]; then
last_result=$(${virsh_bin} list --all > "${dump_dir}/virsh-list.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* virsh list OK"
else
debug "* virsh list ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* virsh not found"
fi
}
task_lxc() {
debug "Task: lxc list"
lxc_ls_bin=$(command -v lxc-ls)
if [ -n "${lxc_ls_bin}" ]; then
last_result=$(${lxc_ls_bin} --fancy > "${dump_dir}/lxc-list.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* lxc list OK"
else
debug "* lxc list ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* lxc-ls not found"
fi
}
task_disks() {
debug "Task: Disks"
lsblk_bin=$(command -v lsblk)
awk_bin=$(command -v awk)
if [ -n "${lsblk_bin}" ] && [ -n "${awk_bin}" ]; then
disks=$(${lsblk_bin} -l | grep disk | grep -v -E '(drbd|fd[0-9]+)' | ${awk_bin} '{print $1}')
for disk in ${disks}; do
dd_bin=$(command -v dd)
if [ -n "${dd_bin}" ]; then
last_result=$(${dd_bin} if="/dev/${disk}" of="${dump_dir}/MBR-${disk}" bs=512 count=1 2>&1)
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* dd ${disk} OK"
else
debug "* dd ${disk} ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* dd not found"
fi
fdisk_bin=$(command -v fdisk)
if [ -n "${fdisk_bin}" ]; then
last_result=$(${fdisk_bin} -l "/dev/${disk}" > "${dump_dir}/partitions-${disk}" 2>&1)
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* fdisk ${disk} OK"
else
debug "* fdisk ${disk} ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* fdisk not found"
fi
done
cat "${dump_dir}"/partitions-* > "${dump_dir}/partitions"
else
if [ -n "${lsblk_bin}" ]; then
debug "* lsblk not found"
fi
if [ -n "${awk_bin}" ]; then
debug "* awk not found"
fi
fi
}
task_mount() {
debug "Task: Mount points"
findmnt_bin=$(command -v findmnt)
if [ -n "${findmnt_bin}" ]; then
last_result=$(${findmnt_bin} > "${dump_dir}/mount.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* mount points OK"
else
debug "* mount points ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* findmnt not found"
mount_bin=$(command -v mount)
if [ -n "${mount_bin}" ]; then
last_result=$(${mount_bin} > "${dump_dir}/mount.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* mount points OK"
else
debug "* mount points ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* mount not found"
fi
fi
}
task_df() {
debug "Task: df"
df_bin=$(command -v df)
if [ -n "${df_bin}" ]; then
last_result=$(${df_bin} --portability > "${dump_dir}/df.txt" 2>&1)
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* df OK"
else
debug "* df ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* df not found"
fi
}
task_dmesg() {
debug "Task: dmesg"
dmesg_bin=$(command -v dmesg)
if [ -n "${dmesg_bin}" ]; then
last_result=$(${dmesg_bin} > "${dump_dir}/dmesg.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* dmesg OK"
else
debug "* dmesg ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* dmesg not found"
fi
}
task_mysql_processes() {
debug "Task: MySQL processes"
mysqladmin_bin=$(command -v mysqladmin)
if [ -n "${mysqladmin_bin}" ]; then
# Look for local MySQL or MariaDB process
if pgrep mysqld > /dev/null || pgrep mariadbd > /dev/null; then
if ${mysqladmin_bin} ping > /dev/null 2>&1; then
${mysqladmin_bin} --verbose processlist > "${dump_dir}/mysql-processlist.txt" 2> "${dump_dir}/mysql-processlist.err"
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* mysqladmin OK"
else
debug "* mysqladmin ERROR"
debug < "${dump_dir}/mysql-processlist.err"
rm "${dump_dir}/mysql-processlist.err"
rc=10
fi
else
debug "* unable to ping with mysqladmin"
fi
else
debug "* no mysqld or mariadbd process is running"
fi
else
debug "* mysqladmin not found"
fi
}
task_systemctl() {
debug "Task: Systemd services"
systemctl_bin=$(command -v systemctl)
if [ -n "${systemctl_bin}" ]; then
last_result=$(${systemctl_bin} --no-legend --state=failed --type=service > "${dump_dir}/systemctl-failed-services.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* failed services OK"
else
debug "* failed services ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* systemctl not found"
fi
}
main() {
if [ -z "${dump_dir}" ]; then
echo "ERROR: You must provide the --dump-dir argument" >&2
exit 1
fi
if [ -d "${dump_dir}" ]; then
if [ "${FORCE}" != "1" ]; then
echo "ERROR: The dump directory ${dump_dir} already exists. Delete it first." >&2
exit 2
fi
else
create_dump_dir
fi
if [ "${TASK_ETC}" -eq 1 ]; then
task_etc
fi
if [ "${TASK_DPKG_FULL}" -eq 1 ]; then
task_dpkg_full
fi
if [ "${TASK_DPKG_STATUS}" -eq 1 ]; then
task_dpkg_status
fi
if [ "${TASK_APT_STATES}" -eq 1 ]; then
task_apt_states
fi
if [ "${TASK_APT_CONFIG}" -eq 1 ]; then
task_apt_config
fi
if [ "${TASK_PACKAGES}" -eq 1 ]; then
task_packages
fi
if [ "${TASK_PROCESSES}" -eq 1 ]; then
task_processes
fi
if [ "${TASK_UPTIME}" -eq 1 ]; then
task_uptime
fi
if [ "${TASK_UNAME}" -eq 1 ]; then
task_uname
fi
if [ "${TASK_NETSTAT}" -eq 1 ]; then
task_netstat
fi
if [ "${TASK_NETCFG}" -eq 1 ]; then
task_netcfg
fi
if [ "${TASK_IPTABLES}" -eq 1 ]; then
task_iptables
fi
if [ "${TASK_SYSCTL}" -eq 1 ]; then
task_sysctl
fi
if [ "${TASK_VIRSH}" -eq 1 ]; then
task_virsh
fi
if [ "${TASK_LXC}" -eq 1 ]; then
task_lxc
fi
if [ "${TASK_DISKS}" -eq 1 ]; then
task_disks
fi
if [ "${TASK_MOUNT}" -eq 1 ]; then
task_mount
fi
if [ "${TASK_DF}" -eq 1 ]; then
task_df
fi
if [ "${TASK_DMESG}" -eq 1 ]; then
task_dmesg
fi
if [ "${TASK_MYSQL_PROCESSES}" -eq 1 ]; then
task_mysql_processes
fi
if [ "${TASK_SYSTEMCTL}" -eq 1 ]; then
task_systemctl
fi
debug "=> Your dump is available at ${dump_dir}"
exit ${rc}
}
# parse options
# based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
while :; do
case $1 in
-h|-\?|--help)
show_help
exit 0
;;
-V|--version)
show_version
exit 0
;;
-v|--verbose)
VERBOSE=1
;;
-f|--force)
FORCE=1
;;
-d|--dump-dir)
# with value separated by space
if [ -n "$2" ]; then
dump_dir=$2
shift
else
printf 'ERROR: "-d|--dump-dir" requires a non-empty option argument.\n' >&2
exit 1
fi
;;
--dump-dir=?*)
# with value speparated by =
dump_dir=${1#*=}
;;
--dump-dir=)
# without value
printf 'ERROR: "--dump-dir" requires a non-empty option argument.\n' >&2
exit 1
;;
--backup-dir)
printf 'WARNING: "--backup-dir" is deprecated in favor of "--dump-dir".\n'
if [ -n "${dump_dir}" ]; then
debug "Dump directory is already set, let's ignore this one."
else
debug "Dump directory is not set already, let's stay backward compatible."
# with value separated by space
if [ -n "$2" ]; then
dump_dir=$2
shift
else
printf 'ERROR: "--backup-dir" requires a non-empty option argument.\n' >&2
exit 1
fi
fi
;;
--backup-dir=?*)
# with value speparated by =
printf 'WARNING: "--backup-dir" is deprecated in favor of "--dump-dir".\n'
if [ -n "${dump_dir}" ]; then
debug "Dump directory is already set, let's ignore this one."
else
debug "Dump directory is not set already, let's stay backward compatible."
dump_dir=${1#*=}
fi
;;
--backup-dir=)
# without value
printf 'WARNING: "--backup-dir" is deprecated in favor of "--dump-dir".\n'
if [ -n "${dump_dir}" ]; then
debug "Dump directory is already set, let's ignore this one."
else
printf 'ERROR: "--backup-dir" requires a non-empty option argument.\n' >&2
exit 1
fi
;;
--all)
for option in \
TASK_ETC \
TASK_DPKG_FULL \
TASK_DPKG_STATUS \
TASK_APT_STATES \
TASK_APT_CONFIG \
TASK_PACKAGES \
TASK_PROCESSES \
TASK_UNAME \
TASK_UPTIME \
TASK_NETSTAT \
TASK_NETCFG \
TASK_IPTABLES \
TASK_SYSCTL \
TASK_VIRSH \
TASK_LXC \
TASK_DISKS \
TASK_MOUNT \
TASK_DF \
TASK_DMESG \
TASK_MYSQL_PROCESSES \
TASK_SYSTEMCTL
do
eval "${option}=1"
done
;;
--none)
for option in \
TASK_ETC \
TASK_DPKG_FULL \
TASK_DPKG_STATUS \
TASK_APT_STATES \
TASK_APT_CONFIG \
TASK_PACKAGES \
TASK_PROCESSES \
TASK_UNAME \
TASK_UPTIME \
TASK_NETSTAT \
TASK_NETCFG \
TASK_IPTABLES \
TASK_SYSCTL \
TASK_VIRSH \
TASK_LXC \
TASK_DISKS \
TASK_MOUNT \
TASK_DF \
TASK_DMESG \
TASK_MYSQL_PROCESSES \
TASK_SYSTEMCTL
do
eval "${option}=0"
done
;;
--etc)
TASK_ETC=1
;;
--no-etc)
TASK_ETC=0
;;
--dpkg-full)
TASK_DPKG_FULL=1
;;
--no-dpkg-full)
TASK_DPKG_FULL=0
;;
--dpkg-status)
TASK_DPKG_STATUS=1
;;
--no-dpkg-status)
TASK_DPKG_STATUS=0
;;
--apt-states)
TASK_APT_STATES=1
;;
--no-apt-states)
TASK_APT_STATES=0
;;
--apt-config)
TASK_APT_CONFIG=1
;;
--no-apt-config)
TASK_APT_CONFIG=0
;;
--packages)
TASK_PACKAGES=1
;;
--no-packages)
TASK_PACKAGES=0
;;
--processes)
TASK_PROCESSES=1
;;
--no-processes)
TASK_PROCESSES=0
;;
--uptime)
TASK_UPTIME=1
;;
--no-uptime)
TASK_UPTIME=0
;;
--uname)
TASK_UNAME=1
;;
--no-uname)
TASK_UNAME=0
;;
--netstat)
TASK_NETSTAT=1
;;
--no-netstat)
TASK_NETSTAT=0
;;
--netcfg)
TASK_NETCFG=1
;;
--no-netcfg)
TASK_NETCFG=0
;;
--iptables)
TASK_IPTABLES=1
;;
--no-iptables)
TASK_IPTABLES=0
;;
--sysctl)
TASK_SYSCTL=1
;;
--no-sysctl)
TASK_SYSCTL=0
;;
--virsh)
TASK_VIRSH=1
;;
--no-virsh)
TASK_VIRSH=0
;;
--lxc)
TASK_LXC=1
;;
--no-lxc)
TASK_LXC=0
;;
--disks)
TASK_DISKS=1
;;
--no-disks)
TASK_DISKS=0
;;
--mount)
TASK_MOUNT=1
;;
--no-mount)
TASK_MOUNT=0
;;
--df)
TASK_DF=1
;;
--no-df)
TASK_DF=0
;;
--dmesg)
TASK_DMESG=1
;;
--no-dmesg)
TASK_DMESG=0
;;
--mysql-processes)
TASK_MYSQL_PROCESSES=1
;;
--no-mysql-processes)
TASK_MYSQL_PROCESSES=0
;;
--systemctl)
TASK_SYSTEMCTL=1
;;
--no-systemctl)
TASK_SYSTEMCTL=0
;;
--)
# End of all options.
shift
break
;;
-?*)
# ignore unknown options
printf 'WARN: Unknown option : %s\n' "$1" >&2
exit 1
;;
*)
# Default case: If no more options then break out of the loop.
break
;;
esac
shift
done
# Default values
: "${VERBOSE:=0}"
: "${FORCE:=0}"
: "${TASK_ETC:=0}"
: "${TASK_DPKG_FULL:=0}"
: "${TASK_DPKG_STATUS:=1}"
: "${TASK_APT_STATES:=1}"
: "${TASK_APT_CONFIG:=1}"
: "${TASK_PACKAGES:=1}"
: "${TASK_PROCESSES:=1}"
: "${TASK_UNAME:=1}"
: "${TASK_UPTIME:=1}"
: "${TASK_NETSTAT:=1}"
: "${TASK_NETCFG:=1}"
: "${TASK_IPTABLES:=1}"
: "${TASK_SYSCTL:=1}"
: "${TASK_VIRSH:=1}"
: "${TASK_LXC:=1}"
: "${TASK_DISKS:=1}"
: "${TASK_MOUNT:=1}"
: "${TASK_DF:=1}"
: "${TASK_DMESG:=1}"
: "${TASK_MYSQL_PROCESSES:=1}"
: "${TASK_SYSTEMCTL:=1}"
export LC_ALL=C
set -u
main

View file

@ -1,15 +1,15 @@
top's Config File (Linux processes with windows)
Id:j, Mode_altscr=0, Mode_irixps=1, Delay_time=3.0, Curwin=0
Def fieldscur=ķ&')*+,-./012568>?ABCFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz
winflags=193844, sortindx=18, maxtasks=0, graph_cpus=0, graph_mems=0, double_up=0, combine_cpus=0
summclr=1, msgsclr=1, headclr=3, taskclr=1
Job fieldscur=(Ļ@<)*+,-./012568>?ABCFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz
winflags=193844, sortindx=0, maxtasks=0, graph_cpus=0, graph_mems=0, double_up=0, combine_cpus=0
summclr=6, msgsclr=6, headclr=7, taskclr=6
Mem fieldscur=<MBND34&'()*+,-./0125689FGHIJKLOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz
winflags=193844, sortindx=21, maxtasks=0, graph_cpus=0, graph_mems=0, double_up=0, combine_cpus=0
summclr=5, msgsclr=5, headclr=4, taskclr=5
Usr fieldscur=)+,-./1234568;<=>?@ABCFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz
winflags=193844, sortindx=3, maxtasks=0, graph_cpus=0, graph_mems=0, double_up=0, combine_cpus=0
summclr=3, msgsclr=3, headclr=2, taskclr=3
Def fieldscur=¥¨³´»½À¼Ä·º¹Å&')*+,-./012568>?ABCFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz
winflags=177460, sortindx=18, maxtasks=0, graph_cpus=0, graph_mems=0, double_up=0, combine_cpus=0
summclr=1, msgsclr=1, headclr=3, taskclr=1
Job fieldscur=¥¦¹·º(³´Ä»½@<§Å)*+,-./012568>?ABCFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz
winflags=193844, sortindx=0, maxtasks=0, graph_cpus=0, graph_mems=0, double_up=0, combine_cpus=0
summclr=6, msgsclr=6, headclr=7, taskclr=6
Mem fieldscur=¥º»<½¾¿ÀÁMBNÃD34·Å&'()*+,-./0125689FGHIJKLOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz
winflags=193844, sortindx=21, maxtasks=0, graph_cpus=0, graph_mems=0, double_up=0, combine_cpus=0
summclr=5, msgsclr=5, headclr=4, taskclr=5
Usr fieldscur=¥¦§¨ª°¹·ºÄÅ)+,-./1234568;<=>?@ABCFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz
winflags=193844, sortindx=3, maxtasks=0, graph_cpus=0, graph_mems=0, double_up=0, combine_cpus=0
summclr=3, msgsclr=3, headclr=2, taskclr=3
Fixed_widest=0, Summ_mscale=1, Task_mscale=0, Zero_suppress=0

View file

@ -72,3 +72,8 @@
name: postfix
state: reloaded
- name: restart log2mail
service:
name: log2mail
state: restarted

View file

@ -32,11 +32,14 @@
## Dedicated hardware
- name: Install freepmi when it's dedicated hardware
- name: Install some additionnals tools when it dedicated hardware
apt:
name:
- libipc-run-perl
- freeipmi
- ipmitool
- firmware-linux-nonfree
- intel-microcode
state: present
tags:
- packages

View file

@ -16,3 +16,20 @@
daemon-reload: yes
state: started
enabled: yes
- name: log2mail config is present
blockinfile:
dest: /etc/log2mail/config/default
owner: log2mail
group: adm
mode: "0640"
marker: "# {mark} ANSIBLE MANAGED RULES FOR DEFAULT INSTANCE"
block: |
file = /var/log/syslog
pattern = "Out of memory: Kill"
mailto = {{ log2mail_alert_email or general_alert_email | mandatory }}
template = /etc/log2mail/mail
notify: restart log2mail
tags:
- log2mail

View file

@ -14,6 +14,7 @@
apt_install_basics: "{{ evolinux_apt_replace_default_sources }}"
apt_install_evolix_public: "{{ evolinux_apt_public_sources }}"
apt_upgrade: "{{ evolinux_apt_upgrade }}"
apt_basics_components: "{{ 'main contrib non-free' if ansible_virtualization_role == 'host' else 'main' }}"
when: evolinux_apt_include | bool
- name: /etc versioning with Git

View file

@ -2,6 +2,6 @@
- name: Deploy top configuration file
copy:
# The config format is unredable; ATM it only add the SWAP column
src: htoprc
src: topdefaultrc
dest: /etc/topdefaultrc
mode: "0644"

View file

@ -3,15 +3,22 @@
- include_role:
name: evolix/remount-usr
- name: backup-server-state script is present
- name: dump-server-state script is present
copy:
src: "backup-server-state.sh"
dest: /usr/local/sbin/backup-server-state
src: "dump-server-state.sh"
dest: /usr/local/sbin/dump-server-state
force: True
owner: root
group: root
mode: "0750"
- name: symlink backup-server-state to dump-server-state
file:
src: /usr/local/sbin/dump-server-state
dest: /usr/local/sbin/backup-server-state
state: link
force: yes
- name: "/sbin/deny script is present"
copy:
src: deny.sh

View file

@ -3,8 +3,9 @@
- name: restart minifirewall
command: /etc/init.d/minifirewall restart
register: minifirewall_init_restart
failed_when: "'starting IPTables rules is now finish : OK' not in minifirewall_init_restart.stdout"
changed_when: "'starting IPTables rules is now finish : OK' in minifirewall_init_restart.stdout"
failed_when:
- "'starting IPTables rules is now finish : OK' not in minifirewall_init_restart.stdout"
- "'minifirewall started' not in minifirewall_init_restart.stdout"
- name: restart minifirewall (noop)
meta: noop

View file

@ -0,0 +1,31 @@
---
- include_role:
name: evolix/remount-usr
tags:
- evomaintenance
- name: /usr/share/scripts exists
file:
dest: /usr/share/scripts
mode: "0700"
owner: root
group: root
state: directory
tags:
- evomaintenance
- name: Evomaintenance script and template are installed
copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
owner: root
group: root
mode: "{{ item.mode }}"
force: yes
backup: yes
loop:
- { src: 'evomaintenance.sh', dest: '/usr/share/scripts/', mode: '0700' }
- { src: 'evomaintenance.tpl', dest: '/usr/share/scripts/', mode: '0600' }
tags:
- evomaintenance

View file

@ -10,6 +10,12 @@
- evomaintenance_install_vendor | bool
- ansible_distribution == "Debian"
- include: install_vendor_other.yml
when:
- evomaintenance_install_vendor | bool
- ansible_distribution != "Debian"
- include: config.yml
- include: minifirewall.yml

View file

@ -608,11 +608,11 @@ if is_pkg_installed lxc; then
if lxc-ls | grep -q php56 ; then
cat <<EOT >> "${ldif_file}"
dn: ServiceName=ServiceName=php-fpm56,${computer_dn}
dn: ServiceName=php-fpm56,${computer_dn}
NagiosEnabled: TRUE
ipServiceProtocol: tcp
objectClass: EvoService
ServiceName: PHP-FPM (multiphp)
ServiceName: php-fpm56
ipServicePort: 443
ServiceType: web
ServiceVersion: PHP-FPM 5.6 (multiphp)
@ -622,11 +622,11 @@ fi
if lxc-ls | grep -q php70 ; then
cat <<EOT >> "${ldif_file}"
dn: ServiceName=ServiceName=php-fpm70,${computer_dn}
dn: ServiceName=php-fpm70,${computer_dn}
NagiosEnabled: TRUE
ipServiceProtocol: tcp
objectClass: EvoService
ServiceName: PHP-FPM (multiphp)
ServiceName: php-fpm70
ipServicePort: 443
ServiceType: web
ServiceVersion: PHP-FPM 7.0 (multiphp)
@ -636,11 +636,11 @@ fi
if lxc-ls | grep -q php73 ; then
cat <<EOT >> "${ldif_file}"
dn: ServiceName=ServiceName=php-fpm73,${computer_dn}
dn: ServiceName=php-fpm73,${computer_dn}
NagiosEnabled: TRUE
ipServiceProtocol: tcp
objectClass: EvoService
ServiceName: PHP-FPM (multiphp)
ServiceName: php-fpm73
ipServicePort: 443
ServiceType: web
ServiceVersion: PHP-FPM 7.3 (multiphp)
@ -650,11 +650,11 @@ fi
if lxc-ls | grep -q php74 ; then
cat <<EOT >> "${ldif_file}"
dn: ServiceName=ServiceName=php-fpm74,${computer_dn}
dn: ServiceName=php-fpm74,${computer_dn}
NagiosEnabled: TRUE
ipServiceProtocol: tcp
objectClass: EvoService
ServiceName: PHP-FPM (multiphp)
ServiceName: php-fpm74
ipServicePort: 443
ServiceType: web
ServiceVersion: PHP-FPM 7.4 (multiphp)
@ -664,11 +664,11 @@ fi
if lxc-ls | grep -q php80 ; then
cat <<EOT >> "${ldif_file}"
dn: ServiceName=ServiceName=php-fpm80,${computer_dn}
dn: ServiceName=php-fpm80,${computer_dn}
NagiosEnabled: TRUE
ipServiceProtocol: tcp
objectClass: EvoService
ServiceName: PHP-FPM (multiphp)
ServiceName: php-fpm80
ipServicePort: 443
ServiceType: web
ServiceVersion: PHP-FPM 8.0 (multiphp)
@ -678,11 +678,11 @@ fi
if lxc-ls | grep -q php81 ; then
cat <<EOT >> "${ldif_file}"
dn: ServiceName=ServiceName=php-fpm81,${computer_dn}
dn: ServiceName=php-fpm81,${computer_dn}
NagiosEnabled: TRUE
ipServiceProtocol: tcp
objectClass: EvoService
ServiceName: PHP-FPM (multiphp)
ServiceName: php-fpm81
ipServicePort: 443
ServiceType: web
ServiceVersion: PHP-FPM 8.1 (multiphp)
@ -709,6 +709,37 @@ EOT
fi
# bkctld
if is_pkg_installed bkctld; then
bkctld_version=$(get_pkg_version bkctld)
fi
if [ -n "${bkctld_version}" ]; then
cat <<EOT >> "${ldif_file}"
dn: ServiceName=bkctld_jails,${computer_dn}
NagiosEnabled: TRUE
objectClass: EvoService
ServiceName: bkctld_jails
ServiceType: backup
ServiceVersion: bkctld ${bkctld_version}
dn: ServiceName=bkctld_setup,${computer_dn}
NagiosEnabled: TRUE
objectClass: EvoService
ServiceName: bkctld_setup
ServiceType: backup
ServiceVersion: bkctld ${bkctld_version}
dn: ServiceName=disk-worktime,${computer_dn}
NagiosEnabled: TRUE
objectClass: EvoService
ServiceName: disk-worktime
ServiceType: disk
ServiceVersion: Undefined
EOT
fi
# test if we have a stdout
if [ -t 1 ]; then
echo "Output is in ${ldif_file}"

View file

@ -28,7 +28,7 @@
owner: root
group: root
force: yes
tags:
tags:
- keepalived
- nrpe

View file

@ -33,7 +33,7 @@
state: present
special_time: "hourly"
user: root
job: "rsync -a --delete /etc/libvirt/qemu/*xml {{ hostvars[kvm_pair]['lan.ip'] }}:/root/libvirt-{{ inventory_hostname }}/"
job: "if ls /etc/libvirt/qemu/*xml > /dev/null 2> /dev/null; then rsync -a --delete /etc/libvirt/qemu/*xml {{ hostvars[kvm_pair]['lan.ip'] }}:/root/libvirt-{{ inventory_hostname }}/; fi"
when:
- kvm_pair is defined
- kvm_pair is not none

View file

@ -36,4 +36,6 @@ lxc.start.auto = 1
{% if ansible_distribution_major_version is version('9', '>') %}
# Set LXC container unconfined in AppArmor
lxc.apparmor.profile = unconfined
{% else %}
lxc.aa_profile = unconfined
{% endif %}

View file

@ -1,24 +1,35 @@
---
minifirewall_main_file: /etc/default/minifirewall
minifirewall_tail_file: /etc/default/minifirewall.tail
# possible values: Null (default), modern or legacy
minifirewall_install_mode: Null
# BEGIN legacy variables
minifirewall_legacy_main_file: /etc/default/minifirewall
minifirewall_legacy_tail_file: /etc/default/minifirewall.tail
# END legacy variabes
minifirewall_tail_file: /etc/minifirewall.d/zzz-tail
minifirewall_tail_included: False
minifirewall_tail_force: True
# Overwrite files completely
minifirewall_force_upgrade_script: False
minifirewall_force_upgrade_config: False
minifirewall_git_url: "https://forge.evolix.org/minifirewall.git"
minifirewall_checkout_path: "/tmp/minifirewall"
# Update specific values in configuration
minifirewall_update_config: True
minifirewall_int: "{{ ansible_default_ipv4.interface }}"
minifirewall_ipv6: "on"
minifirewall_intlan: "{{ ansible_default_ipv4.address }}/32"
minifirewall_docker: "off"
minifirewall_default_trusted_ips: []
minifirewall_legacy_fallback_trusted_ips: ['0.0.0.0/0']
minifirewall_fallback_trusted_ips: ['0.0.0.0/0', '::/0']
minifirewall_additional_trusted_ips: []
# and default to ['0.0.0.0/0'] if the result is still empty
minifirewall_trusted_ips: "{{ minifirewall_default_trusted_ips | union(minifirewall_additional_trusted_ips) | unique | default(['0.0.0.0/0'], true) }}"
# and default to ['0.0.0.0/0', '::/0'] if the result is still empty
minifirewall_trusted_ips: "{{ minifirewall_default_trusted_ips | union(minifirewall_additional_trusted_ips) | unique }}"
minifirewall_privilegied_ips: []
minifirewall_protected_ports_tcp: [22]
@ -31,7 +42,7 @@ minifirewall_private_ports_tcp: [5666]
minifirewall_private_ports_udp: []
# Keep a null value to leave the setting as is
# otherwise use an Array, eg. "minifirewall_ssh_ok: ['0.0.0.0/0']"
# otherwise use an Array, eg. "minifirewall_ssh_ok: ['0.0.0.0/0', '::/0']"
minifirewall_dns_servers: Null
minifirewall_http_sites: Null
minifirewall_https_sites: Null
@ -41,6 +52,22 @@ minifirewall_smtp_ok: Null
minifirewall_smtp_secure_ok: Null
minifirewall_ntp_ok: Null
minifirewall_proxy: "off"
minifirewall_proxyport: 8888
minifirewall_proxybypass:
- "${INTLAN}"
- "127.0.0.0/8"
- "::1/128"
minifirewall_backupservers: Null
minifirewall_sysctl_icmp_echo_ignore_broadcasts : Null
minifirewall_sysctl_icmp_ignore_bogus_error_responses : Null
minifirewall_sysctl_accept_source_route : Null
minifirewall_sysctl_tcp_syncookies : Null
minifirewall_sysctl_icmp_redirects : Null
minifirewall_sysctl_rp_filter : Null
minifirewall_sysctl_log_martians : Null
minifirewall_autostart: False
minifirewall_restart_if_needed: True
minifirewall_restart_force: False

View file

@ -0,0 +1,23 @@
#!/bin/sh
ripedeny_file=/var/tmp/ripe_deny
cd /var/tmp
rm -f $ripedeny_file
GET http://antispam00.evolix.org/spam/ripe.cidr.md5 > ripe.cidr.md5
GET http://antispam00.evolix.org/spam/ripe.cidr > ripe.cidr
for i in CN KR RU; do
grep "^$i|" ripe.cidr >> $ripedeny_file
done
/sbin/iptables -F NEEDRESTRICT
for i in $(cat $ripedeny_file); do
BLOCK=$(echo $i | cut -d"|" -f2)
/sbin/iptables -I NEEDRESTRICT -s $BLOCK -j DROP
done

1099
minifirewall/files/minifirewall Executable file
View file

@ -0,0 +1,1099 @@
#!/bin/sh
# shellcheck disable=SC2059
# minifirewall is a shell script for easy firewalling on a standalone server
# It uses netfilter/iptables http://netfilter.org/ designed for recent Linux kernel
# See https://gitea.evolix.org/evolix/minifirewall
# Copyright (c) 2007-2022 Evolix
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License.
# Description
# script for standalone server
# Start or stop minifirewall
#
### BEGIN INIT INFO
# Provides: minifirewall
# Required-Start:
# Required-Stop:
# Should-Start: $network $syslog $named
# Should-Stop: $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: start and stop the firewall
# Description: Firewall designed for standalone server
### END INIT INFO
VERSION="22.05"
NAME="minifirewall"
# shellcheck disable=SC2034
DESC="Firewall designed for standalone server"
set -u
# Variables configuration
#########################
config_file="/etc/default/minifirewall"
includes_dir="/etc/minifirewall.d"
# iptables paths
IPT=$(command -v iptables)
if [ -z "${IPT}" ]; then
echo "Unable to find 'iptables\` command in PATH." >&2
exit 1
fi
IPT6=$(command -v ip6tables)
if [ -z "${IPT6}" ]; then
echo "Unable to find 'ip6tables\` command in PATH." >&2
exit 1
fi
# TCP/IP variables
LOOPBACK='127.0.0.0/8'
CLASSA='10.0.0.0/8'
CLASSB='172.16.0.0/12'
CLASSC='192.168.0.0/16'
CLASSD='224.0.0.0/4'
CLASSE='240.0.0.0/5'
ALL='0.0.0.0'
BROAD='255.255.255.255'
PORTSROOT='0:1023'
PORTSUSER='1024:65535'
# Configuration
INT=''
IPV6=''
DOCKER=''
INTLAN=''
TRUSTEDIPS=''
PRIVILEGIEDIPS=''
SERVICESTCP1p=''
SERVICESUDP1p=''
SERVICESTCP1=''
SERVICESUDP1=''
SERVICESTCP2=''
SERVICESUDP2=''
SERVICESTCP3=''
SERVICESUDP3=''
DNSSERVEURS=''
HTTPSITES=''
HTTPSSITES=''
FTPSITES=''
SSHOK=''
SMTPOK=''
SMTPSECUREOK=''
NTPOK=''
PROXY=''
PROXYBYPASS=''
PROXYPORT=''
BACKUPSERVERS=''
LEGACY_CONFIG='off'
STATE_FILE_LATEST='/var/run/minifirewall_state_latest'
STATE_FILE_CURRENT='/var/run/minifirewall_state_current'
STATE_FILE_PREVIOUS='/var/run/minifirewall_state_previous'
STATE_FILE_DIFF='/var/run/minifirewall_state_diff'
LOGGER_BIN=$(command -v logger)
# No colors by default
RED=''
GREEN=''
YELLOW=''
BLUE=''
MAGENTA=''
CYAN=''
WHITE=''
BOLD=''
RESET=''
# check if stdout is a terminal...
if [ -t 1 ]; then
# see if it supports colors...
ncolors=$(tput colors)
if [ -n "${ncolors}" ] && [ ${ncolors} -ge 8 ]; then
RED=$(tput setaf 1)
GREEN=$(tput setaf 2)
YELLOW=$(tput setaf 3)
BLUE=$(tput setaf 4)
MAGENTA=$(tput setaf 5)
CYAN=$(tput setaf 6)
WHITE=$(tput setaf 7)
BOLD=$(tput bold)
RESET='\e[m'
fi
fi
## pseudo dry-run :
## Uncomment and call these functions instead of the real iptables and ip6tables commands
# IPT="fake_iptables"
# IPT6="fake_ip6tables"
# fake_iptables() {
# printf "DRY-RUN iptables %s\n" "$*"
# }
# fake_ip6tables() {
# printf "DRY-RUN ip6tables %s\n" "$*"
# }
## Beware that commands executed from included files are not modified by this trick.
syslog_info() {
if [ -x "${LOGGER_BIN}" ]; then
${LOGGER_BIN} -t "${NAME}" -p daemon.info "$1"
fi
}
syslog_error() {
if [ -x "${LOGGER_BIN}" ]; then
${LOGGER_BIN} -t "${NAME}" -p daemon.error "$1"
fi
}
sort_values() {
echo "$*" | tr ' ' '\n' | sort -h
}
is_ipv6_enabled() {
test "${IPV6}" != "off"
}
is_docker_enabled() {
test "${DOCKER}" = "on"
}
is_proxy_enabled() {
test "${PROXY}" = "on"
}
is_ipv6() {
echo "$1" | grep -q ':'
}
is_legacy_config() {
test "${LEGACY_CONFIG}" != "off"
}
chain_exists() {
chain_name="$1"
if [ $# -ge 2 ]; then
intable="--table $2"
else
intable=""
fi
# shellcheck disable=SC2086
iptables ${intable} -nL "${chain_name}" >/dev/null 2>&1
}
source_file_or_error() {
file=$1
syslog_info "sourcing \`${file}'"
printf "${BLUE}sourcing \`%s'${RESET}\n" "${file}"
tmpfile=$(mktemp --tmpdir=/tmp minifirewall.XXX)
. "${file}" 2>"${tmpfile}" >&2
if [ -s "${tmpfile}" ]; then
syslog_error "Error while sourcing ${file}"
printf "${RED}%s returns standard or error output (see below). Stopping.${RESET}\n" ${file} >&2
cat "${tmpfile}"
exit 1
fi
rm -f "${tmpfile}"
}
source_configuration() {
if ! test -f ${config_file}; then
printf "${RED}%s does not exist${RESET}\n" "${config_file}" >&2
## We still want to deal with this really old configuration file
## even if it has been deprecated since Debian 8
old_config_file="/etc/firewall.rc"
if test -f ${old_config_file}; then
printf "${YELLOW}%s is deprecated and ignored. Rename it to %s${RESET}\n" "${old_config_file}" "${config_file}" >&2
fi
exit 1
fi
# If we find something other than a blank line, a comment or a variable assignment
if grep --quiet --extended-regexp --invert-match "^\s*(#|$|\w+=)" "${config_file}"; then
# Backward compatible mode
###########################
printf "${YELLOW}legacy config detected${RESET}\n"
LEGACY_CONFIG='on'
# Non-backward compatible mode
###############################
# If we ever want to remove the backward compatible mode
# we can remove the two lines above and uncomment the lines below.
# They break if any iptables/ip6tables command is found in the configuration file
# echo "iptables/ip6tables commands found in ${config_file}." >&2
# echo "Move them in included files (in ${includes_dir})." >&2
# exit 1
fi
if is_legacy_config; then
# In this mode, we extract all variable definitions
# to a temporary file that we can source.
# It allow iptables/ip6tables commands to remain in the configuration file
# and not interfere with the configuration step.
tmp_config_file=$(mktemp --tmpdir=/tmp minifirewall.XXX)
# get only variable assignments
grep -E "^\s*\w+=" "${config_file}" > "${tmp_config_file}"
source_file_or_error "${tmp_config_file}"
rm -f "${tmp_config_file}"
else
source_file_or_error "${config_file}"
fi
}
source_includes() {
if [ -d "${includes_dir}" ]; then
include_files=$(find ${includes_dir} -type f -readable -not -name '*.*' | sort -h)
for include_file in ${include_files}; do
source_file_or_error "${include_file}"
done
fi
}
check_unpersisted_state() {
cmp_bin=$(command -v cmp)
diff_bin=$(command -v diff)
if [ -z "${cmp_bin}" ]; then
printf "${YELLOW}skip state comparison (Can't find cmp command)${RESET}\n" >&2
elif [ -z "${diff_bin}" ]; then
printf "${YELLOW}skip state comparison (Can't find diff command)${RESET}\n" >&2
else
# store current state
mkdir -p "$(dirname "${STATE_FILE_CURRENT}")"
status_without_numbers > "${STATE_FILE_CURRENT}"
# clean previous diff file
rm -f "${STATE_FILE_DIFF}"
if [ -f "${STATE_FILE_LATEST}" ]; then
cmp_result=$(cmp "${STATE_FILE_LATEST}" "${STATE_FILE_CURRENT}")
cmp_rc=$?
if [ ${cmp_rc} -eq 0 ]; then
# echo " rules have not changed since latest start"
:
elif [ ${cmp_rc} -eq 1 ]; then
diff -u "${STATE_FILE_LATEST}" "${STATE_FILE_CURRENT}" > "${STATE_FILE_DIFF}"
printf "${YELLOW}WARNING: current state is different than persisted state, check %s${RESET}\n" "${STATE_FILE_DIFF}" >&2
else
printf "${RED}ERROR comparing rules:${RESET}\n" >&2
echo "${cmp_result}" >&2
fi
fi
# cleanup
rm -f "${STATE_FILE_CURRENT}"
fi
}
report_state_changes() {
cmp_bin=$(command -v cmp)
diff_bin=$(command -v diff)
if [ -z "${cmp_bin}" ]; then
printf "${YELLOW}skip state comparison (Can't find cmp command)${RESET}\n" >&2
return
elif [ -z "${diff_bin}" ]; then
printf "${YELLOW}skip state comparison (Can't find diff command)${RESET}\n" >&2
else
# If there is a known state
# let's compare it with the current state
if [ -f "${STATE_FILE_LATEST}" ]; then
check_unpersisted_state
fi
# Then reset the known state
mkdir -p "$(dirname "${STATE_FILE_LATEST}")"
status_without_numbers > "${STATE_FILE_LATEST}"
# But if there is a previous known state
# let's compare with the new known state
if [ -f "${STATE_FILE_PREVIOUS}" ]; then
cmp_result=$(cmp "${STATE_FILE_PREVIOUS}" "${STATE_FILE_LATEST}")
cmp_rc=$?
if [ ${cmp_rc} -eq 0 ]; then
# echo "Rules have not changed since previous start"
:
elif [ ${cmp_rc} -eq 1 ]; then
diff -u "${STATE_FILE_PREVIOUS}" "${STATE_FILE_LATEST}" > "${STATE_FILE_DIFF}"
printf "${YELLOW}INFO: rules have changed since latest start, check %s${RESET}\n" "${STATE_FILE_DIFF}" >&2
else
printf "${RED}ERROR comparing rules:${RESET}\n" >&2
echo "${cmp_result}" >&2
fi
fi
fi
}
start() {
syslog_info "starting"
printf "${BOLD}${NAME} starting${RESET}\n"
# Stop and warn if error!
set -e
trap 'printf "${RED}${NAME} failed : an error occured during startup.${RESET}\n"; syslog_error "failed" ' INT TERM EXIT
# sysctl network security settings
##################################
# Set 1 to ignore broadcast pings (default)
: "${SYSCTL_ICMP_ECHO_IGNORE_BROADCASTS:=1}"
# Set 1 to ignore bogus ICMP responses (default)
: "${SYSCTL_ICMP_IGNORE_BOGUS_ERROR_RESPONSES:=1}"
# Set 0 to disable source routing (default)
: "${SYSCTL_ACCEPT_SOURCE_ROUTE:=0}"
# Set 1 to enable TCP SYN cookies (default)
# cf http://cr.yp.to/syncookies.html
: "${SYSCTL_TCP_SYNCOOKIES:=1}"
# Set 0 to disable ICMP redirects (default)
: "${SYSCTL_ICMP_REDIRECTS:=0}"
# Set 1 to enable Reverse Path filtering (default)
# Set 0 if VRRP is used
: "${SYSCTL_RP_FILTER:=1}"
# Set 1 to log packets with inconsistent address (default)
: "${SYSCTL_LOG_MARTIANS:=1}"
if [ "${SYSCTL_ICMP_ECHO_IGNORE_BROADCASTS}" = "1" ] || [ "${SYSCTL_ICMP_ECHO_IGNORE_BROADCASTS}" = "0" ]; then
echo "${SYSCTL_ICMP_ECHO_IGNORE_BROADCASTS}" > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
else
printf "${RED}ERROR: invalid %s value '%s', must be '0' or '1'.\n" "SYSCTL_ICMP_ECHO_IGNORE_BROADCASTS" "${SYSCTL_ICMP_ECHO_IGNORE_BROADCASTS}" >&2
exit 1
fi
if [ "${SYSCTL_ICMP_IGNORE_BOGUS_ERROR_RESPONSES}" = "1" ] || [ "${SYSCTL_ICMP_IGNORE_BOGUS_ERROR_RESPONSES}" = "0" ]; then
echo "${SYSCTL_ICMP_IGNORE_BOGUS_ERROR_RESPONSES}" > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses
else
printf "${RED}ERROR: invalid %s value '%s', must be '0' or '1'.\n" "SYSCTL_ICMP_IGNORE_BOGUS_ERROR_RESPONSES" "${SYSCTL_ICMP_IGNORE_BOGUS_ERROR_RESPONSES}" >&2
exit 1
fi
if [ "${SYSCTL_ACCEPT_SOURCE_ROUTE}" = "1" ] || [ "${SYSCTL_ACCEPT_SOURCE_ROUTE}" = "0" ]; then
for proc_sys_file in /proc/sys/net/ipv4/conf/*/accept_source_route; do
echo "${SYSCTL_ACCEPT_SOURCE_ROUTE}" > "${proc_sys_file}"
done
else
printf "${RED}ERROR: invalid %s value '%s', must be '0' or '1'.\n" "SYSCTL_ACCEPT_SOURCE_ROUTE" "${SYSCTL_ACCEPT_SOURCE_ROUTE}" >&2
exit 1
fi
if [ "${SYSCTL_TCP_SYNCOOKIES}" = "1" ] || [ "${SYSCTL_TCP_SYNCOOKIES}" = "0" ]; then
echo "${SYSCTL_TCP_SYNCOOKIES}" > /proc/sys/net/ipv4/tcp_syncookies
else
printf "${RED}ERROR: invalid %s value '%s', must be '0' or '1'.\n" "SYSCTL_TCP_SYNCOOKIES" "${SYSCTL_TCP_SYNCOOKIES}" >&2
exit 1
fi
if [ "${SYSCTL_ICMP_REDIRECTS}" = "1" ] || [ "${SYSCTL_ICMP_REDIRECTS}" = "0" ]; then
for proc_sys_file in /proc/sys/net/ipv4/conf/*/accept_redirects; do
echo "${SYSCTL_ICMP_REDIRECTS}" > "${proc_sys_file}"
done
for proc_sys_file in /proc/sys/net/ipv4/conf/*/send_redirects; do
echo "${SYSCTL_ICMP_REDIRECTS}" > "${proc_sys_file}"
done
else
printf "${RED}ERROR: invalid %s value '%s', must be '0' or '1'.\n" "SYSCTL_ICMP_REDIRECTS" "${SYSCTL_ICMP_REDIRECTS}" >&2
exit 1
fi
if [ "${SYSCTL_RP_FILTER}" = "1" ] || [ "${SYSCTL_RP_FILTER}" = "0" ]; then
for proc_sys_file in /proc/sys/net/ipv4/conf/*/rp_filter; do
echo "${SYSCTL_RP_FILTER}" > "${proc_sys_file}"
done
else
printf "${RED}ERROR: invalid %s value '%s', must be '0' or '1'.\n" "SYSCTL_RP_FILTER" "${SYSCTL_RP_FILTER}" >&2
exit 1
fi
if [ "${SYSCTL_LOG_MARTIANS}" = "1" ] || [ "${SYSCTL_LOG_MARTIANS}" = "0" ]; then
for proc_sys_file in /proc/sys/net/ipv4/conf/*/log_martians; do
echo "${SYSCTL_LOG_MARTIANS}" > "${proc_sys_file}"
done
else
printf "${RED}ERROR: invalid %s value '%s', must be '0' or '1'.\n" "SYSCTL_LOG_MARTIANS" "${SYSCTL_LOG_MARTIANS}" >&2
exit 1
fi
# IPTables configuration
########################
${IPT} -N LOG_DROP
${IPT} -A LOG_DROP -j LOG --log-prefix '[IPTABLES DROP] : '
${IPT} -A LOG_DROP -j DROP
${IPT} -N LOG_ACCEPT
${IPT} -A LOG_ACCEPT -j LOG --log-prefix '[IPTABLES ACCEPT] : '
${IPT} -A LOG_ACCEPT -j ACCEPT
if is_ipv6_enabled; then
${IPT6} -N LOG_DROP
${IPT6} -A LOG_DROP -j LOG --log-prefix '[IPTABLES DROP] : '
${IPT6} -A LOG_DROP -j DROP
${IPT6} -N LOG_ACCEPT
${IPT6} -A LOG_ACCEPT -j LOG --log-prefix '[IPTABLES ACCEPT] : '
${IPT6} -A LOG_ACCEPT -j ACCEPT
fi
# Source additional rules and commands
# * from legacy configuration file (/etc/default/minifirewall)
# * from configuration directory (/etc/minifirewall.d/*)
source_includes
# IP/ports lists are sorted to have consistent ordering
# You can disable this feature by simply commenting the following lines
LOOPBACK=$(sort_values ${LOOPBACK})
INTLAN=$(sort_values ${INTLAN})
TRUSTEDIPS=$(sort_values ${TRUSTEDIPS})
PRIVILEGIEDIPS=$(sort_values ${PRIVILEGIEDIPS})
SERVICESTCP1p=$(sort_values ${SERVICESTCP1p})
SERVICESUDP1p=$(sort_values ${SERVICESUDP1p})
SERVICESTCP1=$(sort_values ${SERVICESTCP1})
SERVICESUDP1=$(sort_values ${SERVICESUDP1})
SERVICESTCP2=$(sort_values ${SERVICESTCP2})
SERVICESUDP2=$(sort_values ${SERVICESUDP2})
SERVICESTCP3=$(sort_values ${SERVICESTCP3})
SERVICESUDP3=$(sort_values ${SERVICESUDP3})
DNSSERVEURS=$(sort_values ${DNSSERVEURS})
HTTPSITES=$(sort_values ${HTTPSITES})
HTTPSSITES=$(sort_values ${HTTPSSITES})
FTPSITES=$(sort_values ${FTPSITES})
SSHOK=$(sort_values ${SSHOK})
SMTPOK=$(sort_values ${SMTPOK})
SMTPSECUREOK=$(sort_values ${SMTPSECUREOK})
NTPOK=$(sort_values ${NTPOK})
PROXYBYPASS=$(sort_values ${PROXYBYPASS})
BACKUPSERVERS=$(sort_values ${BACKUPSERVERS})
# Trusted ip addresses
${IPT} -N ONLYTRUSTED
${IPT} -A ONLYTRUSTED -j LOG_DROP
if is_ipv6_enabled; then
${IPT6} -N ONLYTRUSTED
${IPT6} -A ONLYTRUSTED -j LOG_DROP
fi
for ip in ${TRUSTEDIPS}; do
if is_ipv6 ${ip}; then
if is_ipv6_enabled; then
${IPT6} -I ONLYTRUSTED -s ${ip} -j ACCEPT
fi
else
${IPT} -I ONLYTRUSTED -s ${ip} -j ACCEPT
fi
done
# Privilegied ip addresses
# (trusted ip addresses *are* privilegied)
${IPT} -N ONLYPRIVILEGIED
${IPT} -A ONLYPRIVILEGIED -j ONLYTRUSTED
if is_ipv6_enabled; then
${IPT6} -N ONLYPRIVILEGIED
${IPT6} -A ONLYPRIVILEGIED -j ONLYTRUSTED
fi
for ip in ${PRIVILEGIEDIPS}; do
if is_ipv6 ${ip}; then
if is_ipv6_enabled; then
${IPT6} -I ONLYPRIVILEGIED -s ${ip} -j ACCEPT
fi
else
${IPT} -I ONLYPRIVILEGIED -s ${ip} -j ACCEPT
fi
done
# Chain for restrictions (blacklist IPs/ranges)
${IPT} -N NEEDRESTRICT
if is_ipv6_enabled; then
${IPT6} -N NEEDRESTRICT
fi
# We allow all on loopback interface
${IPT} -A INPUT -i lo -j ACCEPT
if is_ipv6_enabled; then
${IPT6} -A INPUT -i lo -j ACCEPT
fi
# if OUTPUTDROP
${IPT} -A OUTPUT -o lo -j ACCEPT
if is_ipv6_enabled; then
${IPT6} -A OUTPUT -o lo -j ACCEPT
fi
# We avoid "martians" packets, typical when W32/Blaster virus
# attacked windowsupdate.com and DNS was changed to 127.0.0.1
# ${IPT} -t NAT -I PREROUTING -s ${LOOPBACK} -i ! lo -j DROP
for IP in ${LOOPBACK}; do
if is_ipv6 ${IP}; then
if is_ipv6_enabled; then
${IPT6} -A INPUT -s ${IP} ! -i lo -j DROP
fi
else
${IPT} -A INPUT -s ${IP} ! -i lo -j DROP
fi
done
if is_docker_enabled; then
# WARN: IPv6 not yet supported for Docker rules
${IPT} -N MINIFW-DOCKER-TRUSTED
${IPT} -A MINIFW-DOCKER-TRUSTED -j DROP
${IPT} -N MINIFW-DOCKER-PRIVILEGED
${IPT} -A MINIFW-DOCKER-PRIVILEGED -j MINIFW-DOCKER-TRUSTED
${IPT} -A MINIFW-DOCKER-PRIVILEGED -j RETURN
${IPT} -N MINIFW-DOCKER-PUB
${IPT} -A MINIFW-DOCKER-PUB -j MINIFW-DOCKER-PRIVILEGED
${IPT} -A MINIFW-DOCKER-PUB -j RETURN
# Flush DOCKER-USER if exist, create it if absent
if chain_exists 'DOCKER-USER'; then
${IPT} -F DOCKER-USER
else
${IPT} -N DOCKER-USER
fi;
# Pipe new connection through MINIFW-DOCKER-PUB
${IPT} -A DOCKER-USER -i ${INT} -m state --state NEW -j MINIFW-DOCKER-PUB
${IPT} -A DOCKER-USER -j RETURN
fi
# Local services restrictions
#############################
# Allow services for ${INTLAN} (local server or local network)
for IP in ${INTLAN}; do
if is_ipv6 ${IP}; then
if is_ipv6_enabled; then
${IPT6} -A INPUT -s ${IP} -j ACCEPT
fi
else
${IPT} -A INPUT -s ${IP} -j ACCEPT
fi
done
# Enable protection chain for sensible services
for port in ${SERVICESTCP1p}; do
${IPT} -A INPUT -p tcp --dport ${port} -j NEEDRESTRICT
if is_ipv6_enabled; then
${IPT6} -A INPUT -p tcp --dport ${port} -j NEEDRESTRICT
fi
done
for port in ${SERVICESUDP1p}; do
${IPT} -A INPUT -p udp --dport ${port} -j NEEDRESTRICT
if is_ipv6_enabled; then
${IPT6} -A INPUT -p udp --dport ${port} -j NEEDRESTRICT
fi
done
# Public service
for port in ${SERVICESTCP1}; do
${IPT} -A INPUT -p tcp --dport ${port} -j ACCEPT
if is_ipv6_enabled; then
${IPT6} -A INPUT -p tcp --dport ${port} -j ACCEPT
fi
done
for port in ${SERVICESUDP1}; do
${IPT} -A INPUT -p udp --dport ${port} -j ACCEPT
if is_ipv6_enabled; then
${IPT6} -A INPUT -p udp --dport ${port} -j ACCEPT
fi
done
# Privilegied services
for port in ${SERVICESTCP2}; do
${IPT} -A INPUT -p tcp --dport ${port} -j ONLYPRIVILEGIED
if is_ipv6_enabled; then
${IPT6} -A INPUT -p tcp --dport ${port} -j ONLYPRIVILEGIED
fi
done
for port in ${SERVICESUDP2}; do
${IPT} -A INPUT -p udp --dport ${port} -j ONLYPRIVILEGIED
if is_ipv6_enabled; then
${IPT6} -A INPUT -p udp --dport ${port} -j ONLYPRIVILEGIED
fi
done
# Private services
for port in ${SERVICESTCP3}; do
${IPT} -A INPUT -p tcp --dport ${port} -j ONLYTRUSTED
if is_ipv6_enabled; then
${IPT6} -A INPUT -p tcp --dport ${port} -j ONLYTRUSTED
fi
done
for port in ${SERVICESUDP3}; do
${IPT} -A INPUT -p udp --dport ${port} -j ONLYTRUSTED
if is_ipv6_enabled; then
${IPT6} -A INPUT -p udp --dport ${port} -j ONLYTRUSTED
fi
done
if is_docker_enabled; then
# WARN: IPv6 not yet supported
# Public services defined in SERVICESTCP1 & SERVICESUDP1
for dstport in ${SERVICESTCP1}; do
${IPT} -I MINIFW-DOCKER-PUB -p tcp --dport "${dstport}" -j RETURN
done
for dstport in ${SERVICESUDP1}; do
${IPT} -I MINIFW-DOCKER-PUB -p udp --dport "${dstport}" -j RETURN
done
# Privileged services (accessible from privileged & trusted IPs)
for dstport in ${SERVICESTCP2}; do
for srcip in ${PRIVILEGIEDIPS}; do
if ! is_ipv6 ${srcip}; then
${IPT} -I MINIFW-DOCKER-PRIVILEGED -p tcp -s "${srcip}" --dport "${dstport}" -j RETURN
fi
done
for srcip in ${TRUSTEDIPS}; do
if ! is_ipv6 ${srcip}; then
${IPT} -I MINIFW-DOCKER-PRIVILEGED -p tcp -s "${srcip}" --dport "${dstport}" -j RETURN
fi
done
done
for dstport in ${SERVICESUDP2}; do
for srcip in ${PRIVILEGIEDIPS}; do
if ! is_ipv6 ${srcip}; then
${IPT} -I MINIFW-DOCKER-PRIVILEGED -p udp -s "${srcip}" --dport "${dstport}" -j RETURN
fi
done
for srcip in ${TRUSTEDIPS}; do
if ! is_ipv6 ${srcip}; then
${IPT} -I MINIFW-DOCKER-PRIVILEGED -p udp -s "${srcip}" --dport "${dstport}" -j RETURN
fi
done
done
# Trusted services (accessible from trusted IPs)
for dstport in ${SERVICESTCP3}; do
for srcip in ${TRUSTEDIPS}; do
if ! is_ipv6 ${srcip}; then
${IPT} -I MINIFW-DOCKER-TRUSTED -p tcp -s "${srcip}" --dport "${dstport}" -j RETURN
fi
done
done
for dstport in ${SERVICESUDP3}; do
for srcip in ${TRUSTEDIPS}; do
if ! is_ipv6 ${srcip}; then
${IPT} -I MINIFW-DOCKER-TRUSTED -p udp -s "${srcip}" --dport "${dstport}" -j RETURN
fi
done
done
fi
# External services
###################
# DNS authorizations
for IP in ${DNSSERVEURS}; do
if is_ipv6 ${IP}; then
if is_ipv6_enabled; then
${IPT6} -A INPUT -p tcp ! --syn --sport 53 --dport ${PORTSUSER} -s ${IP} -j ACCEPT
${IPT6} -A INPUT -p udp --sport 53 --dport ${PORTSUSER} -s ${IP} -m state --state ESTABLISHED,RELATED -j ACCEPT
${IPT6} -A OUTPUT -o ${INT} -p udp -d ${IP} --dport 53 --match state --state NEW -j ACCEPT
fi
else
${IPT} -A INPUT -p tcp ! --syn --sport 53 --dport ${PORTSUSER} -s ${IP} -j ACCEPT
${IPT} -A INPUT -p udp --sport 53 --dport ${PORTSUSER} -s ${IP} -m state --state ESTABLISHED,RELATED -j ACCEPT
${IPT} -A OUTPUT -o ${INT} -p udp -d ${IP} --dport 53 --match state --state NEW -j ACCEPT
fi
done
# HTTP (TCP/80) authorizations
for IP in ${HTTPSITES}; do
if is_ipv6 ${IP}; then
if is_ipv6_enabled; then
${IPT6} -A INPUT -p tcp ! --syn --sport 80 --dport ${PORTSUSER} -s ${IP} -j ACCEPT
fi
else
${IPT} -A INPUT -p tcp ! --syn --sport 80 --dport ${PORTSUSER} -s ${IP} -j ACCEPT
fi
done
# HTTPS (TCP/443) authorizations
for IP in ${HTTPSSITES}; do
if is_ipv6 ${IP}; then
if is_ipv6_enabled; then
${IPT6} -A INPUT -p tcp ! --syn --sport 443 --dport ${PORTSUSER} -s ${IP} -j ACCEPT
fi
else
${IPT} -A INPUT -p tcp ! --syn --sport 443 --dport ${PORTSUSER} -s ${IP} -j ACCEPT
fi
done
# FTP (so complex protocol...) authorizations
for IP in ${FTPSITES}; do
if is_ipv6 ${IP}; then
if is_ipv6_enabled; then
# requests on Control connection
${IPT6} -A INPUT -p tcp ! --syn --sport 21 --dport ${PORTSUSER} -s ${IP} -j ACCEPT
# FTP port-mode on Data Connection
${IPT6} -A INPUT -p tcp --sport 20 --dport ${PORTSUSER} -s ${IP} -j ACCEPT
# FTP passive-mode on Data Connection
# WARNING, this allow all connections on TCP ports > 1024
${IPT6} -A INPUT -p tcp ! --syn --sport ${PORTSUSER} --dport ${PORTSUSER} -s ${IP} -j ACCEPT
fi
else
# requests on Control connection
${IPT} -A INPUT -p tcp ! --syn --sport 21 --dport ${PORTSUSER} -s ${IP} -j ACCEPT
# FTP port-mode on Data Connection
${IPT} -A INPUT -p tcp --sport 20 --dport ${PORTSUSER} -s ${IP} -j ACCEPT
# FTP passive-mode on Data Connection
# WARNING, this allow all connections on TCP ports > 1024
${IPT} -A INPUT -p tcp ! --syn --sport ${PORTSUSER} --dport ${PORTSUSER} -s ${IP} -j ACCEPT
fi
done
# SSH authorizations
for IP in ${SSHOK}; do
if is_ipv6 ${IP}; then
if is_ipv6_enabled; then
${IPT6} -A INPUT -p tcp ! --syn --sport 22 --dport ${PORTSUSER} -s ${IP} -j ACCEPT
fi
else
${IPT} -A INPUT -p tcp ! --syn --sport 22 --dport ${PORTSUSER} -s ${IP} -j ACCEPT
fi
done
# SMTP authorizations
for IP in ${SMTPOK}; do
if is_ipv6 ${IP}; then
if is_ipv6_enabled; then
${IPT6} -A INPUT -p tcp ! --syn --sport 25 --dport ${PORTSUSER} -s ${IP} -j ACCEPT
fi
else
${IPT} -A INPUT -p tcp ! --syn --sport 25 --dport ${PORTSUSER} -s ${IP} -j ACCEPT
fi
done
# secure SMTP (TCP/465 et TCP/587) authorizations
for IP in ${SMTPSECUREOK}; do
if is_ipv6 ${IP}; then
if is_ipv6_enabled; then
${IPT6} -A INPUT -p tcp ! --syn --sport 465 --dport ${PORTSUSER} -s ${IP} -j ACCEPT
${IPT6} -A INPUT -p tcp ! --syn --sport 587 --dport ${PORTSUSER} -s ${IP} -j ACCEPT
fi
else
${IPT} -A INPUT -p tcp ! --syn --sport 465 --dport ${PORTSUSER} -s ${IP} -j ACCEPT
${IPT} -A INPUT -p tcp ! --syn --sport 587 --dport ${PORTSUSER} -s ${IP} -j ACCEPT
fi
done
# NTP authorizations
for IP in ${NTPOK}; do
if is_ipv6 ${IP}; then
if is_ipv6_enabled; then
${IPT6} -A INPUT -p udp --sport 123 -s ${IP} -j ACCEPT
${IPT6} -A OUTPUT -o ${INT} -p udp -d ${IP} --dport 123 --match state --state NEW -j ACCEPT
fi
else
${IPT} -A INPUT -p udp --sport 123 -s ${IP} -j ACCEPT
${IPT} -A OUTPUT -o ${INT} -p udp -d ${IP} --dport 123 --match state --state NEW -j ACCEPT
fi
done
# Proxy (Squid)
if is_proxy_enabled; then
# WARN: Squid only listen on IPv4 yet
# TODO: verify that the pattern used for IPv4 is relevant with IPv6
${IPT} -t nat -A OUTPUT -p tcp --dport 80 -m owner --uid-owner proxy -j ACCEPT
for dstip in ${PROXYBYPASS}; do
if ! is_ipv6 ${dstip}; then
${IPT} -t nat -A OUTPUT -p tcp --dport 80 -d "${dstip}" -j ACCEPT
fi
done
${IPT} -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-port "${PROXYPORT:-'8888'}"
fi
# Output for backup servers
for server in ${BACKUPSERVERS}; do
server_port=$(echo "${server}" | awk -F : '{print $(NF)}')
server_ip=$(echo "${server}" | sed -e "s/:${server_port}$//")
if [ -n "${server_ip}" ] && [ -n "${server_port}" ]; then
if is_ipv6 ${server_ip}; then
if is_ipv6_enabled; then
${IPT6} -A INPUT -p tcp --sport "${server_port}" --dport 1024:65535 -s "${server_ip}" -m state --state ESTABLISHED,RELATED -j ACCEPT
fi
else
${IPT} -A INPUT -p tcp --sport "${server_port}" --dport 1024:65535 -s "${server_ip}" -m state --state ESTABLISHED,RELATED -j ACCEPT
fi
else
printf "${RED}ERROR: unrecognized syntax for BACKUPSERVERS '%s\`. Use space-separated IP:PORT tuples.${RESET}\n" "${server}" >&2
exit 1
fi
done
# Always allow ICMP
${IPT} -A INPUT -p icmp -j ACCEPT
if is_ipv6_enabled; then
${IPT6} -A INPUT -p icmpv6 -j ACCEPT
fi
# source config file for remaining commands
if is_legacy_config; then
source_file_or_error "${config_file}"
fi
# IPTables policy
#################
# by default DROP INPUT packets
${IPT} -P INPUT DROP
if is_ipv6_enabled; then
${IPT6} -P INPUT DROP
fi
# by default, no FORWARDING (deprecated for Virtual Machines)
#echo 0 > /proc/sys/net/ipv4/ip_forward
#${IPT} -P FORWARD DROP
#${IPT6} -P FORWARD DROP
# by default allow OUTPUT packets... but drop UDP packets (see OUTPUTDROP to drop OUTPUT packets)
${IPT} -P OUTPUT ACCEPT
if is_ipv6_enabled; then
${IPT6} -P OUTPUT ACCEPT
fi
${IPT} -A OUTPUT -o ${INT} -p udp --dport 33434:33523 --match state --state NEW -j ACCEPT
if is_ipv6_enabled; then
${IPT6} -A OUTPUT -o ${INT} -p udp --dport 33434:33523 --match state --state NEW -j ACCEPT
fi
${IPT} -A OUTPUT -p udp --match state --state ESTABLISHED,RELATED -j ACCEPT
if is_ipv6_enabled; then
${IPT6} -A OUTPUT -p udp --match state --state ESTABLISHED,RELATED -j ACCEPT
fi
${IPT} -A OUTPUT -p udp -j DROP
if is_ipv6_enabled; then
${IPT6} -A OUTPUT -p udp -j DROP
fi
# Finish
########################
trap - INT TERM EXIT
syslog_info "started"
printf "${GREEN}${BOLD}${NAME} started${RESET}\n"
# No need to exit on error anymore
set +e
report_state_changes
}
stop() {
syslog_info "stopping"
printf "${BOLD}${NAME} stopping${RESET}\n"
printf "${BLUE}flushing all rules and accepting everything${RESET}\n"
mkdir -p "$(dirname "${STATE_FILE_PREVIOUS}")"
status_without_numbers > "${STATE_FILE_PREVIOUS}"
# Delete all rules
${IPT} -F INPUT
if is_ipv6_enabled; then
${IPT6} -F INPUT
fi
${IPT} -F OUTPUT
if is_ipv6_enabled; then
${IPT6} -F OUTPUT
fi
${IPT} -F LOG_DROP
${IPT} -F LOG_ACCEPT
${IPT} -F ONLYTRUSTED
${IPT} -F ONLYPRIVILEGIED
${IPT} -F NEEDRESTRICT
if is_ipv6_enabled; then
${IPT6} -F LOG_DROP
${IPT6} -F LOG_ACCEPT
${IPT6} -F ONLYTRUSTED
${IPT6} -F ONLYPRIVILEGIED
${IPT6} -F NEEDRESTRICT
fi
${IPT} -t mangle -F
if is_ipv6_enabled; then
${IPT6} -t mangle -F
fi
if is_docker_enabled; then
# WARN: IPv6 not yet supported
${IPT} -F DOCKER-USER
${IPT} -A DOCKER-USER -j RETURN
${IPT} -F MINIFW-DOCKER-PUB
${IPT} -X MINIFW-DOCKER-PUB
${IPT} -F MINIFW-DOCKER-PRIVILEGED
${IPT} -X MINIFW-DOCKER-PRIVILEGED
${IPT} -F MINIFW-DOCKER-TRUSTED
${IPT} -X MINIFW-DOCKER-TRUSTED
else
${IPT} -t nat -F
fi
# Accept all
${IPT} -P INPUT ACCEPT
if is_ipv6_enabled; then
${IPT6} -P INPUT ACCEPT
fi
${IPT} -P OUTPUT ACCEPT
if is_ipv6_enabled; then
${IPT6} -P OUTPUT ACCEPT
fi
#${IPT} -P FORWARD ACCEPT
#${IPT} -t nat -P PREROUTING ACCEPT
#${IPT} -t nat -P POSTROUTING ACCEPT
# Delete non-standard chains
${IPT} -X LOG_DROP
${IPT} -X LOG_ACCEPT
${IPT} -X ONLYPRIVILEGIED
${IPT} -X ONLYTRUSTED
${IPT} -X NEEDRESTRICT
if is_ipv6_enabled; then
${IPT6} -X LOG_DROP
${IPT6} -X LOG_ACCEPT
${IPT6} -X ONLYPRIVILEGIED
${IPT6} -X ONLYTRUSTED
${IPT6} -X NEEDRESTRICT
fi
rm -f "${STATE_FILE_LATEST}" "${STATE_FILE_CURRENT}"
syslog_info "stopped"
printf "${GREEN}${BOLD}${NAME} stopped${RESET}\n"
}
status() {
printf "${BLUE}#### iptables --list ###############################${RESET}\n"
${IPT} --list --numeric --verbose --line-numbers
printf "\n${BLUE}#### iptables --table nat --list ###################${RESET}\n"
${IPT} --table nat --list --numeric --verbose --line-numbers
printf "\n${BLUE}#### iptables --table mangle --list ################${RESET}\n"
${IPT} --table mangle --list --numeric --verbose --line-numbers
if is_ipv6_enabled; then
printf "\n${BLUE}#### ip6tables --list ##############################${RESET}\n"
${IPT6} --list --numeric --verbose --line-numbers
printf "\n${BLUE}#### ip6tables --table mangle --list ###############${RESET}\n"
${IPT6} --table mangle --list --numeric --verbose --line-numbers
fi
}
status_without_numbers() {
printf "${BLUE}#### iptables --list ###############################${RESET}\n"
${IPT} --list --numeric
printf "\n${BLUE}#### iptables --table nat --list ###################${RESET}\n"
${IPT} --table nat --list --numeric
printf "\n${BLUE}#### iptables --table mangle --list ################${RESET}\n"
${IPT} --table mangle --list --numeric
if is_ipv6_enabled; then
printf "\n${BLUE}#### ip6tables --list ##############################${RESET}\n"
${IPT6} --list --numeric
printf "\n${BLUE}#### ip6tables --table mangle --list ###############${RESET}\n"
${IPT6} --table mangle --list --numeric
fi
}
reset() {
syslog_info "resetting"
printf "${BOLD}${NAME} resetting${RESET}\n"
${IPT} -Z
if is_ipv6_enabled; then
${IPT6} -Z
fi
${IPT} -t nat -Z
${IPT} -t mangle -Z
if is_ipv6_enabled; then
${IPT6} -t mangle -Z
fi
syslog_info "reset"
printf "${GREEN}${BOLD}${NAME} reset${RESET}\n"
}
show_version() {
cat <<END
${NAME} version ${VERSION}
Copyright 2007-2022 Evolix <info@evolix.fr>.
${NAME} comes with ABSOLUTELY NO WARRANTY.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License.
END
}
case "${1:-''}" in
start)
source_configuration
check_unpersisted_state
start
;;
stop)
source_configuration
check_unpersisted_state
stop
;;
status)
source_configuration
check_unpersisted_state
status
;;
reset)
source_configuration
check_unpersisted_state
reset
;;
restart)
source_configuration
check_unpersisted_state
stop
start
;;
version)
show_version
;;
*)
echo "Usage: $0 {start|stop|restart|status|reset|version}"
exit 1
;;
esac
exit 0

View file

@ -1,31 +1,37 @@
# Configuration for minifirewall : https://gitea.evolix.org/evolix/minifirewall
# Version 20.12 — 2020-12-01 22:55:35
# Version 22.03.1 — 2022-03-15
# shellcheck shell=sh disable=SC2034
# Main interface
INT='eth0'
# IPv6
IPV6=on
IPV6='on'
# Docker Mode
# Changes the behaviour of minifirewall to not break the containers' network
# For instance, turning it on will disable nat table purge
# Also, we'll add the DOCKER-USER chain, in iptable
# Also, we'll add the DOCKER-USER chain, in iptables
#
# WARNING : If the port mapping is different between the host and the container
# (ie: Listen on :8090 on host, but :8080 in container)
# then you need to give the port used inside the container
DOCKER='off'
# Trusted IPv4 local network
# ...will be often IP/32 if you don't trust anything
INTLAN='192.168.0.2/32'
# Trusted local network
# ...will be often IPv4/32 or IPv6/128 if you don't trust anything
INTLAN='192.0.2.1/32 2001:db8::1/128'
# Trusted IPv4 addresses for private and semi-public services
TRUSTEDIPS='31.170.9.129 62.212.121.90 31.170.8.4 82.65.34.85 54.37.106.210 51.210.84.146'
# Trusted IP addresses for private and semi-public services
# TODO: add all our IPv6 adresses
TRUSTEDIPS='31.170.9.129 2a01:9500:37:129::/64 62.212.121.90 31.170.8.4 2a01:9500::fada/128 82.65.34.85 54.37.106.210 51.210.84.146'
# Privilegied IPv4 addresses for semi-public services
# Privilegied IP addresses for semi-public services
# (no need to add again TRUSTEDIPS)
PRIVILEGIEDIPS=''
# Local services IPv4/IPv6 restrictions
# Local services IP restrictions
#######################################
# Protected services
@ -45,62 +51,86 @@ SERVICESUDP2=''
SERVICESTCP3='5666'
SERVICESUDP3=''
# Standard output IPv4 access restrictions
# Standard output IPv4/IPv6 access restrictions
##########################################
# DNS authorizations
# (if you have local DNS server, set 0.0.0.0/0)
DNSSERVEURS='0.0.0.0/0'
DNSSERVEURS='0.0.0.0/0 ::/0'
# HTTP authorizations
# (you can use DNS names but set cron to reload minifirewall regularly)
# (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='0.0.0.0/0'
HTTPSITES='0.0.0.0/0 ::/0'
# HTTPS authorizations
HTTPSSITES='0.0.0.0/0'
HTTPSSITES='0.0.0.0/0 ::/0'
# FTP authorizations
FTPSITES=''
# SSH authorizations
SSHOK='0.0.0.0/0'
SSHOK='0.0.0.0/0 ::/0'
# SMTP authorizations
SMTPOK='0.0.0.0/0'
SMTPOK='0.0.0.0/0 ::/0'
# SMTP secure authorizations (ports TCP/465 and TCP/587)
SMTPSECUREOK=''
# NTP authorizations
NTPOK='0.0.0.0/0'
NTPOK='0.0.0.0/0 ::/0'
# Proxy (Squid)
PROXY='off'
# (proxy port)
PROXYPORT='8888'
# (destinations that bypass the proxy)
PROXYBYPASS="${INTLAN} 127.0.0.0/8 ::1/128"
# Backup servers
# (add IP:PORT for each one, example: '192.168.10.1:1234 192.168.10.2:5678')
BACKUPSERVERS=''
# IPv6 Specific rules
# Includes
#####################
# Example: allow SSH from Trusted IPv6 addresses
/sbin/ip6tables -A INPUT -i $INT -p tcp --dport 22 -s 2a01:9500:37:129::/64 -j ACCEPT
# Files in /etc/minifirewall.d/* (without "." in name)
# are automatically included in alphanumerical order.
#
# Within included files, you can use those helper functions :
# * is_ipv6_enabled: returns true if IPv6 is enabled, or false
# * is_docker_enabled: returns true if Docker mode is eabled, or false
# * is_proxy_enabled: returns true if Proxy mode is enabled , or false
# Example: allow outgoing SSH/HTTP/HTTPS/SMTP/DNS traffic
/sbin/ip6tables -A INPUT -i $INT -p tcp --sport 22 --match state --state ESTABLISHED,RELATED -j ACCEPT
/sbin/ip6tables -A INPUT -i $INT -p tcp --sport 80 --match state --state ESTABLISHED,RELATED -j ACCEPT
/sbin/ip6tables -A INPUT -i $INT -p tcp --sport 443 --match state --state ESTABLISHED,RELATED -j ACCEPT
/sbin/ip6tables -A INPUT -i $INT -p tcp --sport 25 --match state --state ESTABLISHED,RELATED -j ACCEPT
/sbin/ip6tables -A INPUT -i $INT -p udp --sport 53 --match state --state ESTABLISHED,RELATED -j ACCEPT
/sbin/ip6tables -A INPUT -i $INT -p tcp --sport 53 --match state --state ESTABLISHED,RELATED -j ACCEPT
# Example: allow output DNS, NTP and traceroute traffic
/sbin/ip6tables -A OUTPUT -o $INT -p udp --dport 53 --match state --state NEW -j ACCEPT
/sbin/ip6tables -A OUTPUT -o $INT -p udp --dport 123 --match state --state NEW -j ACCEPT
#/sbin/ip6tables -A OUTPUT -o $INT -p udp --dport 33434:33523 --match state --state NEW -j ACCEPT
# Custom sysctl values (advanced)
#################################
# Example: allow DHCPv6
/sbin/ip6tables -A INPUT -i $INT -p udp --dport 546 -d fe80::/64 -j ACCEPT
/sbin/ip6tables -A OUTPUT -o $INT -p udp --dport 547 -j ACCEPT
# In most cases, the default values set by minifirewall are good.
# If you really know what you are doing,
# you can uncomment some lines and customize the values.
# IPv4 Specific rules
#####################
# Set 1 to ignore broadcast pings (default)
# SYSCTL_ICMP_ECHO_IGNORE_BROADCASTS='1'
# /sbin/iptables ...
# Set 1 to ignore bogus ICMP responses (default)
# SYSCTL_ICMP_IGNORE_BOGUS_ERROR_RESPONSES='1'
# Set 0 to disable source routing (default)
# SYSCTL_ACCEPT_SOURCE_ROUTE='0'
# Set 1 to enable TCP SYN cookies (default)
# SYSCTL_TCP_SYNCOOKIES='1'
# Set 0 to disable ICMP redirects (default)
# SYSCTL_ICMP_REDIRECTS='0'
# Set 1 to enable Reverse Path filtering (default)
# Set 0 if VRRP is used
# SYSCTL_RP_FILTER='1'
# Set 1 to log packets with inconsistent address (default)
# SYSCTL_LOG_MARTIANS='1'

View file

@ -0,0 +1,11 @@
### custom minifirewall commands
#
# You can add any custom command in files like this;
# either this one, or others in the same directory.
# They are executed as shell scripts.
# They are automatically included in alphanumerical order.
#
# Within included files, you can use those helper functions :
# * is_ipv6_enabled: returns true if IPv6 is enabled, or false
# * is_docker_enabled: returns true if Docker mode is eabled, or false
# * is_proxy_enabled: returns true if Proxy mode is enabled , or false

View file

@ -0,0 +1,7 @@
### ban rules
#
# If you have ban rules in /root/ban.iptables
# (either manually or with /usr/share/scripts/blacklist-countries.sh)
# ou can automatically import them with the following command:
#
# cat /root/ban.iptables | iptables-restore -n

View file

@ -0,0 +1,106 @@
# Configuration for minifirewall : https://gitea.evolix.org/evolix/minifirewall
# Version 20.12 — 2020-12-01 22:55:35
# Main interface
INT='eth0'
# IPv6
IPV6=on
# Docker Mode
# Changes the behaviour of minifirewall to not break the containers' network
# For instance, turning it on will disable nat table purge
# Also, we'll add the DOCKER-USER chain, in iptable
DOCKER='off'
# Trusted IPv4 local network
# ...will be often IP/32 if you don't trust anything
INTLAN='192.168.0.2/32'
# Trusted IPv4 addresses for private and semi-public services
TRUSTEDIPS='31.170.9.129 62.212.121.90 31.170.8.4 82.65.34.85 54.37.106.210 51.210.84.146'
# Privilegied IPv4 addresses for semi-public services
# (no need to add again TRUSTEDIPS)
PRIVILEGIEDIPS=''
# Local services IPv4/IPv6 restrictions
#######################################
# Protected services
# (add also in Public services if needed)
SERVICESTCP1p='22222'
SERVICESUDP1p=''
# Public services (IPv4/IPv6)
SERVICESTCP1='22222'
SERVICESUDP1=''
# Semi-public services (IPv4)
SERVICESTCP2='22'
SERVICESUDP2=''
# Private services (IPv4)
SERVICESTCP3='5666'
SERVICESUDP3=''
# Standard output IPv4 access restrictions
##########################################
# DNS authorizations
# (if you have local DNS server, set 0.0.0.0/0)
DNSSERVEURS='0.0.0.0/0'
# HTTP authorizations
# (you can use DNS names but set cron to reload minifirewall regularly)
# (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='0.0.0.0/0'
# HTTPS authorizations
HTTPSSITES='0.0.0.0/0'
# FTP authorizations
FTPSITES=''
# SSH authorizations
SSHOK='0.0.0.0/0'
# SMTP authorizations
SMTPOK='0.0.0.0/0'
# SMTP secure authorizations (ports TCP/465 and TCP/587)
SMTPSECUREOK=''
# NTP authorizations
NTPOK='0.0.0.0/0'
# IPv6 Specific rules
#####################
# Example: allow SSH from Trusted IPv6 addresses
/sbin/ip6tables -A INPUT -i $INT -p tcp --dport 22 -s 2a01:9500:37:129::/64 -j ACCEPT
# Example: allow outgoing SSH/HTTP/HTTPS/SMTP/DNS traffic
/sbin/ip6tables -A INPUT -i $INT -p tcp --sport 22 --match state --state ESTABLISHED,RELATED -j ACCEPT
/sbin/ip6tables -A INPUT -i $INT -p tcp --sport 80 --match state --state ESTABLISHED,RELATED -j ACCEPT
/sbin/ip6tables -A INPUT -i $INT -p tcp --sport 443 --match state --state ESTABLISHED,RELATED -j ACCEPT
/sbin/ip6tables -A INPUT -i $INT -p tcp --sport 25 --match state --state ESTABLISHED,RELATED -j ACCEPT
/sbin/ip6tables -A INPUT -i $INT -p udp --sport 53 --match state --state ESTABLISHED,RELATED -j ACCEPT
/sbin/ip6tables -A INPUT -i $INT -p tcp --sport 53 --match state --state ESTABLISHED,RELATED -j ACCEPT
# Example: allow output DNS, NTP and traceroute traffic
/sbin/ip6tables -A OUTPUT -o $INT -p udp --dport 53 --match state --state NEW -j ACCEPT
/sbin/ip6tables -A OUTPUT -o $INT -p udp --dport 123 --match state --state NEW -j ACCEPT
#/sbin/ip6tables -A OUTPUT -o $INT -p udp --dport 33434:33523 --match state --state NEW -j ACCEPT
# Example: allow DHCPv6
/sbin/ip6tables -A INPUT -i $INT -p udp --dport 546 -d fe80::/64 -j ACCEPT
/sbin/ip6tables -A OUTPUT -o $INT -p udp --dport 547 -j ACCEPT
# IPv4 Specific rules
#####################
# /sbin/iptables ...

View file

@ -0,0 +1,218 @@
---
- debug:
var: minifirewall_trusted_ips
verbosity: 1
- debug:
var: minifirewall_privilegied_ips
verbosity: 1
- name: Stat minifirewall config file (before)
stat:
path: "{{ minifirewall_main_file }}"
register: minifirewall_before
- name: Check if minifirewall is running
shell: /sbin/iptables -L -n | grep -E "^(DROP\s+udp|ACCEPT\s+icmp)\s+--\s+0\.0\.0\.0\/0\s+0\.0\.0\.0\/0\s*$"
changed_when: False
failed_when: False
check_mode: no
register: minifirewall_is_running
- debug:
var: minifirewall_is_running
verbosity: 1
- name: Begin marker for IP addresses
lineinfile:
dest: "{{ minifirewall_main_file }}"
line: "# BEGIN ANSIBLE MANAGED BLOCK FOR IPS"
insertbefore: '^# Main interface'
create: no
- name: End marker for IP addresses
lineinfile:
dest: "{{ minifirewall_main_file }}"
create: no
line: "# END ANSIBLE MANAGED BLOCK FOR IPS"
insertafter: '^PRIVILEGIEDIPS='
- name: Verify that at least 1 trusted IP is provided
assert:
that: minifirewall_trusted_ips | length > 0
msg: You must provide at least 1 trusted IP
- debug:
msg: "Warning: minifirewall_trusted_ips='0.0.0.0/0', the firewall is useless!"
when: minifirewall_trusted_ips == ["0.0.0.0/0"]
- name: Configure IP addresses
blockinfile:
dest: "{{ minifirewall_main_file }}"
marker: "# {mark} ANSIBLE MANAGED BLOCK FOR IPS"
block: |
# Main interface
INT='{{ minifirewall_int }}'
# IPv6
IPV6='{{ minifirewall_ipv6 }}'
# Docker Mode
# Changes the behaviour of minifirewall to not break the containers' network
# For instance, turning it on will disable nat table purge
# Also, we'll add the DOCKER-USER chain, in iptable
DOCKER='{{ minifirewall_docker }}'
# Trusted IPv4 local network
# ...will be often IP/32 if you don't trust anything
INTLAN='{{ minifirewall_intlan }}'
# Trusted IPv4 addresses for private and semi-public services
TRUSTEDIPS='{{ minifirewall_trusted_ips | join(' ') }}'
# Privilegied IPv4 addresses for semi-public services
# (no need to add again TRUSTEDIPS)
PRIVILEGIEDIPS='{{ minifirewall_privilegied_ips | join(' ') }}'
create: no
register: minifirewall_config_ips
- name: Begin marker for ports
lineinfile:
dest: "{{ minifirewall_main_file }}"
line: "# BEGIN ANSIBLE MANAGED BLOCK FOR PORTS"
insertbefore: '^# Protected services'
create: no
- name: End marker for ports
lineinfile:
dest: "{{ minifirewall_main_file }}"
line: "# END ANSIBLE MANAGED BLOCK FOR PORTS"
insertafter: '^SERVICESUDP3='
create: no
- name: Configure ports
blockinfile:
dest: "{{ minifirewall_main_file }}"
marker: "# {mark} ANSIBLE MANAGED BLOCK FOR PORTS"
block: |
# Protected services
# (add also in Public services if needed)
SERVICESTCP1p='{{ minifirewall_protected_ports_tcp | join(' ') }}'
SERVICESUDP1p='{{ minifirewall_protected_ports_udp | join(' ') }}'
# Public services (IPv4/IPv6)
SERVICESTCP1='{{ minifirewall_public_ports_tcp | join(' ') }}'
SERVICESUDP1='{{ minifirewall_public_ports_udp | join(' ') }}'
# Semi-public services (IPv4)
SERVICESTCP2='{{ minifirewall_semipublic_ports_tcp | join(' ') }}'
SERVICESUDP2='{{ minifirewall_semipublic_ports_udp | join(' ') }}'
# Private services (IPv4)
SERVICESTCP3='{{ minifirewall_private_ports_tcp | join(' ') }}'
SERVICESUDP3='{{ minifirewall_private_ports_udp | join(' ') }}'
create: no
register: minifirewall_config_ports
- name: Configure DNSSERVEURS
lineinfile:
dest: "{{ minifirewall_main_file }}"
line: "DNSSERVEURS='{{ minifirewall_dns_servers | join(' ') }}'"
regexp: "DNSSERVEURS='.*'"
create: no
when: minifirewall_dns_servers is not none
- name: Configure HTTPSITES
lineinfile:
dest: "{{ minifirewall_main_file }}"
line: "HTTPSITES='{{ minifirewall_http_sites | join(' ') }}'"
regexp: "HTTPSITES='.*'"
create: no
when: minifirewall_http_sites is not none
- name: Configure HTTPSSITES
lineinfile:
dest: "{{ minifirewall_main_file }}"
line: "HTTPSSITES='{{ minifirewall_https_sites | join(' ') }}'"
regexp: "HTTPSSITES='.*'"
create: no
when: minifirewall_https_sites is not none
- name: Configure FTPSITES
lineinfile:
dest: "{{ minifirewall_main_file }}"
line: "FTPSITES='{{ minifirewall_ftp_sites | join(' ') }}'"
regexp: "FTPSITES='.*'"
create: no
when: minifirewall_ftp_sites is not none
- name: Configure SSHOK
lineinfile:
dest: "{{ minifirewall_main_file }}"
line: "SSHOK='{{ minifirewall_ssh_ok | join(' ') }}'"
regexp: "SSHOK='.*'"
create: no
when: minifirewall_ssh_ok is not none
- name: Configure SMTPOK
lineinfile:
dest: "{{ minifirewall_main_file }}"
line: "SMTPOK='{{ minifirewall_smtp_ok | join(' ') }}'"
regexp: "SMTPOK='.*'"
create: no
when: minifirewall_smtp_ok is not none
- name: Configure SMTPSECUREOK
lineinfile:
dest: "{{ minifirewall_main_file }}"
line: "SMTPSECUREOK='{{ minifirewall_smtp_secure_ok | join(' ') }}'"
regexp: "SMTPSECUREOK='.*'"
create: no
when: minifirewall_smtp_secure_ok is not none
- name: Configure NTPOK
lineinfile:
dest: "{{ minifirewall_main_file }}"
line: "NTPOK='{{ minifirewall_ntp_ok | join(' ') }}'"
regexp: "NTPOK='.*'"
create: no
when: minifirewall_ntp_ok is not none
- name: evomaintenance
lineinfile:
dest: "{{ minifirewall_main_file }}"
line: "/sbin/iptables -A INPUT -p tcp --sport 5432 --dport 1024:65535 -s {{ item }} -m state --state ESTABLISHED,RELATED -j ACCEPT"
insertafter: "^# EvoMaintenance"
loop: "{{ evomaintenance_hosts }}"
- name: remove minifirewall example rule for the evomaintenance
lineinfile:
dest: "{{ minifirewall_main_file }}"
regexp: '^#.*(--sport 5432).*(-s X\.X\.X\.X)'
state: absent
when: evomaintenance_hosts | length > 0
- name: Stat minifirewall config file (after)
stat:
path: "{{ minifirewall_main_file }}"
register: minifirewall_after
- name: restart minifirewall
command: /etc/init.d/minifirewall restart
register: minifirewall_init_restart
failed_when: "'starting IPTables rules is now finish : OK' not in minifirewall_init_restart.stdout"
when:
- minifirewall_restart_if_needed | bool
- minifirewall_is_running.rc == 0
- minifirewall_before.stat.checksum != minifirewall_after.stat.checksum
- name: restart minifirewall (noop)
meta: noop
register: minifirewall_init_restart
failed_when: False
changed_when: False
when: not (minifirewall_restart_if_needed | bool)
- debug:
var: minifirewall_init_restart
verbosity: 2

View file

@ -9,11 +9,12 @@
- name: Stat minifirewall config file (before)
stat:
path: "{{ minifirewall_main_file }}"
path: "/etc/default/minifirewall"
register: minifirewall_before
- name: Check if minifirewall is running
shell: /sbin/iptables -L -n | grep -E "^(DROP\s+udp|ACCEPT\s+icmp)\s+--\s+0\.0\.0\.0\/0\s+0\.0\.0\.0\/0\s*$"
shell:
cmd: /sbin/iptables -L -n | grep -E "^(DROP\s+udp|ACCEPT\s+icmp)\s+--\s+0\.0\.0\.0\/0\s+0\.0\.0\.0\/0\s*$"
changed_when: False
failed_when: False
check_mode: no
@ -25,14 +26,14 @@
- name: Begin marker for IP addresses
lineinfile:
dest: "{{ minifirewall_main_file }}"
dest: "/etc/default/minifirewall"
line: "# BEGIN ANSIBLE MANAGED BLOCK FOR IPS"
insertbefore: '^# Main interface'
create: no
- name: End marker for IP addresses
lineinfile:
dest: "{{ minifirewall_main_file }}"
dest: "/etc/default/minifirewall"
create: no
line: "# END ANSIBLE MANAGED BLOCK FOR IPS"
insertafter: '^PRIVILEGIEDIPS='
@ -43,12 +44,16 @@
msg: You must provide at least 1 trusted IP
- debug:
msg: "Warning: minifirewall_trusted_ips='0.0.0.0/0', the firewall is useless!"
when: minifirewall_trusted_ips == ["0.0.0.0/0"]
msg: "Warning: minifirewall_trusted_ips contains '0.0.0.0/0', the firewall is useless on IPv4!"
when: "'0.0.0.0/0' in minifirewall_trusted_ips"
- debug:
msg: "Warning: minifirewall_trusted_ips contains '::/0', the firewall is useless on IPv6!"
when: "'::/0' in minifirewall_trusted_ips"
- name: Configure IP addresses
blockinfile:
dest: "{{ minifirewall_main_file }}"
dest: "/etc/default/minifirewall"
marker: "# {mark} ANSIBLE MANAGED BLOCK FOR IPS"
block: |
# Main interface
@ -60,8 +65,12 @@
# Docker Mode
# Changes the behaviour of minifirewall to not break the containers' network
# For instance, turning it on will disable nat table purge
# Also, we'll add the DOCKER-USER chain, in iptable
DOCKER='{{ minifirewall_docker }}'
# Also, we'll add the DOCKER-USER chain, in iptables
#
# WARNING : If the port mapping is different between the host and the container
# (ie: Listen on :8090 on host, but :8080 in container)
# then you need to give the port used inside the container
DOCKER='off'
# Trusted IPv4 local network
# ...will be often IP/32 if you don't trust anything
@ -78,21 +87,21 @@
- name: Begin marker for ports
lineinfile:
dest: "{{ minifirewall_main_file }}"
dest: "/etc/default/minifirewall"
line: "# BEGIN ANSIBLE MANAGED BLOCK FOR PORTS"
insertbefore: '^# Protected services'
create: no
- name: End marker for ports
lineinfile:
dest: "{{ minifirewall_main_file }}"
dest: "/etc/default/minifirewall"
line: "# END ANSIBLE MANAGED BLOCK FOR PORTS"
insertafter: '^SERVICESUDP3='
create: no
- name: Configure ports
blockinfile:
dest: "{{ minifirewall_main_file }}"
dest: "/etc/default/minifirewall"
marker: "# {mark} ANSIBLE MANAGED BLOCK FOR PORTS"
block: |
# Protected services
@ -116,106 +125,171 @@
- name: Configure DNSSERVEURS
lineinfile:
dest: "{{ minifirewall_main_file }}"
dest: "/etc/default/minifirewall"
line: "DNSSERVEURS='{{ minifirewall_dns_servers | join(' ') }}'"
regexp: "DNSSERVEURS='.*'"
regexp: "DNSSERVEURS=('|\").*('|\")"
create: no
when: minifirewall_dns_servers is not none
- name: Configure HTTPSITES
lineinfile:
dest: "{{ minifirewall_main_file }}"
dest: "/etc/default/minifirewall"
line: "HTTPSITES='{{ minifirewall_http_sites | join(' ') }}'"
regexp: "HTTPSITES='.*'"
regexp: "HTTPSITES=('|\").*('|\")"
create: no
when: minifirewall_http_sites is not none
- name: Configure HTTPSSITES
lineinfile:
dest: "{{ minifirewall_main_file }}"
dest: "/etc/default/minifirewall"
line: "HTTPSSITES='{{ minifirewall_https_sites | join(' ') }}'"
regexp: "HTTPSSITES='.*'"
regexp: "HTTPSSITES=('|\").*('|\")"
create: no
when: minifirewall_https_sites is not none
- name: Configure FTPSITES
lineinfile:
dest: "{{ minifirewall_main_file }}"
dest: "/etc/default/minifirewall"
line: "FTPSITES='{{ minifirewall_ftp_sites | join(' ') }}'"
regexp: "FTPSITES='.*'"
regexp: "FTPSITES=('|\").*('|\")"
create: no
when: minifirewall_ftp_sites is not none
- name: Configure SSHOK
lineinfile:
dest: "{{ minifirewall_main_file }}"
dest: "/etc/default/minifirewall"
line: "SSHOK='{{ minifirewall_ssh_ok | join(' ') }}'"
regexp: "SSHOK='.*'"
regexp: "SSHOK=('|\").*('|\")"
create: no
when: minifirewall_ssh_ok is not none
- name: Configure SMTPOK
lineinfile:
dest: "{{ minifirewall_main_file }}"
dest: "/etc/default/minifirewall"
line: "SMTPOK='{{ minifirewall_smtp_ok | join(' ') }}'"
regexp: "SMTPOK='.*'"
regexp: "SMTPOK=('|\").*('|\")"
create: no
when: minifirewall_smtp_ok is not none
- name: Configure SMTPSECUREOK
lineinfile:
dest: "{{ minifirewall_main_file }}"
dest: "/etc/default/minifirewall"
line: "SMTPSECUREOK='{{ minifirewall_smtp_secure_ok | join(' ') }}'"
regexp: "SMTPSECUREOK='.*'"
regexp: "SMTPSECUREOK=('|\").*('|\")"
create: no
when: minifirewall_smtp_secure_ok is not none
- name: Configure NTPOK
lineinfile:
dest: "{{ minifirewall_main_file }}"
dest: "/etc/default/minifirewall"
line: "NTPOK='{{ minifirewall_ntp_ok | join(' ') }}'"
regexp: "NTPOK='.*'"
regexp: "NTPOK=('|\").*('|\")"
create: no
when: minifirewall_ntp_ok is not none
- name: evomaintenance
- name: Configure PROXY
lineinfile:
dest: "{{ minifirewall_main_file }}"
line: "/sbin/iptables -A INPUT -p tcp --sport 5432 --dport 1024:65535 -s {{ item }} -m state --state ESTABLISHED,RELATED -j ACCEPT"
insertafter: "^# EvoMaintenance"
loop: "{{ evomaintenance_hosts }}"
dest: "/etc/default/minifirewall"
line: "PROXY='{{ minifirewall_proxy }}'"
regexp: "PROXY=('|\").*('|\")"
create: no
when: minifirewall_proxy is not none
- name: remove minifirewall example rule for the evomaintenance
- name: Configure PROXYPORT
lineinfile:
dest: "{{ minifirewall_main_file }}"
regexp: '^#.*(--sport 5432).*(-s X\.X\.X\.X)'
state: absent
when: evomaintenance_hosts | length > 0
dest: "/etc/default/minifirewall"
line: "PROXYPORT='{{ minifirewall_proxyport }}'"
regexp: "PROXYPORT=('|\").*('|\")"
create: no
when: minifirewall_proxyport is not none
# Warning: keep double quotes for the value,
# since we often reference a shell variable that needs to be interpolated
- name: Configure PROXYBYPASS
lineinfile:
dest: "/etc/default/minifirewall"
line: "PROXYBYPASS=\"{{ minifirewall_proxybypass | join(' ') }}\""
regexp: "PROXYBYPASS=('|\").*('|\")"
create: no
when: minifirewall_proxybypass is not none
- name: Configure BACKUPSERVERS
lineinfile:
dest: "/etc/default/minifirewall"
line: "BACKUPSERVERS='{{ minifirewall_backupservers | join(' ') }}'"
regexp: "BACKUPSERVERS=('|\").*('|\")"
create: no
when: minifirewall_backupservers is not none
- name: Configure SYSCTL_ICMP_ECHO_IGNORE_BROADCASTS
lineinfile:
dest: "/etc/default/minifirewall"
line: "SYSCTL_ICMP_ECHO_IGNORE_BROADCASTS='{{ minifirewall_sysctl_icmp_echo_ignore_broadcasts }}'"
regexp: "SYSCTL_ICMP_ECHO_IGNORE_BROADCASTS=('|\").*('|\")"
create: no
when: minifirewall_sysctl_icmp_echo_ignore_broadcasts is not none
- name: Configure SYSCTL_ICMP_IGNORE_BOGUS_ERROR_RESPONSES
lineinfile:
dest: "/etc/default/minifirewall"
line: "SYSCTL_ICMP_IGNORE_BOGUS_ERROR_RESPONSES='{{ minifirewall_sysctl_icmp_ignore_bogus_error_responses }}'"
regexp: "SYSCTL_ICMP_IGNORE_BOGUS_ERROR_RESPONSES=('|\").*('|\")"
create: no
when: minifirewall_sysctl_icmp_ignore_bogus_error_responses is not none
- name: Configure SYSCTL_ACCEPT_SOURCE_ROUTE
lineinfile:
dest: "/etc/default/minifirewall"
line: "SYSCTL_ACCEPT_SOURCE_ROUTE='{{ minifirewall_sysctl_accept_source_route }}'"
regexp: "SYSCTL_ACCEPT_SOURCE_ROUTE=('|\").*('|\")"
create: no
when: minifirewall_sysctl_accept_source_route is not none
- name: Configure SYSCTL_TCP_SYNCOOKIES
lineinfile:
dest: "/etc/default/minifirewall"
line: "SYSCTL_TCP_SYNCOOKIES='{{ minifirewall_sysctl_tcp_syncookies }}'"
regexp: "SYSCTL_TCP_SYNCOOKIES=('|\").*('|\")"
create: no
when: minifirewall_sysctl_tcp_syncookies is not none
- name: Configure SYSCTL_ICMP_REDIRECTS
lineinfile:
dest: "/etc/default/minifirewall"
line: "SYSCTL_ICMP_REDIRECTS='{{ minifirewall_sysctl_icmp_redirects }}'"
regexp: "SYSCTL_ICMP_REDIRECTS=('|\").*('|\")"
create: no
when: minifirewall_sysctl_icmp_redirects is not none
- name: Configure SYSCTL_RP_FILTER
lineinfile:
dest: "/etc/default/minifirewall"
line: "SYSCTL_RP_FILTER='{{ minifirewall_sysctl_rp_filter }}'"
regexp: "SYSCTL_RP_FILTER=('|\").*('|\")"
create: no
when: minifirewall_sysctl_rp_filter is not none
- name: Configure SYSCTL_LOG_MARTIANS
lineinfile:
dest: "/etc/default/minifirewall"
line: "SYSCTL_LOG_MARTIANS='{{ minifirewall_sysctl_log_martians }}'"
regexp: "SYSCTL_LOG_MARTIANS=('|\").*('|\")"
create: no
when: minifirewall_sysctl_log_martians is not none
- name: Stat minifirewall config file (after)
stat:
path: "{{ minifirewall_main_file }}"
path: "/etc/default/minifirewall"
register: minifirewall_after
- name: restart minifirewall
# service:
# name: minifirewall
# state: restarted
command: /etc/init.d/minifirewall restart
register: minifirewall_init_restart
failed_when: "'starting IPTables rules is now finish : OK' not in minifirewall_init_restart.stdout"
changed_when: "'starting IPTables rules is now finish : OK' in minifirewall_init_restart.stdout"
failed_when: "'minifirewall failed' in minifirewall_init_restart.stdout"
when:
- minifirewall_restart_if_needed | bool
- minifirewall_is_running.rc == 0
- minifirewall_before.stat.checksum != minifirewall_after.stat.checksum
- name: restart minifirewall (noop)
meta: noop
register: minifirewall_init_restart
failed_when: False
changed_when: False
when: not (minifirewall_restart_if_needed | bool)
- minifirewall_before.stat.checksum != minifirewall_after.stat.checksum or minifirewall_upgrade_script is changed or minifirewall_upgrade_config is changed
- debug:
var: minifirewall_init_restart

View file

@ -0,0 +1,24 @@
---
- name: dependencies are satisfied
apt:
name: iptables
state: present
- name: init script is copied
template:
src: minifirewall.legacy.j2
dest: /etc/init.d/minifirewall
force: "{{ minifirewall_force_upgrade_script | default('no') }}"
mode: "0700"
owner: root
group: root
- name: configuration is copied
copy:
src: minifirewall.legacy.conf
dest: "{{ minifirewall_main_file }}"
force: "{{ minifirewall_force_upgrade_config | default('no') }}"
mode: "0600"
owner: root
group: root

View file

@ -6,19 +6,38 @@
state: present
- name: init script is copied
template:
src: minifirewall.j2
copy:
src: minifirewall
dest: /etc/init.d/minifirewall
force: "{{ minifirewall_force_upgrade_script | default('no') }}"
mode: "0700"
owner: root
group: root
register: minifirewall_upgrade_script
- name: configuration is copied
copy:
src: minifirewall.conf
dest: "{{ minifirewall_main_file }}"
dest: "/etc/default/minifirewall"
force: "{{ minifirewall_force_upgrade_config | default('no') }}"
mode: "0600"
owner: root
group: root
register: minifirewall_upgrade_config
- name: includes directory is present
file:
path: /etc/minifirewall.d/
state: directory
owner: root
group: root
mode: "0700"
- name: examples for includes are present
copy:
src: "minifirewall.d/"
dest: "/etc/minifirewall.d/"
force: "no"
mode: "0600"
owner: root
group: root

View file

@ -4,19 +4,105 @@
set_fact:
minifirewall_restart_handler_name: "{{ minifirewall_restart_if_needed | bool | ternary('restart minifirewall', 'restart minifirewall (noop)') }}"
- include: install.yml
# Legacy or modern mode? ##############################################
- include: config.yml
- name: Check minifirewall
stat:
path: /etc/init.d/minifirewall
register: _minifirewall_check
- include: nrpe.yml
- include: activate.yml
- include: tail.yml
when: minifirewall_tail_included | bool
- name: Force restart minifirewall
command: /bin/true
notify: restart minifirewall
# Legacy versions of minifirewall don't define the VERSION variable
- name: Look for minifirewall version
shell: "grep -E '^\\s*VERSION=' /etc/init.d/minifirewall"
failed_when: False
changed_when: False
when: minifirewall_restart_force | bool
check_mode: False
register: _minifirewall_version_check
- name: Set install mode to legacy if needed
set_fact:
minifirewall_install_mode: legacy
minifirewall_main_file: "{{ minifirewall_legacy_main_file }}"
minifirewall_tail_file: "{{ minifirewall_legacy_tail_file }}"
when:
- minifirewall_install_mode != 'modern'
- not (minifirewall_force_upgrade_script | bool)
- _minifirewall_version_check.rc == 1 # grep didn't find but the file exists
- name: Set install mode to modern if not legacy
set_fact:
minifirewall_install_mode: modern
when: minifirewall_install_mode != 'legacy'
- name: Debug install mode
debug:
var: minifirewall_install_mode
verbosity: 1
#######################################################################
- name: Fail if minifirewall_main_file is defined (legacy mode)
fail:
msg: "Variable minifirewall_main_file is deprecated and not configurable anymore."
when:
- minifirewall_install_mode != 'legacy'
- minifirewall_main_file is defined
- name: Install tasks (modern mode)
include: install.yml
when: minifirewall_install_mode != 'legacy'
- name: Install tasks (legacy mode)
include: install.legacy.yml
when: minifirewall_install_mode == 'legacy'
- name: Config tasks (modern mode)
include: config.yml
when:
- minifirewall_install_mode != 'legacy'
- minifirewall_update_config | bool
- name: Config tasks (legacy mode)
include: config.legacy.yml
when:
- minifirewall_install_mode == 'legacy'
- minifirewall_update_config | bool
- name: Utils tasks
include: utils.yml
- name: NRPE tasks
include: nrpe.yml
- name: Activation tasks
include: activate.yml
- name: Tail tasks (modern mode)
include: tail.yml
when:
- minifirewall_install_mode != 'legacy'
- minifirewall_tail_included | bool
- name: Tail tasks (legacy mode)
include: tail.legacy.yml
when:
- minifirewall_install_mode == 'legacy'
- minifirewall_tail_included | bool
# Restart?
- name: Force restart minifirewall (modern mode)
command: /etc/init.d/minifirewall restart
register: minifirewall_init_restart
failed_when: "'minifirewall failed' in minifirewall_init_restart.stdout"
when:
- minifirewall_install_mode != 'legacy'
- minifirewall_restart_force | bool
- name: Force restart minifirewall (legacy mode)
command: /etc/init.d/minifirewall restart
register: minifirewall_init_restart
failed_when: "'starting IPTables rules is now finish : OK' not in minifirewall_init_restart.stdout"
when:
- minifirewall_install_mode == 'legacy'
- minifirewall_restart_force | bool

View file

@ -0,0 +1,50 @@
---
- name: Add some rules at the end of minifirewall file
template:
src: "{{ item }}"
dest: "{{ minifirewall_tail_file }}"
force: "{{ minifirewall_tail_force | bool }}"
follow: yes
loop: "{{ query('first_found', templates) }}"
vars:
templates:
- "templates/minifirewall-tail/minifirewall.{{ inventory_hostname }}.tail.j2"
- "templates/minifirewall-tail/minifirewall.{{ host_group | default('all') }}.tail.j2"
- "templates/minifirewall-tail/minifirewall.default.tail.j2"
- "templates/minifirewall.default.tail.j2"
register: minifirewall_tail_template
- debug:
var: minifirewall_tail_template
verbosity: 1
- name: source minifirewall.tail at the end of the main file
blockinfile:
dest: "{{ minifirewall_main_file }}"
marker: "# {mark} ANSIBLE MANAGED EXTERNAL RULES"
block: ". {{ minifirewall_tail_file }}"
insertbefore: EOF
register: minifirewall_tail_source
- debug:
var: minifirewall_tail_source
verbosity: 1
- name: restart minifirewall
command: /etc/init.d/minifirewall restart
register: minifirewall_init_restart
failed_when: "'starting IPTables rules is now finish : OK' not in minifirewall_init_restart.stdout"
when:
- minifirewall_tail_template is changed
- minifirewall_restart_if_needed | bool
- name: restart minifirewall (noop)
meta: noop
register: minifirewall_init_restart
failed_when: False
changed_when: False
when: not (minifirewall_restart_if_needed | bool)
- debug:
var: minifirewall_init_restart
verbosity: 1

View file

@ -18,26 +18,10 @@
var: minifirewall_tail_template
verbosity: 1
- name: source minifirewall.tail at the end of the main file
blockinfile:
dest: "{{ minifirewall_main_file }}"
marker: "# {mark} ANSIBLE MANAGED EXTERNAL RULES"
block: ". {{ minifirewall_tail_file }}"
insertbefore: EOF
register: minifirewall_tail_source
- debug:
var: minifirewall_tail_source
verbosity: 1
- name: restart minifirewall
# service:
# name: minifirewall
# state: restarted
command: /etc/init.d/minifirewall restart
register: minifirewall_init_restart
failed_when: "'starting IPTables rules is now finish : OK' not in minifirewall_init_restart.stdout"
changed_when: "'starting IPTables rules is now finish : OK' in minifirewall_init_restart.stdout"
failed_when: "'minifirewall failed' in minifirewall_init_restart.stdout"
when:
- minifirewall_tail_template is changed
- minifirewall_restart_if_needed | bool

View file

@ -0,0 +1,21 @@
---
- include_role:
name: evolix/remount-usr
- name: /usr/share/scripts exists
file:
dest: /usr/share/scripts
mode: "0700"
owner: root
group: root
state: directory
- name: blacklist-countries.sh is copied
copy:
src: blacklist-countries.sh
dest: /usr/share/scripts/blacklist-countries.sh
force: "no"
mode: "0700"
owner: root
group: root

View file

@ -0,0 +1,213 @@
#!/usr/bin/perl -w
#
# Copyright (C) 2008 Rien Broekstra <rien@rename-it.nl>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; version 2 dated June,
# 1991.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
# Munin plugin to measure saturation of DHCP pools.
#
# Configuration variables:
#
# conffile - path to dhcpd's configuration file (default "/etc/dhcpd.conf")
# leasefile - path to dhcpd's leases file (default "/var/lib/dhcp/dhcpd.leases")
#
# Parameters:
#
# config (required)
#
# Version 1.0, 2-12-2008
#
#%# family=auto
#%# capabilities=autoconf
use POSIX;
use Time::Local;
use strict;
my $CONFFILE = exists $ENV{'conffile'} ? $ENV{'conffile'} : "/etc/dhcp/dhcpd.conf";
my $LEASEFILE = exists $ENV{'leasefile'} ? $ENV{'leasefile'} : "/var/lib/dhcp/dhcpd.leases";
if ( defined $ARGV[0] and $ARGV[0] eq "autoconf" ) {
if (-e ${CONFFILE} and -e ${LEASEFILE}) {
my %pools;
%pools = determine_pools();
if (%pools) {
print "yes\n";
} else {
print "no (no pools defined in config)\n";
}
} else {
print "no (no config or lease file)\n";
}
}
elsif ( defined $ARGV[0] and $ARGV[0] eq "config" ) {
my (%pools, $start, $label);
# Print general information
print "graph_title DHCP pool usage (in %)\n";
print "graph_args --upper-limit 100 -l 0\n";
print "graph_vlabel %\n";
#___ORI___# print "graph_category network\n";
print "graph_category dhcpd\n";
# Determine the available IP pools
%pools = determine_pools();
# Print a label for each pool
foreach $start (sort (keys %pools)) {
$label = ip2string($start);
$label =~ s/\./\_/g;
print "_$label.label Pool " . ip2string($start) . " - " . ip2string($start + $pools{$start} - 1) . "\n";
print "_$label.warning 90\n";
print "_$label.critical 100\n";
}
}
else {
my (@activeleases, %pools, $start, $end, $size, $free, $label, $lease);
# Determine all leased IP addresses
@activeleases = determine_active_leases();
# Determine the available IP pools
%pools = determine_pools();
# For each pool, count how many leases from that pool are currently active
foreach $start (keys %pools) {
$size = $pools{$start};
$end = $start+$size-1;
$free = $size;
foreach $lease (@activeleases) {
if ($lease >= $start && $lease <= $end) {
$free--;
}
}
$label = ip2string($start);
$label =~ s/\./\_/g;
print "_$label.value ".sprintf("%.1f", 100*($size-$free)/$size)."\n";
}
}
# Parse dhcpd.conf for range statements.
#
# Returns a hash with start IP -> size
sub determine_pools {
my (%pools, @conffile, $line, $start, $end, $size);
open(CONFFILE, "<${CONFFILE}") || exit -1;
@conffile = <CONFFILE>;
close (CONFFILE);
foreach $line (@conffile) {
next if $line =~ /^\s*#/;
if ($line =~ /range[\s]+([\d]+\.[\d]+\.[\d]+\.[\d]+)[\s]+([\d]+\.[\d]+\.[\d]+\.[\d]+)/) {
$start = string2ip($1);
$end = string2ip($2);
defined($start) || next;
defined($end) || next;
# The range statement gives the lowest and highest IP addresses in a range.
$size = $end - $start + 1;
$pools{$start} = $size;
}
}
return %pools;
}
# Very simple parser for dhcpd.leases. This will break very easily if dhcpd decides to
# format the file differently. Ideally a simple recursive-descent parser should be used.
#
# Returns an array with currently leased IP's
sub determine_active_leases {
my (@leasefile, $startdate, $enddate, $lease, @activeleases, $mytz, $line, %saw);
open(LEASEFILE, "<${LEASEFILE}") || exit -1;
@leasefile = <LEASEFILE>;
close (LEASEFILE);
@activeleases = ();
# Portable way of converting a GMT date/time string to timestamp is setting TZ to UTC, and then calling mktime()
$mytz = $ENV{'TZ'};
$ENV{'TZ'} = 'UTC 0';
tzset();
foreach $line (@leasefile) {
if ($line =~ /lease ([\d]+\.[\d]+\.[\d]+\.[\d]+)/) {
$lease = string2ip($1);
defined($lease) || next;
undef $startdate;
undef $enddate;
}
elsif ($line =~ /starts \d ([\d]{4})\/([\d]{2})\/([\d]{2}) ([\d]{2}):([\d]{2}):([\d]{2})/) {
$startdate = mktime($6, $5, $4, $3, $2-1, $1-1900, 0, 0);
}
elsif ($line =~ /ends \d ([\d]{4})\/([\d]{2})\/([\d]{2}) ([\d]{2}):([\d]{2}):([\d]{2})/) {
$enddate = mktime($6, $5, $4, $3, $2-1, $1-1900, 0, 0);
}
elsif ($line =~ /binding state active/) {
if (defined($enddate) && defined($startdate) && defined($lease)) {
if ($startdate < time() && $enddate > time()) {
push (@activeleases, $lease);
}
}
}
}
# Set TZ back to its original setting
if (defined($mytz)) {
$ENV{'TZ'} = $mytz;
}
else {
delete $ENV{'TZ'};
}
tzset();
# Sort the array, strip doubles, and return
return grep(!$saw{$_}++, @activeleases);
}
#
# Helper routine to convert an IP address a.b.c.d into an integer
#
# Returns an integer representation of an IP address
sub string2ip {
my $string = shift;
defined($string) || return undef;
if ($string =~ /([\d]+)\.([\d]+)\.([\d]+)\.([\d]+)/) {
if ($1 < 0 || $1 > 255 || $2 < 0 || $2 > 255 || $3 < 0 || $3 > 255 || $4 < 0 || $4 > 255) {
return undef;
}
else {
return $1 << 24 | $2 << 16 | $3 << 8 | $4;
}
}
return undef;
}
#
# Returns a dotted quad notation of an
#
sub ip2string {
my $ip = shift;
defined ($ip) || return undef;
return sprintf ("%d.%d.%d.%d", ($ip >> 24) & 0xff, ($ip >> 16) & 0xff, ($ip >> 8) & 0xff, $ip & 0xff);
}

View file

@ -12,6 +12,10 @@
- munin
- packages
- name: Ensure /usr is still writable
include_role:
name: evolix/remount-usr
- block:
- name: Replace localdomain in Munin config
replace:
@ -31,6 +35,18 @@
tags:
- munin
- include_role:
name: evolix/remount-usr
- name: Install some Munin plugins (disabled)
copy:
src: 'plugins/{{ item }}'
dest: '/usr/share/munin/plugins/{{ item }}'
loop:
- dhcp_pool
tags:
- munin
- name: Ensure some Munin plugins are disabled
file:
path: '/etc/munin/plugins/{{ item }}'

View file

@ -0,0 +1,223 @@
#!/usr/bin/perl -w
#
# Copyright (C) 2008 Rien Broekstra <rien@rename-it.nl>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; version 2 dated June,
# 1991.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
# Configuration variables:
#
# conffile - path to dhcpd's configuration file (default "/etc/dhcpd.conf")
# leasefile - path to dhcpd's leases file (default "/var/lib/dhcp/dhcpd.leases")
#
use POSIX;
use Time::Local;
use strict;
my $CONFFILE = exists $ENV{'conffile'} ? $ENV{'conffile'} : "/etc/dhcp/dhcpd.conf";
my $LEASEFILE = exists $ENV{'leasefile'} ? $ENV{'leasefile'} : "/var/lib/dhcp/dhcpd.leases";
my $WARNING_LEVEL = 70;
my $CRITICAL_LEVEL = 90;
my (@activeleases, %dhcp_pools, $pool_start, $pool_end, $pool_size, $pool_free, $pool_usage, $pool_status, $label, $lease, $nagios_return_code, $nagios_ok, $nagios_warning, $nagios_critical, @nagios_text, @nagios_perfdata);
# Determine all leased IP addresses
@activeleases = determine_active_leases();
# Determine the available IP pools
%dhcp_pools = determine_pools();
# Nagios return code
$nagios_return_code = 0;
$nagios_ok = 0;
$nagios_warning = 0;
$nagios_critical = 0;
# For each pool, count how many leases from that pool are currently active
foreach $pool_start (keys %dhcp_pools) {
$pool_size = $dhcp_pools{$pool_start};
$pool_end = $pool_start+$pool_size-1;
$pool_free = $pool_size;
foreach $lease (@activeleases) {
if ($lease >= $pool_start && $lease <= $pool_end) {
$pool_free--;
}
}
$label = ip2string($pool_start)."-".ip2string($pool_end);
$pool_usage = sprintf("%.1f", 100*($pool_size-$pool_free)/$pool_size);
if ($pool_usage >= $CRITICAL_LEVEL) {
$nagios_return_code = 2;
$nagios_critical++;
$pool_status = "CRITICAL";
} elsif ($pool_usage >= $WARNING_LEVEL) {
if ($nagios_return_code == 0 ) {
$nagios_return_code = 1;
}
$nagios_warning++;
$pool_status = "WARNING";
}
else {
$nagios_ok++;
$pool_status = "OK";
}
push(@nagios_text, "$pool_status : $label - $pool_usage \n");
push(@nagios_perfdata, "$label=$pool_usage%;$WARNING_LEVEL%;$CRITICAL_LEVEL%;;" );
# 'label'=value[UOM];[warn];[crit];;
}
print nagios_code_2_txt($nagios_return_code)." - ".$nagios_critical." CRIT / ".$nagios_warning." WARN / ".$nagios_ok." OK \n\n";
print grep(/CRITICAL/, @nagios_text);
print grep(/WARNING/, @nagios_text);
print grep(/OK/, @nagios_text);
print "|@nagios_perfdata";
exit $nagios_return_code;
################
###### FUNCTIONS
# Parse dhcpd.conf for range statements.
#
# Returns a hash with start IP -> size
sub determine_pools {
my (%pools, @conffile, $line, $start, $end, $size);
open(CONFFILE, "<${CONFFILE}") || exit -1;
@conffile = <CONFFILE>;
close (CONFFILE);
foreach $line (@conffile) {
next if $line =~ /^\s*#/;
if ($line =~ /range[\s]+([\d]+\.[\d]+\.[\d]+\.[\d]+)[\s]+([\d]+\.[\d]+\.[\d]+\.[\d]+)/) {
$start = string2ip($1);
$end = string2ip($2);
defined($start) || next;
defined($end) || next;
# The range statement gives the lowest and highest IP addresses in a range.
$size = $end - $start + 1;
$pools{$start} = $size;
}
}
return %pools;
}
# Very simple parser for dhcpd.leases. This will break very easily if dhcpd decides to
# format the file differently. Ideally a simple recursive-descent parser should be used.
#
# Returns an array with currently leased IP's
sub determine_active_leases {
my (@leasefile, $startdate, $enddate, $lease, @activeleases, $mytz, $line, %saw);
open(LEASEFILE, "<${LEASEFILE}") || exit -1;
@leasefile = <LEASEFILE>;
close (LEASEFILE);
@activeleases = ();
# Portable way of converting a GMT date/time string to timestamp is setting TZ to UTC, and then calling mktime()
$mytz = $ENV{'TZ'};
$ENV{'TZ'} = 'UTC 0';
tzset();
foreach $line (@leasefile) {
if ($line =~ /lease ([\d]+\.[\d]+\.[\d]+\.[\d]+)/) {
$lease = string2ip($1);
defined($lease) || next;
undef $startdate;
undef $enddate;
}
elsif ($line =~ /starts \d ([\d]{4})\/([\d]{2})\/([\d]{2}) ([\d]{2}):([\d]{2}):([\d]{2})/) {
$startdate = mktime($6, $5, $4, $3, $2-1, $1-1900, 0, 0);
}
elsif ($line =~ /ends \d ([\d]{4})\/([\d]{2})\/([\d]{2}) ([\d]{2}):([\d]{2}):([\d]{2})/) {
$enddate = mktime($6, $5, $4, $3, $2-1, $1-1900, 0, 0);
}
elsif ($line =~ /binding state active/) {
if (defined($enddate) && defined($startdate) && defined($lease)) {
if ($startdate < time() && $enddate > time()) {
push (@activeleases, $lease);
}
}
}
}
# Set TZ back to its original setting
if (defined($mytz)) {
$ENV{'TZ'} = $mytz;
}
else {
delete $ENV{'TZ'};
}
tzset();
# Sort the array, strip doubles, and return
return grep(!$saw{$_}++, @activeleases);
}
#
# Helper routine to convert an IP address a.b.c.d into an integer
#
# Returns an integer representation of an IP address
sub string2ip {
my $string = shift;
defined($string) || return undef;
if ($string =~ /([\d]+)\.([\d]+)\.([\d]+)\.([\d]+)/) {
if ($1 < 0 || $1 > 255 || $2 < 0 || $2 > 255 || $3 < 0 || $3 > 255 || $4 < 0 || $4 > 255) {
return undef;
}
else {
return $1 << 24 | $2 << 16 | $3 << 8 | $4;
}
}
return undef;
}
#
# Returns a dotted quad notation of an
#
sub ip2string {
my $ip = shift;
defined ($ip) || return undef;
return sprintf ("%d.%d.%d.%d", ($ip >> 24) & 0xff, ($ip >> 16) & 0xff, ($ip >> 8) & 0xff, $ip & 0xff);
}
#
# Return textual status of return code
#
sub nagios_code_2_txt{
my $code = shift;
defined ($code) || return undef;
if($code == 0 ) { return "OK" }
elsif( $code == 1 ) { return "WARNING" }
elsif( $code == 2 ) { return "CRITICAL" }
}

View file

@ -1,30 +1,40 @@
#!/bin/sh
#
# Verify that given mountpoints have 'read-write' option.
output=$(mktemp --tmpdir $(basename $0).XXXXXXXXXX)
output=$(mktemp --tmpdir $(basename "$0").XXXXXXXXXX)
critical_count=0
ok_count=0
trap "rm -f $output" EXIT
for mountpoint in $@; do
# We verify no mointpoints have 'read-only' option instead of checking
# for 'read-write' option, because there could be multiple device
# mounted on a sigle path. In that edge case only checking for the
# presence of the 'read-write' option would yeild a flase positive.
if findmnt -O ro --noheadings "$mountpoint" 1>/dev/null 2>&1; then
echo "CRITICAL - $mountpoint" >> "$output"
critical_count=$(( critical_count + 1))
critical_count=$(( critical_count + 1))
else
echo "OK - $mountpoint" >> "$output"
ok_count=$(( ok_count + 1))
ok_count=$(( ok_count + 1))
fi
done
total_count=$(( ok_count + critical_count ))
plural=''
test "$total_count" -gt 1 && plural='s'
if [ $ok_count -eq $total_count ]; then
printf "OK - %d/%d no read-only mountpoint\n\n" "$ok_count" "$total_count"
printf "OK - %d/%d mountpoint%s have 'read-write' option\n\n" \
"$ok_count" "$total_count" "$plural"
cat "$output"
exit 0
else
printf "CRITICAL - %d/%d read-only mountpoint\n\n" "$critical_count" "$total_count"
printf "CRITICAL - %d/%d mountpoint%s don't have 'read-write' option\n\n" \
"$critical_count" "$total_count" "$plural"
cat "$output"
exit 2
fi

View file

@ -57,6 +57,7 @@ command[check_bkctld_jails]=sudo /usr/sbin/bkctld check-jails
command[check_bkctld]=sudo /usr/sbin/bkctld check
command[check_postgrey]=/usr/lib/nagios/plugins/check_tcp -p10023
command[check_influxdb]=/usr/lib/nagios/plugins/check_http -I 127.0.0.1 -u /health -p 8086 -r '"status":"pass"'
command[check_dhcpd]=/usr/lib/nagios/plugins/check_procs -c1:1 -C dhcpd -t 60
# Local checks (not packaged)
command[check_mem]={{ nagios_plugins_directory }}/check_mem -f -C -w 20 -c 10
@ -83,6 +84,7 @@ command[check_php-fpm80]=sudo {{ nagios_plugins_directory }}/check_phpfpm_multi
command[check_php-fpm81]=sudo {{ nagios_plugins_directory }}/check_phpfpm_multi /var/lib/lxc/php81/rootfs/etc/php/8.1/fpm/pool.d/
command[check_ipmi_sensors]=sudo /usr/lib/nagios/plugins/check_ipmi_sensor
command[check_raid_status]=/usr/lib/nagios/plugins/check_raid
command[check_dhcp_pool]={{ nagios_plugins_directory }}/check_dhcp_pool
# Check HTTP "many". Use this to check many websites (http, https, ports, sockets and SSL certificates).
# Beware! All checks must not take more than 10s!

View file

@ -1,4 +1,5 @@
# Evolix default customizations
server_tokens off;
server_names_hash_max_size 512;
server_names_hash_bucket_size 128;

View file

@ -10,7 +10,7 @@ domain="$(echo "$1"|xargs)"
if [ ! -f "/etc/ssl/private/dkim-${servername}.private" ]; then
echo "Generate DKIM keys ..."
opendkim-genkey -D /etc/ssl/private/ -r -d "${domain}" -s "dkim-${servername}"
opendkim-genkey -h sha256 -b 4096 -D /etc/ssl/private/ -r -d "${domain}" -s "dkim-${servername}"
chown opendkim:opendkim "/etc/ssl/private/dkim-${servername}.private"
chmod 640 "/etc/ssl/private/dkim-${servername}.private"
mv "/etc/ssl/private/dkim-${servername}.txt" "/etc/ssl/certs/"

View file

@ -23,6 +23,6 @@ Then, you can use `shellpki` to generate client certificates.
* `openvpn_netmask`: netmask of the network to use for OpenVPN
* `openvpn_netmask_cidr`: automatically generated prefix length of the netmask, in CIDR notation
## TODO
## Dependencies
* See TODO tasks in tasks/*.yml
* Files in `files/shellpki/*` are gotten from the upstream [shellpki](https://gitea.evolix.org/evolix/shellpki) and must be updated when the upstream is.

View file

@ -0,0 +1,26 @@
#!/bin/sh
carp=$(/sbin/ifconfig carp0 2>/dev/null | grep 'status' | cut -d' ' -f2)
if [ "$carp" = "backup" ]; then
exit 0
fi
echo "Warning : all times are in UTC !\n"
echo "CA certificate:"
openssl x509 -enddate -noout -in /etc/shellpki/cacert.pem \
| cut -d '=' -f 2 \
| sed -e "s/^\(.*\)\ \(20..\).*/- \2 \1/"
echo ""
echo "Client certificates:"
cat /etc/shellpki/index.txt \
| grep ^V \
| 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

View file

@ -0,0 +1,58 @@
[ ca ]
default_ca = CA_default
[ CA_default ]
dir = /etc/shellpki
certs = $dir/certs
new_certs_dir = $dir/tmp
database = $dir/index.txt
certificate = $dir/cacert.pem
serial = $dir/serial
crl = $dir/crl.pem
private_key = $dir/cakey.key
RANDFILE = $dir/.rand
default_days = 365
default_crl_days= 365
default_md = sha256
preserve = no
policy = policy_match
[ policy_match ]
countryName = supplied
stateOrProvinceName = supplied
organizationName = supplied
organizationalUnitName = optional
commonName = supplied
emailAddress = supplied
[ req ]
default_bits = 2048
distinguished_name = req_distinguished_name
[ v3_ca ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer:always
basicConstraints = CA:true
[ v3_ocsp ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = OCSPSigning
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = FR
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province
stateOrProvinceName_default = 13
localityName = Locality Name (eg, city)
localityName_default = Marseille
0.organizationName = Organization Name (eg, company)
0.organizationName_default = Evolix
organizationalUnitName = Organizational Unit Name (eg, section)
commonName = Common Name (eg, your name or your server\'s hostname)
commonName_max = 64
emailAddress = Email Address
emailAddress_default = security@evolix.net
emailAddress_max = 40

1106
openvpn/files/shellpki/shellpki Executable file
View file

@ -0,0 +1,1106 @@
#!/bin/sh
#
# shellpki is a wrapper around OpenSSL to manage a small PKI
#
set -u
VERSION="22.04"
show_version() {
cat <<END
shellpki version ${VERSION}
Copyright 2010-2022 Evolix <info@evolix.fr>,
Thomas Martin <tmartin@evolix.fr>,
Gregory Colpart <reg@evolix.fr>,
Romain Dessort <rdessort@evolix.fr>,
Benoit Série <bserie@evolix.fr>,
Victor Laborie <vlaborie@evolix.fr>,
Daniel Jakots <djakots@evolix.fr>,
Patrick Marchand <pmarchand@evolix.fr>,
Jérémy Lecour <jlecour@evolix.fr>,
Jérémy Dubois <jdubois@evolix.fr>
and others.
shellpki comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
See the MIT Licence for details.
END
}
show_usage() {
cat <<EOF
Usage: ${0} <subcommand> [options] [CommonName]
Warning: [options] always must be before [CommonName] and after <subcommand>
EOF
show_usage_init
show_usage_create
show_usage_revoke
show_usage_list
show_usage_check
show_usage_ocsp
cat <<EOF
Show version :
${0} --version
Show help :
${0} --help
EOF
}
show_usage_init() {
cat <<EOF
Initialize PKI (create CA key and self-signed certificate) :
${0} init [options] <commonName_for_CA>
Options
--non-interactive do not prompt the user, and exit if an error occurs
EOF
}
show_usage_create() {
cat <<EOF
Create a client certificate with key and CSR directly generated on server :
${0} create [options] <commonName>
Options
-f, --file, --csr-file create a client certificate from a CSR (doesn't need key)
-p, --password prompt the user for a password to set on the client key
--password-file if provided with a path to a readable file, the first line is read and set as password on the client key
--days specify how many days the certificate should be valid
--end-date specify until which date the certificate should be valid, in "YYYY/MM/DD hh:mm:ss" format, UTC +0
--non-interactive do not prompt the user, and exit if an error occurs
--replace-existing if the certificate already exists, revoke it before creating a new one
EOF
}
show_usage_revoke() {
cat <<EOF
Revoke a client certificate :
${0} revoke [options] <commonName>
Options
--non-interactive do not prompt the user, and exit if an error occurs
EOF
}
show_usage_list() {
cat <<EOF
List certificates :
${0} list <options>
Options
-a, --all list all certificates: valid and revoked ones
-v, --valid list all valid certificates
-r, --revoked list all revoked certificates
EOF
}
show_usage_check() {
cat <<EOF
Check expiration date of valid certificates :
${0} check
EOF
}
show_usage_ocsp() {
cat <<EOF
Run OCSP_D server :
${0} ocsp <ocsp_uri:ocsp_port>
EOF
}
error() {
echo "${1}" >&2
exit 1
}
warning() {
echo "${1}" >&2
}
verify_ca_password() {
"${OPENSSL_BIN}" rsa \
-in "${CA_KEY}" \
-passin pass:"${CA_PASSWORD}" \
>/dev/null 2>&1
}
get_real_path() {
# --canonicalize is supported on Linux
# -f is supported on Linux and OpenBSD
readlink -f -- "${1}"
}
ask_ca_password() {
attempt=${1:-0}
max_attempts=3
trap 'unset CA_PASSWORD' 0
if [ ! -f "${CA_KEY}" ]; then
error "You must initialize your PKI with \`shellpki init' !"
fi
if [ "${attempt}" -gt 0 ]; then
warning "Invalid password, retry."
fi
if [ "${attempt}" -ge "${max_attempts}" ]; then
error "Maximum number of attempts reached (${max_attempts})."
fi
if [ -z "${CA_PASSWORD:-}" ]; then
if [ "${non_interactive}" -eq 1 ]; then
error "In non-interactive mode, you must pass CA_PASSWORD as environment variable"
fi
stty -echo
printf "Password for CA key: "
read -r CA_PASSWORD
stty echo
printf "\n"
fi
if [ -z "${CA_PASSWORD:-}" ] || ! verify_ca_password; then
unset CA_PASSWORD
attempt=$(( attempt + 1 ))
ask_ca_password "${attempt}"
fi
}
ask_user_password() {
trap 'unset PASSWORD' 0
if [ -z "${PASSWORD:-}" ]; then
if [ "${non_interactive}" -eq 1 ]; then
error "In non-interactive mode, you must pass PASSWORD as environment variable or use --password-file"
fi
stty -echo
printf "Password for user key: "
read -r PASSWORD
stty echo
printf "\n"
fi
if [ -z "${PASSWORD:-}" ]; then
warning "Warning: empty password from input"
fi
}
replace_existing_or_abort() {
cn=${1:?}
if [ "${non_interactive}" -eq 1 ]; then
if [ "${replace_existing}" -eq 1 ]; then
revoke --non-interactive "${cn}"
else
error "${cn} already exists, use \`--replace-existing' to force"
fi
else
if [ "${replace_existing}" -eq 1 ]; then
revoke "${cn}"
else
printf "%s already exists, do you want to revoke and recreate it ? [y/N] " "${cn}"
read -r REPLY
resp=$(echo "${REPLY}" | tr 'Y' 'y')
if [ "${resp}" = "y" ]; then
revoke "${cn}"
else
error "Aborted"
fi
fi
fi
}
init() {
umask 0177
[ -d "${CA_DIR}" ] || mkdir -m 0750 "${CA_DIR}"
[ -d "${CRT_DIR}" ] || mkdir -m 0750 "${CRT_DIR}"
[ -f "${INDEX_FILE}" ] || touch "${INDEX_FILE}"
[ -f "${CRL}" ] || touch "${CRL}"
[ -f "${SERIAL}" ] || echo "01" > "${SERIAL}"
non_interactive=0
# Parse options
# based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
while :; do
case ${1:-} in
--non-interactive)
non_interactive=1
;;
--)
# End of all options.
shift
break
;;
-?*)
# ignore unknown options
warning "Warning: unknown option (ignored): \`$1'"
;;
*)
# Default case: If no more options then break out of the loop.
break
;;
esac
shift
done
cn="${1:-}"
if [ -z "${cn}" ]; then
show_usage_init >&2
exit 1
fi
if [ -f "${CA_KEY}" ]; then
if [ "${non_interactive}" -eq 1 ]; then
error "${CA_KEY} already exists, erase it manually if you want to start over."
else
printf "%s already exists, do you really want to erase it ? [y/N] " "${CA_KEY}"
read -r REPLY
resp=$(echo "${REPLY}" | tr 'Y' 'y')
if [ "${resp}" = "y" ]; then
rm -f "${CA_KEY}" "${CA_CERT}"
fi
fi
fi
passout_arg=""
if [ -n "${CA_PASSWORD:-}" ]; then
passout_arg="-passout pass:${CA_PASSWORD}"
elif [ "${non_interactive}" -eq 1 ]; then
error "In non-interactive mode, you must pass CA_PASSWORD as environment variable."
fi
if [ ! -f "${CA_KEY}" ]; then
"${OPENSSL_BIN}" genrsa \
-out "${CA_KEY}" \
${passout_arg} \
-aes256 \
"${CA_KEY_LENGTH}" \
>/dev/null 2>&1
# shellcheck disable=SC2181
if [ "$?" -ne 0 ]; then
error "Error generating the CA key"
fi
fi
if [ -f "${CA_CERT}" ]; then
if [ "${non_interactive}" -eq 1 ]; then
error "${CA_CERT} already exists, erase it manually if you want to start over."
else
printf "%s already exists, do you really want to erase it ? [y/N] " "${CA_CERT}"
read -r REPLY
resp=$(echo "${REPLY}" | tr 'Y' 'y')
if [ "${resp}" = "y" ]; then
rm "${CA_CERT}"
fi
fi
fi
if [ ! -f "${CA_CERT}" ]; then
ask_ca_password 0
fi
if [ ! -f "${CA_CERT}" ]; then
"${OPENSSL_BIN}" req \
-new \
-batch \
-sha512 \
-x509 \
-days 3650 \
-extensions v3_ca \
-passin pass:"${CA_PASSWORD}" \
-key "${CA_KEY}" \
-out "${CA_CERT}" \
-config /dev/stdin <<EOF
$(cat "${CONF_FILE}")
commonName_default = ${cn}
EOF
# shellcheck disable=SC2181
if [ "$?" -ne 0 ]; then
error "Error generating the CA certificate"
fi
"${OPENSSL_BIN}" ca \
-config "${CONF_FILE}" \
-passin pass:${CA_PASSWORD} \
-gencrl \
-out "${CRL}"
fi
}
ocsp() {
umask 0177
ocsp_uri="${1:-}"
if [ -z "${ocsp_uri}" ]; then
show_usage_ocsp >&2
exit 1
fi
ocsp_csr_file="${CSR_DIR}/ocsp.csr"
url=$(echo "${ocsp_uri}" | cut -d':' -f1)
port=$(echo "${ocsp_uri}" | cut -d':' -f2)
if [ ! -f "${OCSP_KEY}" ]; then
"${OPENSSL_BIN}" genrsa \
-out "${OCSP_KEY}" \
"${KEY_LENGTH}" \
>/dev/null 2>&1
# shellcheck disable=SC2181
if [ "$?" -ne 0 ]; then
error "Error generating the OCSP key"
fi
fi
"${OPENSSL_BIN}" req \
-batch \
-new \
-key "${OCSP_KEY}" \
-out "${ocsp_csr_file}" \
-config /dev/stdin <<EOF
$(cat "${CONF_FILE}")
commonName_default = ${url}
[ usr_cert ]
authorityInfoAccess = OCSP;URI:http://${ocsp_uri}
EOF
# shellcheck disable=SC2181
if [ "$?" -ne 0 ]; then
error "Error generating the OCSP request"
fi
if [ ! -f "${OCSP_CERT}" ]; then
ask_ca_password 0
fi
if [ ! -f "${OCSP_CERT}" ]; then
"${OPENSSL_BIN}" ca \
-extensions v3_ocsp \
-in "${ocsp_csr_file}" \
-out "${OCSP_CERT}" \
-passin pass:"${CA_PASSWORD}" \
-config "${CONF_FILE}"
# shellcheck disable=SC2181
if [ "$?" -ne 0 ]; then
error "Error generating the OCSP certificate"
fi
fi
exec "${OPENSSL_BIN}" ocsp \
-ignore_err \
-index "${INDEX_FILE}" \
-port "${port}" \
-rsigner "${OCSP_CERT}" \
-rkey "${OCSP_KEY}" \
-CA "${CA_CERT}" \
-text
}
create() {
from_csr=0
ask_pass=0
non_interactive=0
replace_existing=0
days=""
end_date=""
days_set=0
end_date_set=0
password_set=0
password_file_set=0
# Parse options
# based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
while :; do
case ${1:-} in
-f|--file|--csr-file)
# csr-file option, with value separated by space
if [ -n "$2" ]; then
from_csr=1
csr_file=$(get_real_path "${2}")
# shellcheck disable=SC2181
if [ "$?" -ne 0 ]; then
error "Error accessing file \`${2}'"
fi
shift
else
error "Argument error: \`--csr-file' requires a value"
fi
;;
--file=?*|--csr-file=?*)
from_csr=1
# csr-file option, with value separated by =
csr_file=$(get_real_path "${1#*=}")
# shellcheck disable=SC2181
if [ "$?" -ne 0 ]; then
error "Error accessing file \`${1#*=}'"
fi
;;
--file=|--csr-file=)
# csr-file options, without value
error "Argument error: \`--csr-file' requires a value"
;;
-p|--password)
ask_pass=1
password_set=1
;;
--password-file)
# password-file option, with value separated by space
if [ -n "$2" ]; then
password_file=$(get_real_path "${2}")
# shellcheck disable=SC2181
if [ "$?" -ne 0 ]; then
error "Error accessing file \`${2}'"
fi
password_file_set=1
shift
else
error "Argument error: \`--password-file' requires a value"
fi
;;
--password-file=?*)
# password-file option, with value separated by =
password_file=$(get_real_path "${1#*=}")
# shellcheck disable=SC2181
if [ "$?" -ne 0 ]; then
error "Error accessing file \`${1#*=}'"
fi
password_file_set=1
;;
--password-file=)
# password-file options, without value
error "Argument error: \`--password-file' requires a value"
;;
--days)
# days option, with value separated by space
if [ -n "$2" ]; then
days=${2}
days_set=1
shift
else
error "Argument error: \`--days' requires a value"
fi
;;
--days=?*)
# days option, with value separated by =
days=${1#*=}
days_set=1
;;
--days=)
# days options, without value
error "Argument error: \`--days' requires a value"
;;
--end-date)
# end-date option, with value separated by space
if [ -n "$2" ]; then
end_date=${2}
end_date_set=1
shift
else
error "Argument error: \`--end-date' requires a value"
fi
;;
--end-date=?*)
# end-date option, with value separated by =
end_date=${1#*=}
end_date_set=1
;;
--end-date=)
# end-date options, without value
error "Argument error: \`--end-date' requires a value"
;;
--non-interactive)
non_interactive=1
;;
--replace-existing)
replace_existing=1
;;
--)
# End of all options.
shift
break
;;
-?*)
# ignore unknown options
warning "Warning: unknown option (ignored): \`$1'"
;;
*)
# Default case: If no more options then break out of the loop.
break
;;
esac
shift
done
if [ "${days_set}" -eq 1 ] && [ "${end_date_set}" -eq 1 ]; then
error "Argument error: \`--end-date' and \`--days' cannot be used together."
fi
if [ "${password_set}" -eq 1 ] && [ "${password_file_set}" -eq 1 ]; then
error "Argument error: \`--password' and \`--password-file' cannot be used together."
fi
# The name of the certificate
cn="${1:-}"
# Set expiration argument
crt_expiration_arg=""
if [ -n "${days}" ]; then
if [ "${days}" -gt 0 ]; then
crt_expiration_arg="-days ${days}"
else
error "Argument error: \"${days}\" is not a valid value for \`--days'."
fi
fi
if [ -n "${end_date}" ]; then
if [ "${SYSTEM}" = "linux" ]; then
cert_end_date=$(TZ=:Zulu date --date "${end_date}" +"%Y%m%d%H%M%SZ" 2> /dev/null)
# shellcheck disable=SC2181
if [ "$?" -ne 0 ]; then
error "Invalid end date format: \`${end_date}' can't be parsed by date(1). Expected format: YYYY/MM/DD [hh[:mm[:ss]]]."
else
crt_expiration_arg="-enddate ${cert_end_date}"
fi
elif [ "${SYSTEM}" = "openbsd" ]; then
cert_end_date=$(TZ=:Zulu date -f "%C%y/%m/%d %H:%M:%S" -j "${end_date}" +"%Y%m%d%H%M%SZ" 2> /dev/null)
# shellcheck disable=SC2181
if [ "$?" -ne 0 ]; then
error "Invalid end date format: \`${end_date}' can't be parsed by date(1). Expected format: YYYY/MM/DD hh:mm:ss."
else
crt_expiration_arg="-enddate ${cert_end_date}"
fi
else
error "System ${SYSTEM} not supported."
fi
fi
if [ "${non_interactive}" -eq 1 ]; then
batch_arg="-batch"
else
batch_arg=""
fi
if [ "${from_csr}" -eq 1 ]; then
if [ "${ask_pass}" -eq 1 ]; then
warning "Warning: -p|--password is ignored with -f|--file|--crt-file"
fi
if [ -n "${password_file:-}" ]; then
warning "Warning: --password-file is ignored with -f|--file|--crt-file"
fi
crt_file="${CRT_DIR}/${cn}.crt"
# ask for CA passphrase
ask_ca_password 0
# check if csr_file is a CSR
"${OPENSSL_BIN}" req \
-noout \
-subject \
-in "${csr_file}" \
>/dev/null 2>&1
# shellcheck disable=SC2181
if [ "$?" -ne 0 ]; then
error "${csr_file} is not a valid CSR !"
fi
# check if csr_file contain a CN
"${OPENSSL_BIN}" req \
-noout \
-subject \
-in "${csr_file}" \
| grep -Eo "CN\s*=[^,/]*" \
>/dev/null 2>&1
# shellcheck disable=SC2181
if [ "$?" -ne 0 ]; then
error "${csr_file} doesn't contain a CommonName !"
fi
# get CN from CSR
cn=$("${OPENSSL_BIN}" req -noout -subject -in "${csr_file}" | grep -Eo "CN\s*=[^,/]*" | cut -d'=' -f2 | xargs)
# check if CN already exists
if [ -f "${crt_file}" ]; then
replace_existing_or_abort "${cn}"
fi
# ca sign and generate cert
if [ "${non_interactive}" -eq 1 ]; then
batch_arg="-batch"
else
batch_arg=""
fi
"${OPENSSL_BIN}" ca \
${batch_arg} \
-config "${CONF_FILE}" \
-in "${csr_file}" \
-passin pass:"${CA_PASSWORD}" \
-out "${crt_file}" \
${crt_expiration_arg}
# shellcheck disable=SC2181
if [ "$?" -ne 0 ]; then
error "Error generating the certificate"
else
echo "The certificate file is available at \`${crt_file}'"
fi
else
if [ -z "${cn}" ]; then
show_usage_create >&2
exit 1
fi
csr_file="${CSR_DIR}/${cn}-${SUFFIX}.csr"
crt_file="${CRT_DIR}/${cn}.crt"
key_file="${KEY_DIR}/${cn}-${SUFFIX}.key"
ovpn_file="${OVPN_DIR}/${cn}-${SUFFIX}.ovpn"
pkcs12_file="${PKCS12_DIR}/${cn}-${SUFFIX}.p12"
# ask for CA passphrase
ask_ca_password 0
if [ "${ask_pass}" -eq 1 ]; then
ask_user_password
fi
# check if CN already exists
if [ -f "${crt_file}" ]; then
replace_existing_or_abort "${cn}"
fi
# generate private key
pass_args=""
if [ -n "${password_file:-}" ]; then
pass_args="-aes256 -passout file:${password_file}"
elif [ -n "${PASSWORD:-}" ]; then
pass_args="-aes256 -passout pass:${PASSWORD}"
fi
"${OPENSSL_BIN}" genrsa \
-out "${key_file}" \
${pass_args} \
"${KEY_LENGTH}" \
>/dev/null 2>&1
# shellcheck disable=SC2181
if [ "$?" -eq 0 ]; then
echo "The KEY file is available at \`${key_file}'"
else
error "Error generating the private key"
fi
# generate csr req
pass_args=""
if [ -n "${password_file:-}" ]; then
pass_args="-passin file:${password_file}"
elif [ -n "${PASSWORD:-}" ]; then
pass_args="-passin pass:${PASSWORD}"
fi
"${OPENSSL_BIN}" req \
-batch \
-new \
-key "${key_file}" \
-out "${csr_file}" \
${pass_args} \
-config /dev/stdin <<EOF
$(cat "${CONF_FILE}")
commonName_default = ${cn}
EOF
# shellcheck disable=SC2181
if [ "$?" -ne 0 ]; then
error "Error generating the CSR"
fi
# ca sign and generate cert
"${OPENSSL_BIN}" ca \
${batch_arg} \
-config "${CONF_FILE}" \
-passin pass:${CA_PASSWORD} \
-in "${csr_file}" \
-out "${crt_file}" \
${crt_expiration_arg}
# shellcheck disable=SC2181
if [ "$?" -ne 0 ]; then
error "Error generating the certificate"
fi
# check if CRT is a valid
"${OPENSSL_BIN}" x509 \
-noout \
-subject \
-in "${crt_file}" \
>/dev/null 2>&1
# shellcheck disable=SC2181
if [ "$?" -ne 0 ]; then
rm -f "${crt_file}"
fi
if [ ! -f "${crt_file}" ]; then
error "Error in CSR creation"
fi
chmod 640 "${crt_file}"
echo "The CRT file is available in ${crt_file}"
# generate pkcs12 format
pass_args=""
if [ -n "${password_file:-}" ]; then
# Hack for pkcs12 :
# If passin and passout files are the same path, it expects 2 lines
# so we make a temporary copy of the password file
password_file_out=$(mktemp)
cp "${password_file}" "${password_file_out}"
pass_args="-passin file:${password_file} -passout file:${password_file_out}"
elif [ -n "${PASSWORD:-}" ]; then
pass_args="-passin pass:${PASSWORD} -passout pass:${PASSWORD}"
else
pass_args="-passout pass:"
fi
"${OPENSSL_BIN}" pkcs12 \
-export \
-nodes \
-inkey "${key_file}" \
-in "${crt_file}" \
-out "${pkcs12_file}" \
${pass_args}
# shellcheck disable=SC2181
if [ "$?" -ne 0 ]; then
error "Error generating the pkcs12 file"
fi
if [ -n "${password_file_out:-}" ]; then
# Hack for pkcs12 :
# Destroy the temporary file
rm -f "${password_file_out}"
fi
chmod 640 "${pkcs12_file}"
echo "The PKCS12 config file is available at \`${pkcs12_file}'"
# generate openvpn format
if [ -e "${CA_DIR}/ovpn.conf" ]; then
cat "${CA_DIR}/ovpn.conf" - > "${ovpn_file}" <<EOF
<ca>
$(cat "${CA_CERT}")
</ca>
<cert>
$(cat "${crt_file}")
</cert>
<key>
$(cat "${key_file}")
</key>
EOF
chmod 640 "${ovpn_file}"
echo "The OpenVPN config file is available at \`${ovpn_file}'"
fi
# Copy files if destination exists
if [ -d "${COPY_DIR}" ]; then
for file in "${crt_file}" "${key_file}" "${pkcs12_file}" "${ovpn_file}"; do
if [ -f "${file}" ]; then
new_file="${COPY_DIR}/$(basename "${file}")"
if [ "${replace_existing}" -eq 1 ]; then
cp -f "${file}" "${COPY_DIR}/"
else
if [ "${non_interactive}" -eq 1 ]; then
if [ -f "${new_file}" ]; then
echo "File \`${file}' has not been copied to \`${new_file}', it already exists" >&2
continue
else
cp "${file}" "${COPY_DIR}/"
fi
else
cp -i "${file}" "${COPY_DIR}/"
fi
fi
echo "File \`${file}' has been copied to \`${new_file}'"
fi
done
# shellcheck disable=SC2086
chown -R ${PKI_USER}:${PKI_USER} "${COPY_DIR}/"
chmod -R u=rwX,g=rwX,o= "${COPY_DIR}/"
fi
fi
}
revoke() {
non_interactive=0
# Parse options
# based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
while :; do
case ${1:-} in
--non-interactive)
non_interactive=1
;;
--)
# End of all options.
shift
break
;;
-?*)
# ignore unknown options
warning "Warning: unknown option (ignored): \`$1'"
;;
*)
# Default case: If no more options then break out of the loop.
break
;;
esac
shift
done
# The name of the certificate
cn="${1:-}"
if [ -z "${cn}" ]; then
show_usage_revoke >&2
exit 1
fi
crt_file="${CRT_DIR}/${cn}.crt"
# check if CRT exists
if [ ! -f "${crt_file}" ]; then
error "Unknow CN: ${cn} (\`${crt_file}' not found)"
fi
# check if CRT is a valid
"${OPENSSL_BIN}" x509 \
-noout \
-subject \
-in "${crt_file}" \
>/dev/null 2>&1
# shellcheck disable=SC2181
if [ "$?" -ne 0 ]; then
error "${crt_file} is not a valid CRT, you must delete it !"
fi
# ask for CA passphrase
ask_ca_password 0
echo "Revoke certificate ${crt_file} :"
"${OPENSSL_BIN}" ca \
-config "${CONF_FILE}" \
-passin pass:"${CA_PASSWORD}" \
-revoke "${crt_file}"
# shellcheck disable=SC2181
if [ "$?" -eq 0 ]; then
rm "${crt_file}"
fi
"${OPENSSL_BIN}" ca \
-config "${CONF_FILE}" \
-passin pass:"${CA_PASSWORD}" \
-gencrl \
-out "${CRL}"
}
list() {
if [ ! -f "${INDEX_FILE}" ]; then
exit 0
fi
if [ -z "${1:-}" ]; then
show_usage_list >&2
exit 1
fi
while :; do
case "${1:-}" in
-a|--all)
list_valid=0
list_revoked=0
;;
-v|--valid)
list_valid=0
list_revoked=1
;;
-r|--revoked)
list_valid=1
list_revoked=0
;;
-?*)
warning "unknow option ${1} (ignored)"
;;
*)
break
;;
esac
shift
done
if [ "${list_valid}" -eq 0 ]; then
certs=$(grep "^V" "${INDEX_FILE}")
fi
if [ "${list_revoked}" -eq 0 ]; then
certs=$(grep "^R" "${INDEX_FILE}")
fi
if [ "${list_valid}" -eq 0 ] && [ "${list_revoked}" -eq 0 ]; then
certs=$(cat "${INDEX_FILE}")
fi
echo "${certs}" | grep -Eo "CN\s*=[^,/]*" | cut -d'=' -f2 | xargs -n1
}
cert_end_date() {
"${OPENSSL_BIN}" x509 -noout -enddate -in "${1}" | cut -d'=' -f2
}
check() {
# default expiration alert
# TODO: permit override with parameters
min_day=90
cur_epoch=$(date -u +'%s')
for cert in "${CRT_DIR}"/*; do
end_date=$(cert_end_date "${cert}")
end_epoch=$(date -ud "${end_date}" +'%s')
diff_epoch=$(( end_epoch - cur_epoch ))
diff_day=$(( diff_epoch / 60 / 60 / 24 ))
if [ "${diff_day}" -lt "${min_day}" ]; then
if [ "${diff_day}" -le 0 ]; then
echo "${cert} has expired"
else
echo "${cert} expire in ${diff_day} days"
fi
fi
done
}
is_user() {
getent passwd "${1}" >/dev/null
}
is_group() {
getent group "${1}" >/dev/null
}
main() {
# Know what system we are on, because OpenBSD and Linux do not implement date(1) in the same way
SYSTEM=$(uname | tr '[:upper:]' '[:lower:]')
# default config
# TODO: override with /etc/default/shellpki
CONF_FILE="/etc/shellpki/openssl.cnf"
if [ "$(uname)" = "OpenBSD" ]; then
PKI_USER="_shellpki"
else
PKI_USER="shellpki"
fi
if [ "${USER}" != "root" ] && [ "${USER}" != "${PKI_USER}" ]; then
error "Please become root before running ${0} !"
fi
# retrieve CA path from config file
CA_DIR=$(grep -E "^dir" "${CONF_FILE}" | cut -d'=' -f2 | xargs -n1)
CA_KEY=$(grep -E "^private_key" "${CONF_FILE}" | cut -d'=' -f2 | xargs -n1 | sed "s~\$dir~${CA_DIR}~")
CA_CERT=$(grep -E "^certificate" "${CONF_FILE}" | cut -d'=' -f2 | xargs -n1 | sed "s~\$dir~${CA_DIR}~")
OCSP_KEY="${CA_DIR}/ocsp.key"
OCSP_CERT="${CA_DIR}/ocsp.pem"
CRT_DIR=$(grep -E "^certs" "${CONF_FILE}" | cut -d'=' -f2 | xargs -n1 | sed "s~\$dir~${CA_DIR}~")
TMP_DIR=$(grep -E "^new_certs_dir" "${CONF_FILE}" | cut -d'=' -f2 | xargs -n1 | sed "s~\$dir~${CA_DIR}~")
INDEX_FILE=$(grep -E "^database" "${CONF_FILE}" | cut -d'=' -f2 | xargs -n1 | sed "s~\$dir~${CA_DIR}~")
SERIAL=$(grep -E "^serial" "${CONF_FILE}" | cut -d'=' -f2 | xargs -n1 | sed "s~\$dir~${CA_DIR}~")
CRL=$(grep -E "^crl" "${CONF_FILE}" | cut -d'=' -f2 | xargs -n1 | sed "s~\$dir~${CA_DIR}~")
# directories for clients key, csr, crt
KEY_DIR="${CA_DIR}/private"
CSR_DIR="${CA_DIR}/requests"
PKCS12_DIR="${CA_DIR}/pkcs12"
OVPN_DIR="${CA_DIR}/openvpn"
COPY_DIR="$(dirname "${CONF_FILE}")/copy_output"
CA_KEY_LENGTH=4096
if [ "${CA_KEY_LENGTH}" -lt 4096 ]; then
error "CA key must be at least 4096 bits long."
fi
KEY_LENGTH=2048
if [ "${KEY_LENGTH}" -lt 2048 ]; then
error "User key must be at least 2048 bits long."
fi
OPENSSL_BIN=$(command -v openssl)
SUFFIX=$(TZ=:Zulu /bin/date +"%Y%m%d%H%M%SZ")
if ! is_user "${PKI_USER}" || ! is_group "${PKI_USER}"; then
error "You must create ${PKI_USER} user and group !"
fi
if [ ! -e "${CONF_FILE}" ]; then
error "${CONF_FILE} is missing"
fi
mkdir -p "${CA_DIR}" "${CRT_DIR}" "${KEY_DIR}" "${CSR_DIR}" "${PKCS12_DIR}" "${OVPN_DIR}" "${TMP_DIR}"
command=${1:-help}
case "${command}" in
init)
shift
init "$@"
;;
ocsp)
shift
ocsp "$@"
;;
create)
shift
create "$@"
;;
revoke)
shift
revoke "$@"
;;
list)
shift
list "$@"
;;
check)
shift
check "$@"
;;
version|--version)
show_version
exit 0
;;
help|--help)
show_usage
exit 0
;;
*)
show_usage >&2
exit 1
;;
esac
# fix right
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 600 "${INDEX_FILE}"* "${SERIAL}"* "${CA_KEY}" "${CRL}"
chmod 640 "${CA_CERT}"
}
main "$@"

View file

@ -12,11 +12,6 @@
- client
- server
- name: Clone shellpki repo
git:
repo: "https://gitea.evolix.org/evolix/shellpki.git"
dest: /root/shellpki
- name: Create the shellpki user
user:
name: shellpki
@ -38,30 +33,14 @@
- name: Copy shellpki files
copy:
src: "{{ item.source }}"
src: "shellpki/{{ item.source }}"
dest: "{{ item.destination }}"
remote_src: yes
with_items:
- { source: "/root/shellpki/openssl.cnf", destination: "/etc/shellpki/openssl.cnf" }
- { source: "/root/shellpki/shellpki", destination: "/usr/local/sbin/shellpki" }
- include_role:
name: evolix/remount-usr
- name: Change files permissions
file:
dest: "{{ item.dest }}"
mode: "{{ item.mode }}"
owner: "{{ item.owner }}"
group: "{{ item.group }}"
with_items:
- { dest: "/etc/shellpki/openssl.cnf", mode: "0640", owner: "shellpki", group: "shellpki" }
- { dest: "/usr/local/sbin/shellpki", mode: "0755", owner: "root", group: "root" }
- name: Delete local shellpki repo
file:
state: absent
dest: "/root/shellpki"
- { 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" }
- name: Add sudo rights
lineinfile:
@ -251,30 +230,16 @@
notify: restart nagios-nrpe-server
when: nrpe_evolix_config.stat.exists
# BEGIN TODO : Get this script from master branch when cloning it at the beginning when dev branch is merged with master (this script is currently not available on master branch)
- name: Clone dev branch of shellpki repo
git:
repo: "https://gitea.evolix.org/evolix/shellpki.git"
dest: /root/shellpki-dev
version: dev
- include_role:
name: evolix/remount-usr
- name: Copy shellpki script
copy:
src: "/root/shellpki-dev/cert-expirations.sh"
src: "shellpki/cert-expirations.sh"
dest: "/usr/share/scripts/cert-expirations.sh"
mode: "0700"
owner: root
group: root
remote_src: yes
- name: Delete local shellpki-dev repo
file:
state: absent
dest: "/root/shellpki-dev"
# END TODO
- name: Install cron to warn about certificates expiration
cron:

View file

@ -13,11 +13,6 @@
group: wheel
mode: "0755"
- name: Clone shellpki repo
git:
repo: "https://gitea.evolix.org/evolix/shellpki.git"
dest: /root/shellpki
- name: Create the shellpki user
user:
name: _shellpki
@ -36,27 +31,14 @@
- name: Copy shellpki files
copy:
src: "{{ item.source }}"
src: "shellpki/{{ item.source }}"
dest: "{{ item.destination }}"
remote_src: yes
with_items:
- { source: "/root/shellpki/openssl.cnf", destination: "/etc/shellpki/openssl.cnf" }
- { source: "/root/shellpki/shellpki", destination: "/usr/local/sbin/shellpki" }
- name: Change files permissions
file:
dest: "{{ item.dest }}"
mode: "{{ item.mode }}"
owner: "{{ item.owner }}"
group: "{{ item.group }}"
with_items:
- { dest: "/etc/shellpki/openssl.cnf", mode: "0640", owner: "_shellpki", group: "_shellpki"}
- { dest: "/usr/local/sbin/shellpki", mode: "0755", owner: "root", group: "wheel" }
- name: Delete local shellpki repo
file:
state: absent
dest: "/root/shellpki"
- { 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" }
- name: Add sudo rights
lineinfile:
@ -193,27 +175,13 @@
notify: restart nrpe
when: nrpe_evolix_config.stat.exists
# BEGIN TODO : Get this script from master branch when cloning it at the beginning when dev branch is merged with master (this script is currently not available on master branch)
- name: Clone dev branch of shellpki repo
git:
repo: "https://gitea.evolix.org/evolix/shellpki.git"
dest: /root/shellpki-dev
version: dev
- name: Copy shellpki script
copy:
src: "/root/shellpki-dev/cert-expirations.sh"
src: "shellpki/cert-expirations.sh"
dest: "/usr/share/scripts/cert-expirations.sh"
mode: "0700"
owner: root
group: wheel
remote_src: yes
- name: Delete local shellpki-dev repo
file:
state: absent
dest: "/root/shellpki-dev"
# END TODO
- name: Install cron to warn about certificates expiration
cron:

View file

@ -6,6 +6,7 @@ port 1194
proto udp
dev tun
mode server
topology subnet
keepalive 10 120
tls-exit

View file

@ -158,7 +158,7 @@ smtp-amavis unix - - y - 2 lmtp
-o smtpd_hard_error_limit=1000
-o smtpd_client_connection_count_limit=0
-o smtpd_client_connection_rate_limit=0
-o receive_override_options=no_header_body_checks,no_unknown_recipient_checks
-o receive_override_options=no_header_body_checks,no_unknown_recipient_checks,no_milters
pre-cleanup unix n - n - 0 cleanup
-o virtual_alias_maps=

View file

@ -1,4 +1,4 @@
# munin
# Redis
Installation and basic configuration of Redis.

View file

@ -17,3 +17,14 @@
tags:
- redis
- log2mail
- name: log2mail user is in redis group
user:
name: log2mail
groups: redis
append: yes
state: present
notify: restart log2mail
tags:
- redis
- log2mail

View file

@ -49,6 +49,7 @@
- used_keys
- used_memory
notify: restart munin-node
when: not ansible_check_mode
tags:
- redis

View file

@ -49,6 +49,7 @@
- used_keys
- used_memory
notify: restart munin-node
when: not ansible_check_mode
tags:
- redis

View file

@ -22,6 +22,14 @@
- packages
when: redis_sentinel_install | bool
- name: Linux kernel overcommit memory setting is enabled
sysctl:
name: "vm.overcommit_memory"
value: "1"
sysctl_file: "/etc/sysctl.d/evolinux-redis.conf"
state: present
reload: yes
- name: Get Redis version
shell: "redis-server -v | grep -Eo '(v=\\S+)' | cut -d'=' -f 2 | grep -E '^([0-9]|\\.)+$'"
changed_when: false

View file

@ -79,6 +79,10 @@
- redis
- nrpe
- name: "Remount /usr with RW for 'install check_redis instance'"
include_role:
name: evolix/remount-usr
- name: install check_redis_instances
copy:
src: check_redis_instances.sh

View file

@ -7,4 +7,3 @@ squid_whitelist_items: []
squid_localproxy_enable: False
minifirewall_main_file: /etc/default/minifirewall

View file

@ -0,0 +1,43 @@
---
- name: Check if Minifirewall is present
stat:
path: "/etc/default/minifirewall"
check_mode: no
register: minifirewall_test
- block:
- name: HTTPSITES list is commented in minifirewall
replace:
dest: "/etc/default/minifirewall"
regexp: "^(HTTPSITES='[^0-9])"
replace: '#\1'
notify: restart minifirewall
- name: all HTTPSITES are authorized in minifirewall
lineinfile:
dest: "/etc/default/minifirewall"
line: "HTTPSITES='0.0.0.0/0'"
regexp: "HTTPSITES='.*'"
insertafter: "^#HTTPSITES="
notify: restart minifirewall
- name: add iptables rules for the proxy
lineinfile:
dest: "/etc/default/minifirewall"
regexp: "^#? *{{ item }}"
line: "{{ item }}"
insertafter: "^# Proxy"
loop:
- "/sbin/iptables -t nat -A OUTPUT -p tcp --dport 80 -m owner --uid-owner proxy -j ACCEPT"
- "/sbin/iptables -t nat -A OUTPUT -p tcp --dport 80 -d {{ squid_address }} -j ACCEPT"
- "/sbin/iptables -t nat -A OUTPUT -p tcp --dport 80 -d 127.0.0.0/8 -j ACCEPT"
- "/sbin/iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-port 8888"
notify: restart minifirewall
- name: remove minifirewall example rule for the proxy
lineinfile:
dest: "/etc/default/minifirewall"
regexp: '^#.*(-t nat).*(-d X\.X\.X\.X)'
state: absent
notify: restart minifirewall
when: minifirewall_test.stat.exists

View file

@ -1,29 +1,37 @@
---
- name: Check if Minifirewall is present
stat:
path: "{{ minifirewall_main_file }}"
path: "/etc/default/minifirewall"
check_mode: no
register: minifirewall_test
- block:
- name: HTTPSITES list is commented in minifirewall
replace:
dest: "{{ minifirewall_main_file }}"
dest: "/etc/default/minifirewall"
regexp: "^(HTTPSITES='[^0-9])"
replace: '#\1'
notify: restart minifirewall
- name: all HTTPSITES are authorized in minifirewall
lineinfile:
dest: "{{ minifirewall_main_file }}"
dest: "/etc/default/minifirewall"
line: "HTTPSITES='0.0.0.0/0'"
regexp: "HTTPSITES='.*'"
insertafter: "^#HTTPSITES="
notify: restart minifirewall
- name: add iptables rules for the proxy
# The PROXY variable means that minifirewall is "modern"
- name: Look for PROXY variable
shell: "grep -E '^\\s*PROXY=' /etc/default/minifirewall"
failed_when: False
changed_when: False
check_mode: False
register: _minifirewall_proxy_var_check
- name: Set proxy configuration for minifirewall (legacy mode)
lineinfile:
dest: "{{ minifirewall_main_file }}"
dest: "/etc/default/minifirewall"
regexp: "^#? *{{ item }}"
line: "{{ item }}"
insertafter: "^# Proxy"
@ -33,11 +41,21 @@
- "/sbin/iptables -t nat -A OUTPUT -p tcp --dport 80 -d 127.0.0.0/8 -j ACCEPT"
- "/sbin/iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-port 8888"
notify: restart minifirewall
when: _minifirewall_proxy_var_check.rc == 1
- name: remove minifirewall example rule for the proxy
- name: remove minifirewall example rule for the proxy (legacy mode)
lineinfile:
dest: "{{ minifirewall_main_file }}"
dest: "/etc/default/minifirewall"
regexp: '^#.*(-t nat).*(-d X\.X\.X\.X)'
state: absent
notify: restart minifirewall
when: _minifirewall_proxy_var_check.rc == 1
- name: Set proxy configuration for minifirewall (modern mode)
replace:
dest: "/etc/default/minifirewall"
replace: "PROXY='on'"
regexp: "PROXY='.*'"
notify: restart minifirewall
when: _minifirewall_proxy_var_check.rc == 0
when: minifirewall_test.stat.exists

View file

@ -21,9 +21,9 @@
- ansible_distribution_release == "buster"
- tomcat_version is not defined
- name: Set Tomcat version to 10 on Debian 11 if missing
- name: Set Tomcat version to 9 on Debian 11 if missing
set_fact:
tomcat_version: 10
tomcat_version: 9
when:
- ansible_distribution_release == "bullseye"
- tomcat_version is not defined

View file

@ -3,6 +3,8 @@
include_role:
name: evolix/apt
tasks_from: evolix_public.yml
tags:
- vrrpd
- name: Install vrrpd packages
apt:
@ -10,12 +12,13 @@
allow_unauthenticated: yes
state: present
tags:
- vrrpd
- vrrpd
- name: Adjust sysctl config
sysctl:
name: "{{ item.name }}"
value: "{{ item.value }}"
sysctl_file: /etc/sysctl.d/vrrpd.conf
sysctl_set: yes
state: present
loop:
@ -26,4 +29,4 @@
- { name: 'net.ipv4.conf.all.arp_announce', value: 2 }
- { name: 'net.ipv4.ip_nonlocal_bind', value: 1 }
tags:
- vrrpd
- vrrpd