Merge pull request 'Release of EvoBSD 6.8.0' (#37) from dev into master
continuous-integration/drone/push Build is failing Details
continuous-integration/drone/tag Build is failing Details

Reviewed-on: #37
Reviewed-by: Jérémy Lecour <jlecour@noreply.gitea.evolix.org>
This commit is contained in:
Jérémy Lecour 2020-10-23 12:13:26 +02:00
commit f89751669f
92 changed files with 4542 additions and 708 deletions

30
.drone.yml Normal file
View File

@ -0,0 +1,30 @@
---
kind: pipeline
type: docker
name: default
steps:
- name: lint markdown files
image: pipelinecomponents/remark-lint:latest
commands:
- "remark --no-stdout --color --use preset-lint-recommended ."
- name: lint yaml files
image: pipelinecomponents/yamllint:latest
commands:
- "yamllint ."
- name: lint ansible scripts
image: pipelinecomponents/ansible-lint:latest
commands:
- >
find . -maxdepth 1 -name '*.yml'
| sort
| grep -v '.drone.yml'
| xargs ansible-playbook --syntax-check --list-tasks
- >
find . -maxdepth 1 -name '*.yml'
| sort
| grep -v '.drone.yml'
| xargs ansible-lint

75
CHANGELOG Normal file
View File

@ -0,0 +1,75 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [6.8.0] - 2020-10-23
### Added
- Add a PF tag to be able to skip that part when rerunning EvoBSD
- Add a doas authorization for NRPE check_ipsecctl_critiques
### Changed
- The task mail.yml replace the former boot/reboot message only if it is untouched
- Replace the variable used to set the email address in etc-git role - now using inventory_hostname
- Not checking syspatch when OpenBSD <= 6.1
- Amend fstab file adding noatime option to each entrie
- Import evocheck v.6.7.7
- Comment NRPE checks that cannot be used as is
### Fixed
- Add the creation of the NRPE plugins directory in nagios-nrpe role
- Add collectd doas rights in the base role to avoid broking anything if EvoBSD is rerun without the collectd role included
- Do not add the motd cron if the same line is already there but uncommented
- Amend fstab entries only when the filesystem is ffs
## [6.7.2] - 2020-10-13
### Added
- Now handling deletion of evobackup crontab (replaced by daily.local cron)
- Customize fstab with noexec and softdep
- Collectd role
### Changed
- Improve rc.local file configuration
- Update evocheck to version 6.7.5
- Hide default daily output mail content (VERBOSESTATUS=0)
- Add deletion of old log files in the OSPF role
### Fixed
- Fix duplicate evobackup cron if the entry is uncommented in daily.local
## [6.7.1] - 2020-09-10
### Added
- Add completions functions in root's profile dotfile
- Add check_connections_state.sh NRPE plugin
- Add an evocheck role
- Add stricter ssh and doas access
- Add an openvpn role
- Add an OpenBGPd NRPE plugin
- Add ospf and bgp roles
- Add an unbound NRPE check since it is part of the base system
- Add a motd-carp-state.sh script that checks the carp state and generates the /etc/motd file
### Changed
- Disable sndiod since it is not required on serveurs
- Replace sudo with doas for script executions
- Update evomaintenance version to 0.6.3
- Disable mouse function in vim configuration
- Drop openup since syspatch can apply stable patches now
- Update evobackup script
- Rewrite newsyslog configuration
- Drop postgresql-client package since evomaintenance use an API now

View File

@ -2,17 +2,17 @@
Contributions are welcome, as long as they respect our current workflow: Contributions are welcome, as long as they respect our current workflow:
1. The master branch is only for releases. Once properly tested, 1. The master branch is only for releases. Once properly tested,
the dev branch can be merged, the release tagged and a tar archive the dev branch can be merged, the release tagged and a tar archive
created. created.
2. The dev branch should never be commited to directly, unless 2. The dev branch should never be commited to directly, unless
you're updating the CHANGELOG file. you're updating the CHANGELOG file.
3. Use feature branches for anything else, once they've passed all 3. Use feature branches for anything else, once they've passed all
CI tests and have been reviewed by other contributors through a CI test, lints and have been reviewed by other contributors through a
pull request, they may be merged into the dev branch. pull request, they may be merged into the dev branch.
Open issues liberally, but please review closed and opened issues Open issues liberally, but please review closed and opened issues
for duplicates before hand. for duplicates before hand.

View File

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2019 Evolix Copyright (c) 2020 Evolix
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

134
README.md
View File

@ -1,4 +1,4 @@
# EvoBSD 1.0 # EvoBSD 6.8.0
EvoBSD is an ansible project used for customising OpenBSD hosts EvoBSD is an ansible project used for customising OpenBSD hosts
used by Evolix. used by Evolix.
@ -9,16 +9,24 @@ used by Evolix.
Put your public key in the remote root's autorized_keys Put your public key in the remote root's autorized_keys
(/root/.ssh/authorized_keys) (/root/.ssh/authorized_keys)
1 - Install ansible's prerequisites 1. Install ansible's prerequisites
``` ```
ansible-playbook prerequisite.yml -CDi hosts -l HOSTNAME ansible-playbook prerequisite.yml -CDi hosts -l HOSTNAME
``` ```
2 - Run it 2. Run it
First use (become_method: su) :
``` ```
ansible-playbook evolixisation.yml --ask-vault-pass -CDKi hosts -l HOSTNAME ansible-playbook evolixisation.yml --ask-vault-pass -CDki hosts -u root -l HOSTNAME
```
Subsequent use (become_method: sudo) :
```
ansible-playbook evolixisation.yml --ask-vault-pass -CDKi hosts --skip-tags pf -l HOSTNAME
``` ```
### Testing ### Testing
@ -26,100 +34,40 @@ ansible-playbook evolixisation.yml --ask-vault-pass -CDKi hosts -l HOSTNAME
Changes can be tested by using [Packer](https://www.packer.io/) and Changes can be tested by using [Packer](https://www.packer.io/) and
[vmm(4)](https://man.openbsd.org/vmm.4) : [vmm(4)](https://man.openbsd.org/vmm.4) :
* This process depends on the [Go](https://golang.org/) programming language. * This process depends on the [Go](https://golang.org/) programming language.
**Packages**
Needing a Golang eco system and some basics
````
pkg_add go-- packer-- git--
````
* We use the [packer-builder-openbsd-vmm](https://github.com/double-p/packer-builder-openbsd-vmm) project to bridge Packer and vmm(4)
````
git clone https://github.com/double-p/packer-builder-openbsd-vmm.git
````
**builds**
Set ````GOPATH```` (default: ~/go), if the 1.4GB dependencies wont fit.
````
make
make install
````
* You need your unprivileged user to be able to run vmctl(8) through doas(1)
``` ```
# pkg_add go packer echo "permit nopass myunprivilegeduser as root cmd /usr/sbin/vmctl" >> /etc/doas.conf
``` ```
* We use the [packer-builder-vmm](https://github.com/prep/packer-builder-vmm) project to bridge Packer and vmm(4) See packer-builder-openbsd-vmm/examples/README.examples for further instructions
``` * Enable NAT on your host machine
$ go get -u github.com/prep/packer-builder-vmm/cmd/packer-builder-vmm
```
* Here is an example build file
```
$ vim openbsd.json
```
{
"description": "OpenBSD installation on vmm(4)",
"variables": {
"hostname": "evobsd",
"domain": "example.com",
"password": "evolix"
},
"builders": [
{
"type": "vmm",
"vm_name": "evobsd",
"disk_size": "2G",
"format": "qcow2",
"mem_size": "1024M",
"iso_urls": ["downloads/install64.fs", "https://ftp.nluug.nl/pub/OpenBSD/6.4/amd64/install64.fs"],
"iso_checksum": "7aa4344cb39efbf67300f97ac7eec005b607e8c19d4e31a0a593a8ee2b7136e4",
"iso_checksum_type": "sha256",
"boot_wait": "10s",
"boot_command": [
"S<enter>",
"cat <<EOF >disklabel.template<enter>",
"/ 1G-* 100%<enter>",
"EOF<enter>",
"cat <<EOF >install.conf<enter>",
"System hostname = {{user `hostname`}}<enter>",
"DNS domain name = {{user `domain`}}<enter>",
"Password for root account = {{user `password`}}<enter>",
"Do you expect to run the X Window System = no<enter>",
"Setup a user = no<enter>",
"Which disk is the root disk = sd1<enter>",
"Use (A)uto layout, (E)dit auto layout, or create (C)ustom layout = c<enter>",
"URL to autopartitioning template for disklabel = file://disklabel.template<enter>",
"Location of sets = disk<enter>",
"Is the disk partition already mounted = no<enter>",
"Set name(s) = -bsd.rd<enter>",
"Set name(s) = done<enter>",
"Directory does not contain SHA256.sig. Continue without verification = yes<enter>",
"What timezone are you in = Europe/Paris<enter>",
"EOF<enter>",
"install -af install.conf<enter>",
"<wait2m>",
"/sbin/halt -p<enter><wait15>"
]
}
]
}
* You need your unprivileged user to be able to run vmctl(8) through doas(1)
```
# echo "permit nopass myunprivilegeduser as root cmd /usr/sbin/vmctl" >> /etc/doas.conf
```
* Build the virtual machine
```
$ packer build openbsd.json
```
* Start it
```
doas vmctl start evobsd -cL -d output-vmm/evobsd.qcow2
```
* Enable NAT on your host machine
``` ```
pass out on em0 inet from tap0:network to any nat-to (em0) pass out on em0 inet from tap0:network to any nat-to (em0)

View File

@ -1,5 +1,9 @@
# yamllint disable rule:line-length
# Playbook command # Playbook command
# ansible-playbook evolixisation.yml --ask-vault-pass -CDKi hosts -l HOSTNAME # First use (become_method: su) :
# ansible-playbook evolixisation.yml --ask-vault-pass -CDki hosts -u root -l HOSTNAME
# Subsequent use (become_method: sudo) :
# ansible-playbook evolixisation.yml --ask-vault-pass -CDKi hosts --skip-tags pf -l HOSTNAME
--- ---
- name: Evolixisation of an OpenBSD system - name: Evolixisation of an OpenBSD system
@ -7,11 +11,13 @@
become: true become: true
become_user: root become_user: root
become_method: sudo become_method: sudo
# become_method: su
vars_files: vars_files:
- vars/main.yml - vars/main.yml
# - vars/secrets.yml - vars/secrets.yml
- vars/openbsd-secret.yml
roles: roles:
- etc-git - etc-git
@ -20,14 +26,20 @@
- pf - pf
- accounts - accounts
- nagios-nrpe - nagios-nrpe
- evocheck
- post-install - post-install
# - openvpn
# - ospf
# - bgp
# - { role: collectd, collectd_server: "127.0.0.1" }
post_tasks: post_tasks:
- include: "tasks/commit_etc_git.yml" - include: "tasks/commit_etc_git.yml"
vars: vars:
commit_message: "Ansible - Evolixisation" commit_message: "Ansible - Evolixisation"
- include_role:
name: evocheck
tasks_from: exec.yml
environment: # environment:
PKG_PATH: "http://ftp.openbsd.org/pub/OpenBSD/{{ ansible_distribution_version }}/packages/{{ ansible_architecture }}/" # PKG_PATH: "http://ftp.openbsd.org/pub/OpenBSD/{{ ansible_distribution_version }}/packages/{{ ansible_architecture }}/"
# vim:ft=ansible

2
hosts
View File

@ -2,4 +2,4 @@
foo.example.com foo.example.com
[openbsd:vars] [openbsd:vars]
ansible_python_interpreter=/usr/local/bin/python2.7 ansible_python_interpreter=/usr/local/bin/python3

View File

@ -2,15 +2,16 @@
# ansible-playbook prerequisite.yml -CDi hosts -l HOSTNAME # ansible-playbook prerequisite.yml -CDi hosts -l HOSTNAME
--- ---
- hosts: all - hosts: all
become: yes become: true
become_method: su become_method: su
user: root user: root
gather_facts: no gather_facts: false
tasks: tasks:
- name: Install ansible's prerequisite - name: Install ansible's prerequisite
raw: export PKG_PATH=http://ftp.eu.openbsd.org/pub/OpenBSD/$(uname -r)/packages/$(uname -p)/; pkg_add -z python-2 # yamllint disable-line rule:line-length
raw: export PKG_PATH=http://ftp.eu.openbsd.org/pub/OpenBSD/$(uname -r)/packages/$(uname -p)/; pkg_add -z python-3
# vim:ft=ansible # vim:ft=ansible

View File

@ -0,0 +1,6 @@
---
- name: reload sshd
service:
name: sshd
state: reloaded

View File

@ -1,7 +1,85 @@
--- ---
- name: "Create {{ evobsd_ssh_group }} group"
group:
name: "{{ evobsd_ssh_group }}"
system: true
- name: "Create {{ evobsd_sudo_group }} group"
group:
name: "{{ evobsd_sudo_group }}"
system: true
- name: Create user accounts - name: Create user accounts
include: user.yml include: user.yml
vars: vars:
user: "{{ item.value }}" user: "{{ item.value }}"
with_dict: "{{ evolinux_users }}" with_dict: "{{ evolix_users }}"
when: evolinux_users != {} when: evolix_users != {}
- name: verify AllowGroups directive
command: "grep -E '^AllowGroups' /etc/ssh/sshd_config"
changed_when: false
failed_when: false
check_mode: false
register: grep_allowgroups_ssh
- name: verify AllowUsers directive
command: "grep -E '^AllowUsers' /etc/ssh/sshd_config"
changed_when: false
failed_when: false
check_mode: false
register: grep_allowusers_ssh
- name: "Check that AllowUsers and AllowGroup do not override each other"
assert:
that: "not (grep_allowusers_ssh.rc == 0 and grep_allowgroups_ssh.rc == 0)"
msg: "We can't deal with AllowUsers and AllowGroups at the same time"
- name: "If AllowGroups is present then use it"
set_fact:
ssh_allowgroups:
"{{ (grep_allowgroups_ssh.rc == 0) or (grep_allowusers_ssh.rc != 0) }}"
- name: "Add AllowGroups sshd directive with '{{ evobsd_ssh_group }}'"
lineinfile:
dest: /etc/ssh/sshd_config
line: "\nAllowGroups {{ evobsd_ssh_group }}"
insertafter: 'Subsystem'
validate: '/usr/sbin/sshd -t -f %s'
notify: reload sshd
when:
- ssh_allowgroups
- grep_allowgroups_ssh.rc == 1
- name: "Append '{{ evobsd_ssh_group }}' to AllowGroups sshd directive"
replace:
dest: /etc/ssh/sshd_config
regexp: '^(AllowGroups ((?!\b{{ evobsd_ssh_group }}\b).)*)$'
replace: '\1 {{ evobsd_ssh_group }}'
validate: '/usr/sbin/sshd -t -f %s'
notify: reload sshd
when:
- ssh_allowgroups
- grep_allowgroups_ssh.rc == 0
- name: "Security directives for EvoBSD"
blockinfile:
dest: /etc/ssh/sshd_config
marker: "# {mark} EVOBSD PASSWORD RESTRICTIONS"
block: |
Match Address {{ evolix_trusted_ips | join(',') }}
PasswordAuthentication yes
Match Group {{ evobsd_ssh_group }}
PasswordAuthentication no
insertafter: EOF
validate: '/usr/sbin/sshd -t -f %s'
notify: reload sshd
when:
- evolix_trusted_ips != []
- name: "Disable root login"
replace:
dest: /etc/ssh/sshd_config
regexp: '^PermitRootLogin (yes|without-password|prohibit-password)'
replace: "PermitRootLogin no"
notify: reload sshd

View File

@ -1,16 +1,31 @@
--- ---
- name: "Group '{{ user.name }}' is present"
group:
state: present
name: "{{ user.name }}"
gid: "{{ user.uid }}"
- name: "User '{{ user.name }}' is present" - name: "User '{{ user.name }}' is present"
user: user:
state: present state: present
name: '{{ user.name }}' name: '{{ user.name }}'
uid: '{{ user.uid }}' uid: '{{ user.uid }}'
password: '{{ user.password_hash_openbsd }}' password: '{{ user.password_hash_openbsd }}'
group: "{{ user.name }}"
groups: wheel groups: wheel
shell: /bin/ksh shell: /bin/ksh
append: yes append: true
tags: tags:
- admin - admin
- name: "Home directory for '{{ user.name }}' is only accesible by owner"
file:
name: '/home/{{ user.name }}'
mode: "0700"
owner: "{{ user.name }}"
group: "{{ user.name }}"
state: directory
- name: "SSH public keys for '{{ user.name }}' are present" - name: "SSH public keys for '{{ user.name }}' are present"
authorized_key: authorized_key:
user: "{{ user.name }}" user: "{{ user.name }}"
@ -21,4 +36,20 @@
loop_var: ssk_key loop_var: ssk_key
when: user.ssh_keys is defined when: user.ssh_keys is defined
tags: tags:
- admin - admin
- name: "Add {{ user.name }} to {{ evobsd_ssh_group }} group"
user:
name: "{{ user.name }}"
groups: "{{ evobsd_ssh_group }}"
append: true
tags:
- admin
- name: "Add {{ user.name }} to {{ evobsd_sudo_group }} group"
user:
name: "{{ user.name }}"
groups: "{{ evobsd_sudo_group }}"
append: true
tags:
- admin

View File

@ -1,19 +1,39 @@
--- ---
ntpd_servers: ntpd_servers:
- "ntp.evolix.net" - "ntp.evolix.net"
general_alert_email: "root@localhost" general_alert_email: "root@localhost"
general_technical_realm: "example.com" general_technical_realm: "example.com"
evomaintenance_realm: "example.com" evomaintenance_realm: "example.com"
evomaintenance_alert_email: "evomaintenance-{{ inventory_hostname }}@{{ evomaintenance_realm }}" evomaintenance_alert_email:
evomaintenance_hostname: "{{ inventory_hostname }}.{{ general_technical_realm }}" "evomaintenance-{{ inventory_hostname }}@{{ evomaintenance_realm }}"
evomaintenance_pg_host: Null evomaintenance_hostname:
evomaintenance_pg_passwd: Null "{{ inventory_hostname }}.{{ general_technical_realm }}"
evomaintenance_pg_db: Null evomaintenance_pg_host: null
evomaintenance_pg_table: Null evomaintenance_pg_passwd: null
evomaintenance_pg_db: null
evomaintenance_pg_table: null
evomaintenance_from_domain: "{{ evomaintenance_realm }}" evomaintenance_from_domain: "{{ evomaintenance_realm }}"
evomaintenance_from: "evomaintenance@{{ evomaintenance_from_domain }}" evomaintenance_from: "evomaintenance@{{ evomaintenance_from_domain }}"
evomaintenance_full_from: "Evomaintenance <{{ evomaintenance_from }}>" evomaintenance_full_from: "Evomaintenance <{{ evomaintenance_from }}>"
evomaintenance_urgency_from: mama.doe@example.com evomaintenance_urgency_from: mama.doe@example.com
evomaintenance_urgency_tel: "06.00.00.00.00" evomaintenance_urgency_tel: "06.00.00.00.00"
evomaintenance_install_vendor: false
evomaintenance_force_config: true
evomaintenance_api_endpoint: null
evomaintenance_api_key: null
evomaintenance_hook_api: true
evomaintenance_hook_db: false
evomaintenance_hook_commit: true
evomaintenance_hook_mail: true
evomaintenance_default_hosts: []
evomaintenance_additional_hosts: []
evomaintenance_hosts: >
{{ evomaintenance_default_hosts
| union(evomaintenance_additional_hosts)
| unique }}
evobsd_path: >-
"$HOME/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"
cron_root_path: "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"

View File

@ -4,82 +4,489 @@
# Dependencies (all OS): git postgresql-client # Dependencies (all OS): git postgresql-client
# Dependencies (Debian): sudo # Dependencies (Debian): sudo
# version 0.4.1 # Copyright 2007-2019 Evolix <info@evolix.fr>, Gregory Colpart <reg@evolix.fr>,
# Copyright 2007-2018 Evolix <info@evolix.fr> # Jérémy Lecour <jlecour@evolix.fr> and others.
VERSION="0.6.3"
show_version() {
cat <<END
evomaintenance version ${VERSION}
Copyright 2007-2019 Evolix <info@evolix.fr>,
Gregory Colpart <reg@evolix.fr>,
Jérémy Lecour <jlecour@evolix.fr>
and others.
evomaintenance 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
evomaintenance is a program that helps reporting what you've done on a server
Usage: evomaintenance
or evomaintenance --message="add new host"
or evomaintenance --no-api --no-mail --no-commit
or echo "add new vhost" | evomaintenance
Options
-m, --message=MESSAGE set the message from the command line
--mail enable the mail hook (default)
--no-mail disable the mail hook
--db enable the database hook
--no-db disable the database hook (default)
--api enable the API hook (default)
--no-api disable the API hook
--commit enable the commit hook (default)
--no-commit disable the commit hook
--evocheck enable evocheck execution (default)
--no-evocheck disable evocheck execution
--auto use "auto" mode
--no-auto use "manual" mode (default)
-v, --verbose increase verbosity
-n, --dry-run actions are not executed
--help print this message and exit
--version print version and exit
END
}
syslog() {
if [ -x "${LOGGER_BIN}" ]; then
${LOGGER_BIN} -t "evomaintenance" "$1"
fi
}
get_system() { get_system() {
uname -s uname -s
} }
get_fqdn() { get_fqdn() {
if [ "$(get_system)" = "Linux" ]; then if [ "$(get_system)" = "Linux" ]; then
hostname --fqdn hostname --fqdn
elif [ "$(get_system)" = "OpenBSD" ]; then elif [ "$(get_system)" = "OpenBSD" ]; then
hostname hostname
else else
echo "OS not detected!" echo "OS not detected!"
exit 1 exit 1
fi fi
} }
get_tty() { get_tty() {
if [ "$(get_system)" = "Linux" ]; then if [ "$(get_system)" = "Linux" ]; then
ps -o tty= | tail -1 ps -o tty= | tail -1
elif [ "$(get_system)" = "OpenBSD" ]; then elif [ "$(get_system)" = "OpenBSD" ]; then
env | grep SSH_TTY | cut -d"/" -f3 env | grep SSH_TTY | cut -d"/" -f3
else else
echo "OS not detected!" echo "OS not detected!"
exit 1 exit 1
fi fi
} }
get_who() { get_who() {
who=$(LC_ALL=C who -m) who=$(LC_ALL=C who -m | tr -s ' ')
if [ -n "${who}" ]; then if [ -n "${who}" ]; then
echo "${who}" echo "${who}"
else else
LC_ALL=C who | grep $(get_tty) | tr -s ' ' LC_ALL=C who | grep "$(get_tty)" | tr -s ' '
fi fi
} }
get_begin_date() { get_begin_date() {
echo "$(date "+%Y") $(echo $(get_who) | cut -d" " -f3,4,5)" printf "%s %s" "$(date "+%Y")" "$(get_who | cut -d" " -f3,4,5)"
} }
get_ip() { get_ip() {
ip=$(echo $(get_who) | cut -d" " -f6 | sed -e "s/^(// ; s/)$//") ip=$(get_who | cut -d" " -f6 | sed -e "s/^(// ; s/)$//")
[ -z "${ip}" ] && ip="unknown (no tty)" [ -z "${ip}" ] && ip="unknown (no tty)"
[ "${ip}" = ":0" ] && ip="localhost" [ "${ip}" = ":0" ] && ip="localhost"
echo "${ip}" echo "${ip}"
} }
get_end_date() { get_end_date() {
date +"%Y %b %d %H:%M" date +"%Y %b %d %H:%M"
} }
get_now() { get_now() {
date +"%Y-%m-%dT%H:%M:%S%z" date +"%Y-%m-%dT%H:%M:%S%z"
} }
get_complete_hostname() {
REAL_HOSTNAME=$(get_fqdn)
if [ "${HOSTNAME}" = "${REAL_HOSTNAME}" ]; then
echo "${HOSTNAME}"
else
echo "${HOSTNAME} (${REAL_HOSTNAME})"
fi
}
get_repository_status() {
dir=$1
# tell Git where to find the repository and the work tree (no need to `cd …` there)
export GIT_DIR="${dir}/.git" GIT_WORK_TREE="${dir}"
# If the repository and the work tree exist, try to commit changes
if [ -d "${GIT_DIR}" ] && [ -d "${GIT_WORK_TREE}" ]; then
CHANGED_LINES=$(${GIT_BIN} status --porcelain | wc -l | tr -d ' ')
if [ "${CHANGED_LINES}" != "0" ]; then
STATUS=$(${GIT_BIN} status --short | tail -n ${GIT_STATUS_MAX_LINES})
printf "%s\n%s\n" "${GIT_DIR} (last ${GIT_STATUS_MAX_LINES} lines)" "${STATUS}" | sed -e '/^$/d'
fi
fi
# unset environment variables to prevent accidental influence on other git commands
unset GIT_DIR GIT_WORK_TREE
}
get_evocheck() {
if [ -x "${EVOCHECK_BIN}" ]; then
printf "Evocheck status :"
EVOCHECK_OUT=$(${EVOCHECK_BIN})
EVOCHECK_RC=$?
if [ "${EVOCHECK_RC}" = "0" ] && [ -z "${EVOCHECK_OUT}" ]; then
printf " OK\n\n"
else
printf " ERROR\n%s\n\n" "${EVOCHECK_OUT}"
fi
fi
}
print_log() {
printf "*********** %s ***************\n" "$(get_now)"
print_session_data
printf "Hooks : commit=%s db=%s api=%s mail=%s\n"\
"${HOOK_COMMIT}" "${HOOK_DB}" "${HOOK_API}" "${HOOK_MAIL}"
if [ "${HOOK_MAIL}" = "1" ]; then
printf "Mailto : %s\n" "${EVOMAINTMAIL}"
fi
}
print_session_data() {
printf "Host : %s\n" "${HOSTNAME_TEXT}"
printf "User : %s\n" "${USER}"
printf "IP : %s\n" "${IP}"
printf "Begin : %s\n" "${BEGIN_DATE}"
printf "End : %s\n" "${END_DATE}"
printf "Message : %s\n" "${MESSAGE}"
}
is_repository_readonly() {
if [ "$(get_system)" = "OpenBSD" ]; then
partition=$(stat -f '%Sd' $1)
mount | grep ${partition} | grep -q "read-only"
else
mountpoint=$(stat -c '%m' $1)
findmnt ${mountpoint} --noheadings --output OPTIONS -O ro
fi
}
remount_repository_readwrite() {
if [ "$(get_system)" = "OpenBSD" ]; then
partition=$(stat -f '%Sd' $1)
mount -u -w /dev/${partition} 2>/dev/null
else
mountpoint=$(stat -c '%m' $1)
mount -o remount,rw ${mountpoint}
syslog "Re-mount ${mountpoint} as read-write to commit in repository $1"
fi
}
remount_repository_readonly() {
if [ "$(get_system)" = "OpenBSD" ]; then
partition=$(stat -f '%Sd' $1)
mount -u -r /dev/${partition} 2>/dev/null
else
mountpoint=$(stat -c '%m' $1)
mount -o remount,ro ${mountpoint} 2>/dev/null
syslog "Re-mount ${mountpoint} as read-only after commit to repository $1"
fi
}
hook_commit() {
if [ -x "${GIT_BIN}" ]; then
# loop on possible directories managed by GIT
for dir in ${GIT_REPOSITORIES}; do
# tell Git where to find the repository and the work tree (no need to `cd …` there)
export GIT_DIR="${dir}/.git" GIT_WORK_TREE="${dir}"
# reset variable used to track if a mount point is readonly
READONLY_ORIG=0
# If the repository and the work tree exist, try to commit changes
if [ -d "${GIT_DIR}" ] && [ -d "${GIT_WORK_TREE}" ]; then
CHANGED_LINES=$(${GIT_BIN} status --porcelain | wc -l | tr -d ' ')
if [ "${CHANGED_LINES}" != "0" ]; then
if [ "${DRY_RUN}" = "1" ]; then
# STATS_SHORT=$(${GIT_BIN} diff --stat | tail -1)
STATS=$(${GIT_BIN} diff --stat | tail -n ${GIT_STATUS_MAX_LINES})
# GIT_COMMITS_SHORT=$(printf "%s\n%s : %s" "${GIT_COMMITS_SHORT}" "${GIT_DIR}" "${STATS_SHORT}" | sed -e '/^$/d')
GIT_COMMITS=$(printf "%s\n%s\n%s" "${GIT_COMMITS}" "${GIT_DIR}" "${STATS}" | sed -e '/^$/d')
else
# remount mount point read-write if currently readonly
is_repository_readonly ${dir} && { READONLY_ORIG=1; remount_repository_readwrite ${dir}; }
# commit changes
${GIT_BIN} add --all
${GIT_BIN} commit --message "${MESSAGE}" --author="${USER} <${USER}@evolix.net>" --quiet
# remount mount point read-only if it was before
test "$READONLY_ORIG" = "1" && remount_repository_readonly ${dir}
# Add the SHA to the log file if something has been committed
SHA=$(${GIT_BIN} rev-parse --short HEAD)
# STATS_SHORT=$(${GIT_BIN} show --stat | tail -1)
STATS=$(${GIT_BIN} show --stat --pretty=format:"" | tail -n ${GIT_STATUS_MAX_LINES})
# append commit data, without empty lines
# GIT_COMMITS_SHORT=$(printf "%s\n%s : %s %s" "${GIT_COMMITS_SHORT}" "${GIT_DIR}" "${SHA}" "${STATS_SHORT}" | sed -e '/^$/d')
GIT_COMMITS=$(printf "%s\n%s : %s\n%s" "${GIT_COMMITS}" "${GIT_DIR}" "${SHA}" "${STATS}" | sed -e '/^$/d')
fi
fi
fi
# unset environment variables to prevent accidental influence on other git commands
unset GIT_DIR GIT_WORK_TREE
done
if [ -n "${GIT_COMMITS}" ]; then
# if [ "${VERBOSE}" = "1" ]; then
printf "\n********** Commits ****************\n%s\n***********************************\n" "${GIT_COMMITS}"
# fi
if [ "${DRY_RUN}" != "1" ]; then
echo "${GIT_COMMITS}" >> "${LOGFILE}"
fi
fi
fi
}
hook_db() {
SQL_DETAILS=$(echo "${MESSAGE}" | sed "s/'/''/g")
PG_QUERY="INSERT INTO evomaint(hostname,userid,ipaddress,begin_date,end_date,details) VALUES ('${HOSTNAME}','${USER}','${IP}','${BEGIN_DATE}',now(),'${SQL_DETAILS}')"
if [ "${VERBOSE}" = "1" ]; then
printf "\n********** DB query **************\n%s\n***********************************\n" "${PG_QUERY}"
fi
if [ "${DRY_RUN}" != "1" ] && [ -x "${PSQL_BIN}" ]; then
echo "${PG_QUERY}" | ${PSQL_BIN} "${PGDB}" "${PGTABLE}" -h "${PGHOST}"
fi
}
hook_api() {
if [ "${VERBOSE}" = "1" ]; then
printf "\n********** API call **************\n"
printf "curl -f -s -S -X POST [REDACTED] -k -F api_key=[REDACTED] -F action=insertEvoMaintenance -F hostname=%s -F userid=%s -F ipaddress=%s -F begin_date=%s -F end_date='now()' -F details=%s" \
"${HOSTNAME}" "${USER}" "${IP}" "${BEGIN_DATE}" "${MESSAGE}"
printf "\n***********************************\n"
fi
if [ "${DRY_RUN}" != "1" ] && [ -x "${CURL_BIN}" ]; then
API_RETURN_STATUS=$(curl -f -s -S -X POST \
"${API_ENDPOINT}" -k \
-F api_key="${API_KEY}" \
-F action=insertEvoMaintenance \
-F hostname="${HOSTNAME}" \
-F userid="${USER}" \
-F ipaddress="${IP}" \
-F begin_date="${BEGIN_DATE}" \
-F end_date='now()' \
-F details="${MESSAGE}")
# either cURL or the API backend can throw an error, otherwise it returns this JSON response
if [ "$API_RETURN_STATUS" = '{"status":"Ok"}' ]; then
echo "API call OK."
else
echo "API call FAILED."
fi
fi
}
format_mail() {
cat <<EOTEMPLATE
From: ${FULLFROM}
Content-Type: text/plain; charset=UTF-8
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
To: ${EVOMAINTMAIL}
Subject: [evomaintenance] Intervention sur ${HOSTNAME_TEXT} (${USER})
Bonjour,
Une intervention vient de se terminer sur votre serveur.
Nom du serveur : ${HOSTNAME_TEXT}
Personne ayant réalisée l'intervention : ${USER}
Intervention réalisée depuis : ${IP}
Début de l'intervention : ${BEGIN_DATE}
Fin de l'intervention : ${END_DATE}
### Renseignements sur l'intervention
${MESSAGE}
###
EOTEMPLATE
if [ -n "${GIT_COMMITS}" ]; then
cat << EOTEMPLATE
### Commits
${GIT_COMMITS}
###
EOTEMPLATE
fi
cat <<EOTEMPLATE
Pour réagir à cette intervention, vous pouvez répondre à ce message
(sur l'adresse mail ${FROM}). En cas d'urgence, utilisez
l'adresse ${URGENCYFROM} ou notre téléphone portable d'astreinte
(${URGENCYTEL})
Cordialement,
--
${FULLFROM}
EOTEMPLATE
}
hook_mail() {
MAIL_CONTENT=$(format_mail)
if [ "${VERBOSE}" = "1" ]; then
printf "\n********** Mail *******************\n%s\n***********************************\n" "${MAIL_CONTENT}"
fi
if [ "${DRY_RUN}" != "1" ] && [ -x "${SENDMAIL_BIN}" ]; then
echo "${MAIL_CONTENT}" | ${SENDMAIL_BIN} -oi -t -f "${FROM}"
fi
}
hook_log() {
if [ "${VERBOSE}" = "1" ]; then
print_log
fi
if [ "${DRY_RUN}" != "1" ]; then
print_log >> "${LOGFILE}"
fi
}
# load configuration if present.
test -f /etc/evomaintenance.cf && . /etc/evomaintenance.cf test -f /etc/evomaintenance.cf && . /etc/evomaintenance.cf
[ -n "${HOSTNAME}" ] || HOSTNAME=$(get_fqdn) HOSTNAME=${HOSTNAME:-$(get_fqdn)}
[ -n "${EVOMAINTMAIL}" ] || EVOMAINTMAIL=evomaintenance-$(echo "${HOSTNAME}" | cut -d- -f1)@${REALM} EVOMAINTMAIL=${EVOMAINTMAIL:-"evomaintenance-$(echo "${HOSTNAME}" | cut -d- -f1)@${REALM}"}
[ -n "${LOGFILE}" ] || LOGFILE=/var/log/evomaintenance.log LOGFILE=${LOGFILE:-"/var/log/evomaintenance.log"}
HOOK_COMMIT=${HOOK_COMMIT:-"1"}
HOOK_DB=${HOOK_DB:-"0"}
HOOK_API=${HOOK_API:-"1"}
HOOK_MAIL=${HOOK_MAIL:-"1"}
DRY_RUN=${DRY_RUN:-"0"}
VERBOSE=${VERBOSE:-"0"}
AUTO=${AUTO:-"0"}
EVOCHECK=${EVOCHECK:-"0"}
GIT_STATUS_MAX_LINES=${GIT_STATUS_MAX_LINES:-20}
API_ENDPOINT=${API_ENDPOINT:-""}
# initialize variables
MESSAGE=""
# GIT_COMMITS_SHORT=""
GIT_COMMITS=""
# 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
;;
-m|--message)
# message options, with value speparated by space
if [ -n "$2" ]; then
MESSAGE=$2
shift
else
printf 'ERROR: "--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 'ERROR: "--message" requires a non-empty option argument.\n' >&2
exit 1
;;
--no-commit)
# disable commit hook
HOOK_COMMIT=0
;;
--commit)
# enable commit hook
HOOK_COMMIT=1
;;
--no-db)
# disable DB hook
HOOK_DB=0
;;
--db)
# enable DB hook
HOOK_DB=1
;;
--no-api)
# disable API hook
HOOK_API=0
;;
--api)
# enable API hook
HOOK_API=1
;;
--no-mail)
# disable mail hook
HOOK_MAIL=0
;;
--mail)
# enable mail hook
HOOK_MAIL=1
;;
--no-auto)
# use "manual" mode
AUTO=0
;;
--auto)
# use "auto" mode
AUTO=1
;;
-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 'WARN: Unknown option (ignored): %s\n' "$1" >&2
;;
*)
# Default case: If no more options then break out of the loop.
break
;;
esac
shift
done
# Treat unset variables as an error when substituting. # Treat unset variables as an error when substituting.
# Only after this line, because some config variables might be missing. # Only after this line, because some config variables might be missing.
set -u set -u
REAL_HOSTNAME=$(get_fqdn) # Gather information
if [ "${HOSTNAME}" = "${REAL_HOSTNAME}" ]; then HOSTNAME_TEXT=$(get_complete_hostname)
HOSTNAME_TEXT="${HOSTNAME}"
else
HOSTNAME_TEXT="${HOSTNAME} (${REAL_HOSTNAME})"
fi
# TTY=$(get_tty) # TTY=$(get_tty)
# WHO=$(get_who) # WHO=$(get_who)
IP=$(get_ip) IP=$(get_ip)
@ -90,109 +497,281 @@ USER=$(logname)
PATH=${PATH}:/usr/sbin PATH=${PATH}:/usr/sbin
SENDMAIL_BIN=$(command -v sendmail) SENDMAIL_BIN=$(command -v sendmail)
GIT_BIN=$(command -v git) readonly SENDMAIL_BIN
if [ "${HOOK_MAIL}" = "1" ] && [ -z "${SENDMAIL_BIN}" ]; then
GIT_REPOSITORIES="/etc /etc/bind" echo "No \`sendmail' command has been found, can't send mail." 2>&1
# git statuses
GIT_STATUSES=""
if test -x "${GIT_BIN}"; then
# loop on possible directories managed by GIT
for dir in ${GIT_REPOSITORIES}; do
# tell Git where to find the repository and the work tree (no need to `cd …` there)
export GIT_DIR="${dir}/.git" GIT_WORK_TREE="${dir}"
# If the repository and the work tree exist, try to commit changes
if test -d "${GIT_DIR}" && test -d "${GIT_WORK_TREE}"; then
CHANGED_LINES=$(${GIT_BIN} status --porcelain | wc -l | tr -d ' ')
if [ "${CHANGED_LINES}" != "0" ]; then
STATUS=$(${GIT_BIN} status --short | tail -n 10)
# append diff data, without empty lines
GIT_STATUSES=$(printf "%s\n%s\n%s\n" "${GIT_STATUSES}" "${GIT_DIR} (last 10 lines)" "${STATUS}" | sed -e '/^$/d')
fi
fi
# unset environment variables to prevent accidental influence on other git commands
unset GIT_DIR GIT_WORK_TREE
done
if [ -n "${GIT_STATUSES}" ]; then
echo "/!\ There are some uncommited changes. If you proceed, everything will be commited."
echo "${GIT_STATUSES}"
echo ""
fi
fi fi
# get input from stdin GIT_BIN=$(command -v git)
echo "> Please, enter details about your maintenance" readonly GIT_BIN
read TEXTE if [ "${HOOK_COMMIT}" = "1" ] && [ -z "${GIT_BIN}" ]; then
echo "No \`git' command has been found, can't commit changes" 2>&1
fi
if [ "${TEXTE}" = "" ]; then PSQL_BIN=$(command -v psql)
readonly PSQL_BIN
if [ "${HOOK_DB}" = "1" ] && [ -z "${PSQL_BIN}" ]; then
echo "No \`psql' command has been found, can't save to the database." 2>&1
fi
CURL_BIN=$(command -v curl)
readonly CURL_BIN
if [ "${HOOK_API}" = "1" ] && [ -z "${CURL_BIN}" ]; then
echo "No \`curl' command has been found, can't call the API." 2>&1
fi
LOGGER_BIN=$(command -v logger)
readonly LOGGER_BIN
if [ "${HOOK_API}" = "1" ] && [ -z "${API_ENDPOINT}" ]; then
echo "No API endpoint specified, can't call the API." 2>&1
fi
EVOCHECK_BIN="/usr/share/scripts/evocheck.sh"
GIT_REPOSITORIES="/etc /etc/bind /usr/share/scripts"
# initialize variable
GIT_STATUSES=""
# git statuses
if [ -x "${GIT_BIN}" ]; then
# loop on possible directories managed by GIT
for dir in ${GIT_REPOSITORIES}; do
RESULT=$(get_repository_status "${dir}")
if [ -n "${RESULT}" ]; then
# append diff data, without empty lines
GIT_STATUSES=$(printf "%s\n%s\n" "${GIT_STATUSES}" "${RESULT}" | sed -e '/^$/d')
fi
unset RESULT
done
fi
# find out if running in interactive mode, or not
if [ -t 0 ]; then
INTERACTIVE=1
else
INTERACTIVE=0
fi
readonly INTERACTIVE
if [ "${INTERACTIVE}" = "1" ] && [ "${EVOCHECK}" = "1" ]; then
get_evocheck
fi
if [ -n "${GIT_STATUSES}" ] && [ "${INTERACTIVE}" = "1" ]; then
printf "/!\\\ There are some uncommited changes.\n%s\n\n" "${GIT_STATUSES}"
fi
if [ -z "${MESSAGE}" ]; then
if [ "${INTERACTIVE}" = "1" ]; then
printf "> Please, enter details about your maintenance:\n"
fi
read -r MESSAGE
fi
if [ -z "${MESSAGE}" ]; then
echo "no value..." echo "no value..."
exit 1 exit 1
fi fi
# recapitulatif print_session_data
BLOB=$(cat <<END
Host : $HOSTNAME_TEXT
User : $USER
IP : $IP
Begin : $BEGIN_DATE
End : $END_DATE
Message : $TEXTE
END
)
echo "" if [ "${INTERACTIVE}" = "1" ] && [ "${AUTO}" = "0" ]; then
echo "${BLOB}" if [ "${HOOK_COMMIT}" = "1" ] || [ "${HOOK_MAIL}" = "1" ] || [ "${HOOK_DB}" = "1" ]; then
echo "" printf "\nActions to execute:\n"
echo "> Press <Enter> to submit, or <Ctrl+c> to cancel." if [ "${HOOK_COMMIT}" = "1" ]; then
read enter printf "* commit changes in repositories\n"
# write log
echo "----------- $(get_now) ---------------" >> "${LOGFILE}"
echo "${BLOB}" >> "${LOGFILE}"
# git commit
GIT_COMMITS=""
if test -x "${GIT_BIN}"; then
# loop on possible directories managed by GIT
for dir in ${GIT_REPOSITORIES}; do
# tell Git where to find the repository and the work tree (no need to `cd …` there)
export GIT_DIR="${dir}/.git" GIT_WORK_TREE="${dir}"
# If the repository and the work tree exist, try to commit changes
if test -d "${GIT_DIR}" && test -d "${GIT_WORK_TREE}"; then
CHANGED_LINES=$(${GIT_BIN} status --porcelain | wc -l | tr -d ' ')
if [ "${CHANGED_LINES}" != "0" ]; then
${GIT_BIN} add --all
${GIT_BIN} commit --message "${TEXTE}" --author="${USER} <${USER}@evolix.net>" --quiet
# Add the SHA to the log file if something has been committed
SHA=$(${GIT_BIN} rev-parse --short HEAD)
STATS=$(${GIT_BIN} show --stat | tail -1)
# append commit data, without empty lines
GIT_COMMITS=$(printf "%s\n%s : %s %s" "${GIT_COMMITS}" "${GIT_DIR}" "${SHA}" "${STATS}" | sed -e '/^$/d')
fi
fi fi
# unset environment variables to prevent accidental influence on other git commands if [ "${HOOK_MAIL}" = "1" ]; then
unset GIT_DIR GIT_WORK_TREE printf "* send mail to %s\n" "${EVOMAINTMAIL}"
done fi
if [ -n "${GIT_COMMITS}" ]; then if [ "${HOOK_DB}" = "1" ]; then
echo "${GIT_COMMITS}" >> "${LOGFILE}" printf "* save metadata to the database\n"
fi
if [ "${HOOK_API}" = "1" ]; then
printf "* send metadata to the API\n"
fi
echo ""
answer=""
while :; do
printf "> Let's continue? [Y,n,i,?] "
read -r answer
case $answer in
[Yy]|"" )
# force "auto" mode, but keep hooks settings
AUTO=1
break
;;
[Nn] )
# force "auto" mode, and disable all hooks
HOOK_COMMIT=0
HOOK_MAIL=0
HOOK_DB=0
HOOK_API=0
AUTO=1
break
;;
[Ii] )
# force "manual" mode
AUTO=0
break
;;
* )
printf "y - yes, execute actions and exit\n"
printf "n - no, don't execute actions and exit\n"
printf "i - switch to interactive mode\n"
printf "? - print this help\n"
;;
esac
done
fi fi
fi fi
# insert into PG if [ "${INTERACTIVE}" = "1" ] && [ "${AUTO}" = "0" ]; then
# SQL_TEXTE=`echo "${TEXTE}" | sed "s/'/\\\\\\'/g ; s@/@\\\\\/@g ; s@\\&@et@g"` # Commit hook
SQL_TEXTE=`echo "${TEXTE}" | sed "s/'/''/g"` if [ -n "${GIT_STATUSES}" ] && [ "${HOOK_COMMIT}" = "1" ]; then
printf "/!\ There are some uncommited changes.\n%s\n\n" "${GIT_STATUSES}"
PG_QUERY="INSERT INTO evomaint(hostname,userid,ipaddress,begin_date,end_date,details) VALUES ('${HOSTNAME}','${USER}','${IP}','${BEGIN_DATE}',now(),'${SQL_TEXTE}')" y="Y"; n="n"
echo "${PG_QUERY}" | psql ${PGDB} ${PGTABLE} -h ${PGHOST} --quiet answer=""
while :; do
printf "> Do you want to commit the changes? [%s] " "${y},${n}"
read -r answer
case $answer in
[Yy] )
hook_commit;
break
;;
[Nn] )
break
;;
"" )
if [ "${HOOK_COMMIT}" = "1" ]; then
hook_commit
fi
break
;;
* )
echo "answer with a valid choice"
;;
esac
done
fi
# send mail # Mail hook
MAIL_TEXTE=$(echo "${TEXTE}" | sed -e "s@/@\\\\\/@g ; s@&@\\\\&@") if [ "${HOOK_MAIL}" = "1" ]; then
MAIL_GIT_COMMITS=$(echo "${GIT_COMMITS}" | sed -e "s@/@\\\\\/@g ; s@&@\\\\&@") y="Y"; n="n"
else
y="y"; n="N"
fi
answer=""
while :; do
printf "> Do you want to send an email to <%s>? [%s] " "${EVOMAINTMAIL}" "${y},${n},e"
read -r answer
case $answer in
[Yy] )
hook_mail;
break
;;
[Nn] )
break
;;
[Ee] )
printf "> To: [%s] " "${EVOMAINTMAIL}"
read -r mail_recipient
if [ -n "${mail_recipient}" ]; then
EVOMAINTMAIL="${mail_recipient}"
fi
;;
"" )
if [ "${HOOK_MAIL}" = "1" ]; then
hook_mail
fi
break
;;
* )
echo "answer with a valid choice"
;;
esac
done
cat /usr/share/scripts/evomaintenance.tpl | \ # Database hook
sed -e "s/__TO__/${EVOMAINTMAIL}/ ; s/__HOSTNAME__/${HOSTNAME_TEXT}/ ; s/__USER__/${USER}/ ; s/__BEGIN_DATE__/${BEGIN_DATE}/ ; s/__END_DATE__/${END_DATE}/ ; s/__GIT_COMMITS__/${MAIL_GIT_COMMITS}/ ; s/__TEXTE__/${MAIL_TEXTE}/ ; s/__IP__/${IP}/ ; s/__FULLFROM__/${FULLFROM}/ ; s/__FROM__/${FROM}/ ; s/__URGENCYFROM__/${URGENCYFROM}/ ; s/__URGENCYTEL__/${URGENCYTEL}/" | \ if [ "${HOOK_DB}" = "1" ]; then
${SENDMAIL_BIN} -oi -t -f ${FROM} y="Y"; n="n"
else
y="y"; n="N"
fi
answer=""
while :; do
printf "> Do you want to insert your message into the database? [%s] " "${y},${n}"
read -r answer
case $answer in
[Yy] )
hook_db;
break
;;
[Nn] )
break
;;
"" )
if [ "${HOOK_DB}" = "1" ]; then
hook_db
fi
break
;;
* )
echo "answer with a valid choice"
;;
esac
done
# API hook
if [ "${HOOK_API}" = "1" ]; then
y="Y"; n="n"
else
y="y"; n="N"
fi
answer=""
while :; do
printf "> Do you want to send the metadata to the API? [%s] " "${y},${n}"
read -r answer
case $answer in
[Yy] )
hook_api;
break
;;
[Nn] )
break
;;
"" )
if [ "${HOOK_API}" = "1" ]; then
hook_api
fi
break
;;
* )
echo "answer with a valid choice"
;;
esac
done
fi
# Log hook
hook_log
if [ "${INTERACTIVE}" = "0" ] || [ "${AUTO}" = "1" ]; then
if [ "${HOOK_COMMIT}" = "1" ]; then
hook_commit
fi
if [ "${HOOK_MAIL}" = "1" ]; then
hook_mail
fi
if [ "${HOOK_DB}" = "1" ]; then
hook_db
fi
if [ "${HOOK_API}" = "1" ]; then
hook_api
fi
fi
exit 0 exit 0

