Update to 2021-12-01 19:13

This commit is contained in:
Daniel Berteaud
2021-12-01 19:13:34 +01:00
commit 4c4556c660
2153 changed files with 60999 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
---
zabbix_server_port: 10051
zabbix_server_src_ip: []
zabbix_server_java_gateway_port: 10052
# If defined, can restrict IP to access the web interface
# zabbix_server_web_src_ip:
zabbix_server_db_server: "{{ mysql_server | default('localhost') }}"
zabbix_server_db_port: 3306
zabbix_server_db_user: zabbix
zabbix_server_db_name: zabbix
# zabbix_server_db_pass: secret
zabbix_server_php_user: zabbix
zabbix_server_php_version: 74
# If you want to use a custom php pool
# zabbix_server_php_fpm_pool: php70
zabbix_server_base_conf:
Timeout: 4
LogSlowQueries: 2000
LoadModulePath: /usr/lib64/zabbix/modules
LogType: system
PidFile: /var/run/zabbix/zabbix_server.pid
SocketDir: /var/run/zabbix
AlertScriptsPath: /var/lib/zabbix/bin
ExternalScripts: /var/lib/zabbix/bin
TmpDir: /tmp
ProxyConfigFrequency: 900
ProxyDataFrequency: 30
JavaGateway: 127.0.0.1
JavaGatewayPort: "{{ zabbix_server_java_gateway_port }}"
StartJavaPollers: 0
zabbix_server_extra_conf: {}
zabbix_server_conf: "{{ zabbix_server_base_conf | combine(zabbix_server_extra_conf, recursive=True) }}"
zabbix_server_auth_http: False
# Housekeeping settings
# Matrix notifications
# zabbix_server_matrix_server: matrix.org
# zabbix_server_matrix_user: alerts
# zabbix_server_matrix_pass: secret
#
# Or
#
# zabbix_server_matrix_access_token: ...
# Zabbix DB can be huge. If zabbix_server_backup_on_full_only is true
# pre-backup will skip history tables from the dump. Except if called with
# pre-backup full
zabbix_server_backup_on_full_only: False
# Disable zabbix pre/post backup if you need to handle it with your own script
zabbix_server_backup_hooks: True
# You might want to ignore system proxy for Zabbix server itself,
# so its web monitoring can be direct
# This will only have an effect if system_proxy is defined
zabbix_server_uses_system_proxy: True

View File

