diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3128709 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.retry +manual.yml +inventory/hosts +group_vars/pilote.yml +files/easyrsa/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..349ea2c --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +# ansible-pilote + +Ansible repository to manage `pilote`, a Raspberry Pi host running monitoring +software at home. This host was described in my [Journey of a Home-based +Personal Cloud Storage +Project](https://julien.riou.xyz/socallinuxexpo2024.handout.html) talk. This is +a personal repository that you can use as an example. + +# Requirements + +1. Configure network +1. Configure password for root user +1. Allow password for root user on SSH +1. Enable and start ssh.service +1. Write IP address in `inventory/hosts` file +1. Update variables in `group_vars/pilote.yml` file + +# First run + +``` +ansible-playbook --ask-pass main.yml +``` + +# Subsequent runs + +``` +ansible-playbook main.yml +``` + +# Variables + +See [documentation](group_vars/README.md). diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..b1a75ed --- /dev/null +++ b/TODO.md @@ -0,0 +1,4 @@ +# TODO + +* EasyRSA tasks +* Variables documentation diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..6b8ac0d --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,6 @@ +[defaults] +inventory = ./inventory/hosts +interpreter_python = /usr/bin/python3 +remote_user = root +pipelining = True +ssh_args = -o ControlMaster=auto -o ControlPersist=1200 diff --git a/files/apt/raspi.list b/files/apt/raspi.list new file mode 100644 index 0000000..4ef8d00 --- /dev/null +++ b/files/apt/raspi.list @@ -0,0 +1,3 @@ +# Managed by Ansible +deb http://mirror.unix-solutions.be/raspbian/raspbian/ buster main +deb http://mirror.nl.leaseweb.net/raspbian/raspbian/ buster main diff --git a/files/bacula/bacula-director-sqlite3.conf b/files/bacula/bacula-director-sqlite3.conf new file mode 100644 index 0000000..643a115 --- /dev/null +++ b/files/bacula/bacula-director-sqlite3.conf @@ -0,0 +1,16 @@ +# Managed by Ansible +dbc_install='true' +dbc_upgrade='true' +dbc_remove='true' +dbc_dbtype='sqlite3' +dbc_dbuser='' +dbc_dbpass='' +dbc_dballow='' +dbc_dbserver='' +dbc_dbport='' +dbc_dbname='bacula.db' +dbc_dbadmin='' +dbc_basepath='/var/lib/bacula' +dbc_ssl='' +dbc_authmethod_admin='' +dbc_authmethod_user='' diff --git a/files/bacula/make_catalog_backup.pl b/files/bacula/make_catalog_backup.pl new file mode 100755 index 0000000..90e1045 --- /dev/null +++ b/files/bacula/make_catalog_backup.pl @@ -0,0 +1,196 @@ +#!/usr/bin/perl +# Managed by Ansible +# +# Author: Eric Bollengier, Copyright, 2006-2017 +# License: BSD 2-Clause; see file LICENSE-FOSS + +use strict; + +=head1 SCRIPT + + This script dumps your Bacula catalog in ASCII format + It works for MySQL, SQLite, and PostgreSQL + +=head1 USAGE + + make_catalog_backup.pl [-m] MyCatalog + +=head1 LICENSE + Author: Eric Bollengier, 2010 + License: BSD 2-Clause; see file LICENSE-FOSS +=cut + +my $cat = shift or die "Usage: $0 [-m] catalogname"; +my $mode = "dump"; + +if ($cat eq '-m') { + $mode = "analyse"; + $cat = shift or die "Usage: $0 [-m] catalogname"; +} + +my $dir_conf='/usr/sbin/dbcheck -B -c /etc/bacula/bacula-dir.conf'; +my $wd = "/var/lib/bacula"; + +sub dump_sqlite3 +{ + my %args = @_; + + exec("echo .dump | sqlite3 '$wd/$args{db_name}.db' > '$wd/$args{db_name}.sql'"); + print "Error while executing sqlite dump $!\n"; + return 1; +} + +# TODO: use just ENV and drop the pg_service.conf file +sub setup_env_pgsql +{ + my %args = @_; + my $username = getpwuid $ENV{'UID'}; + umask(0077); + + if ($args{db_address}) { + $ENV{PGHOST}=$args{db_address}; + } + if ($args{db_socket}) { + $ENV{PGHOST}=$args{db_socket}; + } + if ($args{db_port}) { + $ENV{PGPORT}=$args{db_port}; + } + if ($args{db_user}) { + $ENV{PGUSER}=$args{db_user}; + } + if ($args{db_password}) { + $ENV{PGPASSWORD}=$args{db_password}; + } + $ENV{PGDATABASE}=$args{db_name}; + system("echo '\\q' | HOME='$wd' psql") == 0 or die "$username doesn't have access to the catalog database\n"; +} + +sub dump_pgsql +{ + my %args = @_; + setup_env_pgsql(%args); + exec("HOME='$wd' pg_dump -c > '$wd/$args{db_name}.sql'"); + print "Error while executing postgres dump $!\n"; + return 1; # in case of error +} + +sub analyse_pgsql +{ + my %args = @_; + setup_env_pgsql(%args); + my @output =`LANG=C HOME='$wd' vacuumdb -z 2>&1`; + my $exitcode = $? >> 8; + print grep { !/^WARNING:\s+skipping\s\"(pg_|sql_)/ } @output; + if ($exitcode != 0) { + print "Error while executing postgres analyse. Exitcode=$exitcode\n"; + } + return $exitcode; +} + +sub setup_env_mysql +{ + my %args = @_; + umask(0077); + unlink("$wd/.my.cnf"); + open(MY, ">$wd/.my.cnf") + or die "Can't open $wd/.my.cnf for writing $@"; + + $args{db_address} = $args{db_address} || "localhost"; + my $addr = "host=$args{db_address}"; + if ($args{db_socket}) { # unix socket is fastest than net socket + $addr = "socket=\"$args{db_socket}\""; + } + my $mode = $args{mode} || 'client'; + print MY "[$mode] +$addr +user=\"$args{db_user}\" +password=\"$args{db_password}\" +"; + if ($args{db_port}) { + print MY "port=$args{db_port}\n"; + } + close(MY); +} + +sub dump_mysql +{ + my %args = @_; + + setup_env_mysql(%args); + exec("HOME='$wd' mysqldump -f --opt $args{db_name} > '$wd/$args{db_name}.sql'"); + print "Error while executing mysql dump $!\n"; + return 1; +} + +sub analyse_mysql +{ + my %args = @_; + + $args{mode} = 'mysqlcheck'; + setup_env_mysql(%args); + + exec("HOME='$wd' mysqlcheck -a $args{db_name}"); + print "Error while executing mysql analyse $!\n"; + return 1; +} + +sub handle_catalog +{ + my ($mode, %args) = @_; + if ($args{db_type} eq 'SQLite3') { + $ENV{PATH}="/usr/bin:$ENV{PATH}"; + if ($mode eq 'dump') { + dump_sqlite3(%args); + } + } elsif ($args{db_type} eq 'PostgreSQL') { + $ENV{PATH}="/usr/bin:$ENV{PATH}"; + if ($mode eq 'dump') { + dump_pgsql(%args); + } else { + analyse_pgsql(%args); + } + } elsif ($args{db_type} eq 'MySQL') { + $ENV{PATH}="/usr/bin:$ENV{PATH}"; + if ($mode eq 'dump') { + dump_mysql(%args); + } else { + analyse_mysql(%args); + } + } else { + die "This database type isn't supported"; + } +} + +open(FP, "$dir_conf -C '$cat'|") or die "Can't get catalog information $@"; +# catalog=MyCatalog +# db_type=SQLite +# db_name=regress +# db_driver= +# db_user=regress +# db_password= +# db_address= +# db_port=0 +# db_socket= +my %cfg; + +while(my $l = ) +{ + if ($l =~ /catalog=(.+)/) { + if (exists $cfg{catalog} and $cfg{catalog} eq $cat) { + exit handle_catalog($mode, %cfg); + } + %cfg = (); # reset + } + + if ($l =~ /(\w+)=(.+)/) { + $cfg{$1}=$2; + } +} + +if (exists $cfg{catalog} and $cfg{catalog} eq $cat) { + exit handle_catalog($mode, %cfg); +} + +print "Can't find your catalog ($cat) in director configuration\n"; +exit 1; diff --git a/files/nagios/apache2.conf b/files/nagios/apache2.conf new file mode 100644 index 0000000..e87d3e5 --- /dev/null +++ b/files/nagios/apache2.conf @@ -0,0 +1,24 @@ +# Managed by Ansible + +ScriptAlias /cgi-bin/nagios4 /usr/lib/cgi-bin/nagios4 +ScriptAlias /nagios4/cgi-bin /usr/lib/cgi-bin/nagios4 + +Alias /nagios4/stylesheets /etc/nagios4/stylesheets +Alias /nagios4 /usr/share/nagios4/htdocs + + + Options FollowSymLinks + DirectoryIndex index.php index.html + AllowOverride AuthConfig + + AuthUserFile "/etc/nagios4/htdigest.users" + AuthType Basic + AuthName "Restricted Files" + AuthBasicProvider file + AuthUserFile "/etc/nagios4/htdigest.users" + Require user admin + + + + Options +ExecCGI + diff --git a/files/nagios/cgi.cfg b/files/nagios/cgi.cfg new file mode 100644 index 0000000..ffd51fb --- /dev/null +++ b/files/nagios/cgi.cfg @@ -0,0 +1,27 @@ +# Managed by Ansible + +main_config_file=/etc/nagios4/nagios.cfg +physical_html_path=/usr/share/nagios4/htdocs +url_html_path=/nagios4 +show_context_help=0 +use_pending_states=1 +use_authentication=1 +use_ssl_authentication=0 +default_user_name=admin +authorized_for_system_information=nagiosadmin +authorized_for_configuration_information=nagiosadmin +authorized_for_system_commands=nagiosadmin +authorized_for_all_services=nagiosadmin +authorized_for_all_hosts=nagiosadmin +authorized_for_all_service_commands=nagiosadmin +authorized_for_all_host_commands=nagiosadmin +default_statuswrl_layout=4 +ping_syntax=/bin/ping -n -U -c 5 $HOSTADDRESS$ +refresh_rate=90 +result_limit=100 +escape_html_tags=1 +action_url_target=_blank +notes_url_target=_blank +lock_author_names=1 +navbar_search_for_addresses=1 +navbar_search_for_aliases=1 diff --git a/files/nagios/check_timesyncd b/files/nagios/check_timesyncd new file mode 100755 index 0000000..d749080 --- /dev/null +++ b/files/nagios/check_timesyncd @@ -0,0 +1,15 @@ +#!/bin/bash +/usr/bin/timedatectl status | grep -q "NTP service: active" +if [ $? -ne 0 ] ; then + echo "NTP service not active" + exit 1 +fi + +/usr/bin/timedatectl status | grep -q "System clock synchronized: yes" +if [ $? -ne 0 ] ; then + echo "System clock not synchronized" + exit 1 +fi + +echo "NTP is healthy" +exit 0 diff --git a/files/nagios/nagios.cfg b/files/nagios/nagios.cfg new file mode 100644 index 0000000..b94c0c1 --- /dev/null +++ b/files/nagios/nagios.cfg @@ -0,0 +1,112 @@ +# Managed by Ansible +log_file=/var/log/nagios4/nagios.log +cfg_dir=/etc/nagios-plugins/config +cfg_dir=/etc/nagios4/conf.d +cfg_file=/etc/nagios4/objects/commands.cfg +cfg_file=/etc/nagios4/objects/contacts.cfg +cfg_file=/etc/nagios4/objects/timeperiods.cfg +cfg_file=/etc/nagios4/objects/templates.cfg +object_cache_file=/var/lib/nagios4/objects.cache +precached_object_file=/var/lib/nagios4/objects.precache +resource_file=/etc/nagios4/resource.cfg +status_file=/var/lib/nagios4/status.dat +status_update_interval=10 +nagios_user=nagios +nagios_group=nagios +check_external_commands=1 +command_file=/var/lib/nagios4/rw/nagios.cmd +lock_file=/var/run/nagios4/nagios4.pid +temp_file=/var/lib/nagios4/nagios.tmp +temp_path=/tmp +event_broker_options=-1 +log_rotation_method=d +log_archive_path=/var/log/nagios4/archives +use_syslog=1 +log_notifications=1 +log_service_retries=1 +log_host_retries=1 +log_event_handlers=1 +log_initial_states=0 +log_current_states=1 +log_external_commands=1 +log_passive_checks=1 +service_inter_check_delay_method=s +max_service_check_spread=30 +service_interleave_factor=s +host_inter_check_delay_method=s +max_host_check_spread=30 +max_concurrent_checks=0 +check_result_reaper_frequency=10 +max_check_result_reaper_time=30 +check_result_path=/var/lib/nagios4/spool/checkresults +max_check_result_file_age=3600 +cached_host_check_horizon=15 +cached_service_check_horizon=15 +enable_predictive_host_dependency_checks=1 +enable_predictive_service_dependency_checks=1 +soft_state_dependencies=0 +auto_reschedule_checks=0 +auto_rescheduling_interval=30 +auto_rescheduling_window=180 +service_check_timeout=60 +host_check_timeout=30 +event_handler_timeout=30 +notification_timeout=30 +ocsp_timeout=5 +perfdata_timeout=5 +retain_state_information=1 +state_retention_file=/var/lib/nagios4/retention.dat +retention_update_interval=60 +use_retained_program_state=1 +use_retained_scheduling_info=1 +retained_host_attribute_mask=0 +retained_service_attribute_mask=0 +retained_process_host_attribute_mask=0 +retained_process_service_attribute_mask=0 +retained_contact_host_attribute_mask=0 +retained_contact_service_attribute_mask=0 +interval_length=60 +check_for_updates=1 +bare_update_check=0 +use_aggressive_host_checking=0 +execute_service_checks=1 +accept_passive_service_checks=1 +execute_host_checks=1 +accept_passive_host_checks=1 +enable_notifications=1 +enable_event_handlers=1 +process_performance_data=0 +obsess_over_services=0 +obsess_over_hosts=0 +translate_passive_host_checks=0 +passive_host_checks_are_soft=0 +check_for_orphaned_services=1 +check_for_orphaned_hosts=1 +check_service_freshness=1 +service_freshness_check_interval=60 +service_check_timeout_state=c +check_host_freshness=0 +host_freshness_check_interval=60 +additional_freshness_latency=15 +enable_flap_detection=1 +low_service_flap_threshold=5.0 +high_service_flap_threshold=20.0 +low_host_flap_threshold=5.0 +high_host_flap_threshold=20.0 +date_format=us +illegal_object_name_chars=`~!$%^&*|'"<>?,()= +illegal_macro_output_chars=`~$&|'"<> +use_regexp_matching=0 +use_true_regexp_matching=0 +admin_email=nagios@localhost +admin_pager=pagenagios@localhost +daemon_dumps_core=0 +use_large_installation_tweaks=0 +enable_environment_macros=0 +debug_level=0 +debug_verbosity=1 +debug_file=/var/log/nagios4/nagios.debug +max_debug_file_size=1000000 +allow_empty_hostgroup_assignment=0 +cfg_file=/opt/notify-by-telegram/nagios.cfg +host_down_disable_service_checks=1 diff --git a/files/nagios/security.conf b/files/nagios/security.conf new file mode 100644 index 0000000..be7ed59 --- /dev/null +++ b/files/nagios/security.conf @@ -0,0 +1,16 @@ +# Managed by Ansible + +ServerTokens Prod +ServerSignature Off +TraceEnable Off + + + Require all denied + + + + Require all denied + + +Header set X-Content-Type-Options: "nosniff" +Header set X-Frame-Options: "sameorigin" diff --git a/files/serial2mqtt/serial2mqtt.default b/files/serial2mqtt/serial2mqtt.default new file mode 100644 index 0000000..1b5816a --- /dev/null +++ b/files/serial2mqtt/serial2mqtt.default @@ -0,0 +1,3 @@ +# Managed by Ansible +# Options passed as daemon argument +DAEMON_OPTS="-c /etc/serial2mqtt.ini -v" diff --git a/files/serial2mqtt/serial2mqtt.service b/files/serial2mqtt/serial2mqtt.service new file mode 100644 index 0000000..fc4c06e --- /dev/null +++ b/files/serial2mqtt/serial2mqtt.service @@ -0,0 +1,18 @@ +# Managed by Ansible + +[Unit] +Description=Read serial port and send sensors measurements to MQTT broker +After=syslog.target network.target + +[Service] +Type=simple +User=serial2mqtt +Group=serial2mqtt +EnvironmentFile=-/etc/default/serial2mqtt +ExecStart=/opt/arduino-sensors-toolkit/serial2mqtt.py $DAEMON_OPTS +KillMode=process +TimeoutSec=30 +Restart=no + +[Install] +WantedBy=multi-user.target diff --git a/files/ssh/sshd_config b/files/ssh/sshd_config new file mode 100644 index 0000000..3829173 --- /dev/null +++ b/files/ssh/sshd_config @@ -0,0 +1,8 @@ +# Managed by Ansible +PermitRootLogin without-password +ChallengeResponseAuthentication no +UsePAM yes +X11Forwarding no +PrintMotd no +AcceptEnv LANG LC_* +Subsystem sftp /usr/lib/openssh/sftp-server diff --git a/files/users/bashrc b/files/users/bashrc new file mode 100644 index 0000000..539d2eb --- /dev/null +++ b/files/users/bashrc @@ -0,0 +1,13 @@ +# Managed by Ansible + +if [[ ${EUID} == 0 ]] ; then + PS1='\[\033[01;31m\]\h\[\033[01;34m\] \w \$\[\033[00m\] ' +else + PS1='\[\033[01;32m\]\u@\h\[\033[01;34m\] \w \$\[\033[00m\] ' +fi + +alias ls='ls $LS_OPTIONS' +alias ll='ls $LS_OPTIONS -l' +alias l='ls $LS_OPTIONS -lA' + +export EDITOR=vim diff --git a/files/vim/vimrc b/files/vim/vimrc new file mode 100644 index 0000000..fe52bf4 --- /dev/null +++ b/files/vim/vimrc @@ -0,0 +1,6 @@ +" Managed by Ansible +set mouse=r +set paste +set tabstop=4 +set shiftwidth=4 +set expandtab diff --git a/group_vars/README.md b/group_vars/README.md new file mode 100644 index 0000000..18d23c0 --- /dev/null +++ b/group_vars/README.md @@ -0,0 +1,3 @@ +# Variables + +Soon. diff --git a/inventory/hosts.example b/inventory/hosts.example new file mode 100644 index 0000000..69d51ad --- /dev/null +++ b/inventory/hosts.example @@ -0,0 +1,2 @@ +[pilote] +192.168.0.1 diff --git a/main.yml b/main.yml new file mode 100644 index 0000000..0b65dbb --- /dev/null +++ b/main.yml @@ -0,0 +1,23 @@ +--- +- hosts: pilote + gather_facts: true + tasks: + - ansible.builtin.include_tasks: tasks/sysctl.yml + - ansible.builtin.include_tasks: tasks/apt.yml + - ansible.builtin.include_tasks: tasks/users.yml + - ansible.builtin.include_tasks: tasks/profile.yml + - ansible.builtin.include_tasks: tasks/hostname.yml + - ansible.builtin.include_tasks: tasks/motd.yml + - ansible.builtin.include_tasks: tasks/time.yml + - ansible.builtin.include_tasks: tasks/ssh.yml + - ansible.builtin.include_tasks: tasks/openvpn.yml + - ansible.builtin.include_tasks: tasks/nagios.yml + - ansible.builtin.include_tasks: tasks/nrpe.yml + - ansible.builtin.include_tasks: tasks/mosquitto.yml + - ansible.builtin.include_tasks: tasks/serial2mqtt.yml + - ansible.builtin.include_tasks: tasks/telegraf.yml + - ansible.builtin.include_tasks: tasks/bacula.yml + - ansible.builtin.include_tasks: tasks/iptables.yml + # TODO + #- ansible.builtin.include_tasks: tasks/easyrsa.yml + - ansible.builtin.include_tasks: tasks/vim.yml diff --git a/tasks/apt-upgrade.yml b/tasks/apt-upgrade.yml new file mode 100644 index 0000000..a11cca4 --- /dev/null +++ b/tasks/apt-upgrade.yml @@ -0,0 +1,5 @@ +--- +- name: Run apt upgrade + ansible.builtin.apt: + update_cache: true + upgrade: dist diff --git a/tasks/apt.yml b/tasks/apt.yml new file mode 100644 index 0000000..6a1df3b --- /dev/null +++ b/tasks/apt.yml @@ -0,0 +1,17 @@ +--- +- name: Remove useless packages + ansible.builtin.apt: + name: + - wpasupplicant + - pi-bluetooth + state: absent + +- name: Define repositories + ansible.builtin.copy: + src: files/apt/raspi.list + dest: /etc/apt/sources.list.d/raspi.list + +- name: Update system + ansible.builtin.apt: + update_cache: 'yes' + upgrade: 'yes' diff --git a/tasks/bacula.yml b/tasks/bacula.yml new file mode 100644 index 0000000..f015f12 --- /dev/null +++ b/tasks/bacula.yml @@ -0,0 +1,89 @@ +--- +- name: Install bacula + ansible.builtin.apt: + name: + - bacula-director + - bacula-director-sqlite3 + - bacula-fd + - bacula-sd + - bacula-console + state: latest + +- name: Configure database + ansible.builtin.copy: + src: files/bacula/bacula-director-sqlite3.conf + dest: /etc/dbconfig-common/bacula-director-sqlite3.conf + mode: '0600' + owner: root + group: root + +- name: Configure catalog backup script + ansible.builtin.copy: + src: files/bacula/make_catalog_backup.pl + dest: /etc/bacula/scripts/make_catalog_backup.pl + mode: '0755' + owner: root + group: bacula + +- name: Configure director + ansible.builtin.template: + src: bacula/bacula-dir.conf.j2 + dest: /etc/bacula/bacula-dir.conf + mode: '0640' + owner: root + group: bacula + +- name: Configure bconsole + ansible.builtin.template: + src: bacula/bconsole.conf.j2 + dest: /etc/bacula/bconsole.conf + mode: '0640' + owner: root + group: nagios + +- name: Configure bacula fd + ansible.builtin.template: + src: bacula/bacula-fd.conf.j2 + dest: /etc/bacula/bacula-fd.conf + mode: '0640' + owner: root + group: bacula + +- name: Configure bacula sd + ansible.builtin.template: + src: bacula/bacula-sd.conf.j2 + dest: /etc/bacula/bacula-sd.conf + mode: '0640' + owner: root + group: bacula + +- name: Copy configuration files + ansible.builtin.template: + src: "bacula/conf.d/{{ item }}.conf.j2" + dest: "/etc/bacula/conf.d/{{ item }}.conf" + loop: + - clients + - filesets + - jobs + - messages + - pools + - schedules + - storages + +- name: Allow bacula from vpn + ansible.builtin.iptables: + chain: INPUT + protocol: tcp + source: "{{ openvpn_subnet }}" + destination_port: "9102" + jump: ACCEPT + comment: allow bacula from vpn + +- name: Restart bacula services + ansible.builtin.service: + name: "{{ item }}" + state: restarted + loop: + - bacula-director + - bacula-sd + - bacula-fd diff --git a/tasks/easyrsa.yml b/tasks/easyrsa.yml new file mode 100644 index 0000000..16c897c --- /dev/null +++ b/tasks/easyrsa.yml @@ -0,0 +1,13 @@ +--- +# TODO +- name: copy easyrsa sources to /root + copy: + src: files/easyrsa/EasyRSA-v3.0.6 + dest: /root/ + mode: preserve + +- name: add easyrsa binary to path + file: + src: /root/EasyRSA-v3.0.6/easyrsa + dest: /usr/local/sbin/easyrsa + state: link diff --git a/tasks/hostname.yml b/tasks/hostname.yml new file mode 100644 index 0000000..66a03f4 --- /dev/null +++ b/tasks/hostname.yml @@ -0,0 +1,9 @@ +--- +- name: Setup hostname + hostname: + name: "{{ hostname }}" + +- name: Manage /etc/hosts + ansible.builtin.template: + src: hostname/hosts.j2 + dest: /etc/hosts diff --git a/tasks/iptables.yml b/tasks/iptables.yml new file mode 100644 index 0000000..f127180 --- /dev/null +++ b/tasks/iptables.yml @@ -0,0 +1,63 @@ +--- +- name: Allow related and established connections + ansible.builtin.iptables: + chain: INPUT + ctstate: ESTABLISHED,RELATED + jump: ACCEPT + comment: allow related and established connections + +- name: Allow local connections + ansible.builtin.iptables: + chain: INPUT + in_interface: lo + jump: ACCEPT + comment: allow local connections + +- name: Allow ping + ansible.builtin.iptables: + chain: INPUT + protocol: icmp + jump: ACCEPT + comment: allow ping from the world + +- name: Deny input connections by default + ansible.builtin.iptables: + chain: INPUT + policy: DROP + +- name: Allow SSH to VPN + ansible.builtin.iptables: + chain: OUTPUT + protocol: tcp + destination: "{{ openvpn_subnet }}" + destination_port: "22" + jump: ACCEPT + comment: allow ssh to vpn + +- name: Deny SSH to the world + ansible.builtin.iptables: + chain: OUTPUT + protocol: tcp + destination_port: "22" + jump: DROP + comment: deny ssh to the world + +- name: Deny IPv6 connections + ansible.builtin.iptables: + ip_version: ipv6 + chain: "{{ item }}" + policy: DROP + loop: + - INPUT + - FORWARD + - OUTPUT + +- name: Install netfilter-persistent + ansible.builtin.apt: + name: + - netfilter-persistent + - iptables-persistent + state: latest + +- name: Save iptables + ansible.builtin.command: netfilter-persistent save diff --git a/tasks/mosquitto.yml b/tasks/mosquitto.yml new file mode 100644 index 0000000..4ee6111 --- /dev/null +++ b/tasks/mosquitto.yml @@ -0,0 +1,24 @@ +--- +- name: Install packages + ansible.builtin.apt: + name: + - mosquitto + state: latest + +- name: Configure mosquitto + ansible.builtin.copy: + src: files/mosquitto/conf.d + dest: /etc/mosquitto + +- name: Copy mosquitto password + ansible.builtin.template: + src: mosquitto/passwd.j2 + dest: /etc/mosquitto/passwd + mode: '0600' + owner: root + group: root + +- name: Restart mosquitto + ansible.builtin.service: + name: mosquitto + state: restarted diff --git a/tasks/motd.yml b/tasks/motd.yml new file mode 100644 index 0000000..3830398 --- /dev/null +++ b/tasks/motd.yml @@ -0,0 +1,15 @@ +--- +- name: Install figlet + ansible.builtin.package: + name: figlet + state: present + +- name: Run figlet + ansible.builtin.shell: + cmd: "hostname | figlet -f /usr/share/figlet/smslant.flf" + register: _motd + +- name: Create motd + ansible.builtin.copy: + dest: /etc/motd + content: "{{ _motd.stdout }}\n" diff --git a/tasks/nagios.yml b/tasks/nagios.yml new file mode 100644 index 0000000..298bb55 --- /dev/null +++ b/tasks/nagios.yml @@ -0,0 +1,110 @@ +--- +- name: Install nagios + ansible.builtin.apt: + name: + - nagios4 + - git + - nagios-nrpe-plugin + - python3-jinja2 + - python3-requests + - python3-jsonschema + - python-pexpect + state: latest + +- name: Generate nagios configurations + ansible.builtin.template: + src: "nagios/conf.d/{{ item }}.cfg.j2" + dest: "/etc/nagios4/conf.d/{{ item }}.cfg" + loop: + - commands + - hosts + - hostgroups + - services + - templates + +- name: Copy nagios contacts configuration + ansible.builtin.template: + src: nagios/contacts.cfg.j2 + dest: /etc/nagios4/objects/contacts.cfg + +- name: Copy check_timesyncd + ansible.builtin.copy: + src: files/nagios/check_timesyncd + dest: /usr/lib/nagios/plugins/check_timesyncd + mode: '0755' + +- name: Deploy sudoers rule for nagios + community.general.sudoers: + name: nagios + user: nagios + commands: + - /usr/lib/nagios/plugins/ + +- name: Clone notify-by-telegram source code + ansible.builtin.git: + repo: https://github.com/jouir/notify-by-telegram.git + dest: /opt/notify-by-telegram + +- name: Configure notify-by-telegram + ansible.builtin.copy: + content: "{{ {'auth_key': nagios_telegram_auth_key, 'chat_id': nagios_telegram_chat_id } | to_json }}" + dest: /etc/nagios4/telegram.json + owner: root + group: nagios + mode: '0640' + +- name: Clone nagios-plugin-bacula source code + ansible.builtin.git: + repo: https://github.com/twpayne/nagios-plugin-bacula.git + dest: /opt/nagios-plugin-bacula + +- name: Copy global configuration + ansible.builtin.copy: + src: files/nagios/nagios.cfg + dest: /etc/nagios4/nagios.cfg + +- name: Copy CGI configuration + ansible.builtin.copy: + src: files/nagios/cgi.cfg + dest: /etc/nagios4/cgi.cfg + +- name: Reload nagios + ansible.builtin.service: + name: nagios4 + state: reloaded + +- name: Configure htaccess for the web interface + ansible.builtin.template: + src: nagios/htdigest.users.j2 + dest: /etc/nagios4/htdigest.users + +- name: Secure Apache + copy: + src: files/nagios/security.conf + dest: /etc/apache2/conf-available/security.conf + +- name: Configure vhost for the web interface + ansible.builtin.copy: + src: files/nagios/apache2.conf + dest: /etc/nagios4/apache2.conf + +- name: Enable Apache modules + ansible.builtin.command: + cmd: "a2enmod {{ item }}" + loop: + - auth_digest + - headers + +- name: Restart apache + ansible.builtin.service: + name: apache2 + state: restarted + +- name: Allow HTTP from vpn + iptables: + chain: INPUT + protocol: tcp + source: "{{ openvpn_subnet }}" + destination_port: "80" + jump: ACCEPT + comment: allow http from vpn diff --git a/tasks/nrpe.yml b/tasks/nrpe.yml new file mode 100644 index 0000000..fdf1f72 --- /dev/null +++ b/tasks/nrpe.yml @@ -0,0 +1,66 @@ +--- +- name: Install NRPE + ansible.builtin.apt: + name: + - nagios-nrpe-server + - bc + - python3-pip + +- name: Copy NRPE global configuration + ansible.builtin.template: + src: nrpe/nrpe.cfg.j2 + dest: /etc/nagios/nrpe.cfg + +- name: Generate NRPE local configuration + ansible.builtin.template: + src: nrpe/nrpe_local.cfg.j2 + dest: /etc/nagios/nrpe_local.cfg + +- name: Manage daemon settings + ansible.builtin.template: + src: nrpe/nagios-nrpe-server.j2 + dest: /etc/default/nagios-nrpe-server + +- name: Clone check-mqtt source code + ansible.builtin.git: + repo: https://github.com/jpmens/check-mqtt.git + dest: /opt/check-mqtt + +- name: Clone check_ssl_cert source code + ansible.builtin.git: + repo: https://github.com/matteocorti/check_ssl_cert.git + dest: /opt/check_ssl_cert + +- name: Clone check_ovhcloud source code + ansible.builtin.git: + repo: https://github.com/jouir/check_ovhcloud.git + dest: /opt/check_ovhcloud + +- name: Configure check_ovhcloud + ansible.builtin.template: + src: nrpe/ovh.conf.j2 + dest: /etc/ovh.conf + owner: root + group: nagios + mode: "0640" + +- name: Install check_ovhcloud dependencies + ansible.builtin.pip: + requirements: /opt/check_ovhcloud/requirements.txt + extra_args: "--user" + become: true + become_user: nagios + +- name: Restart NRPE service + ansible.builtin.service: + name: nagios-nrpe-server + state: restarted + +- name: Allow NRPE from vpn + ansible.builtin.iptables: + chain: INPUT + protocol: tcp + source: "{{ openvpn_subnet }}" + destination_port: "5666" + jump: ACCEPT + comment: allow nrpe from vpn diff --git a/tasks/openvpn.yml b/tasks/openvpn.yml new file mode 100644 index 0000000..f7089c8 --- /dev/null +++ b/tasks/openvpn.yml @@ -0,0 +1,38 @@ +--- +- name: Install OpenVPN + ansible.builtin.apt: + name: openvpn + state: latest + +- name: Deploy OpenVPN configuration + ansible.builtin.template: + src: openvpn/client.conf.j2 + dest: /etc/openvpn/client.conf + +- name: Deploy OpenVPN CA cert + ansible.builtin.copy: + content: "{{ openvpn_ca }}" + dest: /etc/openvpn/ca.crt + +- name: Deploy OpenVPN TLS auth + ansible.builtin.copy: + content: "{{ openvpn_ta }}" + dest: /etc/openvpn/ta.key + +- name: Deploy OpenVPN client cert + ansible.builtin.copy: + content: "{{ openvpn_cert }}" + dest: /etc/openvpn/client.crt + mode: '0644' + +- name: Deploy OpenVPN client key + ansible.builtin.copy: + content: "{{ openvpn_key }}" + dest: /etc/openvpn/client.key + mode: '0600' + +- name: Start OpenVPN + ansible.builtin.systemd: + name: "openvpn@client.service" + state: started + enabled: true diff --git a/tasks/profile.yml b/tasks/profile.yml new file mode 100644 index 0000000..c06a14f --- /dev/null +++ b/tasks/profile.yml @@ -0,0 +1,8 @@ +--- +- name: Remove raspberry pi profiles + ansible.builtin.file: + path: "{{ item }}" + state: absent + loop: + - /etc/profile.d/sshpwd.sh + - /etc/profile.d/wifi-check.sh diff --git a/tasks/serial2mqtt.yml b/tasks/serial2mqtt.yml new file mode 100644 index 0000000..33e1901 --- /dev/null +++ b/tasks/serial2mqtt.yml @@ -0,0 +1,48 @@ +--- +- name: Install packages + ansible.builtin.apt: + name: + - python3-serial + - python3-paho-mqtt + state: latest + +- name: Clone arduino-sensors-toolkit sources + ansible.builtin.git: + repo: https://github.com/jouir/arduino-sensors-toolkit.git + dest: /opt/arduino-sensors-toolkit + +- name: Add serial2mqtt user + ansible.builtin.user: + name: serial2mqtt + system: yes + password: '!' + home: /var/lib/serial2mqtt + create_home: no + append: yes + groups: + - dialout + +- name: Copy serial2mqtt configuration + ansible.builtin.template: + src: serial2mqtt/serial2mqtt.ini.j2 + dest: /etc/serial2mqtt.ini + mode: '0640' + owner: root + group: serial2mqtt + +- name: Copy serial2mqtt default file + ansible.builtin.copy: + src: files/serial2mqtt/serial2mqtt.default + dest: /etc/default/serial2mqtt + +- name: Copy serial2mqtt service unit + ansible.builtin.copy: + src: files/serial2mqtt/serial2mqtt.service + dest: /etc/systemd/system/serial2mqtt.service + +- name: Start serial2mqtt service + ansible.builtin.systemd: + name: serial2mqtt.service + daemon_reload: yes + state: restarted + enabled: yes diff --git a/tasks/ssh.yml b/tasks/ssh.yml new file mode 100644 index 0000000..45c74be --- /dev/null +++ b/tasks/ssh.yml @@ -0,0 +1,38 @@ +--- +- name: Install OpenSSH + ansible.builtin.apt: + name: openssh-server + state: latest + +- name: Allow authorized keys + ansible.posix.authorized_key: + user: "{{ item['user'] }}" + key: "{{ item['key'] }}" + comment: "{{ item['comment'] | default(omit) }}" + loop: "{{ ssh_authorized_keys }}" + +- name: Copy configuration file + ansible.builtin.copy: + src: files/ssh/sshd_config + dest: /etc/ssh/sshd_config + owner: root + group: root + mode: '0644' + +- name: Reload and enable SSH service + service: + name: ssh + state: reloaded + enabled: true + +- name: Allow SSH network flows + ansible.builtin.iptables: + chain: INPUT + protocol: tcp + source: "{{ item }}" + destination_port: "22" + jump: ACCEPT + comment: allow ssh + loop: + - "{{ openvpn_subnet }}" + - "{{ local_subnet }}" diff --git a/tasks/sysctl.yml b/tasks/sysctl.yml new file mode 100644 index 0000000..fc3e9a9 --- /dev/null +++ b/tasks/sysctl.yml @@ -0,0 +1,8 @@ +--- +- name: Disable ipv6 + ansible.posix.sysctl: + name: net.ipv6.conf.all.disable_ipv6 + value: '1' + state: present + sysctl_file: /etc/sysctl.d/70-disable-ipv6.conf + reload: yes diff --git a/tasks/telegraf.yml b/tasks/telegraf.yml new file mode 100644 index 0000000..a5c5051 --- /dev/null +++ b/tasks/telegraf.yml @@ -0,0 +1,31 @@ +--- +- name: Configure telegraf repository + ansible.builtin.template: + src: telegraf/influxdata.list.j2 + dest: /etc/apt/sources.list.d/influxdata.list + +- name: Download influxdata APT key + ansible.builtin.apt_key: + url: https://repos.influxdata.com/influxdb.key + state: present + +- name: Install telegraf and dependencies + ansible.builtin.apt: + name: + - telegraf + - lm-sensors + update_cache: true + state: latest + +- name: Generate telegraf configurations + ansible.builtin.template: + src: "telegraf/{{ item }}.conf.j2" + dest: "/etc/telegraf/telegraf.d/{{ item }}.conf" + loop: + - inputs + - output + +- name: Restart telegraf service + ansible.builtin.service: + name: telegraf + state: restarted diff --git a/tasks/time.yml b/tasks/time.yml new file mode 100644 index 0000000..d4410b2 --- /dev/null +++ b/tasks/time.yml @@ -0,0 +1,4 @@ +--- +- name: Manage time zone + ansible.builtin.command: + cmd: "timedatectl set-timezone {{ timezone }}" diff --git a/tasks/users.yml b/tasks/users.yml new file mode 100644 index 0000000..2355d60 --- /dev/null +++ b/tasks/users.yml @@ -0,0 +1,14 @@ +--- +- name: Create users + ansible.builtin.user: + name: "{{ item['name'] }}" + password: "{{ item['password'] }}" + loop: "{{ users }}" + +- name: Define bashrc + ansible.builtin.copy: + dest: "{% if item['name'] == 'root' %}/root{% else %}/home/{{ item['name'] }}{% endif %}/.bashrc" + src: files/users/bashrc + owner: "{{ item['name'] }}" + group: "{{ item['name'] }}" + loop: "{{ users }}" diff --git a/tasks/vim.yml b/tasks/vim.yml new file mode 100644 index 0000000..ea21d14 --- /dev/null +++ b/tasks/vim.yml @@ -0,0 +1,13 @@ +--- +- name: Install vim packages + ansible.builtin.apt: + name: vim + state: present + +- name: Copy configurations + ansible.builtin.copy: + src: files/vim/vimrc + dest: "{{ '/root/.vimrc' if item['name'] == 'root' else '/home/' + item['name'] + '/.vimrc' }}" + loop: "{{ users }}" + loop_control: + label: "{{ item['name'] }}" diff --git a/templates/bacula/bacula-dir.conf.j2 b/templates/bacula/bacula-dir.conf.j2 new file mode 100644 index 0000000..6ff678c --- /dev/null +++ b/templates/bacula/bacula-dir.conf.j2 @@ -0,0 +1,26 @@ +{{ ansible_managed | comment }} + +Director { + Name = {{ bacula_director_name }} + DIRport = 9101 + QueryFile = "/etc/bacula/scripts/query.sql" + WorkingDirectory = "/var/lib/bacula" + PidDirectory = "/run/bacula" + Maximum Concurrent Jobs = 20 + Password = "{{ bacula_director_password }}" + Messages = Daemon + DirAddress = {{ bacula_director_address | default('127.0.0.1') }} +} + +Catalog { + Name = {{ bacula_catalog_name }} + dbname = "bacula"; dbuser = ""; dbpassword = "" +} + +@/etc/bacula/conf.d/jobs.conf +@/etc/bacula/conf.d/filesets.conf +@/etc/bacula/conf.d/schedules.conf +@/etc/bacula/conf.d/clients.conf +@/etc/bacula/conf.d/messages.conf +@/etc/bacula/conf.d/pools.conf +@/etc/bacula/conf.d/storages.conf diff --git a/templates/bacula/bacula-fd.conf.j2 b/templates/bacula/bacula-fd.conf.j2 new file mode 100644 index 0000000..accfd47 --- /dev/null +++ b/templates/bacula/bacula-fd.conf.j2 @@ -0,0 +1,21 @@ +{{ ansible_managed | comment }} + +Director { + Name = {{ bacula_director_name }} + Password = "{{ bacula_filedaemon_password }}" +} + +FileDaemon { + Name = {{ bacula_filedaemon_name }} + FDport = 9102 + WorkingDirectory = /var/lib/bacula + Pid Directory = /run/bacula + Maximum Concurrent Jobs = 20 + Plugin Directory = /usr/lib/bacula + FDAddress = {{ bacula_filedaemon_address | default('127.0.0.1') }} +} + +Messages { + Name = Standard + director = {{ bacula_director_name }} = all, !skipped, !restored +} diff --git a/templates/bacula/bacula-sd.conf.j2 b/templates/bacula/bacula-sd.conf.j2 new file mode 100644 index 0000000..88a868b --- /dev/null +++ b/templates/bacula/bacula-sd.conf.j2 @@ -0,0 +1,31 @@ +{{ ansible_managed | comment }} + +Director { + Name = {{ bacula_director_name }} + Password = "{{ bacula_storage_password }}" +} + +Storage { + Name = {{ bacula_storage_name }} + SDPort = 9103 + WorkingDirectory = "/var/lib/bacula" + Pid Directory = "/var/run/bacula" + Maximum Concurrent Jobs = 20 + SDAddress = {{ bacula_storage_address | default('127.0.0.1') }} +} + +Device { + Name = {{ bacula_device_name }} + Media Type = File + Archive Device = {{ bacula_device_archive_device }} + LabelMedia = yes + Random Access = yes + AutomaticMount = yes + RemovableMedia = no + AlwaysOpen = no +} + +Messages { + Name = Standard + director = {{ bacula_director_name }} = all +} diff --git a/templates/bacula/bconsole.conf.j2 b/templates/bacula/bconsole.conf.j2 new file mode 100644 index 0000000..7d6cd19 --- /dev/null +++ b/templates/bacula/bconsole.conf.j2 @@ -0,0 +1,8 @@ +{{ ansible_managed | comment }} + +Director { + Name = {{ bacula_director_name }} + DIRport = 9101 + address = 127.0.0.1 + Password = "{{ bacula_director_password }}" +} diff --git a/templates/bacula/conf.d/clients.conf.j2 b/templates/bacula/conf.d/clients.conf.j2 new file mode 100644 index 0000000..e320cbc --- /dev/null +++ b/templates/bacula/conf.d/clients.conf.j2 @@ -0,0 +1,15 @@ +{{ ansible_managed | comment }} + +{% for client in bacula_clients %} +Client { + Name = {{ client['name'] }} + Address = {{ client['address'] }} + FDPort = 9102 + Catalog = {{ client['catalog'] }} + Password = "{{ client['password'] }}" + File Retention = {{ client['file_retention'] }} + Job Retention = {{ client['job_retention'] }} + AutoPrune = {{ client['autoprune'] }} +} + +{% endfor %} diff --git a/templates/bacula/conf.d/filesets.conf.j2 b/templates/bacula/conf.d/filesets.conf.j2 new file mode 100644 index 0000000..de71aca --- /dev/null +++ b/templates/bacula/conf.d/filesets.conf.j2 @@ -0,0 +1,32 @@ +{{ ansible_managed | comment }} + +{% for fileset in bacula_filesets %} +FileSet { + Name = {{ fileset['name'] }} +{% if 'include' in fileset %} + Include { +{% if 'options' in fileset['include'] %} + Options { +{% if 'signature' in fileset['include']['options'] %} + signature = {{ fileset['include']['options']['signature'] }} +{% endif %} +{% if 'compression' in fileset['include']['options'] %} + compression = {{ fileset['include']['options']['compression'] }} +{% endif %} + } +{% endif %} +{% for file in fileset['include']['files'] | default([]) | sort %} + File = "{{ file }}" +{% endfor %} + } +{% endif %} +{% if 'exclude' in fileset %} + Exclude { +{% for file in fileset['exclude']['files'] | default([]) | sort %} + File = "{{ file }}" +{% endfor %} + } +{% endif %} +} + +{% endfor %} diff --git a/templates/bacula/conf.d/jobs.conf.j2 b/templates/bacula/conf.d/jobs.conf.j2 new file mode 100644 index 0000000..bbe2e10 --- /dev/null +++ b/templates/bacula/conf.d/jobs.conf.j2 @@ -0,0 +1,60 @@ +{{ ansible_managed | comment }} + +JobDefs { + Name = BackupDefaults + Type = Backup + Storage = {{ bacula_storage_name }} + Schedule = DefaultSchedule + Priority = 10 + Messages = Standard + Pool = FullFile + Full Backup Pool = FullFile + Differential Backup Pool = DiffFile + Incremental Backup Pool = IncrFile +} + +{% for job in bacula_jobs %} +Job { + Name = {{ job['name'] }} + JobDefs = BackupDefaults + Client = {{ job['client'] }} + FileSet = {{ job['fileset'] }} +{% if 'priority' in job %} + Priority = {{ job['priority'] }} +{% endif %} +{% if 'level' in job %} + Level = {{ job['level'] }} +{% endif %} +{% if 'schedule' in job %} + Schedule = {{ job['schedule'] }} +{% endif %} +{% if 'run_before_job' in job %} + RunBeforeJob = "{{ job['run_before_job'] }}" +{% endif %} +{% if 'run_after_job' in job %} + RunAfterJob = "{{ job['run_after_job'] }}" +{% endif %} +{% if 'client_run_before_job' in job %} + ClientRunBeforeJob = "{{ job['client_run_before_job'] }}" +{% endif %} +{% if 'client_run_after_job' in job %} + ClientRunAfterJob = "{{ job['client_run_after_job'] }}" +{% endif %} +{% if 'pool' in job %} + Pool = {{ job['pool'] }} +{% endif %} +{% if 'storage' in job %} + Storage = {{ job['storage'] }} +{% endif %} +{% if 'messages' in job %} + Messages = {{ job['messages'] }} +{% endif %} +{% if 'where' in job %} + Where = {{ job['where'] }} +{% endif %} +{% if 'type' in job %} + Type = {{ job['type'] }} +{% endif %} +} + +{% endfor %} diff --git a/templates/bacula/conf.d/messages.conf.j2 b/templates/bacula/conf.d/messages.conf.j2 new file mode 100644 index 0000000..ee2caf3 --- /dev/null +++ b/templates/bacula/conf.d/messages.conf.j2 @@ -0,0 +1,22 @@ +Messages { + Name = Standard +{% if bacula_email_address is defined %} + mailcommand = "/usr/bin/mail -r \"Bacula \<%r\>\" -s \"Bacula: %t %e of %c %l\" %r" + operatorcommand = "/usr/bin/mail -r \"Bacula \<%r\>\" -s \"Bacula: Intervention needed for %j\" %r" + mail on error = {{ bacula_email_address }} = all, !skipped, !terminate +{% endif %} + operator = root = mount + console = all, !skipped, !saved + append = "/var/log/bacula/bacula.log" = all, !skipped + catalog = all +} + +Messages { + Name = Daemon +{% if bacula_email_address is defined %} + mailcommand = "/usr/bin/mail -r \"Bacula \<%r\>\" -s \"Bacula daemon message\" %r" + mail on error = {{ bacula_email_address }} = all, !skipped, !terminate +{% endif %} + console = all, !skipped, !saved + append = "/var/log/bacula/bacula.log" = all, !skipped +} diff --git a/templates/bacula/conf.d/pools.conf.j2 b/templates/bacula/conf.d/pools.conf.j2 new file mode 100644 index 0000000..3380fdb --- /dev/null +++ b/templates/bacula/conf.d/pools.conf.j2 @@ -0,0 +1,16 @@ +{{ ansible_managed | comment }} + +{% for pool in bacula_pools | default([]) %} +Pool { + Name = {{ pool['name'] }} + Pool Type = {{ pool['pool_type'] }} + Recycle = {{ pool['recycle'] }} + AutoPrune = {{ pool['auto_prune'] }} + Volume Retention = {{ pool['volume_retention'] }} + Storage = {{ pool['storage'] }} + Maximum Volume Bytes = {{ pool['maximum_volume_bytes'] }} + Maximum Volumes = {{ pool['maximum_volumes'] }} + LabelFormat = "{{ pool['labelformat'] }}" +} + +{% endfor %} diff --git a/templates/bacula/conf.d/schedules.conf.j2 b/templates/bacula/conf.d/schedules.conf.j2 new file mode 100644 index 0000000..057d2f8 --- /dev/null +++ b/templates/bacula/conf.d/schedules.conf.j2 @@ -0,0 +1,11 @@ +{{ ansible_managed | comment }} + +{% for schedule in bacula_schedules | default([]) %} +Schedule { + Name = {{ schedule['name'] }} +{% for run in schedule['runs'] %} + Run = {% for k, v in run.get('job_overrides', {}).items() %}{{ k }}={{ v }} {% endfor %} {{ run['datetime'] }} +{% endfor %} +} + +{% endfor %} diff --git a/templates/bacula/conf.d/storages.conf.j2 b/templates/bacula/conf.d/storages.conf.j2 new file mode 100644 index 0000000..d25d827 --- /dev/null +++ b/templates/bacula/conf.d/storages.conf.j2 @@ -0,0 +1,12 @@ +{{ ansible_managed | comment }} + +{% for storage in bacula_storages | default([]) %} +Storage { + Name = {{ storage['name'] }} + Address = {{ storage['address'] }} + Password = "{{ storage['password'] }}" + Device = {{ storage['device'] }} + Media Type = {{ storage['media_type'] }} +} + +{% endfor %} diff --git a/templates/hostname/hosts.j2 b/templates/hostname/hosts.j2 new file mode 100644 index 0000000..098a5fc --- /dev/null +++ b/templates/hostname/hosts.j2 @@ -0,0 +1,7 @@ +{{ ansible_managed | comment }} +127.0.0.1 localhost +::1 ip6-localhost ip6-loopback +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters + +127.0.1.1 {{ hostname }} diff --git a/templates/mosquitto/passwd.j2 b/templates/mosquitto/passwd.j2 new file mode 100644 index 0000000..b3de992 --- /dev/null +++ b/templates/mosquitto/passwd.j2 @@ -0,0 +1,3 @@ +{% for credentials in mosquitto_passwords | default([]) %} +{{ credentials['user'] }}:{{ credentials['hash'] }} +{% endfor %} diff --git a/templates/nagios/conf.d/commands.cfg.j2 b/templates/nagios/conf.d/commands.cfg.j2 new file mode 100644 index 0000000..34720a9 --- /dev/null +++ b/templates/nagios/conf.d/commands.cfg.j2 @@ -0,0 +1,9 @@ +{{ ansible_managed | comment }} + +{% for command in nagios_commands | default([]) %} +define command { + command_name {{ command['command_name'] }} + command_line {{ command['command_line'] }} +} + +{% endfor %} diff --git a/templates/nagios/conf.d/hostgroups.cfg.j2 b/templates/nagios/conf.d/hostgroups.cfg.j2 new file mode 100644 index 0000000..38e731b --- /dev/null +++ b/templates/nagios/conf.d/hostgroups.cfg.j2 @@ -0,0 +1,10 @@ +{{ ansible_managed | comment }} + +{% for hostgroup in nagios_hostgroups | default([]) %} +define hostgroup { + hostgroup_name {{ hostgroup['hostgroup_name'] }} + alias {{ hostgroup['alias'] }} + members {{ hostgroup['members'] | sort | join(',') }} +} + +{% endfor %} diff --git a/templates/nagios/conf.d/hosts.cfg.j2 b/templates/nagios/conf.d/hosts.cfg.j2 new file mode 100644 index 0000000..fb7a26d --- /dev/null +++ b/templates/nagios/conf.d/hosts.cfg.j2 @@ -0,0 +1,11 @@ +{{ ansible_managed | comment }} + +{% for host in nagios_hosts | default([]) %} +define host { + use {{ host['use'] }} + host_name {{ host['host_name'] }} + alias {{ host['alias'] }} + address {{ host['address'] }} +} + +{% endfor %} diff --git a/templates/nagios/conf.d/services.cfg.j2 b/templates/nagios/conf.d/services.cfg.j2 new file mode 100644 index 0000000..1d9ac6e --- /dev/null +++ b/templates/nagios/conf.d/services.cfg.j2 @@ -0,0 +1,23 @@ +{{ ansible_managed | comment }} + +{% for service in nagios_services | default([]) %} +define service { + use {{ service['use'] }} + hostgroup_name {{ service['hostgroup_name'] }} + service_description {{ service['service_description'] }} + check_command {{ service['check_command'] }} +} + +{% endfor %} + +{% for service_dependency in nagios_service_dependencies | default([]) %} +define servicedependency { + host_name {{ service_dependency['host_name'] }} + service_description {{ service_dependency['service_description'] }} + dependent_host_name {{ service_dependency['dependent_host_name'] }} + dependent_service_description {{ service_dependency['dependent_service_description'] }} + execution_failure_criteria {{ service_dependency['execution_failure_criteria'] }} + notification_failure_criteria {{ service_dependency['notification_failure_criteria'] }} +} + +{% endfor %} diff --git a/templates/nagios/conf.d/templates.cfg.j2 b/templates/nagios/conf.d/templates.cfg.j2 new file mode 100644 index 0000000..ffce2f7 --- /dev/null +++ b/templates/nagios/conf.d/templates.cfg.j2 @@ -0,0 +1,31 @@ +{{ ansible_managed | comment }} + +{% for template in nagios_host_templates | default([]) %} +define host { + register 0 ; template + name {{ template['name'] }} + use {{ template['use'] }} + check_command {{ template['check_command'] }} + contact_groups {{ template['contact_groups'] }} + notification_options {{ template['notification_options'] | sort | join(',') }} + check_interval {{ template['check_interval'] }} + retry_interval {{ template['retry_interval'] }} + max_check_attempts {{ template['max_check_attempts'] }} + notification_interval {{ template['notification_interval'] }} +} + +{% endfor %} + +{% for template in nagios_service_templates | default([]) %} +define service { + register 0 ; template + name {{ template['name'] }} + use {{ template['use'] }} + contact_groups {{ template['contact_groups'] }} + check_interval {{ template['check_interval'] }} + retry_interval {{ template['retry_interval'] }} + max_check_attempts {{ template['max_check_attempts'] }} + notification_interval {{ template['notification_interval'] }} +} + +{% endfor %} diff --git a/templates/nagios/contacts.cfg.j2 b/templates/nagios/contacts.cfg.j2 new file mode 100644 index 0000000..e43216a --- /dev/null +++ b/templates/nagios/contacts.cfg.j2 @@ -0,0 +1,35 @@ +{{ ansible_managed | comment }} + +{% for contact in nagios_contacts | default([]) %} +define contact { + contact_name {{ contact['contact_name'] }} + use {{ contact['use'] }} + alias {{ contact['alias'] }} + email {{ contact['email'] }} +{% if 'pager' in contact %} + pager {{ contact['pager'] }} +{% endif %} +{% if 'host_notifications_enabled' in contact %} + host_notifications_enabled {{ contact['host_notifications_enabled'] }} +{% endif %} +{% if 'service_notifications_enabled' in contact %} + service_notifications_enabled {{ contact['service_notifications_enabled'] }} +{% endif %} +{% if 'host_notification_commands' in contact %} + host_notification_commands {{ contact['host_notification_commands'] }} +{% endif %} +{% if 'service_notification_commands' in contact %} + service_notification_commands {{ contact['service_notification_commands'] }} +{% endif %} +} + +{% endfor %} + +{% for contact_group in nagios_contact_groups | default([]) %} +define contactgroup { + contactgroup_name {{ contact_group['contactgroup_name'] }} + alias {{ contact_group['alias'] }} + members {{ contact_group['members'] | sort | join(',') }} +} + +{% endfor %} diff --git a/templates/nagios/htdigest.users.j2 b/templates/nagios/htdigest.users.j2 new file mode 100644 index 0000000..d9a0e5c --- /dev/null +++ b/templates/nagios/htdigest.users.j2 @@ -0,0 +1,3 @@ +{% for user in nagios_htdigest_users | default([]) %} +{{ user['name'] }}:{{ user['hash'] }} +{% endfor %} diff --git a/templates/nrpe/nagios-nrpe-server.j2 b/templates/nrpe/nagios-nrpe-server.j2 new file mode 100644 index 0000000..c22a4de --- /dev/null +++ b/templates/nrpe/nagios-nrpe-server.j2 @@ -0,0 +1,2 @@ +{{ ansible_managed | comment }} +NRPE_OPTS="{{ nrpe_opts | default('-n') }}" diff --git a/templates/nrpe/nrpe.cfg.j2 b/templates/nrpe/nrpe.cfg.j2 new file mode 100644 index 0000000..9511b62 --- /dev/null +++ b/templates/nrpe/nrpe.cfg.j2 @@ -0,0 +1,14 @@ +{{ ansible_managed | comment }} + +log_facility=daemon +debug=0 +pid_file=/var/run/nagios/nrpe.pid +server_port=5666 +nrpe_user=nagios +nrpe_group=nagios +allowed_hosts={{ nrpe_allowed_hosts | sort | join(',') }} +dont_blame_nrpe=0 +allow_bash_command_substitution=0 +command_timeout=60 +connection_timeout=300 +include=/etc/nagios/nrpe_local.cfg diff --git a/templates/nrpe/nrpe_local.cfg.j2 b/templates/nrpe/nrpe_local.cfg.j2 new file mode 100644 index 0000000..5d027b5 --- /dev/null +++ b/templates/nrpe/nrpe_local.cfg.j2 @@ -0,0 +1,6 @@ +{{ ansible_managed | comment }} + +{% for command in nrpe_commands | default([]) %} +command[{{ command['name'] }}]={{ command['line'] }} +{% endfor %} + diff --git a/templates/nrpe/ovh.conf.j2 b/templates/nrpe/ovh.conf.j2 new file mode 100644 index 0000000..0108f94 --- /dev/null +++ b/templates/nrpe/ovh.conf.j2 @@ -0,0 +1,8 @@ +{{ ansible_managed | comment }} +[default] +endpoint={{ ovh_endpoint }} + +[{{ ovh_endpoint }}] +application_key={{ ovh_application_key }} +application_secret={{ ovh_application_secret }} +consumer_key={{ ovh_consumer_key }} diff --git a/templates/openvpn/client.conf.j2 b/templates/openvpn/client.conf.j2 new file mode 100644 index 0000000..c1a291b --- /dev/null +++ b/templates/openvpn/client.conf.j2 @@ -0,0 +1,21 @@ +{{ ansible_managed | comment }} + +client +dev {{ openvpn_dev | default('tun') }} +proto {{ openvpn_proto | default('udp') }} +remote {{ openvpn_remote_host }} {{ openvpn_remote_port | default(1194) }} +resolv-retry infinite +nobind +user nobody +group nogroup +persist-key +persist-tun +ca ca.crt +cert client.crt +key client.key +remote-cert-tls server +tls-auth ta.key 1 +cipher AES-256-CBC +auth SHA256 +verb 3 +key-direction 1 diff --git a/templates/serial2mqtt/serial2mqtt.ini.j2 b/templates/serial2mqtt/serial2mqtt.ini.j2 new file mode 100644 index 0000000..2a231bb --- /dev/null +++ b/templates/serial2mqtt/serial2mqtt.ini.j2 @@ -0,0 +1,12 @@ +{{ ansible_managed | comment }} + +[mqtt] +host = {{ serial2mqtt_host | default('localhost') }} +port = {{ serial2mqtt_port | default(1883) }} +client_id = serial2mqtt +topic_prefix = {{ serial2mqtt_topic_prefix }} +username = {{ serial2mqtt_username }} +password = {{ serial2mqtt_password }} + +[serial] +interface = {{ serial2mqtt_interface | default('/dev/ttyACM0') }} diff --git a/templates/telegraf/influxdata.list.j2 b/templates/telegraf/influxdata.list.j2 new file mode 100644 index 0000000..0ed418c --- /dev/null +++ b/templates/telegraf/influxdata.list.j2 @@ -0,0 +1,2 @@ +{{ ansible_managed | comment }} +deb https://repos.influxdata.com/{{ ansible_distribution | lower }} {{ ansible_distribution_release }} stable diff --git a/templates/telegraf/inputs.conf.j2 b/templates/telegraf/inputs.conf.j2 new file mode 100644 index 0000000..c7d6412 --- /dev/null +++ b/templates/telegraf/inputs.conf.j2 @@ -0,0 +1,39 @@ +{{ ansible_managed | comment }} + +[[inputs.cpu]] + percpu = false + totalcpu = true + collect_cpu_time = false + report_active = false + +[[inputs.disk]] + mount_points = ["/", "/boot"] + +[[inputs.diskio]] + devices = ["mmcblk0"] + +[[inputs.kernel]] +[[inputs.mem]] +[[inputs.processes]] +[[inputs.swap]] +[[inputs.system]] +[[inputs.net]] + interfaces = ["eth0", "tun0"] + +[[inputs.sensors]] + +[[inputs.ping]] + urls = ["{{ telegraf_ping_ip }}"] + count = 3 + ping_interval = 1.0 + timeout = 1.0 + +[[inputs.mqtt_consumer]] + servers = {{ telegraf_mqtt_consumer_servers }} + topics = {{ telegraf_mqtt_consumer_topics }} + persistent_session = true + client_id = "telegraf" + data_format = "value" + data_type = "float" + username = "{{ telegraf_mqtt_consumer_username }}" + password = "{{ telegraf_mqtt_consumer_password }}" diff --git a/templates/telegraf/output.conf.j2 b/templates/telegraf/output.conf.j2 new file mode 100644 index 0000000..8d09636 --- /dev/null +++ b/templates/telegraf/output.conf.j2 @@ -0,0 +1,10 @@ +{{ ansible_managed | comment }} + +[[outputs.influxdb]] + urls = {{ telegraf_influxdb_urls }} + database = "{{ telegraf_influxdb_database }}" + skip_database_creation = true + username = "{{ telegraf_influxdb_username }}" + password = "{{ telegraf_influxdb_password }}" + insecure_skip_verify = true + content_encoding = "gzip" diff --git a/upgrade.yml b/upgrade.yml new file mode 100644 index 0000000..2654360 --- /dev/null +++ b/upgrade.yml @@ -0,0 +1,5 @@ +--- +- name: Upgrade systems + hosts: all + tasks: + - include_tasks: tasks/apt-upgrade.yml