View File

@ -0,0 +1,15 @@
# EvoBSD configuration file for newsyslog
#
# logfile_name owner:group mode count size when flags
/var/cron/log root:wheel 600 52 * $W1 Z
/var/log/authlog root:wheel 640 52 * $W1 Z
/var/log/daemon 640 365 * $D0 Z
/var/log/lpd-errs 640 7 * $D0 Z
/var/log/maillog 640 52 * $W1 Z
/var/log/messages 644 365 * $D0 Z
/var/log/secure 600 52 * $W1 Z
/var/log/wtmp 644 52 * $W1 B
/var/log/xferlog 640 7 * $D0 Z
/var/log/pflog 600 30 * $D0 ZB "pkill -HUP -u root -U root -t - -x pflogd"
/var/www/logs/access.log 644 52 * $W1 Z "pkill -USR1 -u root -U root -x httpd"
/var/www/logs/error.log 644 52 * $W1 Z "pkill -USR1 -u root -U root -x httpd"

View File

@ -1,27 +0,0 @@
# $OpenBSD: dot.profile,v 1.9 2010/12/13 12:54:31 millert Exp $
#
# sh/ksh initialization
PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin:/usr/local/sbin:/usr/local/bin
export PATH HOME TERM
export PS1="\u@\h:\w\\$ "
HISTFILE=$HOME/.histfile
export HISTSIZE=10000
export HISTCONTROL='ignoredups:ignorespace'
export TMOUT=36000
export PAGER=less
umask 022
export ENV='~/.kshrc'
case "$-" in
*i*) # interactive shell
if [ -x /usr/bin/tset ]; then
if [ X"$XTERM_VERSION" = X"" ]; then
eval `/usr/bin/tset -sQ '-munknown:?vt220' $TERM`
else
eval `/usr/bin/tset -IsQ '-munknown:?vt220' $TERM`
fi
fi
;;
esac

View File

@ -9,3 +9,4 @@ set smarttab
set backspace=indent,eol,start set backspace=indent,eol,start
set showcmd set showcmd
set encoding=utf-8 set encoding=utf-8
set mouse=""

View File