@@ -0,0 +1,109 @@
#!/usr/bin/perl
=head1 SYNOPSIS
check_ssl_certificate.pl
--url,-u URL
--sni,-s HOSTNAME SNI servername (SSL vhost) that will be requested during SSL handshake.
This tells the server which certificate to return.
Default to the host passed with --url
=cut
use strict;
use warnings;
use IO::Socket::SSL;
use LWP::UserAgent;
use URI::URL;
use DateTime::Format::ISO8601;
use Getopt::Long qw/:config auto_help/;
use Pod::Usage;
use JSON qw(to_json);
use constant TIMEOUT => 10;
my ($url, $sni, $status, @san);
sub ssl_opts {
my ($sni, $expiration_date_ref, $status_ref, $san_ref) = @_;
return (
'verify_hostname' => 0,
'SSL_ca_file' => '/etc/pki/tls/certs/ca-bundle.crt',
'SSL_hostname' => $sni,
'SSL_verifycn_name' => $sni,
'SSL_verify_scheme' => 'http',
'SSL_verify_callback' => sub {
my (undef, $ctx_store) = @_;
# Get the error message from openssl verification
$$status_ref = Net::SSLeay::X509_verify_cert_error_string(Net::SSLeay::X509_STORE_CTX_get_error($ctx_store));
# Get the raw cert, to extract the expiration
my $cert = Net::SSLeay::X509_STORE_CTX_get_current_cert($ctx_store);
$$expiration_date_ref = Net::SSLeay::P_ASN1_TIME_get_isotime(Net::SSLeay::X509_get_notAfter($cert));
# Get Alt names so we can check later if the hostname match
@$san_ref = Net::SSLeay::X509_get_subjectAltNames($cert);
# Keep only odd elements. Even ones contains subject types which we're not interested in
@$san_ref = @$san_ref[grep $_ % 2, 0..scalar(@$san_ref)];
# Always return success
return 1;
}
)
}
sub https_get {
my ($url, $sni, $expiration_date_ref, $status_ref, $san_ref) = @_;
my $ua = LWP::UserAgent->new();
$ua->timeout(TIMEOUT);
$ua->ssl_opts( ssl_opts($sni, $expiration_date_ref, $status_ref, $san_ref) );
my $request = HTTP::Request->new('GET', $url);
$request->header(Host => $sni);
my $response = $ua->simple_request($request);
return $response;
}
sub wildcard_match {
my ($cn, $host) = @_;
my $match = 0;
return 0 if $cn !~ m/^\*\.(.*)$/;
my $cn_dom = $1;
my $host_dom = ($sni =~ m/^[^\.]+\.(.*)$/)[0];
return ($cn_dom eq $host_dom);
}
GetOptions ("url|u=s" => \$url,
"sni|s=s" => \$sni) or pod2usage(1);
if (@ARGV) {
print "This script takes no arguments...\n";
pod2usage(1);
}
pod2usage(1) if (!$url);
my $expiration_date;
my $uri = URI->new($url);
die "Only https urls are supported\n" unless $uri->scheme eq 'https';
$sni ||= $uri->host;
my $response = https_get($url, $sni, \$expiration_date, \$status, \@san);
my $out = {
code => $response->code,
status => $response->message,
days_left => undef,
cert_cn => undef,
issuer => undef
};
if ($response->code != 500) { # Even a 404 is good enough, as far as cert validation goes...
my $now = DateTime->now;
$expiration_date = DateTime::Format::ISO8601->parse_datetime( $expiration_date );
$out->{issuer} = $response->headers->{'client-ssl-cert-issuer'};
$out->{cert_cn} = ($response->headers->{'client-ssl-cert-subject'} =~ m/CN=(.*)$/)[0];
$status = "no common name" if !$out->{cert_cn};
$out->{status} = ($status eq 'ok' and !grep { $sni eq $_ } @san and !wildcard_match($out->{cert_cn},$sni)) ?
$out->{status} = "hostname mismatch ($sni doesn't match any of " . join(" ", @san) . ")" :
$status;
$out->{days_left} = ($expiration_date < $now) ? -1 * $expiration_date->delta_days($now)->delta_days :
$expiration_date->delta_days($now)->delta_days
}
print to_json($out, { pretty => 1 });

View File