@ -1,222 +1,419 @@
#!/bin/sh #!/bin/sh
# #
# Script Evobackup plus ou moins forké # Script Evobackup client
# See https://forge.evolix.org/projects/evobackup # See https://gitea.evolix.org/evolix/evobackup
# #
# Author: Gregory Colpart <reg@evolix.fr>
# Contributors:
# Romain Dessort <rdessort@evolix.fr>
# Benoît Série <bserie@evolix.fr>
# Tristan Pilat <tpilat@evolix.fr>
# Victor Laborie <vlaborie@evolix.fr>
# Jérémy Lecour <jlecour@evolix.fr>
#
# Licence: AGPLv3
#
# /!\ DON'T FORGET TO SET "MAIL" and "SERVERS" VARIABLES
# Fail on unassigned variables
set -u
##### Configuration ###################################################
# email adress for notifications
MAIL=jdoe@example.com
# list of hosts (hostname or IP) and SSH port for Rsync
SERVERS="node0.backup.example.com:2XXX node1.backup.example.com:2XXX"
# Should we fallback on servers when the first is unreachable ?
SERVERS_FALLBACK=${SERVERS_FALLBACK:-1}
# timeout (in seconds) for SSH connections
SSH_CONNECT_TIMEOUT=${SSH_CONNECT_TIMEOUT:-30}
## We use /home/backup : feel free to use your own dir
LOCAL_BACKUP_DIR="/home/backup"
# You can set "linux" or "bsd" manually or let it choose automatically
SYSTEM=$(uname | tr '[:upper:]' '[:lower:]')
# Change these 2 variables if you have more than one backup cron
PIDFILE="/var/run/evobackup.pid"
LOGFILE="/var/log/evobackup.log"
## Enable/Disable tasks
LOCAL_TASKS=${LOCAL_TASKS:-1}
SYNC_TASKS=${SYNC_TASKS:-1}
##### SETUP AND FUNCTIONS #############################################
BEGINNING=$(/bin/date +"%d-%m-%Y ; %H:%M")
# shellcheck disable=SC2174
mkdir -p -m 700 ${LOCAL_BACKUP_DIR}
PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin
## lang = C for english outputs ## lang = C for english outputs
LANGUAGE=C export LANGUAGE=C
LANG=C export LANG=C
## Force umask ## Force umask
umask 077 umask 077
## Initialize variable to store SSH connection errors
SERVERS_SSH_ERRORS=""
# Call test_server with "HOST:PORT" string
# It will return with 0 if the server is reachable.
# It will return with 1 and a message on stderr if not.
test_server() {
item=$1
# split HOST and PORT from the input string
host=$(echo "${item}" | cut -d':' -f1)
port=$(echo "${item}" | cut -d':' -f2)
# Test if the server is accepting connections
ssh -q -o "ConnectTimeout ${SSH_CONNECT_TIMEOUT}" "${host}" -p "${port}" -t "exit"
# shellcheck disable=SC2181
if [ $? = 0 ]; then
# SSH connection is OK
return 0
else
# SSH connection failed
new_error=$(printf "Failed to connect to \`%s' within %s seconds" "${item}" "${SSH_CONNECT_TIMEOUT}")
SERVERS_SSH_ERRORS=$(printf "%s\n%s" "${SERVERS_SSH_ERRORS}" "${new_error}" | sed -e '/^$/d')
return 1
fi
}
# Call pick_server with an optional positive integer to get the nth server in the list.
pick_server() {
increment=${1:-0}
list_length=$(echo "${SERVERS}" | wc -w)
if [ "${increment}" -ge "${list_length}" ]; then
# We've reached the end of the list
new_error="No more server available"
SERVERS_SSH_ERRORS=$(printf "%s\n%s" "${SERVERS_SSH_ERRORS}" "${new_error}" | sed -e '/^$/d')
# Log errors to stderr
printf "%s\n" "${SERVERS_SSH_ERRORS}" >&2
# Log errors to logfile
printf "%s\n" "${SERVERS_SSH_ERRORS}" >> $LOGFILE
return 1
fi
# Extract the day of month, without leading 0 (which would give an octal based number)
today=$(date +%e)
# A salt is useful to randomize the starting point in the list
# but stay identical each time it's called for a server (based on hostname).
salt=$(hostname | cksum | cut -d' ' -f1)
# Pick an integer between 0 and the length of the SERVERS list
# It changes each day
item=$(( (today + salt + increment) % list_length ))
# cut starts counting fields at 1, not 0.
field=$(( item + 1 ))
echo "${SERVERS}" | cut -d' ' -f${field}
}
## Verify other evobackup process and kill if needed ## Verify other evobackup process and kill if needed
PIDFILE=/var/run/evobackup.pid if [ -e "${PIDFILE}" ]; then
if [ -e $PIDFILE ]; then pid=$(cat "${PIDFILE}")
# Killing the childs of evobackup. # Does process still exist ?
for pid in $(ps h --ppid $(cat $PIDFILE) -o pid | tr -s '\n' ' '); do if kill -0 ${pid} 2> /dev/null; then
kill -9 $pid; # Killing the childs of evobackup.
for ppid in $(pgrep -P "${pid}"); do
kill -9 "${ppid}";
done
# Then kill the main PID.
kill -9 "${pid}"
printf "%s is still running (PID %s). Process has been killed" "$0" "${pid}\n" >&2
else
rm -f ${PIDFILE}
fi
fi
echo "$$" > ${PIDFILE}
# shellcheck disable=SC2064
trap "rm -f ${PIDFILE}" EXIT
##### LOCAL BACKUP ####################################################
if [ "${LOCAL_TASKS}" = "1" ]; then
# You can comment or uncomment sections below to customize the backup
## OpenLDAP : example with slapcat
# slapcat -l ${LOCAL_BACKUP_DIR}/ldap.bak
## MySQL
## example with global and compressed mysqldump
# mysqldump --defaults-extra-file=/etc/mysql/debian.cnf -P 3306 \
# --opt --all-databases --force --events --hex-blob | gzip --best > ${LOCAL_BACKUP_DIR}/mysql.bak.gz
## example with two dumps for each table (.sql/.txt) for all databases
# for i in $(echo SHOW DATABASES | mysql --defaults-extra-file=/etc/mysql/debian.cnf -P 3306 \
# | egrep -v "^(Database|information_schema|performance_schema|sys)" ); \
# do mkdir -p -m 700 /home/mysqldump/$i ; chown -RL mysql /home/mysqldump ; \
# mysqldump --defaults-extra-file=/etc/mysql/debian.cnf --force -P 3306 -Q --opt --events --hex-blob --skip-comments \
# --fields-enclosed-by='\"' --fields-terminated-by=',' -T /home/mysqldump/$i $i; done
## example with SQL dump (schema only, no data) for each databases
# mkdir -p -m 700 /home/mysqldump/
# for i in $(mysql --defaults-extra-file=/etc/mysql/debian.cnf -P 3306 -e 'show databases' -s --skip-column-names \
# | egrep -v "^(Database|information_schema|performance_schema|sys)"); do
# mysqldump --defaults-extra-file=/etc/mysql/debian.cnf --force -P 3306 --no-data --databases $i > /home/mysqldump/${i}.schema.sql
# done
## example with compressed SQL dump (with data) for each databases
# mkdir -p -m 700 /home/mysqldump/
# for i in $(mysql --defaults-extra-file=/etc/mysql/debian.cnf -P 3306 -e 'show databases' -s --skip-column-names \
# | egrep -v "^(Database|information_schema|performance_schema|sys)"); do
# mysqldump --defaults-extra-file=/etc/mysql/debian.cnf --force -P 3306 --events --hex-blob $i | gzip --best > /home/mysqldump/${i}.sql.gz
# done
## example with *one* uncompressed SQL dump for *one* database (MYBASE)
# mkdir -p -m 700 /home/mysqldump/MYBASE
# chown -RL mysql /home/mysqldump/
# mysqldump --defaults-extra-file=/etc/mysql/debian.cnf --force -Q \
# --opt --events --hex-blob --skip-comments -T /home/mysqldump/MYBASE MYBASE
## example with mysqlhotcopy
# mkdir -p -m 700 /home/mysqlhotcopy/
# mysqlhotcopy BASE /home/mysqlhotcopy/
## example for multiples MySQL instances
# mysqladminpasswd=$(grep -m1 'password = .*' /root/.my.cnf|cut -d" " -f3)
# grep -E "^port\s*=\s*\d*" /etc/mysql/my.cnf |while read instance; do
# instance=$(echo "$instance"|awk '{ print $3 }')
# if [ "$instance" != "3306" ]
# then
# mysqldump -P $instance --opt --all-databases --hex-blob -u mysqladmin -p$mysqladminpasswd > ${LOCAL_BACKUP_DIR}/mysql.$instance.bak
# fi
# done
## PostgreSQL
## example with pg_dumpall (warning: you need space in ~postgres)
# su - postgres -c "pg_dumpall > ~/pg.dump.bak"
# mv ~postgres/pg.dump.bak ${LOCAL_BACKUP_DIR}/
## another method with gzip directly piped
# cd /var/lib/postgresql
# sudo -u postgres pg_dumpall | gzip > ${LOCAL_BACKUP_DIR}/pg.dump.bak.gz
# cd - > /dev/null
## example with all tables from MYBASE excepts TABLE1 and TABLE2
# pg_dump -p 5432 -h 127.0.0.1 -U USER --clean -F t --inserts -f ${LOCAL_BACKUP_DIR}/pg-backup.tar -t 'TABLE1' -t 'TABLE2' MYBASE
## example with only TABLE1 and TABLE2 from MYBASE
# pg_dump -p 5432 -h 127.0.0.1 -U USER --clean -F t --inserts -f ${LOCAL_BACKUP_DIR}/pg-backup.tar -T 'TABLE1' -T 'TABLE2' MYBASE
## MongoDB
## don't forget to create use with read-only access
## > use admin
## > db.createUser( { user: "mongobackup", pwd: "PASS", roles: [ "backup", ] } )
# test -d ${LOCAL_BACKUP_DIR}/mongodump/ && rm -rf ${LOCAL_BACKUP_DIR}/mongodump/
# mkdir -p -m 700 ${LOCAL_BACKUP_DIR}/mongodump/
# mongodump --quiet -u mongobackup -pPASS -o ${LOCAL_BACKUP_DIR}/mongodump/
# if [ $? -ne 0 ]; then
# echo "Error with mongodump!"
# fi
## Redis
## example with copy .rdb file
# cp /var/lib/redis/dump.rdb ${LOCAL_BACKUP_DIR}/
## ElasticSearch
## Take a snapshot as a backup.
## Warning: You need to have a path.repo configured.
## See: https://wiki.evolix.org/HowtoElasticsearch#snapshots-et-sauvegardes
# curl -s -XDELETE "localhost:9200/_snapshot/snaprepo/snapshot.daily" -o /tmp/es_delete_snapshot.daily.log
# curl -s -XPUT "localhost:9200/_snapshot/snaprepo/snapshot.daily?wait_for_completion=true" -o /tmp/es_snapshot.daily.log
## Clustered version here
## It basically the same thing except that you need to check that NFS is mounted
# if ss | grep ':nfs' | grep -q 'ip\.add\.res\.s1' && ss | grep ':nfs' | grep -q 'ip\.add\.res\.s2'
# then
# curl -s -XDELETE "localhost:9200/_snapshot/snaprepo/snapshot.daily" -o /tmp/es_delete_snapshot.daily.log
# curl -s -XPUT "localhost:9200/_snapshot/snaprepo/snapshot.daily?wait_for_completion=true" -o /tmp/es_snapshot.daily.log
# else
# echo 'Cannot make a snapshot of elasticsearch, at least one node is not mounting the repository.'
# fi
## If you need to keep older snapshot, for example the last 10 daily snapshots, replace the XDELETE and XPUT lines by :
# for snapshot in $(curl -s -XGET "localhost:9200/_snapshot/snaprepo/_all?pretty=true" | grep -Eo 'snapshot_[0-9]{4}-[0-9]{2}-[0-9]{2}' | head -n -10); do
# curl -s -XDELETE "localhost:9200/_snapshot/snaprepo/${snapshot}" | grep -v -Fx '{"acknowledged":true}'
# done
# date=$(date +%F)
# curl -s -XPUT "localhost:9200/_snapshot/snaprepo/snapshot_${date}?wait_for_completion=true" -o /tmp/es_snapshot_${date}.log
## RabbitMQ
## export config
#rabbitmqadmin export ${LOCAL_BACKUP_DIR}/rabbitmq.config >> $LOGFILE
## MegaCli config
#megacli -CfgSave -f ${LOCAL_BACKUP_DIR}/megacli_conf.dump -a0 >/dev/null
## Dump system and kernel versions
uname -a > ${LOCAL_BACKUP_DIR}/uname
## Dump network routes with mtr and traceroute (warning: could be long with aggressive firewalls)
for addr in 8.8.8.8 www.evolix.fr travaux.evolix.net; do
mtr -r ${addr} > ${LOCAL_BACKUP_DIR}/mtr-${addr}
traceroute -n ${addr} > ${LOCAL_BACKUP_DIR}/traceroute-${addr} 2>&1
done done
# Then kill the main PID.
kill -9 $(cat $PIDFILE) ## Dump process with ps
echo "$0 tourne encore (PID `cat $PIDFILE`). Processus killé" >&2 ps auwwx >${LOCAL_BACKUP_DIR}/ps.out
if [ "${SYSTEM}" = "linux" ]; then
## Dump network connections with ss
ss -taupen > ${LOCAL_BACKUP_DIR}/netstat.out
## List Debian packages
dpkg -l > ${LOCAL_BACKUP_DIR}/packages
dpkg --get-selections > ${LOCAL_BACKUP_DIR}/packages.getselections
apt-cache dumpavail > ${LOCAL_BACKUP_DIR}/packages.available
## Dump MBR / table partitions
disks=$(lsblk -l | grep disk | grep -v -E '(drbd|fd[0-9]+)' | awk '{print $1}')
for disk in ${disks}; do
dd if="/dev/${disk}" of="${LOCAL_BACKUP_DIR}/MBR-${disk}" bs=512 count=1 2>&1 | grep -Ev "(records in|records out|512 bytes)"
fdisk -l "/dev/${disk}" > "${LOCAL_BACKUP_DIR}/partitions-${disk}" 2>&1
done
cat ${LOCAL_BACKUP_DIR}/partitions-* > ${LOCAL_BACKUP_DIR}/partitions
## Dump iptables
if [ -x /sbin/iptables ]; then
{ /sbin/iptables -L -n -v; /sbin/iptables -t filter -L -n -v; } > ${LOCAL_BACKUP_DIR}/iptables.txt
fi
## Dump findmnt(8) output
FINDMNT_BIN=$(command -v findmnt)
if [ -x ${FINDMNT_BIN} ]; then
${FINDMNT_BIN} > ${LOCAL_BACKUP_DIR}/findmnt.txt
fi
else
## Dump network connections with netstat
netstat -finet -atn > ${LOCAL_BACKUP_DIR}/netstat.out
## List OpenBSD packages
pkg_info -m > ${LOCAL_BACKUP_DIR}/packages
## Dump MBR / table partitions
disklabel sd0 > ${LOCAL_BACKUP_DIR}/partitions
## Dump pf infos
pfctl -sa > ${LOCAL_BACKUP_DIR}/pfctl-sa.txt
fi
## Dump rights
#getfacl -R /var > ${LOCAL_BACKUP_DIR}/rights-var.txt
#getfacl -R /etc > ${LOCAL_BACKUP_DIR}/rights-etc.txt
#getfacl -R /usr > ${LOCAL_BACKUP_DIR}/rights-usr.txt
#getfacl -R /home > ${LOCAL_BACKUP_DIR}/rights-home.txt
fi fi
echo "$$" > $PIDFILE
trap "rm -f $PIDFILE" EXIT
# Variable to choose different backup server with date ##### REMOTE BACKUP ###################################################
NODE=$(expr `date +%d` % 2 + 2)
# port SSH n=0
SSH_PORT=2XXX server=""
if [ "${SERVERS_FALLBACK}" = "1" ]; then
# We try to find a suitable server
while :; do
server=$(pick_server "${n}")
test $? = 0 || exit 2
# email adress for notifications if test_server "${server}"; then
MAIL={{ general_alert_email }} break
else
# backup server used server=""
SRV=node$NODE.backup2.evolix.net n=$(( n + 1 ))
fi
# choose "linux" or "bsd" done
SYSTEME=$(uname | tr '[:upper:]' '[:lower:]')
## We use /home/backup : feel free to use your own dir
mkdir -p -m 700 /home/backup
## OpenLDAP : example with slapcat
# slapcat -l /home/backup/ldap.bak
### MySQL
## example with global and compressed mysqldump
# mysqldump --defaults-extra-file=/etc/mysql/debian.cnf -P 3306 \
# --opt --all-databases --force --events --hex-blob | gzip --best > /home/backup/mysql.bak.gz
## example with two dumps for each table (.sql/.txt) for all databases
# for i in $(echo SHOW DATABASES | mysql --defaults-extra-file=/etc/mysql/debian.cnf -P 3306 \
# | egrep -v "^(Database|information_schema|performance_schema)" ); \
# do mkdir -p /home/mysqldump/$i ; chown -RL mysql /home/mysqldump ; \
# mysqldump --defaults-extra-file=/etc/mysql/debian.cnf --force -P 3306 -Q --opt --events --hex-blob --skip-comments -T \
# /home/mysqldump/$i $i; done
## example with compressed SQL dump for each databases
# mkdir -p /home/mysqldump/
# for i in $(mysql --defaults-extra-file=/etc/mysql/debian.cnf -P 3306 -e 'show databases' -s --skip-column-names \
# | egrep -v "^(Database|information_schema|performance_schema)"); do
# mysqldump --defaults-extra-file=/etc/mysql/debian.cnf --force -P 3306 --events --hex-blob $i | gzip --best > /home/mysqldump/${i}.sql.gz
# done
## example with *one* uncompressed SQL dump for *one* database (MYBASE)
# mkdir -p -m 700 /home/mysqldump/MYBASE
# chown -RL mysql /home/mysqldump/
# mysqldump --defaults-extra-file=/etc/mysql/debian.cnf --force -Q \
# --opt --events --hex-blob --skip-comments -T /home/mysqldump/MYBASE MYBASE
## example with mysqlhotcopy
# mkdir -p /home/mysqlhotcopy/
# mysqlhotcopy BASE /home/mysqlhotcopy/
## example for multiples MySQL instances
# mysqladminpasswd=`cat /root/.my.cnf |grep -m1 'password = .*' |cut -d" " -f3`
# grep -E "^port\s*=\s*\d*" /etc/mysql/my.cnf |while read instance; do
# instance=$(echo $instance |tr -d '\t')
# instance=${instance// /}
# instance=${instance//port=/}
# if [ "$instance" != "3306" ]
# then
# mysqldump -P $instance --opt --all-databases --hex-blob -u mysqladmin -p$mysqladminpasswd > /home/backup/mysql.$instance.bak
# fi
# done
### PostgreSQL
## example with pg_dumpall (warning: you need space in ~postgres)
# su - postgres -c "pg_dumpall > ~/pg.dump.bak"
# mv ~postgres/pg.dump.bak /home/backup/
## example with all tables from MYBASE excepts TABLE1 and TABLE2
# pg_dump -p 5432 -h 127.0.0.1 -U USER --clean -F t --inserts -f /home/backup/pg-backup.tar -t 'TABLE1' -t 'TABLE2' MYBASE
## example with only TABLE1 and TABLE2 from MYBASE
# pg_dump -p 5432 -h 127.0.0.1 -U USER --clean -F t --inserts -f /home/backup/pg-backup.tar -T 'TABLE1' -T 'TABLE2' MYBASE
## MongoDB : example with mongodump
## don't forget to create use with read-only access
## > use admin
## > db.addUser("mongobackup", "PASS", true);
# mongodump -u mongobackup -pPASS -o /home/backup/mongodump/ >/dev/null 2>&1 |grep -v "^connected to:"
## Redis : example with copy .rdb file
# cp /var/lib/redis/dump.rdb /home/backup/
## ElasticSearch : example with rsync (warning: don't forget to use NFS if you have a cluster)
## Disable ES translog flush
# curl -s -XPUT 'localhost:9200/_settings' -d '{"index.translog.disable_flush": true}' >/dev/null
## Flushes translog
# curl -s 'localhost:9200/_flush' | grep -qe '"ok":true'
## If it succeed, do an rsync of the datadir
# if [ $? -eq 0 ]; then
# rsync -a /var/lib/elasticsearch /home/backup/
# else
# echo "Error when flushing ES translog indexes."
# fi
## In any case re-enable translog flush
# curl -s -XPUT 'localhost:9200/_settings' -d '{"index.translog.disable_flush": false}' > /dev/null
## Dump MBR / table partitions with dd and sfdisk
## Linux
# dd if=/dev/sda of=/home/backup/MBR bs=512 count=1 2>&1 | egrep -v "(records in|records out|512 bytes)"
# sfdisk -d /dev/sda > /home/backup/partitions 2>&1 | egrep -v "(Warning: extended partition does not start at a cylinder boundary|DOS and Linux will interpret the contents differently)"
## OpenBSD
# disklabel sd0 > /home/backup/partitions
# backup MegaCli config
#megacli -CfgSave -f /home/backup/megacli_conf.dump -a0 >/dev/null
## Dump network routes with mtr and traceroute (warning: could be long with aggressive firewalls)
for addr in 8.8.8.8 backup.evolix.net www.evolix.fr www.evolix.net; do
mtr -r $addr > /home/backup/mtr-${addr} 2>/dev/null
traceroute -n $addr > /home/backup/traceroute-${addr} 2>/dev/null
done
## Dump process with ps
ps aux >/home/backup/ps.out
if [ $SYSTEME = "linux" ]; then
## Dump network connections with netstat
netstat -taupen >/home/backup/netstat.out
## List Debian packages
dpkg -l >/home/backup/packages
else else
## Dump network connections with netstat # we force the server
netstat -finet -atn >/home/backup/netstat.out server=$(pick_server "${n}")
## List OpenBSD packages
pkg_info -m >/home/backup/packages
fi fi
SSH_SERVER=$(echo "${server}" | cut -d':' -f1)
SSH_PORT=$(echo "${server}" | cut -d':' -f2)
HOSTNAME=$(hostname) HOSTNAME=$(hostname)
DATE=$(/bin/date +"%d-%m-%Y") if [ "${SYSTEM}" = "linux" ]; then
DEBUT=$(/bin/date +"%d-%m-%Y ; %H:%M")
if [ $SYSTEME = "linux" ]; then
rep="/bin /boot /lib /opt /sbin /usr" rep="/bin /boot /lib /opt /sbin /usr"
else else
rep="/bsd /bin /sbin /usr" rep="/bsd /bin /sbin /usr"
fi fi
/usr/local/bin/rsync -avzh --stats --delete --delete-excluded --force --ignore-errors --partial \
--exclude "lost+found" \
--exclude ".nfs.*" \
--exclude "/var/log" \
--exclude "/var/log/evobackup*" \
--exclude "/var/lib/mysql" \
--exclude "/var/lib/postgres" \
--exclude "/var/lib/postgresql" \
--exclude "/var/lib/sympa" \
--exclude "/var/lib/metche" \
--exclude "/var/run" \
--exclude "/var/lock" \
--exclude "/var/state" \
--exclude "/var/apt" \
--exclude "/var/cache" \
--exclude "/usr/src" \
--exclude "/usr/doc" \
--exclude "/usr/share/doc" \
--exclude "/usr/obj" \
--exclude "dev" \
--exclude "/var/spool/postfix" \
--exclude "/var/lib/amavis/amavisd.sock" \
--exclude "/var/lib/munin/*tmp*" \
--exclude "/var/lib/php5" \
--exclude "/var/spool/squid" \
--exclude "/var/lib/elasticsearch" \
--exclude "/var/lib/amavis/tmp" \
--exclude "/var/lib/clamav/*.tmp" \
--exclude "/home/mysqltmp" \
$rep \
/etc \
/root \
/var \
/home \
-e "ssh -p $SSH_PORT" \
root@${SRV}:/var/backup/ \
| tail -30 >> /var/log/evobackup.log
FIN=$(/bin/date +"%d-%m-%Y ; %H:%M") if [ "${SYNC_TASKS}" = "1" ]; then
# /!\ DO NOT USE COMMENTS in the rsync command /!\
# It breaks the command and destroys data, simply remove (or add) lines.
echo "EvoBackup - $HOSTNAME - START $DEBUT" \ # Remote shell command
>> /var/log/evobackup.log RSH_COMMAND="ssh -p ${SSH_PORT} -o 'ConnectTimeout ${SSH_CONNECT_TIMEOUT}'"
echo "EvoBackup - $HOSTNAME - STOP $FIN" \ rsync -avzh --stats --delete --delete-excluded --force --ignore-errors --partial \
>> /var/log/evobackup.log --exclude "lost+found" \
--exclude ".nfs.*" \
--exclude "/var/log" \
--exclude "/var/log/evobackup*" \
--exclude "/var/lib/mysql" \
--exclude "/var/lib/postgres" \
--exclude "/var/lib/postgresql" \
--exclude "/var/lib/sympa" \
--exclude "/var/lib/metche" \
--exclude "/var/run" \
--exclude "/var/lock" \
--exclude "/var/state" \
--exclude "/var/apt" \
--exclude "/var/cache" \
--exclude "/usr/src" \
--exclude "/usr/doc" \
--exclude "/usr/share/doc" \
--exclude "/usr/obj" \
--exclude "dev" \
--exclude "/var/spool/postfix" \
--exclude "/var/lib/amavis/amavisd.sock" \
--exclude "/var/lib/munin/*tmp*" \
--exclude "/var/lib/php5" \
--exclude "/var/spool/squid" \
--exclude "/var/lib/elasticsearch" \
--exclude "/var/lib/amavis/tmp" \
--exclude "/var/lib/clamav/*.tmp" \
--exclude "/home/mysqltmp" \
--exclude "/var/lib/php/sessions" \
${rep} \
/etc \
/root \
/var \
/home \
-e "${RSH_COMMAND}" \
"root@${SSH_SERVER}:/var/backup/" \
| tail -30 >> $LOGFILE
fi
tail -10 /var/log/evobackup.log | \ ##### REPORTING #######################################################
mail -s "[info] EvoBackup - Client $HOSTNAME" \
$MAIL END=$(/bin/date +"%d-%m-%Y ; %H:%M")
printf "EvoBackup - %s - START %s ON %s (LOCAL_TASKS=%s SYNC_TASKS=%s)\n" \
"${HOSTNAME}" "${BEGINNING}" "${SSH_SERVER}" "${LOCAL_TASKS}" "${SYNC_TASKS}" \
>> $LOGFILE
printf "EvoBackup - %s - STOP %s ON %s (LOCAL_TASKS=%s SYNC_TASKS=%s)\n" \
"${HOSTNAME}" "${END}" "${SSH_SERVER}" "${LOCAL_TASKS}" "${SYNC_TASKS}" \
>> $LOGFILE
tail -10 $LOGFILE | \
mail -s "[info] EvoBackup - Client ${HOSTNAME}" \
${MAIL}