@@ -0,0 +1,26 @@
#!/bin/bash
TO=$1
MESSAGE=$2
if [[ $TO =~ ^@ ]]; then
# This is a matrix user. We need to create a room before we can send
# But first check if we haven't already one
if [ -e ~/.matrix_zabbix/$TO ]; then
# We already have a room for this user, just send it there
TO=$(cat ~/.matrix_zabbix/$TO)
else
# Create a new room, invite the user, and grant him admin privileges
USER=$TO
TO=$(patrix --create-room --name="Zabbix Alerter for $TO" --topic='Alerts' --invite=$TO)
patrix --modify-room --room=$TO --user-perm "$USER=100"
echo $TO > ~/.matrix_zabbix/$USER
fi
fi
# Check we now have a room ID or alias
if [[ $TO =~ ^[\!\#] ]]; then
echo "$MESSAGE" | patrix --room=$TO
else
echo "Can't send to $TO"
exit 1
fi

View File

@@ -0,0 +1,20 @@
module zabbix_server 1.2;
require {
type zabbix_var_run_t;
type zabbix_t;
type zabbix_var_lib_t;
type mysqld_db_t;
class sock_file { create unlink write };
class unix_stream_socket connectto;
class file { execute execute_no_trans };
class capability dac_override;
}
#============= zabbix_t ==============
allow zabbix_t self:unix_stream_socket connectto;
allow zabbix_t self:capability dac_override;
allow zabbix_t zabbix_var_lib_t:file { execute execute_no_trans };
allow zabbix_t zabbix_var_run_t:sock_file { create unlink };
allow zabbix_t mysqld_db_t:sock_file write;

View File

@@ -0,0 +1,12 @@
---
- name: restart zabbix-server
service: name=zabbix-server state=restarted
when: not zabbix_server_started.changed # Do not restart if the server has just started
- name: restart zabbix-java-gateway
service:
name: zabbix-java-gateway
state: "{{ (zabbix_server_conf['StartJavaPollers'] is defined and zabbix_server_conf['StartJavaPollers'] > 0) | ternary('restarted','stopped') }}"
tags: zabbix
...

View File

@@ -0,0 +1,6 @@
---
dependencies:
- role: mkdir
- role: repo_zabbix
- role: httpd_php
- role: snmp_mibs

View File

@@ -0,0 +1,90 @@
---
- name: Deploy patrix configuration file
template: src=patrixrc.j2 dest=/var/lib/zabbix/.patrixrc owner=zabbix group=zabbix mode=600
when: (zabbix_server_matrix_user is defined and zabbix_server_matrix_pass is defined) or zabbix_server_matrix_access_token is defined
tags: zabbix
- name: Deploy PHP configuration
template: src=php.conf.j2 dest=/etc/opt/remi/php{{ zabbix_server_php_version }}/php-fpm.d/zabbix_server.conf
when: zabbix_server_php_fpm_pool is not defined
notify: restart php-fpm
tags: zabbix
- name: Remove PHP configuration from other versions
file: path=/etc/opt/remi/php{{ item }}/php-fpm.d/zabbix_server.conf state=absent
with_items: "{{ httpd_php_versions | difference([ zabbix_server_php_version ]) }}"
notify: restart php-fpm
tags: zabbix
- name: Remove PHP configuration (using a custom pool)
file: path=/etc/opt/remi/php{{ zabbix_server_php_version }}/php-fpm.d/zabbix_server.conf state=absent
when: zabbix_server_php_fpm_pool is defined
notify: restart php-fpm
tags: zabbix
- import_tasks: ../includes/webapps_create_mysql_db.yml
vars:
- db_name: "{{ zabbix_server_db_name }}"
- db_user: "{{ zabbix_server_db_user }}"
- db_server: "{{ zabbix_server_db_server }}"
- db_pass: "{{ zabbix_server_db_pass }}"
- db_encoding: utf8
- db_collation: utf8_bin
tags: zabbix
- name: Check if database is initialized
command: mysql -h'{{ zabbix_server_db_server }}' -u'{{ zabbix_server_db_user }}' -p'{{ zabbix_server_db_pass }}' '{{ zabbix_server_db_name }}' -e 'select mandatory,optional from dbversion'
register: zabbix_server_db_init
changed_when: False
failed_when: False
tags: zabbix
- name: Check Zabbix version
shell: rpm -q --qf "%{version}" zabbix-server-mysql
args:
warn: False
register: zabbix_server_version
changed_when: False
tags: zabbix
- when: zabbix_server_db_init.rc != 0
tags: zabbix
block:
- name: Uncompress Zabbix schema file
shell: gzip -dc /usr/share/doc/zabbix-server-mysql/create.sql.gz > /tmp/zabbix.sql
- name: Load DB schema
mysql_db:
name: "{{ zabbix_server_db_name }}"
state: import
target: /tmp/zabbix.sql
login_host: "{{ zabbix_server_db_server }}"
login_user: sqladmin
login_password: "{{ mysql_admin_pass }}"
- name: Remove schema file
file: path=/tmp/zabbix.sql state=absent
- name: Deploy zabbix server config
template: src=zabbix_server.conf.j2 dest=/etc/zabbix/zabbix_server.conf group=zabbix mode=640
notify: restart zabbix-server
tags: zabbix
- name: Deploy java gateway configuration
template: src=zabbix_java_gateway.conf.j2 dest=/etc/zabbix/zabbix_java_gateway.conf
notify: restart zabbix-java-gateway
tags: zabbix
- name: Deploy zabbix web config
template: src=zabbix.conf.php.j2 dest=/etc/zabbix/web/zabbix.conf.php group=apache mode=640
tags: zabbix
- name: Deploy httpd config
template: src=httpd.conf.j2 dest=/etc/httpd/ansible_conf.d/zabbix_server.conf
notify: reload httpd
tags: zabbix
- name: Deploy server scripts
copy: src=scripts/ dest=/var/lib/zabbix/bin/ mode=755
tags: zabbix

View File

@@ -0,0 +1,17 @@
---
- name: Create directories
file: path={{ item.dir }} state=directory owner={{ item.owner | default(omit) }} group={{ item.group | default(omit) }} mode={{ item.mode | default(ompit) }}
with_items:
- dir: /var/lib/zabbix/.matrix_zabbix
owner: zabbix
group: zabbix
mode: 700
- dir: /var/lib/zabbix/sessions
owner: apache
group: apache
mode: 700
tags: zabbix
#- name: Ensure proper permission on the web config dir
# file: path=/etc/zabbix/web/ state=directory mode=750 group={{ zabbix_server_php_user }}
# tags: zabbix

View File

@@ -0,0 +1,10 @@
---
- import_tasks: ../includes/get_rand_pass.yml
vars:
- pass_file: /etc/zabbix/ansible_db_pass
when: zabbix_server_db_pass is not defined
tags: zabbix
- set_fact: zabbix_server_db_pass={{ rand_pass }}
when: zabbix_server_db_pass is not defined
tags: zabbix

View File

@@ -0,0 +1,27 @@
---
- name: Install packages
yum:
name:
- zabbix-server-mysql
- zabbix-web
- zabbix-java-gateway
- zabbix-get
- mariadb
- fping
- patrix
- perl-JSON
- perl-IO-Socket-SSL
- perl-libwww-perl
- perl-URI
- perl-DateTime-Format-ISO8601
- perl-Getopt-Long
- perl-Pod-Usage
tags: zabbix
- name: Install backup scripts
template: src={{ item }}_backup.sh.j2 dest=/etc/backup/{{ item }}.d/zabbix.sh mode=700
loop:
- pre
- post
tags: zabbix

View File

@@ -0,0 +1,9 @@
---
- name: Handle Zabbix Server port
iptables_raw:
name: zabbix_server_port
state: "{{ (zabbix_server_src_ip | length > 0) | ternary('present','absent') }}"
rules: "-A INPUT -m state --state NEW -p tcp --dport {{ zabbix_server_port }} -s {{ zabbix_server_src_ip | join(',') }} -j ACCEPT"
when: iptables_manage | default(True)
tags: zabbix,firewall

View File

@@ -0,0 +1,11 @@
---
- include: facts.yml
- include: install.yml
- include: directories.yml
- include: selinux.yml
when: ansible_selinux.status == 'enabled'
- include: conf.yml
- include: iptables.yml
- include: service.yml

View File

@@ -0,0 +1,40 @@
---
- name: Copy SELinux policy
copy: src=zabbix_server.te dest=/etc/selinux/targeted/local/
register: zabbix_server_selinux_policy
tags: zabbix
- name: Install needed packages
yum:
name: policycoreutils
tags: zabbix
- name: Compile SELinux policy
shell: |
cd /etc/selinux/targeted/local/
checkmodule -M -m -o zabbix_server.mod zabbix_server.te
semodule_package -o zabbix_server.pp -m zabbix_server.mod
when: zabbix_server_selinux_policy.changed
tags: zabbix
- name: Load policy for Zabbix Proxy
command: semodule -i /etc/selinux/targeted/local/zabbix_server.pp
when: zabbix_server_selinux_policy.changed
tags: zabbix
- name: Set SELinux context
sefcontext:
target: '/var/lib/zabbix/sessions(/.*)?'
setype: httpd_var_lib_t
state: present
tags: zabbix
- name: Restore SELinux context
command: restorecon -R /var/lib/zabbix/
changed_when: False
tags: zabbix
- name: Allow network connections in SELinux
seboolean: name=zabbix_can_network state=True persistent=True
tags: zabbix

View File

@@ -0,0 +1,48 @@
---
- name: Remove custom unit
file: path=/etc/systemd/system/zabbix-server.service state=absent
register: zabbix_server_custom_unit
notify: restart zabbix-server
tags: zabbix
- name: Create unit snippet dir
file: path=/etc/systemd/system/zabbix-server.service.d state=directory
tags: zabbix
- name: Customize systemd unit
copy:
content: |
[Service]
ExecReload=/usr/sbin/zabbix_server -R config_cache_reload
PrivateTmp=yes
PrivateDevices=yes
ProtectSystem=full
ProtectHome=yes
{% if not zabbix_server_uses_system_proxy %}
# Disable system proxy
{% for proto in ['http_proxy','https_proxy','HTTP_PROXY','HTTPS_PROXY'] %}
Environment={{ proto }}=
{% endfor %}
{% endif %}
dest: /etc/systemd/system/zabbix-server.service.d/99-ansible.conf
register: zabbix_server_snippet_unit
notify: restart zabbix-server
tags: zabbix
- name: Reload systemd
systemd: daemon_reload=True
when: zabbix_server_custom_unit.changed or zabbix_server_snippet_unit.changed
tags: zabbix
- name: Start and enable the service
service: name=zabbix-server state=started enabled=True
register: zabbix_server_started
tags: zabbix
- name: Handle Zabbix Java Gateway daemon
service:
name: zabbix-java-gateway
state: "{{ (zabbix_server_conf['StartJavaPollers'] is defined and zabbix_server_conf['StartJavaPollers'] > 0) | ternary('started','stopped') }}"
enabled: "{{ (zabbix_server_conf['StartJavaPollers'] is defined and zabbix_server_conf['StartJavaPollers'] > 0) | ternary(True,False) }}"
tags: zabbix

View File

@@ -0,0 +1,18 @@
<Directory "/usr/share/zabbix">
Options FollowSymLinks
AllowOverride All
{% if zabbix_server_web_src_ip is defined %}
Require ip {{ zabbix_server_web_src_ip | join(' ') }}
{% else %}
Require all granted
{% endif %}
{% if zabbix_server_auth_http %}
SetEnvIfNoCase Auth-User "(.*)" PHP_AUTH_USER=$1
SetEnvIfNoCase Auth-User "(.*)" PHP_AUTH_PW=$1
{% endif %}
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php-fpm/{{ zabbix_server_php_fpm_pool | default('zabbix_server') }}.sock|fcgi://localhost"
</FilesMatch>
</Directory>

View File

@@ -0,0 +1,11 @@
; {{ ansible_managed }}
[default]
{% if zabbix_server_matrix_user is defined and zabbix_server_matrix_pass is defined %}
user={{ zabbix_server_matrix_user }}
password={{ zabbix_server_matrix_pass }}
{% elif zabbix_server_matrix_access_token is defined %}
access_token={{ zabbix_server_matrix_access_token }}
{% endif %}
{% if zabbix_server_matrix_server is defined %}
server={{ zabbix_server_matrix_server }}
{% endif %}

View File

@@ -0,0 +1,36 @@
; {{ ansible_managed }}
[zabbix_server]
listen.owner = root
listen.group = apache
listen.mode = 0660
listen = /run/php-fpm/zabbix_server.sock
user = apache
group = apache
catch_workers_output = yes
pm = dynamic
pm.max_children = 15
pm.start_servers = 3
pm.min_spare_servers = 3
pm.max_spare_servers = 6
pm.max_requests = 5000
request_terminate_timeout = 5m
php_flag[display_errors] = off
php_admin_flag[log_errors] = on
php_admin_value[error_log] = syslog
php_admin_value[memory_limit] = 512M
php_admin_value[session.save_path] = /var/lib/zabbix/sessions
php_admin_value[upload_tmp_dir] = /tmp
php_admin_value[post_max_size] = 32M
php_admin_value[upload_max_filesize] = 5M
php_admin_value[disable_functions] = system, show_source, symlink, exec, dl, shell_exec, passthru, phpinfo, escapeshellarg, escapeshellcmd
php_admin_value[open_basedir] = /usr/share/zabbix:/etc/zabbix:/tmp:/var/lib/zabbix/sessions:/etc/alternative/:/usr/share/fonts/dejavu/
php_admin_value[max_execution_time] = 600
php_admin_value[max_input_time] = 600
php_admin_flag[allow_url_include] = off
php_admin_flag[allow_url_fopen] = off
php_admin_flag[file_uploads] = on
php_admin_flag[session.cookie_httponly] = on

View File

@@ -0,0 +1,7 @@
#!/bin/bash -e
{% if zabbix_server_backup_hooks %}
rm -f /home/lbkp/zabbix/*
{% else %}
# pre and post backup hooks are disabled on this host
{% endif %}

View File

@@ -0,0 +1,47 @@
#!/bin/sh
set -eo pipefail
{% if zabbix_server_backup_hooks %}
mkdir -p /home/lbkp/zabbix
# First, backup the schema
/usr/bin/mysqldump --user={{ zabbix_server_db_user | quote }} \
--password={{ zabbix_server_db_pass | quote }} \
--host={{ zabbix_server_db_server | quote }} \
--port={{ zabbix_server_db_port }} \
--no-data \
--quick --single-transaction \
--add-drop-table {{ zabbix_server_db_name | quote }} | zstd -T0 -c > /home/lbkp/zabbix/{{ zabbix_server_db_name }}_schema.sql.zst
# Then, backup data
{% if zabbix_server_backup_on_full_only %}
if [[ "$1" == "full" ]]; then
/usr/bin/mysqldump --user={{ zabbix_server_db_user | quote }} \
--password={{ zabbix_server_db_pass | quote }} \
--host={{ zabbix_server_db_server | quote }} \
--port={{ zabbix_server_db_port }} \
--no-create-info \
--quick --single-transaction \
--add-locks \
{{ zabbix_server_db_name | quote }} | zstd -T0 -c > /home/lbkp/zabbix/{{ zabbix_server_db_name }}_data.sql.zst
else
{% endif %}
/usr/bin/mysqldump --user={{ zabbix_server_db_user | quote }} \
--password={{ zabbix_server_db_pass | quote }} \
--host={{ zabbix_server_db_server | quote }} \
--port={{ zabbix_server_db_port }} \
--no-create-info \
{% if zabbix_server_backup_on_full_only %}
{% for table in ['events', 'history', 'history_uint', 'history_str', 'history_text', 'trends', 'trends_uint'] %}
--ignore-table={{ zabbix_server_db_name }}.{{ table }} \
{% endfor %}
{% endif %}
--quick --single-transaction \
--add-locks \
{{ zabbix_server_db_name | quote }} | zstd -T0 -c > /home/lbkp/zabbix/{{ zabbix_server_db_name }}_data.sql.zst
{% if zabbix_server_backup_on_full_only %}
fi
{% endif %}
{% else %}
# pre and post backup hooks are disabled on this host
{% endif %}

View File

@@ -0,0 +1,15 @@
<?php
global $DB;
$DB['TYPE'] = 'MYSQL';
$DB['SERVER'] = '{{ zabbix_server_db_server }}';
$DB['PORT'] = '{{ zabbix_server_db_port }}';
$DB['DATABASE'] = '{{ zabbix_server_db_name }}';
$DB['USER'] = '{{ zabbix_server_db_user }}';
$DB['PASSWORD'] = '{{ zabbix_server_db_pass }}';
$ZBX_SERVER = 'localhost';
$ZBX_SERVER_PORT = '{{ zabbix_server_port }}';
$IMAGE_FORMAT_DEFAULT = IMAGE_FORMAT_PNG;
{% if zabbix_server_version.stdout is version('5.0', '>=') %}
$DB['DOUBLE_IEEE754'] = 'true';
{% endif %}
?>

View File

@@ -0,0 +1,3 @@
LISTEN_IP=127.0.0.1
LISTEN_PORT={{ zabbix_server_java_gateway_port }}
PID_FILE="/var/run/zabbix/zabbix_java.pid"

View File

@@ -0,0 +1,16 @@
ListenPort={{ zabbix_server_port }}
DBHost={{ zabbix_server_db_server }}
DBName={{ zabbix_server_db_name }}
DBUser={{ zabbix_server_db_user }}
DBPassword={{ zabbix_server_db_pass }}
{% if zabbix_server_db_server == 'localhost' %}
DBSocket=/var/lib/mysql/mysql.sock
{% else %}
DBPort={{ zabbix_server_db_port }}
{% endif %}
{% for key in zabbix_server_conf.keys() | list %}
{{ key }}={{zabbix_server_conf[key] }}
{% endfor %}
{% if ansible_all_ipv6_addresses | length < 1 %}
Fping6Location=
{% endif %}