View File

@ -1,3 +1,33 @@
--- ---
- name: newaliases - name: newaliases
shell: smtpctl update table aliases shell: smtpctl update table aliases
- name: remount / noatime
command: mount -u -o noatime /
args:
warn: false
- name: remount /var noatime
command: mount -u -o noatime /var
args:
warn: false
- name: remount /usr noatime
command: mount -u -o noatime /usr
args:
warn: false
- name: remount /tmp noexec
command: mount -u -o noexec /tmp
args:
warn: false
- name: remount /tmp noatime
command: mount -u -o noatime /tmp
args:
warn: false
- name: remount /home noatime
command: mount -u -o noatime /home
args:
warn: false

19
roles/base/tasks/cron.yml Normal file
View File

@ -0,0 +1,19 @@
---
- name: Customize PATH variable of root crontab
cron:
name: PATH
env: true
value: "{{ cron_root_path }}"
tags:
- cron
- name: Customize daily.local environment
lineinfile:
path: /etc/daily.local
line: 'VERBOSESTATUS=0'
insertbefore: BOF
owner: root
mode: "0644"
create: true
tags:
- cron

View File

@ -6,8 +6,6 @@
owner: root owner: root
group: wheel group: wheel
mode: "0640" mode: "0640"
backup: no backup: false
tags: tags:
- doas - doas

View File

@ -1,7 +1,7 @@
--- ---
- name: Customize root's .profile - name: Customize root's .profile
copy: template:
src: profile src: profile.j2
dest: /root/.profile dest: /root/.profile
tags: tags:
- admin - admin
@ -26,8 +26,8 @@
- dotfiles - dotfiles
- name: Change default .profile skeleton - name: Change default .profile skeleton
copy: template:
src: profile src: profile.j2
dest: /etc/skel/.profile dest: /etc/skel/.profile
tags: tags:
- admin - admin
@ -39,10 +39,10 @@
dest: /etc/skel/.profile dest: /etc/skel/.profile
insertafter: EOF insertafter: EOF
line: 'trap "doas /usr/share/scripts/evomaintenance.sh" 0' line: 'trap "doas /usr/share/scripts/evomaintenance.sh" 0'
create: yes create: true
tags: tags:
- admin - admin
- dotfiles - dotfiles
- name: Add vim configuration to dotfiles for new users - name: Add vim configuration to dotfiles for new users
copy: copy:

View File

@ -6,7 +6,16 @@
owner: root owner: root
group: wheel group: wheel
mode: "0755" mode: "0755"
force: no force: false
tags:
- evobackup
- name: Fetch daily.local content
command: 'grep "sh /usr/share/scripts/zzz_evobackup" /etc/daily.local'
check_mode: false
register: daily_local_content
failed_when: false
changed_when: false
tags: tags:
- evobackup - evobackup
@ -16,5 +25,18 @@
line: '#sh /usr/share/scripts/zzz_evobackup' line: '#sh /usr/share/scripts/zzz_evobackup'
owner: root owner: root
mode: "0644" mode: "0644"
create: true
when:
- not (daily_local_content.stdout
| regex_search('sh /usr/share/scripts/zzz_evobackup'))
tags:
- evobackup
- name: Delete evobackup root crontab replaced by daily.local cron
lineinfile:
path: /var/cron/tabs/root
regexp: '/usr/share/scripts/zzz_evobackup'
validate: /usr/bin/crontab %s
state: absent
tags: tags:
- evobackup - evobackup

View File

@ -10,10 +10,15 @@
- evomaintenance - evomaintenance
- name: Copy evomaintenance script and template - name: Copy evomaintenance script and template
copy: src={{ item.src }} dest={{ item.dest }} owner=root group=wheel mode="0755" copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
owner: 'root'
group: 'wheel'
mode: '0755'
with_items: with_items:
- { src: 'evomaintenance.sh', dest: '/usr/share/scripts/' } - {src: 'evomaintenance.sh', dest: '/usr/share/scripts/'}
- { src: 'evomaintenance.tpl', dest: '/usr/share/scripts/' } - {src: 'evomaintenance.tpl', dest: '/usr/share/scripts/'}
tags: tags:
- evomaintenance - evomaintenance
- script-evomaintenance - script-evomaintenance
@ -25,27 +30,6 @@
owner: root owner: root
group: wheel group: wheel
mode: "0600" mode: "0600"
backup: no backup: false
tags: tags:
- evomaintenance - evomaintenance
- name: Copy mailevomaintenance
template:
src: mailevomaintenance.sh.j2
dest: /usr/share/scripts/mailevomaintenance.sh
owner: root
group: wheel
mode: "0700"
tags:
- evomaintenance
- mailevomaintenance
- name: Add mailevomaintenance cron
cron:
name: "mailevomaintenance"
job: "/usr/share/scripts/mailevomaintenance.sh"
minute: "50"
hour: "22"
disabled: yes
tags:
- mailevomaintenance

138
roles/base/tasks/fstab.yml Normal file
View File

@ -0,0 +1,138 @@
---
- name: Fetch fstab content
command: "grep -v '^#' /etc/fstab"
check_mode: false
register: fstab_content
failed_when: false
changed_when: false
tags:
- fstab
- name: / partition is customized - softdep
replace:
dest: /etc/fstab
regexp: '([^#]\s+/\s+ffs\s+rw)(.*)'
replace: '\1,softdep\2'
when:
- fstab_content.stdout | regex_search('\s/\s')
- not (fstab_content.stdout | regex_search('\s+/\s+ffs\s+rw,softdep'))
tags:
- fstab
- name: / partition is customized - noatime
replace:
dest: /etc/fstab
regexp: '([^#]\s+/\s+ffs\s+rw)(\S*)(\s+.*)'
replace: '\1\2,noatime\3'
notify: remount / noatime
when:
- fstab_content.stdout | regex_search('\s/\s')
- not (fstab_content.stdout | regex_search('\s+/\s+ffs\s+rw\S*noatime'))
tags:
- fstab
- name: /var partition is customized - softdep
replace:
dest: /etc/fstab
regexp: '([^#]\s+/var\s+ffs\s+rw)(.*)'
replace: '\1,softdep\2'
when:
- fstab_content.stdout | regex_search('\s/var\s')
- not (fstab_content.stdout | regex_search('\s+/var\s+ffs\s+rw,softdep'))
tags:
- fstab
- name: /var partition is customized - noatime
replace:
dest: /etc/fstab
regexp: '([^#]\s+/var\s+ffs\s+rw)(\S*)(\s+.*)'
replace: '\1\2,noatime\3'
notify: remount /var noatime
when:
- fstab_content.stdout | regex_search('\s/var\s')
- not (fstab_content.stdout | regex_search('\s+/var\s+ffs\s+rw\S*noatime'))
tags:
- fstab
- name: /usr partition is customized - softdep
replace:
dest: /etc/fstab
regexp: '([^#]\s+/usr\s+ffs\s+rw)(.*)'
replace: '\1,softdep\2'
when:
- fstab_content.stdout | regex_search('\s/usr\s')
- not (fstab_content.stdout | regex_search('\s+/usr\s+ffs\s+rw,softdep'))
tags:
- fstab
- name: /usr partition is customized - noatime
replace:
dest: /etc/fstab
regexp: '([^#]\s+/usr\s+ffs\s+rw)(\S*)(\s+.*)'
replace: '\1\2,noatime\3'
notify: remount /usr noatime
when:
- fstab_content.stdout | regex_search('\s/usr\s')
- not (fstab_content.stdout | regex_search('\s+/usr\s+ffs\s+rw\S*noatime'))
tags:
- fstab
- name: /tmp partition is customized - noexec
replace:
dest: /etc/fstab
regexp: '([^#]\s+/tmp\s+ffs\s+rw(,softdep)*)(.*)'
replace: '\1,noexec\3'
notify: remount /tmp noexec
when:
- fstab_content.stdout | regex_search('\s/tmp\s')
- not (fstab_content.stdout
| regex_search('\s+/tmp\s+ffs\s+rw,(softdep,)*noexec'))
tags:
- fstab
- name: /tmp partition is customized - softdep
replace:
dest: /etc/fstab
regexp: '([^#]\s+/tmp\s+ffs\s+rw)(.*)'
replace: '\1,softdep\2'
when:
- fstab_content.stdout | regex_search('\s/tmp\s')
- not (fstab_content.stdout
| regex_search('\s+/tmp\s+ffs\s+rw,(noexec,)*softdep'))
tags:
- fstab
- name: /tmp partition is customized - noatime
replace:
dest: /etc/fstab
regexp: '([^#]\s+/tmp\s+ffs\s+rw)(\S*)(\s+.*)'
replace: '\1\2,noatime\3'
notify: remount /tmp noatime
when:
- fstab_content.stdout | regex_search('\s/tmp\s')
- not (fstab_content.stdout | regex_search('\s+/tmp\s+ffs\s+rw\S*noatime'))
tags:
- fstab
- name: /home partition is customized - softdep
replace:
dest: /etc/fstab
regexp: '([^#]\s+/home\s+ffs\s+rw)(.*)'
replace: '\1,softdep\2'
when:
- fstab_content.stdout | regex_search('\s/home\s')
- not (fstab_content.stdout | regex_search('\s+/home\s+ffs\s+rw,softdep'))
tags:
- fstab
- name: /home partition is customized - noatime
replace:
dest: /etc/fstab
regexp: '([^#]\s+/home\s+ffs\s+rw)(\S*)(\s+.*)'
replace: '\1\2,noatime\3'
notify: remount /home noatime
when:
- fstab_content.stdout | regex_search('\s/home\s')
- not (fstab_content.stdout | regex_search('\s+/home\s+ffs\s+rw\S*noatime'))
tags:
- fstab

View File

@ -1,9 +1,32 @@
--- ---
- name: Fetch rc.local content
command: "grep -v '^#' /etc/rc.local"
check_mode: false
register: rclocal_content
failed_when: false
changed_when: false
tags:
- misc
- name: Configure rc.local - name: Configure rc.local
lineinfile: lineinfile:
path: /etc/rc.local path: /etc/rc.local
line: 'date | mail -s "boot/reboot of $(hostname -s)" {{ general_alert_email }}' line:
create: yes 'date | mail -s "boot/reboot of $(hostname -s)" {{ general_alert_email }}'
insertbefore: 'echo'
create: true
when:
- not (rclocal_content.stdout
| regex_search('date \| mail -s (\"|\')boot/reboot of \$\(hostname -s\)'))
tags:
- misc
- name: Delete rc.local entry of boot/reboot not precising hostname
lineinfile:
path: /etc/rc.local
regexp:
"^.* mail -s (?!.*of.*).+$"
state: absent
tags: tags:
- misc - misc
@ -12,7 +35,7 @@
dest: /etc/mail/aliases dest: /etc/mail/aliases
regexp: "# root:" regexp: "# root:"
replace: "root: {{ general_alert_email }}" replace: "root: {{ general_alert_email }}"
backup: no backup: false
notify: notify:
- newaliases - newaliases
tags: tags:

View File

@ -7,3 +7,6 @@
- include: mail.yml - include: mail.yml
- include: sudo.yml - include: sudo.yml
- include: evobackup.yml - include: evobackup.yml
- include: newsyslog.yml
- include: cron.yml
- include: fstab.yml

View File

@ -0,0 +1,7 @@
---
- name: Customize newsyslog
copy:
src: newsyslog.conf
dest: /etc/newsyslog.conf
tags:
- newsyslog

View File

@ -9,23 +9,20 @@
- name: Install packages (vim rsync mtr etc) - name: Install packages (vim rsync mtr etc)
openbsd_pkg: openbsd_pkg:
name: "{{ item }}" name:
state: present - wget
with_items: - vim--no_x11
- wget - rsync--
- vim--no_x11 - mtr--
- rsync-- - iftop
- mtr-- - sudo--
- iftop
- postgresql-client
tags: tags:
- pkg - pkg
- name: Install sudo - name: Disable sndiod
openbsd_pkg: service:
name: "{{ item }}" name: sndiod
state: present enabled: false
with_items: state: stopped
- sudo--
tags: tags:
- pkg - pkg

View File

@ -1,14 +1,32 @@
--- ---
# dont't break the tab! - name: Configure sudoers umask
lineinfile:
dest: /etc/sudoers
insertafter: '# Defaults specification'
line: 'Defaults umask=0077'
validate: 'visudo -cf %s'
tags:
- sudo
- name: Allow wheel group to run command as root in sudo - name: Allow wheel group to run command as root in sudo
lineinfile: lineinfile:
dest: /etc/sudoers dest: /etc/sudoers
insertafter: '# and set environment variables.' insertafter: '# and set environment variables.'
line: '%wheel ALL=(ALL) SETENV: ALL' line: "%wheel\tALL=(ALL) SETENV: ALL"
validate: 'visudo -cf %s' validate: 'visudo -cf %s'
backup: no backup: false
tags: tags:
- sudo - sudo
- name: Delete line with space instead of tab
lineinfile:
dest: /etc/sudoers
line: "%wheel ALL=(ALL) SETENV: ALL"
validate: 'visudo -cf %s'
backup: false
state: absent
tags:
- sudo
- name: Configure sudoers for evomaintenance and monitoring - name: Configure sudoers for evomaintenance and monitoring
blockinfile: blockinfile:
@ -18,12 +36,8 @@
block: | block: |
Cmnd_Alias MAINT = /usr/share/scripts/evomaintenance.sh Cmnd_Alias MAINT = /usr/share/scripts/evomaintenance.sh
%wheel ALL=NOPASSWD: MAINT %wheel ALL=NOPASSWD: MAINT
_nrpe ALL=(root) NOPASSWD: /usr/local/libexec/nagios/plugins/check_ipsecctl.sh %evolinux-sudo ALL=(ALL) SETENV: ALL
_nrpe ALL=(root) NOPASSWD: /usr/local/libexec/nagios/check_mailq
_nrpe ALL=(root) NOPASSWD: /usr/local/libexec/nagios/plugins/check_ospfd_simple
validate: 'visudo -cf %s' validate: 'visudo -cf %s'
backup: no backup: false
tags: tags:
- sudo - sudo

View File

@ -1,11 +1,18 @@
# {{ ansible_managed }} # {{ ansible_managed }}
permit setenv {ENV PS1 SSH_AUTH_SOCK SSH_TTY} :wheel permit setenv {SSH_AUTH_SOCK SSH_TTY PKG_PATH HOME=/root ENV=/root/.profile} :{{ evobsd_sudo_group }}
permit nopass root permit nopass root
permit setenv {ENV PS1 SSH_AUTH_SOCK SSH_TTY} nopass :wheel as root cmd /usr/share/scripts/evomaintenance.sh permit setenv {ENV PS1 SSH_AUTH_SOCK SSH_TTY} nopass :{{ evobsd_ssh_group }} as root cmd /usr/share/scripts/evomaintenance.sh
permit nopass _nrpe cmd /usr/local/libexec/nagios/check_ipsecctl.sh permit nopass _collectd as root cmd /bin/cat
permit nopass _nrpe as root cmd /sbin/bioctl args sd2
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/check_openbgpd
permit nopass _collectd as root cmd /usr/sbin/bgpctl permit nopass _collectd as root cmd /usr/sbin/bgpctl
permit nopass _nrpe as root cmd /sbin/bioctl args sd2
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/check_mailq
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/check_dhcp
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_ipsecctl.sh
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_ospfd_simple
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_ospfd permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_ospfd
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_ospf6d permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_ospf6d
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_openbgpd
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_pf_states permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_pf_states
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_connections_state.sh
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_packetfilter.sh
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_ipsecctl_critiques.sh

View File

@ -1,13 +1,20 @@
HOSTNAME={{ evomaintenance_hostname }} HOSTNAME={{ evomaintenance_hostname }}
EVOMAINTMAIL={{ evomaintenance_alert_email or general_alert_email | mandatory }} EVOMAINTMAIL={{ evomaintenance_alert_email or general_alert_email | mandatory }}
export PGPASSWORD={{ evomaintenance_pg_passwd | mandatory }} export PGPASSWORD={{ evomaintenance_pg_passwd }}
PGDB={{ evomaintenance_pg_db | mandatory }} PGDB={{ evomaintenance_pg_db }}
PGTABLE={{ evomaintenance_pg_table | mandatory }} PGTABLE={{ evomaintenance_pg_table }}
PGHOST={{ evomaintenance_pg_host | mandatory }} PGHOST={{ evomaintenance_pg_host }}
FROM={{ evomaintenance_from }} FROM={{ evomaintenance_from }}
FULLFROM="{{ evomaintenance_full_from }}" FULLFROM="{{ evomaintenance_full_from }}"
URGENCYFROM={{ evomaintenance_urgency_from }} URGENCYFROM={{ evomaintenance_urgency_from }}
URGENCYTEL="{{ evomaintenance_urgency_tel }}" URGENCYTEL="{{ evomaintenance_urgency_tel }}"
REALM="{{ evomaintenance_realm }}" REALM="{{ evomaintenance_realm }}"
API_ENDPOINT={{ evomaintenance_api_endpoint }}
API_KEY={{ evomaintenance_api_key }}
HOOK_API={{ evomaintenance_hook_api | bool | ternary('1','0') }}
HOOK_DB={{ evomaintenance_hook_db | bool | ternary('1','0') }}
HOOK_COMMIT={{ evomaintenance_hook_commit | bool | ternary('1','0') }}
HOOK_MAIL={{ evomaintenance_hook_mail | bool | ternary('1','0') }}

View File

@ -1,28 +0,0 @@
#!/bin/sh
set -eu
cd /etc && _STATUS=$(/usr/local/bin/git status --porcelain)
[ -n "${_STATUS}" ] || exit 0
if [ -e /etc/realname ]; then
_HOSTNAME=$(/bin/cat /etc/realname)
else
_HOSTNAME=$(/bin/hostname)
fi
TMPFILE=$(/usr/bin/mktemp) || exit 1
echo "Dear NOC,\n\nSome changes in /etc/ were not committed." >> $TMPFILE
echo "" >> $TMPFILE
echo "${_STATUS}" >> $TMPFILE
echo "" >> $TMPFILE
/usr/bin/last | head -n 10 >> $TMPFILE
echo "" >> $TMPFILE
echo "Please answer this mail to notify people when you've corrected the problem." >> $TMPFILE
/bin/cat $TMPFILE | mail -s "Verif etc-git ${_HOSTNAME}" noc@{{ evomaintenance_realm }}
/bin/rm $TMPFILE

View File

@ -0,0 +1,56 @@
# $OpenBSD: dot.profile,v 1.5 2018/02/02 02:29:54 yasuoka Exp $
#
# sh/ksh initialization
PATH="{{ evobsd_path }}"
export PATH HOME TERM
export PS1="\u@\h:\w\\$ "
HISTFILE=$HOME/.histfile
export HISTSIZE=10000
export HISTCONTROL='ignoredups:ignorespace'
export TMOUT=36000
export PAGER=less
umask 022
export ENV='~/.kshrc'
case "$-" in
*i*) # interactive shell
if [ -x /usr/bin/tset ]; then
if [ X"$XTERM_VERSION" = X"" ]; then
eval `/usr/bin/tset -sQ '-munknown:?vt220' $TERM`
else
eval `/usr/bin/tset -IsQ '-munknown:?vt220' $TERM`
fi
fi
;;
esac
PKG_LIST=$(ls -1 /var/db/pkg)
set -A complete_kill_1 -- -9 -HUP -INFO -KILL -TERM
pgrep -q vmd
if [ $? = 0 ]; then
set -A complete_vmctl -- console load reload start stop reset status
set -A complete_vmctl_2 -- $(vmctl status | awk '!/NAME/{print $NF}')
fi
if [ -d ~/.password-store ]; then
PASS_LIST=$(
cd ~/.password-store
find . -type f -name \*.gpg | sed 's/^\.\///' | sed 's/\.gpg$//g'
)
set -A complete_pass -- $PASS_LIST -c generate edit insert git
set -A complete_pass_2 -- $PASS_LIST push
fi
set -A complete_pkg_delete -- $PKG_LIST
set -A complete_pkg_info -- $PKG_LIST
set -A complete_rcctl_1 -- disable enable get ls order set reload check restart stop start
set -A complete_rcctl_2 -- $(ls /etc/rc.d)
set -A complete_signify_1 -- -C -G -S -V
set -A complete_signify_2 -- -q -p -x -c -m -t -z
set -A complete_signify_3 -- -p -x -c -m -t -z
set -A complete_make_1 -- install clean repackage reinstall
set -A complete_gpg2 -- --refresh --receive-keys --armor --clearsign --sign --list-key --decrypt --verify --detach-sig
set -A complete_git -- pull push mpull mpush status clone branch add rm checkout fetch show tag commit
set -A complete_ifconfig_1 -- $(ifconfig | grep ^[a-z] | cut -d: -f1)

14
roles/bgp/README.md Normal file
View File

@ -0,0 +1,14 @@
# BGP
Deployment of BGP check script with its cron, and a best route log cron.
## Tasks
Everything is in the `tasks/main.yml` file.
## Available variables
The full list of variables (with default values) can be found in `defaults/main.yml`.
* `bgp_mailto` : email address the output of the script will be sent to when a change is detected
* `bgp_exclude_grep_command` : facultative grep -v command for some peers not to be checked

View File

@ -0,0 +1,3 @@
---
bgp_mailto: "foobar@example.com"
bgp_exclude_grep_command: ""

52
roles/bgp/tasks/main.yml Normal file
View File

@ -0,0 +1,52 @@
---
- name: Deploy bgp check script
template:
src: bgpd-check-peers.sh.j2
dest: /usr/share/scripts/bgpd-check-peers.sh
when: group_names | select('search','bgp') | list | count > 0
tags:
- bgp
- name: Cron job for bgp check script is installed
cron:
name: bgp check
job: "/bin/sh /usr/share/scripts/bgpd-check-peers.sh"
when: group_names | select('search','bgp') | list | count > 0
tags:
- bgp
- name: Create bgp log directory
file:
path: /var/log/bgp
state: directory
when: group_names | select('search','bgp') | list | count > 0
tags:
- bgp
- name: daily best routes cron job is installed
cron:
name: bgp best routes
minute: 0
hour: 4
job: >
/usr/sbin/bgpctl show rib selected
> /var/log/bgp/rib-selected-$(date +\%F)
when: group_names | select('search','bgp') | list | count > 0
tags:
- bgp
- name: weekly best routes clean up cron job is installed
cron:
name: bgp best routes clean up
minute: 0
hour: 4
weekday: 0
job: >
/usr/bin/find /var/log/bgp/
-type f
-name "rib-selected-*"
-mtime +30
-exec rm {} \+
when: group_names | select('search','bgp') | list | count > 0
tags:
- bgp

View File

@ -0,0 +1,117 @@
#!/bin/ksh
# Script writen by Daniel Jakots
# First we go through the list of neighbor and we write all the peer and
# their status in "${_TMPDIR}"/bgp-status.
# Then we monitor if this file has changed between now and the previous run.
# If it did, we send a mail with the states of the different sessions.
set -u
PATH=$HOME/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:.
_MAILTO="{{ bgp_mailto }}"
_TMPDIR=/tmp/check-bgp
_PIDFILE="${_TMPDIR}"/bgpd-check-peers.pid
if [ -e /etc/realname ]; then
_REALNAME=$(cat /etc/realname)
_HOSTNAME=$(hostname -s)
else
_HOSTNAME=$(hostname)
fi
mkdir -p "${_TMPDIR}"
# Don't try to run if it's already running
if [ -e "${_PIDFILE}" ]; then
echo "$(date)" >> "${_TMPDIR}"/log
exit 1
else
echo $$ >> "${_PIDFILE}"
fi
# Create an history
if [[ -f "${_TMPDIR}"/bgp-status ]] ; then
mv "${_TMPDIR}"/bgp-status "${_TMPDIR}"/bgp-status.old
else
touch "${_TMPDIR}"/bgp-status
touch "${_TMPDIR}"/bgp-status.old
fi
# List peers and loops on them to list them and their BGP state
bgpctl show neighbor | grep Description {{ bgp_exclude_grep_command }} | sed s,\ Description:\ ,,g > "${_TMPDIR}"/peers-list
while read _PEER
do
_STATUS=$(/usr/sbin/bgpctl show neighbor "${_PEER}" | grep state | awk '{print $4}' |tr -d ',')
echo -n "${_PEER}" >> "${_TMPDIR}"/bgp-status
echo -n " " >> "${_TMPDIR}"/bgp-status
# we note only if it's established or not
if ! [[ "${_STATUS}" = "Established" ]] ; then
_STATUS="NotEstablished"
fi
echo "${_STATUS}" >> "${_TMPDIR}"/bgp-status
done <"${_TMPDIR}"/peers-list
# Check for difference with previous run
different=$(diff -q "${_TMPDIR}"/bgp-status.old "${_TMPDIR}"/bgp-status)
if ! [[ -n "${different}" ]] ; then
rm -f "${_PIDFILE}"
exit 0
fi
# It changed so we're going to send a mail
_TMPMAILDIR="${_TMPDIR}"/mail
mkdir -p "${_TMPMAILDIR}"
# go through sessions and list them depending on their BGP state
echo "*** Session(s) OK ***\n" >> "${_TMPMAILDIR}"/bodyok
while read _LINE
do
# _LINE is session + status
_STATUS=$(echo "${_LINE##* }")
_SESSION=$(echo "${_LINE}" | awk '{$NF=""}1')
if [[ "${_STATUS}" = "Established" ]] ; then
bgpctl show | grep "${_SESSION}" >> "${_TMPMAILDIR}"/bodyok
else
bgpctl show | grep "${_SESSION}" >> "${_TMPMAILDIR}"/bodynok
fi
done <"${_TMPDIR}"/bgp-status
# create the mail body
echo "Dear NOC,\n\nThe state of one or more BGP session(s) has changed:\n" > "${_TMPMAILDIR}"/header
cat "${_TMPMAILDIR}"/header "${_TMPMAILDIR}"/bodyok > "${_TMPMAILDIR}"/body
_STATE="OK"
if [[ -f "${_TMPMAILDIR}"/bodynok ]] ; then
_STATE="NOT OK"
echo "\n*** Session(s) on error ***\n" >> "${_TMPMAILDIR}"/body
cat "${_TMPMAILDIR}"/bodynok >> "${_TMPMAILDIR}"/body
fi
# show a diff
echo "" >> "${_TMPMAILDIR}"/body
echo "Diff is " >> "${_TMPMAILDIR}"/body
diff -U0 "${_TMPDIR}"/bgp-status.old "${_TMPDIR}"/bgp-status >> "${_TMPMAILDIR}"/body
# Send the mail whether we have a realname or not
if [ -n "${_REALNAME}" ]; then
cat "${_TMPMAILDIR}"/body | mail -s "[BGP] ${_REALNAME} (${_HOSTNAME}) - State change - ${_STATE}" "${_MAILTO}"
else
cat "${_TMPMAILDIR}"/body | mail -s "[BGP] ${_HOSTNAME} - State change" "${_MAILTO}"
fi
# cleaning
if [[ -d "${_TMPMAILDIR}" ]] ; then
rm -rf "${_TMPMAILDIR}"
fi
rm -f "${_PIDFILE}"

13
roles/collectd/README.md Normal file
View File

@ -0,0 +1,13 @@
# Collectd
Installation and custom configuration of Collectd daemon.
## Tasks
Everything is in the `tasks/main.yml` file.
## Available variables
The full list of variables (with default values) can be found in `defaults/main.yml`.
* `collectd_server` : server to which the data will be sent (default: 127.0.0.1).

View File

@ -0,0 +1,31 @@
---
# destination server
collectd_server: "127.0.0.1"
# execution interval
collectd_interval: "300"
# exec plugin
collectd_plugin_exec_interval: "{{ collectd_interval }}"
collectd_plugin_exec_ifq_drops: false
collectd_plugin_exec_dns_stats: false # Based on unbound
collectd_plugin_exec_dns_stats_interval: "{{ collectd_interval }}"
# others plugins
collectd_plugin_cpu: true
collectd_plugin_df: true
collectd_plugin_disk: true
collectd_plugin_interface: true
collectd_plugin_load: true
collectd_plugin_memory: true
collectd_plugin_pf: true
collectd_plugin_processes: true
collectd_plugin_swap: true
collectd_plugin_tcpconns: true
collectd_plugin_uptime: true
collectd_plugin_users: true

View File

@ -0,0 +1,3 @@
#!/bin/ksh
echo "PUTVAL $(hostname)/dns_stats/count N:$(doas /bin/cat /var/log/daemon | grep "server stats" | grep -v "requestlist max" | awk '{print $13}' | tail -1)"

View File

@ -0,0 +1,3 @@
#!/bin/ksh
echo "PUTVAL $(hostname)/ifq_drops/count N:$(sysctl net.inet.ip.arpq.drops | awk -F= '{print $NF}')"

View File

@ -0,0 +1,10 @@
---
- name: restart collectd
service:
name: collectd
state: restarted
- name: reload unbound
service:
name: unbound
state: reloaded

View File

@ -0,0 +1,97 @@
---
- name: Install Collectd package
openbsd_pkg:
name: "collectd"
tags:
- collectd
- name: Deploy Collectd configuration
template:
src: "collectd.conf.j2"
dest: "/etc/collectd.conf"
notify: restart collectd
tags:
- collectd
- name: Enabling Collectd
service:
name: collectd
enabled: true
tags:
- collectd
- name: Create scripts directory for exec plugins
file:
path: /usr/local/share/collectd/scripts
state: directory
when: collectd_plugin_exec_ifq_drops or collectd_plugin_exec_dns_stats
tags:
- collectd
- name: Copy ifq_drops.sh
copy:
src: ifq_drops.sh
dest: /usr/local/share/collectd/scripts/ifq_drops.sh
mode: 0755
force: true
when: collectd_plugin_exec_ifq_drops
tags:
- collectd
- name: Remove ifq_drops.sh
file:
path: /usr/local/share/collectd/scripts/ifq_drops.sh
state: absent
when: not collectd_plugin_exec_ifq_drops
tags:
- collectd
- name: Copy dns_stats.sh
copy:
src: dns_stats.sh
dest: /usr/local/share/collectd/scripts/dns_stats.sh
mode: 0755
force: true
when: collectd_plugin_exec_dns_stats
tags:
- collectd
- name: Add stats DNS on unbound
lineinfile:
path: /var/unbound/etc/unbound.conf
regexp: 'statistics-interval'
line:
' statistics-interval: {{ collectd_plugin_exec_dns_stats_interval }}'
insertafter: 'hide-version:'
backup: true
notify: reload unbound
when: collectd_plugin_exec_dns_stats
tags:
- collectd
- name: Remove dns_stats.sh
file:
path: /usr/local/share/collectd/scripts/dns_stats.sh
state: absent
when: not collectd_plugin_exec_dns_stats
tags:
- collectd
- name: Remove stats DNS on unbound
lineinfile:
path: /var/unbound/etc/unbound.conf
regexp: 'statistics-interval'
backup: true
state: absent
notify: reload unbound
when: not collectd_plugin_exec_dns_stats
tags:
- collectd
- name: Add doas configuration for dns_stats.sh execution
lineinfile:
path: /etc/doas.conf
line: 'permit nopass _collectd as root cmd /bin/cat'
when: collectd_plugin_exec_dns_stats
tags:
- collectd

View File

@ -0,0 +1,122 @@
Interval {{ collectd_interval }}
Timeout 2
LoadPlugin syslog
<Plugin syslog>
LogLevel warning
</Plugin>
{% if (collectd_plugin_exec_ifq_drops is sameas true) or (collectd_plugin_exec_dns_stats is sameas true) %}
<LoadPlugin exec>
Interval {{ collectd_plugin_exec_interval }}
</LoadPlugin>
<Plugin exec>
{% if collectd_plugin_exec_ifq_drops is sameas true %}
Exec "_collectd" "/usr/local/share/collectd/scripts/ifq_drops.sh"
{% endif %}
{% if collectd_plugin_exec_dns_stats is sameas true %}
Exec "_collectd" "/usr/local/share/collectd/scripts/dns_stats.sh"
{% endif %}
</Plugin>
{% endif %}
{% if collectd_plugin_load is sameas true %}
LoadPlugin load
{% endif %}
{% if collectd_plugin_processes is sameas true %}
LoadPlugin processes
{% endif %}
{% if collectd_plugin_uptime is sameas true %}
LoadPlugin uptime
{% endif %}
{% if collectd_plugin_users is sameas true %}
LoadPlugin users
{% endif %}
{% if collectd_plugin_pf is sameas true %}
LoadPlugin pf
{% endif %}
{% if collectd_plugin_df is sameas true %}
LoadPlugin df
<Plugin df>
# expose host's mounts into container using -v /:/host:ro (location inside container does not matter much)
# ignore rootfs; else, the root file-system would appear twice, causing
# one of the updates to fail and spam the log
## Seems to be fixed with collectd 5.5+
## FSType rootfs
# ignore the usual virtual / temporary file-systems
FSType sysfs
FSType proc
FSType devtmpfs
FSType devpts
FSType tmpfs
FSType fusectl
FSType cgroup
FSType overlay
FSType debugfs
FSType pstore
FSType securityfs
FSType hugetlbfs
FSType squashfs
FSType mqueue
IgnoreSelected true
ReportByDevice false
ReportInodes true # Default false
ValuesAbsolute true
ValuesPercentage true
</Plugin>
{% endif %}
{% if collectd_plugin_disk is sameas true %}
LoadPlugin disk
<Plugin "disk">
#Disk "/^[hsv]d[a-z]/"
IgnoreSelected false
</Plugin>
{% endif %}
{% if collectd_plugin_cpu is sameas true %}
LoadPlugin cpu
<Plugin cpu>
ValuesPercentage true
</Plugin>
{% endif %}
{% if collectd_plugin_memory is sameas true %}
LoadPlugin memory
<Plugin memory>
ValuesPercentage true
</Plugin>
{% endif %}
{% if collectd_plugin_swap is sameas true %}
LoadPlugin swap
<Plugin swap>
ValuesPercentage true
</Plugin>
{% endif %}
{% if collectd_plugin_interface is sameas true %}
LoadPlugin interface
<Plugin interface>
Interface "/^lo[0-9]*/"
Interface "/^veth.*/"
Interface "/^docker.*/"
IgnoreSelected true
ReportInactive false
</Plugin>
{% endif %}
{% if collectd_plugin_tcpconns is sameas true %}
LoadPlugin tcpconns
<Plugin "tcpconns">
AllPortsSummary true
</Plugin>
{% endif %}
LoadPlugin network
<Plugin "network">
Server "{{ collectd_server }}" "25826"
</Plugin>

View File

@ -1,4 +1,4 @@
--- ---
commit_message: Ansible run commit_message: Ansible run
etc_git_monitor_status: True etc_git_monitor_status: true

View File

@ -3,20 +3,20 @@
command: git status --porcelain command: git status --porcelain
args: args:
chdir: /etc chdir: /etc
changed_when: False changed_when: false
register: git_status register: git_status
when: not ansible_check_mode when: not ansible_check_mode
ignore_errors: yes ignore_errors: true
tags: tags:
- etc-git - etc-git
- commit-etc - commit-etc
- debug: - debug:
var: git_status var: git_status
verbosity: 3 verbosity: 3
tags: tags:
- etc-git - etc-git
- commit-etc - commit-etc
- name: fetch current Git user.email - name: fetch current Git user.email
git_config: git_config:
@ -24,33 +24,49 @@
repo: /etc repo: /etc
scope: local scope: local
register: git_config_user_email register: git_config_user_email
ignore_errors: yes ignore_errors: true
tags: tags:
- etc-git - etc-git
- commit-etc - commit-etc
- name: set commit author - name: set commit author
set_fact: set_fact:
commit_author: '{% if ansible_env.SUDO_USER is not defined %}root{% else %}{{ ansible_env.SUDO_USER }}{% endif %}' commit_author: >
commit_email: '{% if git_config_user_email.config_value is not defined or git_config_user_email.config_value == "" %}root@localhost{% else %}{{ git_config_user_email.config_value }}{% endif %}' {% if ansible_env.SUDO_USER is not defined %}
root
{% else %}
{{ ansible_env.SUDO_USER }}
{% endif %}
commit_email: >
{% if git_config_user_email.config_value is not defined
or git_config_user_email.config_value == "" %}
root@localhost
{% else %}
{{ git_config_user_email.config_value }}
{% endif %}
tags: tags:
- etc-git - etc-git
- commit-etc - commit-etc
- name: /etc modifications are committed - name: /etc modifications are committed
shell: "git add -A . && git commit -m \"{{ commit_message | mandatory }}\" --author \"{{ commit_author | mandatory }} <{{ commit_email | mandatory }}>\"" shell: >
git add -A .
&& git commit
-m "{{ commit_message | mandatory }}"
--author
"{{ commit_author | mandatory }} <{{ commit_email | mandatory }}>"
args: args:
chdir: /etc chdir: /etc
register: etc_commit_end_run register: etc_commit_end_run
when: not ansible_check_mode and git_status.stdout != "" when: not ansible_check_mode and git_status.stdout != ""
ignore_errors: yes ignore_errors: true
tags: tags:
- etc-git - etc-git
- commit-etc - commit-etc
- debug: - debug:
var: etc_commit_end_run var: etc_commit_end_run
verbosity: 4 verbosity: 4
tags: tags:
- etc-git - etc-git
- commit-etc - commit-etc

View File

@ -12,7 +12,7 @@
args: args:
chdir: /etc chdir: /etc
creates: /etc/.git/ creates: /etc/.git/
warn: no warn: false
register: git_init register: git_init
tags: tags:
- etc-git - etc-git
@ -22,7 +22,7 @@
name: user.email name: user.email
repo: /etc repo: /etc
scope: local scope: local
value: "root@{{ ansible_fqdn | default('localhost') }}" value: "root@{{ inventory_hostname }}.{{ general_technical_realm }}"
tags: tags:
- etc-git - etc-git
@ -48,11 +48,11 @@
command: "git log" command: "git log"
args: args:
chdir: /etc chdir: /etc
warn: no warn: false
changed_when: False changed_when: false
failed_when: False failed_when: false
register: git_log register: git_log
check_mode: no check_mode: false
tags: tags:
- etc-git - etc-git
@ -60,7 +60,7 @@
shell: "git add -A . && git commit -m \"Initial commit via Ansible\"" shell: "git add -A . && git commit -m \"Initial commit via Ansible\""
args: args:
chdir: /etc chdir: /etc
warn: no warn: false
register: git_commit register: git_commit
when: git_log.rc != 0 or (git_init is defined and git_init.changed) when: git_log.rc != 0 or (git_init is defined and git_init.changed)
tags: tags:
@ -72,17 +72,31 @@
line: '/usr/local/bin/git --git-dir /etc/.git gc --quiet' line: '/usr/local/bin/git --git-dir /etc/.git gc --quiet'
owner: root owner: root
mode: "0644" mode: "0644"
create: yes create: true
tags: tags:
- etc-git - etc-git
- name: cron job for /etc/.git status is installed - name: cron job for /etc/.git status is installed
lineinfile: lineinfile:
path: /etc/daily.local path: /etc/daily.local
line: '/usr/local/bin/git --git-dir=/etc/.git --work-tree=/etc status --short' line:
'/usr/local/bin/git --git-dir=/etc/.git --work-tree=/etc status --short'
owner: root owner: root
mode: "0644" mode: "0644"
create: yes create: true
when: etc_git_monitor_status
tags:
- etc-git
- name: cron job for /etc/.git status is installed - next_part
lineinfile:
path: /etc/daily.local
line: 'next_part "Checking /etc git status:"'
insertbefore:
'/usr/local/bin/git --git-dir=/etc/.git --work-tree=/etc status --short'
owner: root
mode: "0644"
create: true
when: etc_git_monitor_status when: etc_git_monitor_status
tags: tags:
- etc-git - etc-git
@ -90,10 +104,13 @@
- name: cron job for /etc/.git status is removed - name: cron job for /etc/.git status is removed
lineinfile: lineinfile:
path: /etc/daily.local path: /etc/daily.local
line: '/usr/local/bin/git --git-dir=/etc/.git --work-tree=/etc status --short' line: "{{ item }}"
owner: root owner: root
mode: "0644" mode: "0644"
state: absent state: absent
with_items:
- 'next_part "Checking /etc git status:"'
- '/usr/local/bin/git --git-dir=/etc/.git --work-tree=/etc status --short'
when: not etc_git_monitor_status when: not etc_git_monitor_status
tags: tags:
- etc-git - etc-git
@ -102,7 +119,13 @@
cron: cron:
name: git status name: git status
minute: 42 minute: 42
job: "who > /dev/null || /usr/local/bin/git --git-dir=/etc/.git --work-tree=/etc status --short" job: >
who
> /dev/null
|| /usr/local/bin/git
--git-dir=/etc/.git
--work-tree=/etc
status --short
when: etc_git_monitor_status when: etc_git_monitor_status
tags: tags:
- etc-git - etc-git
@ -111,7 +134,13 @@
cron: cron:
name: git status name: git status
minute: 42 minute: 42
job: "who > /dev/null || /usr/local/bin/git --git-dir=/etc/.git --work-tree=/etc status --short" job: >
who
> /dev/null
|| /usr/local/bin/git
--git-dir=/etc/.git
--work-tree=/etc
status --short
state: absent state: absent
when: not etc_git_monitor_status when: not etc_git_monitor_status
tags: tags:

13
roles/evocheck/README.md Normal file
View File

@ -0,0 +1,13 @@
# evocheck
Install and run evocheck ; a script for checking various settings automatically.
## Tasks
A separate `exec.yml` file can be imported manually in playbooks or roles to execute the script. Example :
```
- include_role:
name: evolix/evocheck
tasks_from: exec.yml
```

View File

@ -0,0 +1,2 @@
---
evocheck_bin_dir: /usr/share/scripts

View File

@ -0,0 +1,5 @@
# Managed by Ansible
#
# Configuration for evocheck
# Use this file to change configuration values defined in evocheck.sh
# Ex : IS_TMP_1777=0

View File

@ -0,0 +1,437 @@
#!/bin/sh
# EvoCheck
# Script to verify compliance of an OpenBSD server powered by Evolix
readonly VERSION="6.7.7"
# Disable LANG*
export LANG=C
export LANGUAGE=C
# Default return code : 0 = no error
RC=0
# Verbose function
verbose() {
msg="${1:-$(cat /dev/stdin)}"
[ "${VERBOSE}" -eq 1 ] && [ -n "${msg}" ] && echo "${msg}"
}
# Source configuration file
test -f /etc/evocheck.cf && . /etc/evocheck.cf
# Functions
show_help() {
cat <<END
NAME:
evocheck - a system configuration verification tool
VERSION:
${VERSION}
DESCRIPTION:
A script that verifies Evolix conventions on OpenBSD servers
AUTHORS:
Benoit Serie <bserie@evolix.fr>
Gregory Colpart <reg@evolix.fr>
Jeremy Dubois <jdubois@evolix.fr>
Jeremy Lecour <jlecour@evolix.fr>
Ludovic Poujol <lpoujol@evolix.fr>
Romain Dessort <rdessort@evolix.fr>
Tristan Pilat <tpilat@evolix.fr>
Victor Laborie <vlaborie@evolix.fr>
USAGE: evocheck
or evocheck --cron
or evocheck --quiet
or evocheck --verbose
OPTIONS:
--cron disable a few checks
-v, --verbose increase verbosity of checks
-q, --quiet nothing is printed on stdout nor stderr
-h, --help, --version print this message and exit
COPYRIGHT:
evocheck comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
See the GNU General Public License v3.0 for details. 2009-2020
END
}
is_installed(){
for pkg in "$@"; do
pkg_info | grep -q $pkg || return 1
done
}
# logging
failed() {
check_name=$1
shift
check_comments=$*
RC=1
if [ "${QUIET}" != 1 ]; then
if [ -n "${check_comments}" ] && [ "${VERBOSE}" = 1 ]; then
printf "%s FAILED! %s\n" "${check_name}" "${check_comments}" 2>&1
else
printf "%s FAILED!\n" "${check_name}" 2>&1
fi
fi
}
# If --cron is passed, ignore some checks.
if [ "$1" = "--cron" ]; then
IS_KERNELUPTODATE=0
IS_UPTIME=0
fi
check_umasksudoers(){
grep -E -qr "umask=0077" /etc/sudoers* || failed "IS_UMASKSUDOERS" "sudoers must set umask to 0077"
}
check_tmpnoexec(){
mount | grep "on /tmp" | grep -q noexec || failed "IS_TMPNOEXEC" "/tmp should be mounted with the noexec option"
}
check_softdep(){
if [ $(grep -c softdep /etc/fstab) -ne $(grep -c ffs /etc/fstab) ]; then
failed "IS_SOFTDEP" "All partitions should have the softdep option"
fi
}
check_noatime(){
if [ $(mount | grep -c noatime) -ne $(grep -c ffs /etc/fstab) ]; then
failed "IS_NOATIME" "All partitions should be mounted with the noatime option"
fi
}
check_tmoutprofile(){
grep -q TMOUT= /etc/skel/.profile /root/.profile || failed "IS_TMOUTPROFILE" "In order to fix, add 'export TMOUT=36000' to both /etc/skel/.profile and /root/.profile files"
}
check_raidok(){
egrep 'sd.*RAID' /var/run/dmesg.boot 1> /dev/null 2>&1
RESULT=$?
if [ $RESULT -eq 0 ]; then
raid_device=$(egrep 'sd.*RAID' /var/run/dmesg.boot | awk '{ print $1 }' | tail -1)
raid_status=$(bioctl $raid_device | grep softraid | awk '{ print $3 }')
if [ $raid_status != "Online" ]; then
failed "IS_RAIDOK" "One of the RAID disk members is faulty. Use bioctl -h $raid_device for more informations"
fi
fi
}
check_evobackup(){
if [ -f /etc/daily.local ]; then
grep -qE "^sh /usr/share/scripts/zzz_evobackup" /etc/daily.local || failed "IS_EVOBACKUP" "Make sure 'sh /usr/share/scripts/zzz_evobackup' is present and activated in /etc/daily.local"
else
failed "IS_EVOBACKUP" "Make sure /etc/daily.local exists and 'sh /usr/share/scripts/zzz_evobackup' is present and activated in /etc/daily.local"
fi
}
check_uptodate(){
if [ $(command -v syspatch) ]; then
if syspatch -c | egrep "." 1> /dev/null 2>&1; then
failed "IS_UPTODATE" "Security update available! Update with syspatch(8)!"
fi
fi
}
check_uptime(){
if [ $(uptime | cut -d" " -f 4) -gt 365 ]; then
failed "IS_UPTIME" "The server is running for more than a year!"
fi
}
check_backupuptodate(){
backup_dir="/home/backup"
if [ -d "${backup_dir}" ]; then
if [ -n "$(ls -A ${backup_dir})" ]; then
for file in ${backup_dir}/*; do
let "limit = $(date +"%s") - 172800"
updated_at=$(stat -f "%m" "$file")
if [ -f "$file" ] && [ "$limit" -gt "$updated_at" ]; then
failed "IS_BACKUPUPTODATE" "$file has not been backed up"
test "${VERBOSE}" = 1 || break;
fi
done
else
failed "IS_BACKUPUPTODATE" "${backup_dir}/ is empty"
fi
else
failed "IS_BACKUPUPTODATE" "${backup_dir}/ is missing"
fi
}
check_gitperms(){
test -d /etc/.git && [ "$(stat -f %p /etc/.git/)" = "40700" ] || failed "IS_GITPERMS" "The directiry /etc/.git sould be in 700"
}
check_advbase(){
if ls /etc/hostname.carp* 1> /dev/null 2>&1; then
bad_advbase=0
for advbase in $(ifconfig carp | grep advbase | awk -F 'advbase' '{print $2}' | awk '{print $1}' | xargs); do
if [[ "$advbase" -gt 5 ]]; then
bad_advbase=1
fi
done
if [[ "$bad_advbase" -eq 1 ]]; then
failed "IS_ADVBASE" "At least one CARP interface has advbase greater than 5 seconds!"
fi
fi
}
check_preempt(){
if ls /etc/hostname.carp* 1> /dev/null 2>&1; then
preempt=$(sysctl net.inet.carp.preempt | cut -d"=" -f2)
if [[ "$preempt" -ne 1 ]]; then
failed "IS_PREEMPT" "The preempt function is not activated! Please type 'sysctl net.inet.carp.preempt=1' in"
fi
if [ -f /etc/sysctl.conf ]; then
grep -qE "^net.inet.carp.preempt=1" /etc/sysctl.conf || failed "IS_PREEMPT" "The preempt parameter is not permanently activated! Please add 'net.inet.carp.preempt=1' in /etc/sysctl.conf"
else
failed "IS_PREEMPT" "Make sure /etc/sysctl.conf exists and contains the line 'net.inet.carp.preempt=1'"
fi
fi
}
check_rebootmail(){
if [ -f /etc/rc.local ]; then
grep -qE '^date \| mail -s "boot/reboot of' /etc/rc.local || failed "IS_REBOOTMAIL" "Make sure the line 'date | mail -s \"boot/reboot of \$hostname' is present in the /etc/rc.local file!"
else
failed "IS_REBOOTMAIL" "Make sure /etc/rc.local exist and 'date | mail -s \"boot/reboot of \$hostname' is present!"
fi
}
check_pfenabled(){
if pfctl -si | grep Disabled 1> /dev/null 2>&1; then
failed "IS_PFENABLED" "PF is disabled! Make sure pf=NO is absent from /etc/rc.conf.local and carefully run pfctl -e"
fi
}
check_pfcustom(){
}
check_wheel(){
if [ -f /etc/sudoers ]; then
grep -qE "^%wheel.*$" /etc/sudoers || failed "IS_WHEEL" ""
fi
}
check_pkgmirror(){
grep -qE "^https://cdn\.openbsd\.org/pub/OpenBSD" /etc/installurl || failed "IS_PKGMIRROR" "Check whether the right repo is present in the /etc/installurl file"
}
check_history(){
file=/root/.profile
grep -qE "^HISTFILE=\$HOME/.histfile" $file && grep -qE "^export HISTSIZE=10000" $file || failed "IS_HISTORY" "Make sure both 'HISTFILE=$HOME/.histfile' and 'export HISTSIZE=10000' are present in /root/.profile"
}
check_vim(){
if ! is_installed vim; then
failed "IS_VIM" "vim is not installed! Please add with pkg_add vim"
fi
}
check_ttyc0secure(){
grep -Eqv "^ttyC0.*secure$" /etc/ttys || failed "IS_TTYC0SECURE" "First tty should be secured"
}
check_customsyslog(){
grep -q EvoBSD /etc/newsyslog.conf || failed "IS_CUSTOMSYSLOG" ""
}
check_sudomaint(){
file=/etc/sudoers
grep -q "Cmnd_Alias MAINT = /usr/share/scripts/evomaintenance.sh" $file \
&& grep -q "%wheel ALL=NOPASSWD: MAINT" $file \
|| failed "IS_SUDOMAINT" ""
}
check_nrpe(){
if ! is_installed monitoring-plugins || ! is_installed nrpe; then
failed "IS_NRPE" "nrpe and/or monitoring-plugins are not installed! Please add with pkg_add nrpe monitoring-plugins"
fi
}
check_rsync(){
if ! is_installed rsync; then
failed "IS_RSYNC" "rsync is not installed! Please add with pkg_add rsync"
fi
}
check_cronpath(){
grep -q "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/usr/share/scripts" /var/cron/tabs/root || failed "IS_CRONPATH" ""
}
check_tmp1777(){
ls -ld /tmp | grep -q drwxrwxrwt || failed "IS_TMP_1777" ""
}
check_root0700(){
ls -ld /root | grep -q drwx------ || failed "IS_ROOT_0700" ""
}
check_usrsharescripts(){
ls -ld /usr/share/scripts | grep -q drwx------ || failed "IS_USRSHARESCRIPTS" ""
}
check_sshpermitrootno() {
grep -qE ^PermitRoot /etc/ssh/sshd_config && ( grep -E -qi "PermitRoot.*no" /etc/ssh/sshd_config || failed "IS_SSHPERMITROOTNO" "" )
}
check_evomaintenanceusers(){
# Can be changed in evocheck.cf
homeDir=${homeDir:-/home}
sudoers="/etc/sudoers"
for i in $( (grep "^User_Alias *ADMIN" $sudoers | cut -d= -f2 | tr -d " "; grep ^sudo /etc/group |cut -d: -f 4) | tr "," "\n" |sort -u); do
grep -qs "^trap.*sudo.*evomaintenance.sh" ${homeDir}/${i}/.*profile
if [ $? != 0 ]; then
failed "IS_EVOMAINTENANCEUSERS" "$i doesn't have evomaintenance trap!"
fi
done
}
check_evomaintenanceconf(){
file=/etc/evomaintenance.cf
( test -e $file \
&& test $(stat -f %p $file) = "100600" \
&& grep "^export PGPASSWORD" $file |grep -qv "your-passwd" \
&& grep "^PGDB" $file |grep -qv "your-db" \
&& grep "^PGTABLE" $file |grep -qv "your-table" \
&& grep "^PGHOST" $file |grep -qv "your-pg-host" \
&& grep "^FROM" $file |grep -qv "jdoe@example.com" \
&& grep "^FULLFROM" $file |grep -qv "John Doe <jdoe@example.com>" \
&& grep "^URGENCYFROM" $file |grep -qv "mama.doe@example.com" \
&& grep "^URGENCYTEL" $file |grep -qv "06.00.00.00.00" \
&& grep "^REALM" $file |grep -qv "example.com" ) || failed "IS_EVOMAINTENANCECONF" ""
}
check_sync(){
if ifconfig carp | grep carp 1> /dev/null 2>&1; then
sync_script=/usr/share/scripts/sync.sh
if [ ! -f $sync_script ]; then
failed "IS_SYNC" "The sync.sh script is absent! As a carp member, a sync.sh script should be present in /usr/share/scripts"
fi
fi
}
check_defaultroute(){
if [ -f /etc/mygate ]; then
file_route=$(cat /etc/mygate)
used_route=$(route -n show -priority 8 | grep default | awk '{print $2}')
if [ "$file_route" != "$used_route" ]; then
failed "IS_DEFAULTROUTE" "The default route in /etc/mygate is different from the one currently used"
fi
else
failed "IS_DEFAULTROUTE" "The file /etc/mygate does not exist. Make sure you have the same default route in this file as the one currently in use."
fi
}
check_ntp(){
if grep -q "server ntp.evolix.net" /etc/ntpd.conf; then
if [ $(wc -l /etc/ntpd.conf | awk '{print $1}') -ne 1 ]; then
failed "IS_NTP" "The /etc/ntpd.conf file should only contains \"server ntp.evolix.net\"."
fi
else
failed "IS_NTP" "The configuration in /etc/ntpd.conf is not compliant. It should contains \"server ntp.evolix.net\"."
fi
}
check_openvpncronlog(){
if /etc/rc.d/openvpn check > /dev/null 2>&1; then
grep -q 'cp /var/log/openvpn.log /var/log/openvpn.log.$(date +\\%F) && echo "$(date +\\%F. .\\%R) - logfile turned over via cron" > /var/log/openvpn.log && gzip /var/log/openvpn.log.$(date +\\%F) && find /var/log/ -type f -name "openvpn.log.\*" -mtime .365 -exec rm {} \\+' /var/cron/tabs/root || failed "IS_OPENVPNCRONLOG" "OpenVPN is enabled but there is no log rotation in the root crontab, or the cron is not up to date (OpenVPN log rotation in newsyslog is not used because a restart is needed)."
fi
}
main() {
# Default return code : 0 = no error
RC=0
test "${IS_UMASKSUDOERS:=1}" = 1 && check_umasksudoers
test "${IS_TMPNOEXEC:=1}" = 1 && check_tmpnoexec
test "${IS_SOFTDEP:=1}" = 1 && check_softdep
test "${IS_NOATIME:=1}" = 1 && check_noatime
test "${IS_TMOUTPROFILE:=1}" = 1 && check_tmoutprofile
test "${IS_RAIDOK:=1}" = 1 && check_raidok
test "${IS_EVOBACKUP:=1}" = 1 && check_evobackup
test "${IS_UPTODATE:=1}" = 1 && check_uptodate
test "${IS_UPTIME:=1}" = 1 && check_uptime
test "${IS_BACKUPUPTODATE:=1}" = 1 && check_backupuptodate
test "${IS_GITPERMS:=1}" = 1 && check_gitperms
test "${IS_ADVBASE:=1}" = 1 && check_advbase
test "${IS_PREEMPT:=1}" = 1 && check_preempt
test "${IS_REBOOTMAIL:=1}" = 1 && check_rebootmail
test "${IS_PFENABLED:=1}" = 1 && check_pfenabled
test "${IS_PFCUSTOM:=1}" = 1 && check_pfcustom
test "${IS_WHEEL:=1}" = 1 && check_wheel
test "${IS_PKGMIRROR:=1}" = 1 && check_pkgmirror
test "${IS_HISTORY:=1}" = 1 && check_history
test "${IS_VIM:=1}" = 1 && check_vim
test "${IS_TTYC0SECURE:=1}" = 1 && check_ttyc0secure
test "${IS_CUSTOMSYSLOG:=1}" = 1 && check_customsyslog
test "${IS_SUDOMAINT:=1}" = 1 && check_sudomaint
test "${IS_NRPE:=1}" = 1 && check_nrpe
test "${IS_RSYNC:=1}" = 1 && check_rsync
test "${IS_CRONPATH:=1}" = 1 && check_cronpath
test "${IS_TMP_1777:=1}" = 1 && check_tmp1777
test "${IS_ROOT_0700:=1}" = 1 && check_root0700
test "${IS_USRSHARESCRIPTS:=1}" = 1 && check_usrsharescripts
test "${IS_SSHPERMITROOTNO:=1}" = 1 && check_sshpermitrootno
test "${IS_EVOMAINTENANCEUSERS:=1}" = 1 && check_evomaintenanceusers
test "${IS_EVOMAINTENANCECONF:=1}" = 1 && check_evomaintenanceconf
test "${IS_SYNC:=1}" = 1 && check_sync
test "${IS_DEFAULTROUTE:=1}" = 1 && check_defaultroute
test "${IS_NTP:=1}" = 1 && check_ntp
test "${IS_OPENVPNCRONLOG:=1}" = 1 && check_openvpncronlog
exit ${RC}
}
# Parse options
# based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
while :; do
case $1 in
-h|-\?|--help|--version)
show_help
exit 0
;;
--cron)
IS_KERNELUPTODATE=0
IS_UPTIME=0
;;
-v|--verbose)
VERBOSE=1
;;
-q|--quiet)
QUIET=1
VERBOSE=0
;;
--)
# End of all options.
shift
break
;;
-?*|[[:alnum:]]*)
# ignore unknown options
printf 'WARN: Unknown option (ignored): %s\n' "$1" >&2
;;
*)
# Default case: If no more options then break out of the loop.
break
;;
esac
shift
done
main ${ARGS}

View File

@ -0,0 +1,15 @@
---
- name: run evocheck
command: "{{ evocheck_bin_dir }}/evocheck.sh"
register: evocheck_run
changed_when: false
failed_when: false
check_mode: false
tags:
- evocheck-exec
- debug:
var: evocheck_run.stdout_lines
when: evocheck_run.stdout != ""
tags:
- evocheck-exec

View File

@ -0,0 +1,49 @@
---
- name: Scripts dir is present
file:
path: "{{ evocheck_bin_dir }}"
state: directory
owner: root
group: wheel
mode: "0700"
tags:
- evocheck
- name: Copy evocheck.sh
copy:
src: evocheck.sh
dest: "{{ evocheck_bin_dir }}/evocheck.sh"
mode: "0700"
owner: root
force: true
tags:
- evocheck
- name: Copy evocheck.cf
copy:
src: evocheck.cf
dest: /etc/evocheck.cf
force: false
tags:
- evocheck
- name: Add evocheck cron
lineinfile:
path: /etc/daily.local
line: 'sh /usr/share/scripts/evocheck.sh --verbose --cron'
owner: root
mode: "0644"
create: true
tags:
- evocheck
- name: Add evocheck cron next_part
lineinfile:
path: /etc/daily.local
line: 'next_part "Evocheck output:"'
insertbefore: 'sh /usr/share/scripts/evocheck.sh --verbose --cron'
owner: root
mode: "0644"
create: true
tags:
- evocheck

View File

@ -0,0 +1,2 @@
---
- include: install.yml

View File

@ -4,7 +4,7 @@
name: net.inet.ip.forwarding name: net.inet.ip.forwarding
value: 1 value: 1
state: present state: present
reload: yes reload: true
tags: tags:
- net - net
@ -13,6 +13,6 @@
name: net.inet6.ip6.forwarding name: net.inet6.ip6.forwarding
value: 1 value: 1
state: present state: present
reload: yes reload: true
tags: tags:
- net - net

View File

@ -8,6 +8,6 @@ Everything is in the `tasks/main.yml` file.
## Available variables ## Available variables
* `nagios_nrpe_allowed_hosts` : list of IP/hosts authorized (default: none). * `nagios_nrpe_allowed_hosts` : list of IP/hosts authorized (default: none).
The full list of variables (with default values) can be found in `defaults/main.yml`. The full list of variables (with default values) can be found in `defaults/main.yml`.

View File

@ -2,7 +2,8 @@
evolix_trusted_ips: [] evolix_trusted_ips: []
additional_trusted_ips: [] additional_trusted_ips: []
# Let's merge evolix_trusted_ips with additional_trusted_ips # Let's merge evolix_trusted_ips with additional_trusted_ips
nagios_nrpe_allowed_hosts: "{{ evolix_trusted_ips | union(additional_trusted_ips) | unique }}" nagios_nrpe_allowed_hosts:
"{{ evolix_trusted_ips | union(additional_trusted_ips) | unique }}"
nagios_nrpe_ldap_dc: "dc=DOMAIN,dc=EXT" nagios_nrpe_ldap_dc: "dc=DOMAIN,dc=EXT"
nagios_nrpe_ldap_passwd: LDAP_PASSWD nagios_nrpe_ldap_passwd: LDAP_PASSWD
nagios_nrpe_pgsql_passwd: PGSQL_PASSWD nagios_nrpe_pgsql_passwd: PGSQL_PASSWD

View File

@ -0,0 +1,87 @@
#!/bin/sh
STATE=0
MAIN_CONNECTION_PINGABLE_IP="31.170.8.95"
MAIN_CONNECTION_GATEWAY="IP"
MAIN_CONNECTION_IP="IP"
SECOND_CONNECTION_PINGABLE_IP="31.170.8.243"
INFO_MAIN_CONNECTION="IP - Description"
INFO_SECOND_CONNECTION="IP - Description"
CURRENT_GATEWAY=$(/usr/bin/netstat -nr | /usr/bin/grep "default" | /usr/bin/awk '{print $2}')
IS_GATEWAY_IN_FILE=1 # Check whether /etc/mygate has the IP of main connection
IS_VPN_USING_MAIN_CONNECTION=1 # Check whether ipsecctl use the main connection
IS_PF_USING_MAIN_CONNECTION=1 # Check whether PacketFilter has route-to using the main connection
IS_MISCELLANEOUS=1 # Check miscellaneous things
CHECK_CARP=0 # No check if host is backup
# No check if host is backup
if [ "${CHECK_CARP}" = 1 ]; then
CARP_STATUS=$(/sbin/ifconfig carp0 | /usr/bin/grep "status" | /usr/bin/awk '{print $2}')
if [ "$CARP_STATUS" = "backup" ]; then
echo "No check, I'm a backup"
exit 0
fi
fi
# If main connection is UP but not used => critical and continue
# If main connection is DOWN (used or not) => warning and exit
/sbin/ping -c1 -w1 ${MAIN_CONNECTION_PINGABLE_IP} >/dev/null 2>&1
if [ $? = 0 ]; then
if [ "${CURRENT_GATEWAY}" != "${MAIN_CONNECTION_GATEWAY}" ]; then
echo "Main connection is UP but not used as gateway !"
STATE=2
fi
else
echo "Main connection (${INFO_MAIN_CONNECTION}) is down"
STATE=1
IS_GATEWAY_IN_FILE=0
IS_VPN_USING_MAIN_CONNECTION=0
IS_PF_USING_MAIN_CONNECTION=0
IS_MISCELLANEOUS=0
fi
# If second connection is DOWN => critical and continue
/sbin/ping -c1 -w1 ${SECOND_CONNECTION_PINGABLE_IP} >/dev/null 2>&1
if [ $? != 0 ]; then
echo "Second connection (${INFO_SECOND_CONNECTION}) is down"
STATE=2
fi
# Check whether /etc/mygate has the IP of main connection
if [ "${IS_GATEWAY_IN_FILE}" = 1 ]; then
/usr/bin/grep -q "${MAIN_CONNECTION_GATEWAY}" /etc/mygate
if [ $? != 0 ]; then
echo "Main connection is not set in /etc/mygate"
STATE=2
fi
fi
# Check whether ipsecctl use the main connection
if [ "${IS_VPN_USING_MAIN_CONNECTION}" = 1 ]; then
/sbin/ipsecctl -sa | /usr/bin/grep -q "${MAIN_CONNECTION_IP}"
if [ $? != 0 ]; then
echo "VPN is not using the main connection !"
STATE=2
fi
fi
# Check whether PacketFilter has route-to using the main connection
if [ "${IS_PF_USING_MAIN_CONNECTION}" = 1 ]; then
/sbin/pfctl -sr | /usr/bin/grep "route-to" | /usr/bin/grep -q "${MAIN_CONNECTION_GATEWAY}"
if [ $? != 0 ]; then
echo "PF is not using the main connection !"
STATE=2
fi
fi
# Check miscellaneous things
if [ "${IS_MISCELLANEOUS}" = 1 ]; then
echo
fi
if [ "${STATE}" = 0 ]; then
echo "OK - Main connection is UP and used, second connection is UP"
fi
exit ${STATE}

View File

@ -0,0 +1,401 @@
#!/usr/bin/perl -T
# $AFresh1: check_openbgpd,v 1.10 2015/03/26 03:44:15 andrew Exp $
########################################################################
# check_openbgpd *** A nagios check for OpenBSD bgpd
#
# 2009.11.12 #*#*# andrew fresh <andrew@afresh1.com>
########################################################################
#
# MODIFIED VERSION FOR THE NEEDS OF EVOLIX
# By Jérémy Dubois <jdubois@evolix.fr>
#
# Line 51 :
# added « open STDERR, '>&STDOUT'; »
#
# Lines 123 to 126 :
# added « or exit 2; »
# commented « or die $! » and the 2 lines below
#
########################################################################
use strict;
use warnings;
use 5.010;
use if $] >= 5.016, experimental => 'switch';
local %ENV = ();
my $NAGIOS_OUTPUT = 1;
my $LICENSE = <<'EOL';
Copyright (c) 2009-2015 Andrew Fresh <andrew@afresh1.com>
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
EOL
my $PROGNAME = 'check_openbgpd';
my $BGPCTL = '/usr/sbin/bgpctl';
use POSIX;
use Config;
my $PREFIX;
open STDERR, '>&STDOUT';
BEGIN {
## no critic 'warnings'
no warnings 'uninitialized';
$PREFIX = "/usr/local" || '/usr/local'; # Magic for OpenBSD ports tree
}
use lib $PREFIX . '/libexec/nagios';
use utils qw($TIMEOUT %ERRORS &support);
$SIG{'ALRM'} = sub {
print("ERROR: $PROGNAME timeout\n");
exit $ERRORS{'UNKNOWN'};
};
alarm($TIMEOUT);
my %CHECKS = getopt(@ARGV);
if ( !%CHECKS ) {
print_help();
exit $ERRORS{'OK'};
}
my @STATUS = read_status( $CHECKS{_SOCKET} );
my %STATES = check_status( \@STATUS, \%CHECKS );
my $have_results = 0;
my $state = 'OK';
foreach
my $error ( reverse sort { $ERRORS{$a} <=> $ERRORS{$b} } keys %ERRORS )
{
if ( exists $STATES{$error} ) {
$have_results++;
$state = $error if $ERRORS{$state} < $ERRORS{$error};
if ($NAGIOS_OUTPUT) {
print $error . ' (' . scalar( @{ $STATES{$error} } ) . ')';
if ( $error ne 'OK' ) {
print '<br>';
print map {" - $_<br>"} @{ $STATES{$error} };
}
}
else {
print $error . ' (' . scalar( @{ $STATES{$error} } ) . "):\n";
foreach ( @{ $STATES{$error} } ) {
print " $_\n";
}
}
}
}
if ( $have_results == 0 ) {
print "No results found\n";
}
exit $ERRORS{$state};
sub read_status {
my ($socket) = @_;
my @S;
my @cmd = ($BGPCTL);
if ($socket) {
push @cmd, '-s', $socket;
}
push @cmd, 'show', 'summary';
#open my $fh, '<', 'output' # XXX
open my $fh, '-|', @cmd or die "Couldn't open bgpctl: $!\n";
while (<$fh>) {
chomp;
push @S, parse_line($_);
}
## no critic 'die'
close $fh
or exit 2;
# or die $!
# ? "Error closing sysctl pipe: $!\n"
# : "Exit status $? from sysctl\n";
return grep { exists $_->{neighbor} && $_->{as} ne 'AS' } @S;
}
sub parse_line {
my ($c) = @_;
my ( $neighbor, $as, $rcvd, $sent, $outq, $updown, $state, )
= $c
=~ /^(.*?)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*$/xms;
return {
neighbor => $neighbor,
as => $as,
rcvd => $rcvd,
sent => $sent,
outq => $outq,
updown => $updown,
state => $state,
line => $c,
};
}
sub parse_check {
my $check = shift;
return { match => [] } unless $check;
my @values = split /,\s*/xms, $check;
my %c = ( match => [] );
foreach my $v (@values) {
if ( $v =~ /:/xms ) {
( $c{low}, $c{high} ) = split /:/xms, $v;
}
else {
push @{ $c{match} }, $v;
}
}
foreach my $d ( 'low', 'high' ) {
if ( defined $c{$d} ) {
$c{$d} =~ s/[^-\d\.\%]//gxms;
if ( !length $c{$d} ) {
delete $c{$d};
}
}
}
return \%c;
}
sub check_status {
my ( $S, $C ) = @_;
my %states;
my %neighbors = map { $_ => $C->{$_} } qw( _SOCKET _UNKNOWN );
STATE: foreach my $s ( @{$S} ) {
my $n = $s->{neighbor};
$neighbors{$n} = $s;
my $result;
if ( my $c = $C->{$n} || $C->{_UNKNOWN} ) {
CODE: foreach my $code ( 'CRITICAL', 'WARNING' ) {
next CODE if ( ref $c->{$code} ne 'HASH' );
my $data = $s->{state};
my $result = check_item( $data, $c->{$code} );
if ($result) {
push @{ $states{$code} }, "[$n] $result";
next STATE;
}
}
}
else {
push @{ $states{CRITICAL} }, '[' . $n . '] Unknown Neighbor';
next STATE;
}
push @{ $states{OK} }, $n;
}
foreach my $n ( keys %{$C} ) {
if ( !exists $neighbors{$n} ) {
push @{ $states{CRITICAL} }, '[' . $n . '] Missing Neighbor';
}
}
return %states;
}
sub check_item {
my ( $d, $c ) = @_;
my $result;
if ( $c->{match} && @{ $c->{match} } ) {
foreach my $m ( @{ $c->{match} } ) {
return if $m eq $d;
}
$result = 'State (' . $d . ') is outside of acceptable values';
}
if ( $c->{low} || $c->{high} ) {
$result = undef;
my ( $num, $max ) = split m{/}xms, $d;
$num =~ s/[^-\d\.]//gxms;
if ( !length $num ) {
return 'State (' . $d . ') is not numeric';
}
DIRECTION: foreach my $dir (qw( low high )) {
if ( !$c->{$dir} ) { next DIRECTION; }
my $check = $c->{$dir};
my $cnum = $num;
if ( $check =~ s/\%$//xms ) {
if ( !defined $max ) {
return 'max-prefix not specified and % check requested';
}
# convert to percent
$cnum = 100 * $cnum / $max;
}
my @nums = ( $cnum, $check );
my $abovebelow = 'below';
my $symbol = '<';
if ( $dir eq 'high' ) {
@nums = ( $check, $cnum );
$abovebelow = 'above';
$symbol = '>';
}
if ( $nums[0] < $nums[1] ) {
return join q{ }, 'is', $abovebelow,
'threshold (' . $d,
$symbol, $c->{$dir} . ')';
}
}
}
return $result;
}
sub getopt {
my (@argv) = @_;
my %checks;
while (@argv) {
state( $w, $c );
my $opt = shift @argv;
for ($opt) {
when ( '-V' || '--version' ) {
print_revision( $PROGNAME, '$Revision: 1.10 $ ' );
exit $ERRORS{'OK'}
}
when (/^-?-h(?:elp)?/xms) { print_help(); exit $ERRORS{'OK'} }
when (/^-?-s(?:ocket)?/xms) { $checks{_SOCKET} = shift @argv }
when (/^-?-w(?:arning)?/xms) { $w = parse_check( shift @argv ) }
when (/^-?-c(?:ritical)?/xms) { $c = parse_check( shift @argv ) }
when (/^-?-u(?:nknown)?/xms) {
$checks{_UNKNOWN} = {
WARNING => $w,
CRITICAL => $c,
};
}
when (/^-?-n(?:eighbor)?/xms) {
while ( @argv && $argv[0] !~ /^-/xms ) {
$checks{ shift @argv } = {
WARNING => $w,
CRITICAL => $c,
};
}
}
default { print_help(); exit $ERRORS{'UNKNOWN'} }
}
}
return %checks;
}
sub print_help {
print <<"EOL";
$PROGNAME - checks status of OpenBGPd peers
$PROGNAME [ -s SOCKET ][ -w ENTRY ][ -c ENTRY ]( -u | -n NEIGHBOR )
Usage:
-s, --socket SOCKET
Path to bgpd socket to use. See -r in bgpd(8).
-w, --warning RANGE or single ENTRY
Exit with WARNING status if outside of RANGE or if != ENTRY
May be entered multiple times.
-c, --critical RANGE or single ENTRY
Exit with CRITICAL status if outside of RANGE or if != ENTRY
May be entered multiple times.
-n, --neighbor NEIGHBOR
The name of the Neighbor, can be a space separated list of neighbors.
May be entered multiple times.
-u, --unknown
As if you specified -n for all unknown neighbors
ENTRY is a comma separated list of items to match against. Each item can be
a RANGE or it will just be matched against the status.
RANGE is specified as two optional numbers separated with a colon (:). The
check is that the value is between the two numbers. If either number is left
off, that check is ignored.
If either number in a RANGE is specified as a percent, check is that
max-prefix is specified and that the number is within the specified percent.
NEIGHBOR is the name that shows when running "bgpctl show summary"
Examples:
(where many of the numbers would probably have to be multiplied by 1000)
Any time a NEIGHBOR is specified on the command line but does NOT show up in
the output causes a CRITICAL result.
Any time a NEIGHBOR that is NOT specified on the command line shows up in the
output causes a CRITICAL result. If -u is specified, it treats NEIGHBOR as if
it were specified at that position.
$PROGNAME -c Idle -n P1 -c 1:1 -n P2 -w 200:300 -c Active,10: -n P3
CRITICAL
If P1 is any value but Idle.
If P2 is any value but 1.
If P3 is below 10 or any non-numeric value other than "Active".
WARNING
If P3 is above 10 and below 200 or above 300.
$PROGNAME -u -w 50%:70% -c 10%:90% -n P2 P3
No checks of unknown neighbors.
CRITICAL
If P2 or P3 do not have max-prefix set or if they do but learned prefixes
are below 10% or above 90% of max-prefix or any non-numeric value.
WARNING
If P2 or P3 have learned prefixes below 50% or above 70% of max-prefix.
$PROGNAME -w 50%:70% -c 10%:90% -u
CRITICAL
If any neighbor does not have max-prefix set or if they do but learned
prefixes are below 10% or above 90% of max-prefix or any non-numeric value.
WARNING
If any neighbor have learned prefixes below 50% or above 70% of max-prefix.
EOL
print_revision( $PROGNAME, '$Revision: 1.10 $' );
print $LICENSE;
return;
}
sub print_revision {
my ( $prog, $rev ) = @_;
$rev =~ s/^\D+([\d\.]+)\D+$/v$1/xms;
say $prog, q{ }, $rev;
return;
}

View File

@ -1,9 +1,12 @@
#!/bin/sh #!/bin/sh
#
# Wrapper of check_openvpn.pl, to use when the server is CARP backup and OpenVPN should not run
if netstat -an|grep '.1194' >/dev/null; then carp=$(/sbin/ifconfig carp0 | /usr/bin/grep 'status' |cut -d' ' -f2)
echo "VPN OK"
return 0 if [ $carp = 'backup' ]; then
echo "No check, I'm a backup"
return 0
else else
echo "PROCESS NOT LISTENING" /usr/local/libexec/nagios/plugins/check_openvpn.pl -H 127.0.0.1 -p 1195 -P PASSWORD
return 2
fi fi

View File

@ -0,0 +1,215 @@
#!/usr/bin/perl -w
#######################################################################
#
# Copyright (c) 2007 Jaime Gascon Romero <jgascon@gmail.com>
#
# License Information:
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# $Id: check_openvpn.pl,v 1.1 2014/09/29 08:39:24 rdessort Exp $
# $Revision: 1.1 $
# Home Site: http://emergeworld.blogspot.com/
# #####################################################################
use diagnostics;
use strict;
use Net::Telnet ();
use Getopt::Long qw(:config no_ignore_case);
use vars qw($PROGNAME $VERSION);
use lib "/usr/local/libexec/nagios/";
use utils qw(%ERRORS);
$PROGNAME = "check_openvpn";
$VERSION = '$Revision: 1.1 $';
$ENV{'PATH'}='';
$ENV{'BASH_ENV'}='';
$ENV{'ENV'}='';
my ($opt_h, $opt_H, $opt_p, $opt_P, $opt_t, $opt_i, $opt_n, $opt_c, $opt_w, $opt_C, $opt_r);
sub print_help ();
sub print_usage ();
GetOptions
("h" => \$opt_h, "help" => \$opt_h,
"H=s" => \$opt_H, "host=s" => \$opt_H,
"p=i" => \$opt_p, "port=i" => \$opt_p,
"P=s" => \$opt_P, "password=s" => \$opt_P,
"t=i" => \$opt_t, "timeout=i" => \$opt_t,
"i" => \$opt_i, "ip" => \$opt_i,
"n" => \$opt_n, "numeric" => \$opt_n,
"c" => \$opt_c, "critical" => \$opt_c,
"w" => \$opt_w, "warning" => \$opt_w,
"C=s" => \$opt_C, "common_name=s" => \$opt_C,
"r=s" => \$opt_r, "remote_ip=s" => \$opt_r,
) or exit $ERRORS{'UNKNOWN'};
# default values
unless ( defined $opt_t ) {
$opt_t = 10;
}
if ($opt_h) {print_help(); exit $ERRORS{'OK'};}
if ( ! defined($opt_H) || ! defined($opt_p) ) {
print_usage();
exit $ERRORS{'UNKNOWN'}
}
my @lines;
my @clients;
my @clients_ip;
my $t;
eval {
$t = new Net::Telnet (Timeout => $opt_t,
Port => $opt_p,
Prompt => '/END$/'
);
$t->open($opt_H);
if ( defined $opt_P ) {
$t->waitfor('/ENTER PASSWORD:$/');
$t->print($opt_P);
}
$t->waitfor('/^$/');
@lines = $t->cmd("status 2");
$t->close;
};
if ($@) {
print "OpenVPN Critical: Can't connect to server\n";
exit $ERRORS{'CRITICAL'};
}
if (defined $opt_i || defined $opt_r) {
foreach (@lines) {
if ($_ =~ /CLIENT_LIST,.*,(\d+\.\d+\.\d+\.\d+):\d+,/) {
push @clients_ip, $1;
}
}
if (defined $opt_i) {
print "OpenVPN OK: "."@clients_ip ";
exit $ERRORS{'OK'};
} elsif (defined $opt_r) {
if ( ! grep /\b$opt_r\b/, @clients_ip) {
if (defined $opt_c) {
print "OpenVPN CRITICAL: $opt_r don't found";
exit $ERRORS{'CRITICAL'};
} else {
print "OpenVPN WARNING: $opt_r don't found";
exit $ERRORS{'WARNING'};
}
}
print "OpenVPN OK: "."@clients_ip ";
exit $ERRORS{'OK'};
}
}
foreach (@lines) {
if ($_ =~ /CLIENT_LIST,(.*),\d+\.\d+\.\d+\.\d+:\d+,/) {
push @clients, $1;
}
}
if (defined $opt_C) {
if ( ! grep /\b$opt_C\b/, @clients) {
if (defined $opt_c) {
print "OpenVPN CRITICAL: $opt_C don't found";
exit $ERRORS{'CRITICAL'};
} else {
print "OpenVPN WARNING: $opt_C don't found";
exit $ERRORS{'WARNING'};
}
}
}
if (defined $opt_n) {
print "OpenVPN OK: ".@clients." connected clients.";
exit $ERRORS{'OK'};
}
print "OpenVPN OK: "."@clients ";
exit $ERRORS{'OK'};
#######################################################################
###### Subroutines ####################################################
sub print_usage() {
print "Usage: $PROGNAME -H | --host <IP or hostname> -p | --port <port number> [-P | --password] <password> [-t | --timeout] <timeout in seconds>
[-i | --ip] [-n | --numeric] [-C | --common_name] <common_name> [-r | --remote_ip] <remote_ip> [-c | --critical] [-w | --warning]\n\n";
print " $PROGNAME [-h | --help]\n";
}
sub print_help() {
print "$PROGNAME $VERSION\n\n";
print "Copyright (c) 2007 Jaime Gascon Romero
Nagios plugin to check the clients connected to a openvpn server.
";
print_usage();
print "
-H | --host
IP address or hostname of the openvpn server.
-p | --port
Management port interface of the openvpn server.
-P | --password
Password for the management interface of the openvpn server.
-t | --timeout
Timeout for the connection attempt. Optional, default 10 seconds.
Optional parameters
===================
-i | --ip
Prints the IP address of the remote client instead of the common name.
-n | --numeric
Prints the number of clients connected to the openvpn server.
Matching Parameters
===================
-C | --common_name
The common name, as it is specified in the client certificate, who is wanted to check.
-r | --remote_ip
The client remote ip address who is wanted to check.
-c | --critical
Exits with CRITICAL status if the client specified by the common name or the remote ip address is not connected.
-w | --warning
Exits with WARNING status if the client specified by the common name or the remote ip address is not connected.
Other Parameters
================
-h | --help
Show this help.
";
}
# vim:sts=2:sw=2:ts=2:et

View File

@ -3,10 +3,16 @@
. /usr/local/libexec/nagios/utils.sh . /usr/local/libexec/nagios/utils.sh
# check if ospfd is running # check if ospfd is running
if [[ "$(ospfctl show 2>&1)" = *"/var/run/ospfd.sock:"* ]]; then if ! ls /var/run/ospfd* > /dev/null 2>&1; then
echo "CRITICAL - OSPFD not running" echo "CRITICAL - OSPFD not running, no socket found"
exit "$STATE_CRITICAL" exit "$STATE_CRITICAL"
else else
echo "OK - OSPFD is running" if ospfctl show 2>&1 | grep -q "Uptime"; then
exit "$STATE_OK" uptime=$(ospfctl show | grep Uptime | awk '{print $2}')
echo "OK - OSPFD has been running for $uptime"
exit "$STATE_OK"
else
echo "CRITICAL - OSPFD not running"
exit "$STATE_CRITICAL"
fi
fi fi

View File

@ -0,0 +1,40 @@
#!/bin/sh
. /usr/local/libexec/nagios/utils.sh
is_pf_disabled() {
if [ -f /etc/rc.conf.local ]; then
grep -q "pf=NO" /etc/rc.conf.local
else
# If /etc/rc.conf.local does not exist, pf cannot be disabled
# If 0 then pf is disabled, so if /etc/rc.conf.local does not exist we have to return 1 => pf is not disabled
return 1
fi
}
is_pf_started() {
pfctl -si | grep -q "Status: Enabled for"
}
main() {
if ! is_pf_disabled; then
if is_pf_started; then
echo "OK: PacketFilter is enabled and started."
exit "${STATE_OK}"
else
echo "CRITICAL: PacketFilter is enabled but not started."
exit "${STATE_CRITICAL}"
fi
else
if is_pf_started; then
echo "WARNING: PacketFilter is started but not enabled."
exit "${STATE_WARNING}"
else
echo "CRITICAL: PacketFilter is disabled and not started."
exit "${STATE_CRITICAL}"
fi
fi
}
main

View File

@ -3,8 +3,8 @@
# Script writen by Evolix # Script writen by Evolix
_MAX_STATES_LIMIT=$(/sbin/pfctl -sm | /usr/bin/grep states | awk '{print $4}') _MAX_STATES_LIMIT=$(/sbin/pfctl -sm | /usr/bin/grep states | awk '{print $4}')
_WARNING_STATES_LIMIT=$((_MAX_STATES_LIMIT*10/100)) _WARNING_STATES_LIMIT=$((_MAX_STATES_LIMIT*50/100))
_CRTICAL_STATES_LIMIT=$((_MAX_STATES_LIMIT*15/100)) _CRTICAL_STATES_LIMIT=$((_MAX_STATES_LIMIT*65/100))
. /usr/local/libexec/nagios/utils.sh . /usr/local/libexec/nagios/utils.sh

View File

@ -1,17 +1,15 @@
--- ---
- name: Install nrpe - name: Install nrpe
openbsd_pkg: openbsd_pkg:
name: "{{ item }}" name:
- nrpe--
state: present state: present
with_items:
- nrpe--
- name: Install monitoring-plugins - name: Install monitoring-plugins
openbsd_pkg: openbsd_pkg:
name: "{{ item }}" name:
- monitoring-plugins
state: present state: present
with_items:
- monitoring-plugins
- name: Create nrpe.d dir - name: Create nrpe.d dir
file: file:
@ -32,29 +30,48 @@
dest: /etc/nrpe.d/evolix.cfg dest: /etc/nrpe.d/evolix.cfg
notify: restart nrpe notify: restart nrpe
- name: Nagios plugins are installed - name: Create nrpe plugins dir
copy: file:
src: plugins_bsd/ path: /usr/local/libexec/nagios/plugins/
dest: /usr/local/libexec/nagios/plugins/ state: directory
owner: root owner: root
group: wheel group: wheel
mode: "0755" mode: "0755"
- name: Nagios plugins are installed
copy:
src: plugins_bsd/{{ item.name }}
dest: /usr/local/libexec/nagios/plugins/{{ item.name }}
owner: root
group: wheel
mode: "0755"
force: "{{ item.force }}"
with_items:
- {name: 'check_carp_if', force: true}
- {name: 'check_connections_state.sh', force: false}
- {name: 'check_ipsecctl.sh', force: false}
- {name: 'check_openbgpd', force: true}
- {name: 'check_openvpn', force: false}
- {name: 'check_openvpn.pl', force: true}
- {name: 'check_ospfd_simple', force: true}
- {name: 'check_packetfilter.sh', force: true}
- {name: 'check_pf_states', force: false}
notify: restart nrpe notify: restart nrpe
- name: Nagios plugins are installed - template - name: Nagios plugins are installed - template
template: template:
src: plugins_bsd/{{ item }}.j2 src: plugins_bsd/{{ item.name }}.j2
dest: /usr/local/libexec/nagios/plugins/{{ item }} dest: /usr/local/libexec/nagios/plugins/{{ item.name }}
owner: root owner: root
group: wheel group: wheel
mode: "0755" mode: "0755"
force: "{{ item.force }}"
with_items: with_items:
- 'check_pf_states' - {name: 'check_free_mem.sh', force: true}
- 'check_free_mem.sh'
notify: restart nrpe notify: restart nrpe
- name: Starting and enabling nrpe - name: Starting and enabling nrpe
service: service:
name: nrpe name: nrpe
enabled: yes enabled: true
state: started state: started

View File

@ -2,37 +2,51 @@
# Custom NRPE configuration file. # Custom NRPE configuration file.
# Part of the EvoBSD distribution. # Part of the EvoBSD distribution.
# #
# This is an Ansible managed file !
# For local modifications use the /etc/nrpe.d/zzz_evolix.cfg file instead
# Allowed IPs # Allowed IPs
allowed_hosts={{ nagios_nrpe_allowed_hosts | join(',') }} allowed_hosts={{ nagios_nrpe_allowed_hosts | join(',') }}
# System checks
command[check_users]=/usr/local/libexec/nagios/check_users -w 5 -c 10 command[check_users]=/usr/local/libexec/nagios/check_users -w 5 -c 10
command[check_load]=/usr/local/libexec/nagios/check_load -w 15,10,5 -c 30,25,20 command[check_load]=/usr/local/libexec/nagios/check_load -w 15,10,5 -c 30,25,20
command[check_disk1]=/usr/local/libexec/nagios/check_disk -x /lib/init/rw -x /dev -x /dev/shm -w 10% -c 3% -W 10% -K 3% -C -w 5% -c 2% -W 5% -K 2% -p /home command[check_disk1]=/usr/local/libexec/nagios/check_disk -x /lib/init/rw -x /dev -x /dev/shm -w 10% -c 3% -W 10% -K 3% -C -w 5% -c 2% -W 5% -K 2% -p /home
command[check_zombie_procs]=/usr/local/libexec/nagios/check_procs -w 5 -c 10 -s Z command[check_zombie_procs]=/usr/local/libexec/nagios/check_procs -w 5 -c 10 -s Z
command[check_total_procs]=/usr/local/libexec/nagios/check_procs -w 150 -c 200 command[check_total_procs]=/usr/local/libexec/nagios/check_procs -w 150 -c 200
command[check_imap]=/usr/local/libexec/nagios/check_imap -H localhost command[check_swap]=/usr/local/libexec/nagios/check_swap --no-swap=ok -a -w 30% -c 20%
# Generic services checks
command[check_smtp]=/usr/local/libexec/nagios/check_smtp -H localhost -f {{ general_alert_email }} command[check_smtp]=/usr/local/libexec/nagios/check_smtp -H localhost -f {{ general_alert_email }}
command[check_dns]=/usr/local/libexec/nagios/check_dns -H evolix.net command[check_dns]=/usr/local/libexec/nagios/check_dns -H evolix.net
command[check_swap]=/usr/local/libexec/nagios/check_swap --no-swap=ok -a -w 30% -c 20% command[check_ntp]=/usr/local/libexec/nagios/check_ntp -H ntp-check.evolix.net
command[check_ntp]=/usr/local/libexec/nagios/check_ntp -H ntp.evolix.net
command[check_http]=/usr/local/libexec/nagios/check_http -H localhost -p 80
command[check_onduleur]=/usr/local/libexec/nagios/check_ups -H localhost -u onduleur
# Pour check_mailq, ajouter dans sudo :
# _nrpe ALL=NOPASSWD: /usr/local/libexec/nagios/check_mailq
command[check_mailq]=sudo /usr/local/libexec/nagios/check_mailq -w 10 -c 20
command[check_bind]=/usr/local/libexec/nagios/check_dig -l evolix.net -H localhost
command[check_ssh]=/usr/local/libexec/nagios/check_ssh -p 22 localhost command[check_ssh]=/usr/local/libexec/nagios/check_ssh -p 22 localhost
command[check_proxy]=/usr/local/libexec/nagios/check_tcp -p PORT command[check_mailq]=doas /usr/local/libexec/nagios/check_mailq -w 10 -c 20
#command[check_vpn]=/usr/local/libexec/nagios/check_ping -H IPDISTANTE -p 1 -w 5000,100% -c 5000,100%
command[check_vpn]=sudo /usr/local/libexec/nagios/plugins/check_ipsecctl.sh IPDISTANTE IPLOCALE "VPN MARSEILLE-ROME" # Specific services checks
command[check_openvpn]=/usr/local/libexec/nagios/plugins/check_openvpn command[check_imap]=/usr/local/libexec/nagios/check_imap -H localhost
command[check_pf_states]=doas /usr/local/libexec/nagios/plugins/check_pf_states command[check_http]=/usr/local/libexec/nagios/check_http -H localhost -p 80
command[check_carp1]=/usr/local/libexec/nagios/plugins/check_carp_if carp0 master command[check_bind]=/usr/local/libexec/nagios/check_dig -l evolix.net -H localhost
command[check_mem]=/usr/local/libexec/nagios/plugins/check_free_mem.sh -w 20 -c 10 command[check_unbound]=/usr/local/libexec/nagios/check_dig -l evolix.net -H localhost
command[check_dhcpclient]=/usr/local/libexec/nagios/check_dhcp -i INTERFACE #command[check_proxy]=/usr/local/libexec/nagios/check_tcp -p PORT
command[check_smb]=/usr/local/libexec/nagios/check_tcp -H IPLOCALE -p 445 #command[check_smb]=/usr/local/libexec/nagios/check_tcp -H IPLOCALE -p 445
#command[check_ospfd]=doas /usr/local/libexec/nagios/plugins/check_ospfd
#command[check_ospf6d]=doas /usr/local/libexec/nagios/plugins/check_ospf6d
command[check_ospfd_simple]=sudo /usr/local/libexec/nagios/plugins/check_ospfd_simple
command[check_mysql]=/usr/local/libexec/nagios/check_mysql -H 127.0.0.1 -f /etc/nrpe.d/.my.cnf command[check_mysql]=/usr/local/libexec/nagios/check_mysql -H 127.0.0.1 -f /etc/nrpe.d/.my.cnf
#command[check_vpn]=/usr/local/libexec/nagios/check_ping -H IPDISTANTE -p 1 -w 5000,100% -c 5000,100%
#command[check_dhcpd]=doas /usr/local/libexec/nagios/check_dhcp -i INTERFACE -s IP -u
# Local checks (not packaged)
#command[check_openvpn]=/usr/local/libexec/nagios/plugins/check_openvpn.pl -H 127.0.0.1 -p 1195 -P PASSWORD
#command[check_openvpn]=/usr/local/libexec/nagios/plugins/check_openvpn # Wrapper of check_openvpn.pl, to use when the server is CARP backup and OpenVPN should not run
#command[check_carp1]=/usr/local/libexec/nagios/plugins/check_carp_if carp0 master
command[check_mem]=/usr/local/libexec/nagios/plugins/check_free_mem.sh -w 20 -c 10
#command[check_vpn]=doas /usr/local/libexec/nagios/plugins/check_ipsecctl.sh IPDISTANTE IPLOCALE "VPN MARSEILLE-ROME"
command[check_pf_states]=doas /usr/local/libexec/nagios/plugins/check_pf_states
command[check_ospfd]=doas /usr/local/libexec/nagios/plugins/check_ospfd
command[check_ospf6d]=doas /usr/local/libexec/nagios/plugins/check_ospf6d
command[check_ospfd_simple]=doas /usr/local/libexec/nagios/plugins/check_ospfd_simple
command[check_bgpd]=doas /usr/local/libexec/nagios/plugins/check_openbgpd -u
command[check_connections_state]=doas /usr/local/libexec/nagios/plugins/check_connections_state.sh
command[check_packetfilter]=doas /usr/local/libexec/nagios/plugins/check_packetfilter.sh
# This is an Ansible managed file !
# For local modifications use the /etc/nrpe.d/zzz_evolix.cfg file instead

View File

@ -64,7 +64,7 @@ __EOT
# Total memory size (in MB) # Total memory size (in MB)
tot_mem=$(( `/sbin/sysctl -n hw.physmem` / BYTES_IN_MB)) tot_mem=$(( `/sbin/sysctl -n hw.physmem` / BYTES_IN_MB))
# Free memory size (in MB) # Free memory size (in MB)
{% if ansible_distribution_version | version_compare("6.2",'<') %} {% if ansible_distribution_version is version_compare("6.2",'<') %}
free_mem=$(( `/usr/bin/vmstat | /usr/bin/tail -1 | /usr/bin/awk '{ print $5 }'` / KB_IN_MB )) free_mem=$(( `/usr/bin/vmstat | /usr/bin/tail -1 | /usr/bin/awk '{ print $5 }'` / KB_IN_MB ))
{% else %} {% else %}
free_mem=$(/usr/bin/vmstat | /usr/bin/tail -1 | /usr/bin/awk '{ print $4 }' | tr -d 'M') free_mem=$(/usr/bin/vmstat | /usr/bin/tail -1 | /usr/bin/awk '{ print $4 }' | tr -d 'M')

13
roles/openvpn/README.md Normal file
View File

@ -0,0 +1,13 @@
# OpenVPN
Installation and custom configuration of OpenVPN server.
## Tasks
Everything is in the `tasks/main.yml` file.
## Available variables
The full list of variables (with default values) can be found in `defaults/main.yml`.
NOTE: Make sure you have already cloned shellpki in ~/GIT/

View File

@ -0,0 +1,3 @@
---
openvpn_lan: "192.168.42.0"
openvpn_netmask: "255.255.255.0"

View File

@ -0,0 +1,215 @@
#!/usr/bin/perl -w
#######################################################################
#
# Copyright (c) 2007 Jaime Gascon Romero <jgascon@gmail.com>
#
# License Information:
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# $Id: check_openvpn.pl,v 1.1 2014/09/29 08:39:24 rdessort Exp $
# $Revision: 1.1 $
# Home Site: http://emergeworld.blogspot.com/
# #####################################################################
use diagnostics;
use strict;
use Net::Telnet ();
use Getopt::Long qw(:config no_ignore_case);
use vars qw($PROGNAME $VERSION);
use lib "/usr/local/libexec/nagios/";
use utils qw(%ERRORS);
$PROGNAME = "check_openvpn";
$VERSION = '$Revision: 1.1 $';
$ENV{'PATH'}='';
$ENV{'BASH_ENV'}='';
$ENV{'ENV'}='';
my ($opt_h, $opt_H, $opt_p, $opt_P, $opt_t, $opt_i, $opt_n, $opt_c, $opt_w, $opt_C, $opt_r);
sub print_help ();
sub print_usage ();
GetOptions
("h" => \$opt_h, "help" => \$opt_h,
"H=s" => \$opt_H, "host=s" => \$opt_H,
"p=i" => \$opt_p, "port=i" => \$opt_p,
"P=s" => \$opt_P, "password=s" => \$opt_P,
"t=i" => \$opt_t, "timeout=i" => \$opt_t,
"i" => \$opt_i, "ip" => \$opt_i,
"n" => \$opt_n, "numeric" => \$opt_n,
"c" => \$opt_c, "critical" => \$opt_c,
"w" => \$opt_w, "warning" => \$opt_w,
"C=s" => \$opt_C, "common_name=s" => \$opt_C,
"r=s" => \$opt_r, "remote_ip=s" => \$opt_r,
) or exit $ERRORS{'UNKNOWN'};
# default values
unless ( defined $opt_t ) {
$opt_t = 10;
}
if ($opt_h) {print_help(); exit $ERRORS{'OK'};}
if ( ! defined($opt_H) || ! defined($opt_p) ) {
print_usage();
exit $ERRORS{'UNKNOWN'}
}
my @lines;
my @clients;
my @clients_ip;
my $t;
eval {
$t = new Net::Telnet (Timeout => $opt_t,
Port => $opt_p,
Prompt => '/END$/'
);
$t->open($opt_H);
if ( defined $opt_P ) {
$t->waitfor('/ENTER PASSWORD:$/');
$t->print($opt_P);
}
$t->waitfor('/^$/');
@lines = $t->cmd("status 2");
$t->close;
};
if ($@) {
print "OpenVPN Critical: Can't connect to server\n";
exit $ERRORS{'CRITICAL'};
}
if (defined $opt_i || defined $opt_r) {
foreach (@lines) {
if ($_ =~ /CLIENT_LIST,.*,(\d+\.\d+\.\d+\.\d+):\d+,/) {
push @clients_ip, $1;
}
}
if (defined $opt_i) {
print "OpenVPN OK: "."@clients_ip ";
exit $ERRORS{'OK'};
} elsif (defined $opt_r) {
if ( ! grep /\b$opt_r\b/, @clients_ip) {
if (defined $opt_c) {
print "OpenVPN CRITICAL: $opt_r don't found";
exit $ERRORS{'CRITICAL'};
} else {
print "OpenVPN WARNING: $opt_r don't found";
exit $ERRORS{'WARNING'};
}
}
print "OpenVPN OK: "."@clients_ip ";
exit $ERRORS{'OK'};
}
}
foreach (@lines) {
if ($_ =~ /CLIENT_LIST,(.*),\d+\.\d+\.\d+\.\d+:\d+,/) {
push @clients, $1;
}
}
if (defined $opt_C) {
if ( ! grep /\b$opt_C\b/, @clients) {
if (defined $opt_c) {
print "OpenVPN CRITICAL: $opt_C don't found";
exit $ERRORS{'CRITICAL'};
} else {
print "OpenVPN WARNING: $opt_C don't found";
exit $ERRORS{'WARNING'};
}
}
}
if (defined $opt_n) {
print "OpenVPN OK: ".@clients." connected clients.";
exit $ERRORS{'OK'};
}
print "OpenVPN OK: "."@clients ";
exit $ERRORS{'OK'};
#######################################################################
###### Subroutines ####################################################
sub print_usage() {
print "Usage: $PROGNAME -H | --host <IP or hostname> -p | --port <port number> [-P | --password] <password> [-t | --timeout] <timeout in seconds>
[-i | --ip] [-n | --numeric] [-C | --common_name] <common_name> [-r | --remote_ip] <remote_ip> [-c | --critical] [-w | --warning]\n\n";
print " $PROGNAME [-h | --help]\n";
}
sub print_help() {
print "$PROGNAME $VERSION\n\n";
print "Copyright (c) 2007 Jaime Gascon Romero
Nagios plugin to check the clients connected to a openvpn server.
";
print_usage();
print "
-H | --host
IP address or hostname of the openvpn server.
-p | --port
Management port interface of the openvpn server.
-P | --password
Password for the management interface of the openvpn server.
-t | --timeout
Timeout for the connection attempt. Optional, default 10 seconds.
Optional parameters
===================
-i | --ip
Prints the IP address of the remote client instead of the common name.
-n | --numeric
Prints the number of clients connected to the openvpn server.
Matching Parameters
===================
-C | --common_name
The common name, as it is specified in the client certificate, who is wanted to check.
-r | --remote_ip
The client remote ip address who is wanted to check.
-c | --critical
Exits with CRITICAL status if the client specified by the common name or the remote ip address is not connected.
-w | --warning
Exits with WARNING status if the client specified by the common name or the remote ip address is not connected.
Other Parameters
================
-h | --help
Show this help.
";
}
# vim:sts=2:sw=2:ts=2:et

View File

@ -0,0 +1 @@
/home/tpilat/GIT/shellpki/

View File

@ -0,0 +1 @@
%shellpki ALL = (root) /usr/local/sbin/shellpki

View File

@ -0,0 +1,5 @@
---
- name: restart openvpn
service:
name: openvpn
state: restarted

View File

@ -0,0 +1,121 @@
---
- name: Install OpenVPN package
openbsd_pkg:
name: "openvpn--"
tags:
- openvpn
- name: Create /etc/openvpn directory
file:
path: /etc/openvpn
state: directory
owner: "root"
group: "wheel"
mode: "0755"
tags:
- openvpn
- name: Deploy OpenVPN configuration
template:
src: "server.conf.j2"
dest: "/etc/openvpn/server.conf"
mode: "0600"
notify: restart openvpn
tags:
- openvpn
- name: Enabling OpenVPN
service:
name: openvpn
enabled: true
tags:
- openvpn
- name: Set OpenVPN flag
shell: 'rcctl set openvpn flags "--config /etc/openvpn/server.conf"'
tags:
- openvpn
- name: Create shellpki user
user:
name: "_shellpki"
system: true
state: present
home: "/etc/shellpki/"
shell: "/sbin/nologin"
tags:
- openvpn
- name: Copy some shellpki files
copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
owner: root
group: wheel
mode: "{{ item.mode }}"
force: true
with_items:
- src: 'files/shellpki/openssl.cnf'
dest: '/etc/shellpki/openssl.cnf'
mode: '0640'
- src: 'files/shellpki/shellpki'
dest: '/usr/local/sbin/shellpki'
mode: '0755'
tags:
- openvpn
- name: Deploy DH PARAMETERS
template:
src: "dh2048.pem.j2"
dest: "/etc/shellpki/dh2048.pem"
mode: "0600"
tags:
- openvpn
- name: Create /etc/sudoers.d directory
file:
path: /etc/sudoers.d
state: directory
owner: "root"
group: "wheel"
mode: "0755"
tags:
- openvpn
- name: Include /etc/sudoers.d in sudoers configuration file
lineinfile:
path: /etc/sudoers
line: '#includedir /etc/sudoers.d'
tags:
- openvpn
- name: Verify shellpki sudoers file presence
copy:
src: "sudo_shellpki"
dest: "/etc/sudoers.d/shellpki"
force: true
mode: "0440"
validate: '/usr/local/sbin/visudo -cf %s'
tags:
- openvpn
- name: Copy check_openvpn
copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
owner: root
group: wheel
mode: "{{ item.mode }}"
force: true
with_items:
- src: 'files/check_openvpn.pl'
dest: '/usr/local/libexec/nagios/plugins/check_openvpn.pl'
mode: '0755'
tags:
- openvpn
- name: Install needed package for check_openvpn
openbsd_pkg:
name: "p5-Net-Telnet"
tags:
- openvpn

View File

@ -0,0 +1,8 @@
-----BEGIN DH PARAMETERS-----
MIIBCAKCAQEAuimweC/f5W/AIIFhLX256Bi5IU+AkN9sKZ9sxGx0xc3J8NwIBnEP
R/2RgclJqJ8OodY70zeDHNLDyc01crGvihuupiWVlvQxS4osdhfdM+GoV9pcmCVr
TRTybsUPkkm4rQ/SC7I2MxiYnXwDrrYnpMvBDaRZjoHlgTKjOGoYSd+DIDZSFKkv
ASkXQkIC9FpvjnxfW5gtzzm6NheqgYUI2Y2QiqM6BmGVZiPcqyUpbWvRCcZLoPa2
Z+FV9LxE4J7CX0ilTJXXhs3RaMlG8qZha3l0hEL4SAZp5xn74Ej/9hA5cWqnKEOQ
aLfwADI4rPe9uTu9Qnw87DgM2tQeETBlmwIBAg==
-----END DH PARAMETERS-----

View File

@ -0,0 +1,26 @@
user nobody
group nogroup
local {{ ansible_default_ipv4.address }}
port 1194
proto udp
dev tun
mode server
keepalive 10 120
cipher AES-128-CBC # AES
#comp-lzo
# compress (à partir d'OpenVPN 2.4)
persist-key
persist-tun
status /var/log/openvpn-status.log
log-append /var/log/openvpn.log
ca /etc/shellpki/cacert.pem
cert /etc/shellpki/certs/{{ ansible_fqdn }}.crt
key /etc/shellpki/private/{{ ansible_fqdn }}.key
dh /etc/shellpki/dh2048.pem
server {{ openvpn_lan }} {{ openvpn_netmask }}

14
roles/ospf/README.md Normal file
View File

@ -0,0 +1,14 @@
# OSPF
Deployment of OSPF check scripts with their cron.
## Tasks
Everything is in the `tasks/main.yml` file.
## Available variables
The full list of variables (with default values) can be found in `defaults/main.yml`.
* `ospf_mailto` : email address the output of the scripts will be sent to when a change is detected
* `ospf_sed_command` : facultative sed command to modify the ospfctl output and add a name to IPs

View File

@ -0,0 +1,3 @@
---
ospf_mailto: "foobar@example.com"
ospf_sed_command: ""

22
roles/ospf/tasks/main.yml Normal file
View File

@ -0,0 +1,22 @@
---
- name: Deploy ospf check scripts
template:
src: "{{ item }}.j2"
dest: /usr/share/scripts/{{ item }}
with_items:
- "ospfd-check-peers.sh"
- "ospf6d-check-peers.sh"
when: group_names | select('search','ospf') | list | count > 0
tags:
- ospf
- name: Cron job for ospf check scripts is installed
cron:
name: "{{ item }} check"
job: "/bin/sh /usr/share/scripts/{{ item }}-check-peers.sh"
with_items:
- ospfd
- ospf6d
when: group_names | select('search','ospf') | list | count > 0
tags:
- ospf

View File

@ -0,0 +1,126 @@
#!/bin/ksh
# Script writen by Daniel Jakots for BGP, adapted by Jeremy Dubois for OSPF
# First we go through the list of neighbor and we write all the peer and
# their status in "${_TMPDIR}"/ospf6-status.
# Then we monitor if this file has changed between now and the previous run.
# If it did, we send a mail with the states of the different sessions.
set -u
PATH=$HOME/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:.
_MAILTO="{{ ospf_mailto }}"
_TMPDIR=/tmp/check-ospf6
_PIDFILE="${_TMPDIR}"/ospf6d-check-peers.pid
if [ -e /etc/realname ]; then
_REALNAME=$(cat /etc/realname)
_HOSTNAME=$(hostname -s)
else
_HOSTNAME=$(hostname)
fi
mkdir -p "${_TMPDIR}"
# Don't try to run if it's already running
if [ -e "${_PIDFILE}" ]; then
echo "$(date)" >> "${_TMPDIR}"/log
exit 1
else
echo $$ >> "${_PIDFILE}"
fi
# Create an history
if [[ -f "${_TMPDIR}"/ospf6-status ]] ; then
mv "${_TMPDIR}"/ospf6-status "${_TMPDIR}"/ospf6-status.old
else
touch "${_TMPDIR}"/ospf6-status
touch "${_TMPDIR}"/ospf6-status.old
fi
# List peers and loops on them to list them and their OSPF6 state
ospf6ctl show neighbor | grep -v "^$" | grep -v "Uptime" | awk {'print $1'} > "${_TMPDIR}"/peers-list
while read _PEER
do
_STATUS=$(/usr/sbin/ospf6ctl show neighbor | grep "${_PEER} " | awk {'print $3'})
echo -n "${_PEER}" >> "${_TMPDIR}"/ospf6-status
echo -n " " >> "${_TMPDIR}"/ospf6-status
if ([[ "${_STATUS}" = "FULL/BCKUP" ]] || [[ "${_STATUS}" = "FULL/DR" ]] || [[ "${_STATUS}" = "2-WAY/OTHER" ]] || [[ "${_STATUS}" = "FULL/OTHER" ]]) ; then
_STATUS="UP"
else
_STATUS="DOWN"
fi
echo "${_STATUS}" >> "${_TMPDIR}"/ospf6-status
done <"${_TMPDIR}"/peers-list
# Check for difference with previous run
different=$(diff -q "${_TMPDIR}"/ospf6-status.old "${_TMPDIR}"/ospf6-status)
if ! [[ -n "${different}" ]] ; then
rm -f "${_PIDFILE}"
exit 0
fi
# It changed so we're going to send a mail
_TMPMAILDIR="${_TMPDIR}"/mail
mkdir -p "${_TMPMAILDIR}"
# go through sessions and list them depending on their OSPF6 state
echo "*** Session(s) OK ***\n" >> "${_TMPMAILDIR}"/bodyok
while read _LINE
do
# _LINE is session + status
_STATUS=$(echo "${_LINE}" | awk {'print $2'})
_SESSION=$(echo "${_LINE}" | awk {'print $1'})
if [[ "${_STATUS}" = "UP" ]] ; then
ospf6ctl show neighbor | grep "${_SESSION} " {{ ospf_sed_command }} >> "${_TMPMAILDIR}"/bodyok
else
ospf6ctl show neighbor | grep "${_SESSION} " {{ ospf_sed_command }} >> "${_TMPMAILDIR}"/bodynok
fi
done <"${_TMPDIR}"/ospf6-status
# create the mail body
echo "Dear NOC,\n\nThe state of one or more OSPF6 session(s) has changed:\n" > "${_TMPMAILDIR}"/header
cat "${_TMPMAILDIR}"/header "${_TMPMAILDIR}"/bodyok > "${_TMPMAILDIR}"/body
_STATE="OK"
if [[ -f "${_TMPMAILDIR}"/bodynok ]] ; then
_STATE="NOT OK"
echo "\n*** Session(s) on error ***\n" >> "${_TMPMAILDIR}"/body
cat "${_TMPMAILDIR}"/bodynok >> "${_TMPMAILDIR}"/body
fi
# Add some infos
echo "\n\n*** Known OSPF routes ***\n" >> "${_TMPMAILDIR}"/body
ospf6ctl show fib ospf >> "${_TMPMAILDIR}"/body
echo "\n\n*** Network used memory ***\n" >> "${_TMPMAILDIR}"/body
netstat -m >> "${_TMPMAILDIR}"/body
echo "\n\n*** Server load ***\n" >> "${_TMPMAILDIR}"/body
w >> "${_TMPMAILDIR}"/body
echo "\n\n*** Processes ***\n" >> "${_TMPMAILDIR}"/body
top >> "${_TMPMAILDIR}"/body
# Send the mail whether we have a realname or not
if [ -n "${_REALNAME}" ]; then
cat "${_TMPMAILDIR}"/body | mail -s "[OSPF6] ${_REALNAME} (${_HOSTNAME}) - State change - ${_STATE}" "${_MAILTO}"
else
cat "${_TMPMAILDIR}"/body | mail -s "[OSPF6] ${_HOSTNAME} - State change - ${_STATE}" "${_MAILTO}"
fi
# cleaning
if [[ -d "${_TMPMAILDIR}" ]] ; then
rm -rf "${_TMPMAILDIR}"
fi
rm -f "${_PIDFILE}"

View File

@ -0,0 +1,127 @@
#!/bin/ksh
# Script writen by Daniel Jakots for BGP, adapted by Jeremy Dubois for OSPF
# First we go through the list of neighbor and we write all the peer and
# their status in "${_TMPDIR}"/ospf-status.
# Then we monitor if this file has changed between now and the previous run.
# If it did, we send a mail with the states of the different sessions.
set -u
PATH=$HOME/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:.
_MAILTO="{{ ospf_mailto }}"
_TMPDIR=/tmp/check-ospf
_PIDFILE="${_TMPDIR}"/ospfd-check-peers.pid
if [ -e /etc/realname ]; then
_REALNAME=$(cat /etc/realname)
_HOSTNAME=$(hostname -s)
else
_HOSTNAME=$(hostname)
fi
mkdir -p "${_TMPDIR}"
# Don't try to run if it's already running
if [ -e "${_PIDFILE}" ]; then
echo "$(date)" >> "${_TMPDIR}"/log
exit 1
else
echo $$ >> "${_PIDFILE}"
fi
# Create an history
if [[ -f "${_TMPDIR}"/ospf-status ]] ; then
mv "${_TMPDIR}"/ospf-status "${_TMPDIR}"/ospf-status.old
else
touch "${_TMPDIR}"/ospf-status
touch "${_TMPDIR}"/ospf-status.old
fi
# List peers and loops on them to list them and their OSPF state
ospfctl show neighbor | grep -v "^$" | grep -v "Uptime" | awk {'print $1'} > "${_TMPDIR}"/peers-list
while read _PEER
do
_STATUS=$(/usr/sbin/ospfctl show neighbor | grep "${_PEER} " | awk {'print $3'})
echo -n "${_PEER}" >> "${_TMPDIR}"/ospf-status
echo -n " " >> "${_TMPDIR}"/ospf-status
if ([[ "${_STATUS}" = "FULL/BCKUP" ]] || [[ "${_STATUS}" = "FULL/DR" ]] || [[ "${_STATUS}" = "2-WAY/OTHER" ]] || [[ "${_STATUS}" = "FULL/OTHER" ]]) ; then
_STATUS="UP"
else
_STATUS="DOWN"
fi
echo "${_STATUS}" >> "${_TMPDIR}"/ospf-status
done <"${_TMPDIR}"/peers-list
# Check for difference with previous run
different=$(diff -q "${_TMPDIR}"/ospf-status.old "${_TMPDIR}"/ospf-status)
if ! [[ -n "${different}" ]] ; then
rm -f "${_PIDFILE}"
exit 0
fi
# It changed so we're going to send a mail
_TMPMAILDIR="${_TMPDIR}"/mail
mkdir -p "${_TMPMAILDIR}"
# go through sessions and list them depending on their OSPF state
echo "*** Session(s) OK ***\n" >> "${_TMPMAILDIR}"/bodyok
while read _LINE
do
# _LINE is session + status
_STATUS=$(echo "${_LINE}" | awk {'print $2'})
_SESSION=$(echo "${_LINE}" | awk {'print $1'})
if [[ "${_STATUS}" = "UP" ]] ; then
ospfctl show neighbor | grep "${_SESSION} " {{ ospf_sed_command }} >> "${_TMPMAILDIR}"/bodyok
else
ospfctl show neighbor | grep "${_SESSION} " {{ ospf_sed_command }} >> "${_TMPMAILDIR}"/bodynok
fi
done <"${_TMPDIR}"/ospf-status
# create the mail body
echo "Dear NOC,\n\nThe state of one or more OSPF session(s) has changed:\n" > "${_TMPMAILDIR}"/header
cat "${_TMPMAILDIR}"/header "${_TMPMAILDIR}"/bodyok > "${_TMPMAILDIR}"/body
_STATE="OK"
if [[ -f "${_TMPMAILDIR}"/bodynok ]] ; then
_STATE="NOT OK"
echo "\n*** Session(s) on error ***\n" >> "${_TMPMAILDIR}"/body
cat "${_TMPMAILDIR}"/bodynok >> "${_TMPMAILDIR}"/body
fi
# Add some infos
echo "\n\n*** Known OSPF routes ***\n" >> "${_TMPMAILDIR}"/body
ospfctl show fib ospf >> "${_TMPMAILDIR}"/body
echo "\n\n*** Network used memory ***\n" >> "${_TMPMAILDIR}"/body
netstat -m >> "${_TMPMAILDIR}"/body
echo "\n\n*** Server load ***\n" >> "${_TMPMAILDIR}"/body
w >> "${_TMPMAILDIR}"/body
echo "\n\n*** Processes ***\n" >> "${_TMPMAILDIR}"/body
top >> "${_TMPMAILDIR}"/body
# Send the mail whether we have a realname or not
if [ -n "${_REALNAME}" ]; then
cat "${_TMPMAILDIR}"/body | mail -s "[OSPF] ${_REALNAME} (${_HOSTNAME}) - State change - ${_STATE}" "${_MAILTO}"
else
cat "${_TMPMAILDIR}"/body | mail -s "[OSPF] ${_HOSTNAME} - State change - ${_STATE}" "${_MAILTO}"
fi
# cleaning
if [[ -d "${_TMPMAILDIR}" ]] ; then
rm -rf "${_TMPMAILDIR}"
fi
rm -f "${_PIDFILE}"

View File

@ -4,4 +4,6 @@
src: pf.conf.j2 src: pf.conf.j2
dest: /etc/pf.conf dest: /etc/pf.conf
mode: "0600" mode: "0600"
backup: yes backup: true
tags:
- pf

View File

@ -54,8 +54,8 @@ block log all
#pass quick on $pfsync_if proto pfsync #pass quick on $pfsync_if proto pfsync
pass out pass out
# 9999 = pfstat, 5666 = nrpe # 5666 = nrpe
pass in on $ext_if proto tcp from <evolix> to (self) port { 9999, ssh, 5666 } pass in on $ext_if proto tcp from <evolix> to (self) port { ssh, 5666 }
# Block Attack # Block Attack
# China 144.0.0.0/16 --> SSH # China 144.0.0.0/16 --> SSH

View File

@ -5,9 +5,10 @@ dnsPTRrecord=$(hostname)
HardwareMark=$(sysctl hw.vendor| sed 's#hw.vendor=##') HardwareMark=$(sysctl hw.vendor| sed 's#hw.vendor=##')
HardwareModel=$(sysctl hw.product| sed 's#hw.product=##') HardwareModel=$(sysctl hw.product| sed 's#hw.product=##')
computerIP=$(ifconfig egress | grep inet | awk -v OFS="\n" '{ print $2, $NF }'| head -1) computerIP=$(ifconfig egress | grep inet | awk -v OFS="\n" '{ print $2, $NF }'| head -1)
computerOS=OpenBSD
computerKernel=$(sysctl kern.osrelease | sed 's#kern.osrelease=##') computerKernel=$(sysctl kern.osrelease | sed 's#kern.osrelease=##')
HardwareSerial=$(sysctl hw.serialno| sed 's#hw.serialno=##') computerOS="OpenBSD $computerKernel"
HardwareSerial=$(sysctl hw.serialno 2>/dev/null | sed 's#hw.serialno=##')
if [ -z $HardwareSerial ]; then sysctl hw | grep -qi qemu && HardwareSerial="Not Specified"; fi
clientNumber="XXX" clientNumber="XXX"
cpuMark=$(sysctl hw.model| sed 's#hw.model=##') cpuMark=$(sysctl hw.model| sed 's#hw.model=##')
cpuModel=$(sysctl hw.model| sed 's#hw.model=##') cpuModel=$(sysctl hw.model| sed 's#hw.model=##')
@ -62,8 +63,8 @@ HardwareSize: $cpuFreq
HardwareType: CPU HardwareType: CPU
HardwareModel: $cpuModel HardwareModel: $cpuModel
dn: HardwareName=ram0,EvoComputerName=${EvoComputerName},ou=computer,dc=evolix,dc=net dn: HardwareName=mem,EvoComputerName=${EvoComputerName},ou=computer,dc=evolix,dc=net
HardwareName: ram0 HardwareName: mem
objectClass: EvoHardware objectClass: EvoHardware
HardwareSize: $mem HardwareSize: $mem
HardwareType: mem HardwareType: mem
@ -119,7 +120,7 @@ objectClass: EvoService
ipServicePort: 22 ipServicePort: 22
ServiceName: openssh ServiceName: openssh
ServiceType: ssh ServiceType: ssh
ServiceVersion: OpenSSH 6.7 ServiceVersion: OpenSSH 8.3
dn: ServiceName=opensmtpd,EvoComputerName=${EvoComputerName},ou=computer,dc=evolix,dc=net dn: ServiceName=opensmtpd,EvoComputerName=${EvoComputerName},ou=computer,dc=evolix,dc=net
ipServiceProtocol: tcp ipServiceProtocol: tcp
@ -128,13 +129,20 @@ objectClass: EvoService
ServiceName: opensmtpd ServiceName: opensmtpd
ipServicePort: 25 ipServicePort: 25
ServiceType: smtp ServiceType: smtp
ServiceVersion: OpenSMTPD 5.4.3 ServiceVersion: OpenSMTPD 6.7.1p1
dn: ServiceName=ntp,EvoComputerName=${EvoComputerName},ou=computer,dc=evolix,dc=net dn: ServiceName=ntp,EvoComputerName=${EvoComputerName},ou=computer,dc=evolix,dc=net
NagiosEnabled: TRUE NagiosEnabled: TRUE
objectClass: EvoService objectClass: EvoService
ServiceName: ntp ServiceName: ntp
ServiceType: ntp ServiceType: ntp
ServiceVersion: OpenNTPd 4.6 ServiceVersion: OpenNTPd 6.2p3
dn: ServiceName=packetfilter,EvoComputerName=${EvoComputerName},ou=computer,dc=evolix,dc=net
NagiosEnabled: TRUE
objectClass: EvoService
ServiceName: packetfilter
ServiceType: firewall
ServiceVersion: packetfilter
EOT EOT

View File

@ -0,0 +1,47 @@
#!/bin/sh
if [ ! -f /etc/motd-original ]; then
cp /etc/motd /etc/motd-original
fi
if [ ! -f /tmp/carp.state ]; then
echo "unknown" > /tmp/carp.state
fi
ifconfig carp0 | grep -q master
master=$?
ifconfig carp0 | grep -q backup
backup=$?
if [ "$master" -eq 0 ]; then
if [ $(cat /tmp/carp.state) = "master" ]; then
# We already were master, no change
exit 0
fi
cat /etc/motd-original - << EOF > /etc/motd
__ ______ _____________________
/ |/ / | / ___/_ __/ ____/ __ \
/ /|_/ / /| | \__ \ / / / __/ / /_/ /
/ / / / ___ |___/ // / / /___/ _, _/
/_/ /_/_/ |_/____//_/ /_____/_/ |_|
EOF
echo "master" > /tmp/carp.state
elif [ "$backup" -eq 0 ]; then
if [ $(cat /tmp/carp.state) = "backup" ]; then
# We already were backup, no change
exit 0
fi
cat /etc/motd-original - << EOF > /etc/motd
____ ___ ________ ____ ______
/ __ )/ | / ____/ //_/ / / / __ \
/ __ / /| |/ / / ,< / / / / /_/ /
/ /_/ / ___ / /___/ /| / /_/ / ____/
/_____/_/ |_\____/_/ |_\____/_/
EOF
echo "backup" > /tmp/carp.state
else
# No CARP
exit 0
fi

View File

@ -2,3 +2,4 @@
# tasks files # tasks files
- include: ldif.yml - include: ldif.yml
- include: update.yml - include: update.yml
- include: motd.yml

View File

@ -0,0 +1,25 @@
---
- name: Deploy dynamic motd script for CARP master or backup
copy:
src: motd-carp-state.sh
dest: /usr/share/scripts/motd-carp-state.sh
owner: root
group: wheel
mode: '0755'
- name: Fetch root crontab content
command: >
'grep "/bin/sh /usr/share/scripts/motd-carp-state.sh" /var/cron/tabs/root'
check_mode: false
register: root_crontab_content
failed_when: false
changed_when: false
- name: Cron job for dynamic motd script is installed
cron:
name: dynamic motd for CARP
job: "/bin/sh /usr/share/scripts/motd-carp-state.sh"
disabled: true
when:
- not (root_crontab_content.stdout
| regex_search('/bin/sh /usr/share/scripts/motd-carp-state.sh'))

View File

@ -1,9 +1,4 @@
--- ---
- name: Fetch and install openup - name: Check and install updates (erratas) if available
get_url: shell: /usr/sbin/syspatch
url: https://stable.mtier.org/openup when: ansible_distribution_version is version_compare("6.1",'>=')
dest: /usr/local/bin/openup
mode: "0750"
- name: Install updates (erratas) with openup
shell: /usr/local/bin/openup

View File

@ -3,19 +3,25 @@
command: git status --porcelain command: git status --porcelain
args: args:
chdir: /etc chdir: /etc
changed_when: False changed_when: false
register: git_status register: git_status
when: not ansible_check_mode when: not ansible_check_mode
ignore_errors: yes ignore_errors: true
tags: tags:
- commit-etc - commit-etc
# yamllint disable rule:line-length
- name: /etc modifications are committed - name: /etc modifications are committed
shell: "git add -A . && git commit -m \"{{ commit_message | default('Ansible run') }}\" --author=\"{{ ansible_env.SUDO_USER | default('Root') }} <{{ ansible_env.SUDO_USER | default('Root') }}@{{ general_technical_realm }}>\"" shell: >
git add -A .
&& git commit
-m "{{ commit_message | default('Ansible run') }}"
--author="{{ ansible_env.SUDO_USER | default('Root') }}
<{{ ansible_env.SUDO_USER | default('Root') }}@{{ general_technical_realm }}>"
args: args:
chdir: /etc chdir: /etc
register: etc_commit_end_evolinux register: etc_commit_end_evolinux
when: not ansible_check_mode and git_status.stdout != "" when: not ansible_check_mode and git_status.stdout != ""
ignore_errors: yes ignore_errors: true
tags: tags:
- commit-etc - commit-etc
# yamllint enable rule:line-length

View File

@ -3,26 +3,31 @@
## Edit and uncomment to overwrite the default values ## ## Edit and uncomment to overwrite the default values ##
######################################################## ########################################################
#ntpd_servers: # ntpd_servers:
#- "ntp.evolix.net" # - "ntp.evolix.net"
# #
#general_alert_email: "root@localhost" # general_alert_email: "root@localhost"
#general_technical_realm: "example.com" # general_technical_realm: "example.com"
# #
#evomaintenance_realm: "example.com" # evomaintenance_realm: "example.com"
#evomaintenance_alert_email: "evomaintenance-{{ inventory_hostname }}@{{ evomaintenance_realm }}" # evomaintenance_alert_email:
#evomaintenance_hostname: "{{ inventory_hostname }}.{{ general_technical_realm }}" # "evomaintenance-{{ inventory_hostname }}@{{ evomaintenance_realm }}"
#evomaintenance_pg_host: Null # evomaintenance_hostname:
#evomaintenance_pg_passwd: Null # "{{ inventory_hostname }}.{{ general_technical_realm }}"
#evomaintenance_pg_db: Null # evomaintenance_pg_host: Null
#evomaintenance_pg_table: Null # evomaintenance_pg_passwd: Null
#evomaintenance_from_domain: "{{ evomaintenance_realm }}" # evomaintenance_pg_db: Null
#evomaintenance_from: "evomaintenance@{{ evomaintenance_from_domain }}" # evomaintenance_pg_table: Null
#evomaintenance_full_from: "Evomaintenance <{{ evomaintenance_from }}>" # evomaintenance_from_domain: "{{ evomaintenance_realm }}"
#evomaintenance_urgency_from: mama.doe@example.com # evomaintenance_from: "evomaintenance@{{ evomaintenance_from_domain }}"
#evomaintenance_urgency_tel: "06.00.00.00.00" # evomaintenance_full_from: "Evomaintenance <{{ evomaintenance_from }}>"
# evomaintenance_urgency_from: mama.doe@example.com
# evomaintenance_urgency_tel: "06.00.00.00.00"
# #
#evolix_users: # evobsd_ssh_group: "foo-ssh"
# evobsd_sudo_group: "foo-sudo"
#
# evolix_users:
# foo: # foo:
# name: foo # name: foo
# uid: 1042 # uid: 1042

0
vars/openbsd-secret.yml Normal file
View File

0
vars/secrets.yml Normal file
View File